@gentbajko/slopify 3.25.8 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (604) hide show
  1. package/dist/adapters/account-limits.js +30 -0
  2. package/dist/adapters/alignment/cache.js +3 -5
  3. package/dist/adapters/alignment/ctc.js +1 -2
  4. package/dist/adapters/alignment/lock.js +4 -3
  5. package/dist/adapters/alignment/multilingual.js +0 -3
  6. package/dist/adapters/alignment/prefetch.js +2 -1
  7. package/dist/adapters/alignment/worker.js +2 -1
  8. package/dist/adapters/explain.js +0 -3
  9. package/dist/adapters/ffmpeg.js +19 -1
  10. package/dist/adapters/host-cli/index.js +19 -3
  11. package/dist/adapters/http-failure.js +53 -0
  12. package/dist/adapters/image/codex.js +36 -4
  13. package/dist/adapters/image/fal.js +17 -50
  14. package/dist/adapters/image/google.js +31 -55
  15. package/dist/adapters/image/openai.js +20 -47
  16. package/dist/adapters/image/reference.js +36 -0
  17. package/dist/adapters/image/replicate.js +18 -47
  18. package/dist/adapters/interest/search-interest.js +113 -0
  19. package/dist/adapters/key-probes.js +53 -2
  20. package/dist/adapters/llm/antigravity.js +4 -0
  21. package/dist/adapters/llm/assistant-cli.js +388 -0
  22. package/dist/adapters/llm/child-session.js +83 -0
  23. package/dist/adapters/llm/claude-code-models.js +51 -98
  24. package/dist/adapters/llm/claude-code.js +13 -2
  25. package/dist/adapters/llm/codex-limits.js +27 -68
  26. package/dist/adapters/llm/codex-server-models.js +61 -109
  27. package/dist/adapters/llm/codex.js +12 -1
  28. package/dist/adapters/llm/openrouter.js +10 -47
  29. package/dist/adapters/llm/run-cli.js +6 -22
  30. package/dist/adapters/llm/sse-lines.js +5 -1
  31. package/dist/adapters/model-access.js +37 -0
  32. package/dist/adapters/tts/cartesia.js +15 -46
  33. package/dist/adapters/tts/elevenlabs.js +20 -52
  34. package/dist/adapters/tts/gemini.js +19 -40
  35. package/dist/adapters/tts/inworld-async.js +4 -1
  36. package/dist/adapters/tts/inworld.js +3 -0
  37. package/dist/adapters/tts/openai.js +20 -50
  38. package/dist/assets/models-lifecycle.yaml +6 -0
  39. package/dist/assistant-wiring.js +60 -0
  40. package/dist/autopilot-timers.js +59 -0
  41. package/dist/catalog/lifecycle.js +52 -0
  42. package/dist/catalog/propose.js +204 -0
  43. package/dist/catalog/registry.js +3 -1
  44. package/dist/catalog/schema.js +2 -0
  45. package/dist/catalog/store.js +39 -0
  46. package/dist/edge/autostart/native.js +3 -5
  47. package/dist/edge/autostart/prompt.js +2 -1
  48. package/dist/edge/autostart/service.js +3 -4
  49. package/dist/edge/cli-args.js +3 -4
  50. package/dist/edge/cli.js +2 -1
  51. package/dist/edge/docker-install/apply.js +11 -11
  52. package/dist/edge/docker-install/run.js +2 -1
  53. package/dist/edge/docker-install/state.js +4 -3
  54. package/dist/edge/docker-install/tree.js +2 -4
  55. package/dist/edge/docker-install/volume.js +3 -2
  56. package/dist/edge/docker.js +5 -4
  57. package/dist/edge/events/hub.js +5 -5
  58. package/dist/edge/http/actions.js +4 -25
  59. package/dist/edge/http/actor.js +5 -3
  60. package/dist/edge/http/app.js +85 -10
  61. package/dist/edge/http/assistant.js +127 -0
  62. package/dist/edge/http/audio-preview.js +4 -11
  63. package/dist/edge/http/auditions.js +1 -1
  64. package/dist/edge/http/autostart.js +5 -5
  65. package/dist/edge/http/backups.js +1 -3
  66. package/dist/edge/http/channel-memory.js +7 -20
  67. package/dist/edge/http/channels.js +13 -26
  68. package/dist/edge/http/checkpoints.js +33 -17
  69. package/dist/edge/http/design-templates.js +167 -0
  70. package/dist/edge/http/designs.js +178 -0
  71. package/dist/edge/http/diagnostics.js +5 -1
  72. package/dist/edge/http/document-themes.js +2 -11
  73. package/dist/edge/http/draft-files.js +1 -3
  74. package/dist/edge/http/draft-problem.js +4 -9
  75. package/dist/edge/http/drafts.js +3 -3
  76. package/dist/edge/http/entries.js +6 -9
  77. package/dist/edge/http/extension-auth.js +27 -0
  78. package/dist/edge/http/external-reviews.js +12 -11
  79. package/dist/edge/http/files.js +5 -11
  80. package/dist/edge/http/folder-location.js +1 -4
  81. package/dist/edge/http/fonts.js +0 -7
  82. package/dist/edge/http/home.js +38 -13
  83. package/dist/edge/http/host-cli.js +18 -8
  84. package/dist/edge/http/ids.js +8 -0
  85. package/dist/edge/http/keywords.js +35 -0
  86. package/dist/edge/http/model-checks.js +132 -0
  87. package/dist/edge/http/narration-peaks.js +5 -13
  88. package/dist/edge/http/onboarding.js +1 -14
  89. package/dist/edge/http/open-folder.js +5 -10
  90. package/dist/edge/http/outputs.js +4 -12
  91. package/dist/edge/http/patch-notes.js +4 -10
  92. package/dist/edge/http/planning.js +2 -6
  93. package/dist/edge/http/problem.js +2 -4
  94. package/dist/edge/http/project-create.js +1 -0
  95. package/dist/edge/http/project-templates.js +29 -17
  96. package/dist/edge/http/projects.js +2 -12
  97. package/dist/edge/http/prompts.js +7 -14
  98. package/dist/edge/http/pronunciations.js +1 -2
  99. package/dist/edge/http/providers.js +39 -24
  100. package/dist/edge/http/refusal.js +29 -0
  101. package/dist/edge/http/remote-access.js +40 -0
  102. package/dist/edge/http/remote-guard.js +71 -0
  103. package/dist/edge/http/request-guard.js +91 -0
  104. package/dist/edge/http/reviews.js +11 -24
  105. package/dist/edge/http/revision-files.js +5 -10
  106. package/dist/edge/http/revisions.js +10 -15
  107. package/dist/edge/http/run-cost.js +1 -2
  108. package/dist/edge/http/same-page.js +80 -0
  109. package/dist/edge/http/schedules.js +59 -32
  110. package/dist/edge/http/settings.js +22 -13
  111. package/dist/edge/http/social.js +282 -0
  112. package/dist/edge/http/staging.js +2 -4
  113. package/dist/edge/http/storage-files.js +5 -7
  114. package/dist/edge/http/storage.js +23 -23
  115. package/dist/edge/http/studio.js +23 -50
  116. package/dist/edge/http/style-preview.js +1 -4
  117. package/dist/edge/http/subtitles.js +3 -17
  118. package/dist/edge/http/template-studio.js +433 -0
  119. package/dist/edge/http/trash.js +10 -11
  120. package/dist/edge/http/tutorial.js +1 -2
  121. package/dist/edge/http/tutorials.js +5 -11
  122. package/dist/edge/http/update.js +7 -13
  123. package/dist/edge/http/waveform.js +3 -6
  124. package/dist/edge/http/youtube-edits.js +2 -3
  125. package/dist/edge/mcp/assistant.js +279 -0
  126. package/dist/edge/mcp/attribution.js +8 -2
  127. package/dist/edge/mcp/call-route.js +11 -2
  128. package/dist/edge/mcp/excluded-routes.js +25 -0
  129. package/dist/edge/mcp/http.js +11 -2
  130. package/dist/edge/mcp/instructions.js +5 -3
  131. package/dist/edge/mcp/library-tools.js +1 -0
  132. package/dist/edge/mcp/route-tool.js +35 -15
  133. package/dist/edge/mcp/server.js +13 -8
  134. package/dist/edge/mcp/tools-channels.js +2 -0
  135. package/dist/edge/mcp/tools-designs.js +165 -0
  136. package/dist/edge/mcp/tools-library.js +14 -2
  137. package/dist/edge/mcp/tools-planning.js +23 -4
  138. package/dist/edge/mcp/tools-projects.js +28 -1
  139. package/dist/edge/mcp/tools-runs.js +14 -1
  140. package/dist/edge/mcp/tools-schedules.js +28 -4
  141. package/dist/edge/mcp/tools-setup.js +61 -3
  142. package/dist/edge/mcp/tools-social.js +46 -0
  143. package/dist/edge/mcp/tools-storage.js +8 -0
  144. package/dist/edge/mcp/tools-template-studio.js +166 -0
  145. package/dist/edge/mcp/tools.js +6 -0
  146. package/dist/edge/remote-access/cli.js +71 -0
  147. package/dist/edge/remote-access/model.js +32 -0
  148. package/dist/edge/remote-access/rules.js +207 -0
  149. package/dist/edge/remote-access/service.js +203 -0
  150. package/dist/edge/remote-access/store.js +44 -0
  151. package/dist/edge/remote-access/views.js +43 -0
  152. package/dist/extension/slopify-studio-chrome.zip +0 -0
  153. package/dist/extension/slopify-studio-firefox.zip +0 -0
  154. package/dist/host-cli/install.js +2 -2
  155. package/dist/host-cli/open-folder.js +2 -2
  156. package/dist/host-cli/paths.js +2 -4
  157. package/dist/host-cli/server.js +4 -4
  158. package/dist/host-cli/service.js +3 -3
  159. package/dist/host-cli/status.js +7 -7
  160. package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
  161. package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
  162. package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
  163. package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
  164. package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
  165. package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
  166. package/dist/kernel/db/migrations/0070-designs.sql +53 -0
  167. package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
  168. package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
  169. package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
  170. package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
  171. package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
  172. package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
  173. package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
  174. package/dist/kernel/db/tx.js +2 -4
  175. package/dist/kernel/errors.js +27 -1
  176. package/dist/kernel/json-answer.js +15 -0
  177. package/dist/kernel/lock.js +4 -9
  178. package/dist/kernel/paths.js +8 -0
  179. package/dist/kernel/ports/assistant-cli.js +4 -0
  180. package/dist/kernel/ports/host-cli.js +3 -0
  181. package/dist/kernel/ports/interest.js +4 -0
  182. package/dist/kernel/ports/languages.js +0 -3
  183. package/dist/kernel/ports/model.js +2 -0
  184. package/dist/kernel/runner/attempt.js +3 -1
  185. package/dist/kernel/runner/audition.js +3 -1
  186. package/dist/kernel/runner/checkpoint-authority.js +2 -1
  187. package/dist/kernel/runner/index.js +8 -10
  188. package/dist/kernel/runner/model-access.js +40 -0
  189. package/dist/kernel/runner/model-check.js +153 -0
  190. package/dist/kernel/runner/providers.js +15 -10
  191. package/dist/kernel/runner/standalone.js +9 -5
  192. package/dist/main.js +334 -19
  193. package/dist/model-checks.js +166 -0
  194. package/dist/patch-notes/3.25.9.md +5 -0
  195. package/dist/patch-notes/4.0.0.md +51 -0
  196. package/dist/patch-notes/index.json +12 -0
  197. package/dist/slices/admission/heads.js +2 -1
  198. package/dist/slices/admission/repo.js +2 -1
  199. package/dist/slices/admission/rules.js +43 -8
  200. package/dist/slices/admission/schema.js +8 -0
  201. package/dist/slices/admission/stage-writes.js +0 -3
  202. package/dist/slices/admission/start.js +48 -31
  203. package/dist/slices/admission/substitute.js +7 -4
  204. package/dist/slices/agents/attention-posts.js +31 -0
  205. package/dist/slices/agents/attention-templates.js +33 -0
  206. package/dist/slices/agents/attention.js +10 -1
  207. package/dist/slices/agents/connection.js +2 -6
  208. package/dist/slices/agents/model.js +6 -3
  209. package/dist/slices/agents/repo.js +15 -7
  210. package/dist/slices/article/continuation.js +0 -63
  211. package/dist/slices/article/plain.js +3 -2
  212. package/dist/slices/article/segments.js +2 -62
  213. package/dist/slices/assistant/access.js +1 -0
  214. package/dist/slices/assistant/asks.js +80 -0
  215. package/dist/slices/assistant/cost.js +54 -0
  216. package/dist/slices/assistant/gate.js +222 -0
  217. package/dist/slices/assistant/model.js +79 -0
  218. package/dist/slices/assistant/names.js +23 -0
  219. package/dist/slices/assistant/prompt.js +74 -0
  220. package/dist/slices/assistant/repo.js +74 -0
  221. package/dist/slices/assistant/tokens.js +18 -0
  222. package/dist/slices/assistant/turn.js +342 -0
  223. package/dist/slices/autopilot/buffer.js +76 -0
  224. package/dist/slices/autopilot/model.js +14 -0
  225. package/dist/slices/autopilot/notify.js +27 -0
  226. package/dist/slices/autopilot/repo.js +34 -0
  227. package/dist/slices/autopilot/signals.js +194 -0
  228. package/dist/slices/autopilot/warnings.js +85 -0
  229. package/dist/slices/autopilot/weekly.js +100 -0
  230. package/dist/slices/backups/files.js +2 -6
  231. package/dist/slices/backups/repo.js +3 -15
  232. package/dist/slices/backups/service.js +4 -3
  233. package/dist/slices/channels/cast-images.js +2 -1
  234. package/dist/slices/channels/model.js +0 -1
  235. package/dist/slices/channels/rebrand.js +0 -3
  236. package/dist/slices/channels/repo.js +4 -0
  237. package/dist/slices/channels/schema.js +6 -0
  238. package/dist/slices/channels/service.js +10 -0
  239. package/dist/slices/channels/videos.js +2 -14
  240. package/dist/slices/checkpoints/index.js +0 -1
  241. package/dist/slices/control/providers.js +0 -26
  242. package/dist/slices/designs/artwork.js +66 -0
  243. package/dist/slices/designs/budget.js +23 -0
  244. package/dist/slices/designs/calls.js +124 -0
  245. package/dist/slices/designs/check-context.js +38 -0
  246. package/dist/slices/designs/check-text.js +43 -0
  247. package/dist/slices/designs/fields.js +88 -0
  248. package/dist/slices/designs/frames.js +34 -0
  249. package/dist/slices/designs/gate.js +128 -0
  250. package/dist/slices/designs/layout.js +293 -0
  251. package/dist/slices/designs/model.js +35 -0
  252. package/dist/slices/designs/pdf-job.js +23 -0
  253. package/dist/slices/designs/pdf-pages.js +30 -0
  254. package/dist/slices/designs/pdf-runner.js +68 -0
  255. package/dist/slices/designs/pdf-worker.js +24 -0
  256. package/dist/slices/designs/picture-size.js +79 -0
  257. package/dist/slices/designs/pictures.js +55 -0
  258. package/dist/slices/designs/quote.js +24 -0
  259. package/dist/slices/designs/render-args.js +36 -0
  260. package/dist/slices/designs/render-input.js +59 -0
  261. package/dist/slices/designs/render.js +215 -0
  262. package/dist/slices/designs/repo.js +101 -0
  263. package/dist/slices/designs/requests.js +80 -0
  264. package/dist/slices/designs/runner.js +239 -0
  265. package/dist/slices/designs/sample-repo.js +91 -0
  266. package/dist/slices/designs/sample.js +222 -0
  267. package/dist/slices/designs/schema.js +87 -0
  268. package/dist/slices/designs/sections.js +44 -0
  269. package/dist/slices/designs/service.js +233 -0
  270. package/dist/slices/designs/steps-repo.js +102 -0
  271. package/dist/slices/designs/studio-kind.js +39 -0
  272. package/dist/slices/designs/template-checks.js +44 -0
  273. package/dist/slices/designs/template-make.js +118 -0
  274. package/dist/slices/designs/templates.js +218 -0
  275. package/dist/slices/document/fonts.js +2 -1
  276. package/dist/slices/episodes/summarize.js +5 -1
  277. package/dist/slices/estimate/index.js +45 -7
  278. package/dist/slices/fonts/catalog.js +3 -2
  279. package/dist/slices/fonts/discovery.js +3 -2
  280. package/dist/slices/fonts/files.js +2 -6
  281. package/dist/slices/fonts/index.js +0 -1
  282. package/dist/slices/fonts/sfnt.js +45 -10
  283. package/dist/slices/images/appearance.js +6 -15
  284. package/dist/slices/images/scenes.js +100 -27
  285. package/dist/slices/keywords/digest.js +84 -0
  286. package/dist/slices/keywords/facts.js +92 -0
  287. package/dist/slices/keywords/fill.js +80 -0
  288. package/dist/slices/keywords/model.js +75 -0
  289. package/dist/slices/keywords/rules.js +187 -0
  290. package/dist/slices/keywords/schema.js +28 -0
  291. package/dist/slices/keywords/specs.js +260 -0
  292. package/dist/slices/keywords/values.js +74 -0
  293. package/dist/slices/library/lint.js +29 -12
  294. package/dist/slices/library/model.js +2 -0
  295. package/dist/slices/library/photorealistic.js +4 -12
  296. package/dist/slices/library/rename.js +9 -7
  297. package/dist/slices/library/save.js +14 -10
  298. package/dist/slices/library/slots.js +37 -11
  299. package/dist/slices/library/transfer.js +2 -1
  300. package/dist/slices/library/used-by.js +25 -10
  301. package/dist/slices/loudness/loudnorm.js +51 -11
  302. package/dist/slices/model-checks/cost.js +61 -0
  303. package/dist/slices/model-checks/listing.js +124 -0
  304. package/dist/slices/model-checks/model.js +20 -0
  305. package/dist/slices/model-checks/record.js +32 -0
  306. package/dist/slices/model-checks/repo.js +120 -0
  307. package/dist/slices/model-checks/rules.js +112 -0
  308. package/dist/slices/model-checks/run.js +143 -0
  309. package/dist/slices/model-checks/service.js +198 -0
  310. package/dist/slices/model-upkeep/switch.js +70 -25
  311. package/dist/slices/model-upkeep/usage.js +26 -11
  312. package/dist/slices/narration/breaths.js +2 -1
  313. package/dist/slices/narration/clean-pieces.js +2 -1
  314. package/dist/slices/narration/concat.js +2 -1
  315. package/dist/slices/narration/peaks.js +3 -4
  316. package/dist/slices/narration/pronunciation-chunks.js +4 -3
  317. package/dist/slices/narration/pronunciation.js +3 -2
  318. package/dist/slices/narration/steering.js +4 -3
  319. package/dist/slices/notifications/notifier.js +4 -3
  320. package/dist/slices/notifications/rules.js +5 -2
  321. package/dist/slices/notifications/settings.js +4 -12
  322. package/dist/slices/notifications/subject.js +2 -1
  323. package/dist/slices/onboarding/copy.js +2 -1
  324. package/dist/slices/onboarding/first-run.js +3 -2
  325. package/dist/slices/onboarding/full-video.js +3 -2
  326. package/dist/slices/onboarding/install.js +4 -3
  327. package/dist/slices/onboarding/model.js +0 -16
  328. package/dist/slices/onboarding/packs.js +22 -22
  329. package/dist/slices/onboarding/quick-short.js +2 -1
  330. package/dist/slices/onboarding/sample.js +0 -1
  331. package/dist/slices/onboarding/state.js +2 -11
  332. package/dist/slices/onboarding/template.js +2 -1
  333. package/dist/slices/patch-notes/library.js +3 -2
  334. package/dist/slices/play-drafts/convert.js +4 -0
  335. package/dist/slices/play-drafts/review-inputs.js +8 -2
  336. package/dist/slices/play-drafts/review.js +5 -4
  337. package/dist/slices/play-drafts/schema.js +4 -0
  338. package/dist/slices/project-templates/from-project.js +9 -2
  339. package/dist/slices/project-templates/repo.js +6 -1
  340. package/dist/slices/project-templates/setup.js +8 -0
  341. package/dist/slices/project-templates/stand-ins.js +22 -0
  342. package/dist/slices/rebuild/activity.js +2 -0
  343. package/dist/slices/rebuild/admission-repo.js +3 -2
  344. package/dist/slices/rebuild/narration-history.js +4 -5
  345. package/dist/slices/rebuild/narration-retry.js +2 -1
  346. package/dist/slices/rebuild/preview-details.js +27 -9
  347. package/dist/slices/rebuild/preview-plan.js +3 -8
  348. package/dist/slices/rebuild/recipe-build.js +8 -3
  349. package/dist/slices/rebuild/recipe-describe.js +3 -3
  350. package/dist/slices/rebuild/recipe-digest.js +58 -0
  351. package/dist/slices/rebuild/recipe-input-schema.js +10 -0
  352. package/dist/slices/rebuild/recipe-keywords.js +71 -0
  353. package/dist/slices/rebuild/recipe-legacy.js +5 -1
  354. package/dist/slices/rebuild/recipe-model.js +4 -0
  355. package/dist/slices/rebuild/recipe-narration-text.js +2 -1
  356. package/dist/slices/rebuild/recipe-preparation.js +3 -3
  357. package/dist/slices/rebuild/recipe-reference.js +8 -4
  358. package/dist/slices/rebuild/recipe-reviews.js +27 -7
  359. package/dist/slices/rebuild/recipe-save.js +6 -3
  360. package/dist/slices/rebuild/recipe-scenes.js +40 -11
  361. package/dist/slices/rebuild/recipe-shorts.js +8 -8
  362. package/dist/slices/rebuild/recipe-social.js +46 -0
  363. package/dist/slices/rebuild/recipe-text.js +64 -20
  364. package/dist/slices/rebuild/recipe-validation.js +98 -28
  365. package/dist/slices/rebuild/recipe-visual.js +55 -16
  366. package/dist/slices/rebuild/recipe-work.js +15 -3
  367. package/dist/slices/rebuild/recipe-youtube.js +4 -3
  368. package/dist/slices/rebuild/recovery-selection.js +3 -1
  369. package/dist/slices/rebuild/recovery.js +3 -2
  370. package/dist/slices/rebuild/repo.js +4 -3
  371. package/dist/slices/rebuild/review-promise.js +25 -0
  372. package/dist/slices/rebuild/review-redo.js +2 -1
  373. package/dist/slices/rebuild/runtime-admission.js +4 -3
  374. package/dist/slices/rebuild/runtime-agent-review.js +11 -5
  375. package/dist/slices/rebuild/runtime-animate.js +9 -8
  376. package/dist/slices/rebuild/runtime-article.js +3 -2
  377. package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
  378. package/dist/slices/rebuild/runtime-document.js +8 -11
  379. package/dist/slices/rebuild/runtime-export-bed.js +6 -11
  380. package/dist/slices/rebuild/runtime-export-edit.js +6 -15
  381. package/dist/slices/rebuild/runtime-export-inputs.js +7 -7
  382. package/dist/slices/rebuild/runtime-export-short.js +8 -4
  383. package/dist/slices/rebuild/runtime-export.js +34 -12
  384. package/dist/slices/rebuild/runtime-figure-card.js +2 -1
  385. package/dist/slices/rebuild/runtime-image.js +4 -9
  386. package/dist/slices/rebuild/runtime-instructions.js +2 -0
  387. package/dist/slices/rebuild/runtime-keywords.js +59 -0
  388. package/dist/slices/rebuild/runtime-lines.js +2 -11
  389. package/dist/slices/rebuild/runtime-local.js +14 -20
  390. package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
  391. package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
  392. package/dist/slices/rebuild/runtime-narration-text.js +10 -15
  393. package/dist/slices/rebuild/runtime-pictures.js +2 -4
  394. package/dist/slices/rebuild/runtime-piece-label.js +10 -6
  395. package/dist/slices/rebuild/runtime-plan.js +31 -5
  396. package/dist/slices/rebuild/runtime-provider.js +60 -19
  397. package/dist/slices/rebuild/runtime-publication.js +10 -9
  398. package/dist/slices/rebuild/runtime-review.js +33 -28
  399. package/dist/slices/rebuild/runtime-run.js +4 -1
  400. package/dist/slices/rebuild/runtime-shorts.js +34 -50
  401. package/dist/slices/rebuild/runtime-store.js +3 -8
  402. package/dist/slices/rebuild/runtime-subtitles.js +16 -14
  403. package/dist/slices/rebuild/runtime-voices.js +8 -15
  404. package/dist/slices/rebuild/runtime-youtube.js +11 -29
  405. package/dist/slices/rebuild/transition-repo.js +6 -5
  406. package/dist/slices/rebuild/work-records.js +6 -0
  407. package/dist/slices/reruns/cascade.js +1 -2
  408. package/dist/slices/reruns/index.js +6 -9
  409. package/dist/slices/reviews/external-model.js +3 -0
  410. package/dist/slices/reviews/external-repo.js +2 -1
  411. package/dist/slices/reviews/external-rows.js +2 -3
  412. package/dist/slices/reviews/model.js +26 -8
  413. package/dist/slices/reviews/repo.js +2 -1
  414. package/dist/slices/reviews/rules.js +1 -0
  415. package/dist/slices/reviews/view.js +5 -2
  416. package/dist/slices/revisions/downloads.js +4 -5
  417. package/dist/slices/revisions/mutation-assets.js +7 -4
  418. package/dist/slices/revisions/mutation-cues.js +2 -5
  419. package/dist/slices/revisions/mutations.js +0 -1
  420. package/dist/slices/revisions/repo.js +3 -1
  421. package/dist/slices/revisions/schema.js +1 -0
  422. package/dist/slices/revisions/view.js +20 -0
  423. package/dist/slices/run-cost/limits.js +5 -2
  424. package/dist/slices/run-cost/meter.js +12 -5
  425. package/dist/slices/run-cost/panel.js +8 -74
  426. package/dist/slices/run-cost/plan-readings.js +127 -0
  427. package/dist/slices/run-cost/plan-use.js +169 -0
  428. package/dist/slices/run-cost/pricing.js +3 -3
  429. package/dist/slices/run-cost/week.js +32 -4
  430. package/dist/slices/schedules/agenda.js +11 -2
  431. package/dist/slices/schedules/by-date.js +42 -0
  432. package/dist/slices/schedules/calendar.js +5 -0
  433. package/dist/slices/schedules/design-agenda.js +36 -0
  434. package/dist/slices/schedules/design-check.js +41 -0
  435. package/dist/slices/schedules/design-run.js +126 -0
  436. package/dist/slices/schedules/next-run.js +62 -0
  437. package/dist/slices/schedules/prepare.js +18 -2
  438. package/dist/slices/schedules/repo.js +24 -16
  439. package/dist/slices/schedules/rescore.js +35 -0
  440. package/dist/slices/schedules/scheduler.js +13 -3
  441. package/dist/slices/schedules/schema.js +54 -3
  442. package/dist/slices/schedules/score.js +107 -0
  443. package/dist/slices/schedules/service.js +57 -24
  444. package/dist/slices/schedules/topic-list.js +15 -0
  445. package/dist/slices/schedules/topic-scores.js +104 -0
  446. package/dist/slices/schedules/topics.js +48 -36
  447. package/dist/slices/settings/cli-paths.js +4 -6
  448. package/dist/slices/settings/first-run.js +2 -11
  449. package/dist/slices/settings/model-reach.js +3 -17
  450. package/dist/slices/settings/model.js +10 -0
  451. package/dist/slices/settings/playback.js +33 -22
  452. package/dist/slices/settings/probe-read.js +16 -0
  453. package/dist/slices/settings/repo.js +33 -0
  454. package/dist/slices/settings/tutorial.js +2 -2
  455. package/dist/slices/settings/voices.js +4 -12
  456. package/dist/slices/shorts/pick.js +2 -15
  457. package/dist/slices/shorts/prompts.js +2 -13
  458. package/dist/slices/shorts/render.js +3 -0
  459. package/dist/slices/social/channel.js +44 -0
  460. package/dist/slices/social/defaults.js +17 -0
  461. package/dist/slices/social/due.js +36 -0
  462. package/dist/slices/social/extension.js +18 -0
  463. package/dist/slices/social/fit.js +115 -0
  464. package/dist/slices/social/limits.js +186 -0
  465. package/dist/slices/social/links.js +21 -0
  466. package/dist/slices/social/media.js +131 -0
  467. package/dist/slices/social/model.js +75 -0
  468. package/dist/slices/social/notice.js +19 -0
  469. package/dist/slices/social/pack.js +176 -0
  470. package/dist/slices/social/post-prompt.js +55 -0
  471. package/dist/slices/social/queue.js +31 -0
  472. package/dist/slices/social/repo.js +133 -0
  473. package/dist/slices/social/reshape.js +97 -0
  474. package/dist/slices/social/rules.js +5 -0
  475. package/dist/slices/social/schema.js +70 -0
  476. package/dist/slices/social/serve.js +51 -0
  477. package/dist/slices/social/service.js +128 -0
  478. package/dist/slices/social/settings.js +21 -0
  479. package/dist/slices/social/sources.js +114 -0
  480. package/dist/slices/social/state.js +110 -0
  481. package/dist/slices/social/text.js +149 -0
  482. package/dist/slices/storage/arrange.js +3 -1
  483. package/dist/slices/storage/assets.js +8 -10
  484. package/dist/slices/storage/backup-designs.js +74 -0
  485. package/dist/slices/storage/backup-export.js +8 -3
  486. package/dist/slices/storage/backup-format.js +10 -0
  487. package/dist/slices/storage/backup-import.js +20 -2
  488. package/dist/slices/storage/delete-project.js +6 -5
  489. package/dist/slices/storage/files-location.js +6 -8
  490. package/dist/slices/storage/layout.js +13 -2
  491. package/dist/slices/storage/model.js +3 -0
  492. package/dist/slices/storage/portable.js +16 -11
  493. package/dist/slices/storage/schema.js +2 -0
  494. package/dist/slices/storage/staging-refs.js +2 -1
  495. package/dist/slices/storage/staging.js +6 -9
  496. package/dist/slices/storage/trim.js +10 -3
  497. package/dist/slices/studio/calendar.js +4 -1
  498. package/dist/slices/studio/pick.js +2 -11
  499. package/dist/slices/studio/plan.js +6 -15
  500. package/dist/slices/studio/queue.js +3 -14
  501. package/dist/slices/studio/releases.js +26 -0
  502. package/dist/slices/studio/settings.js +14 -51
  503. package/dist/slices/studio/videos.js +12 -0
  504. package/dist/slices/style-preview/render.js +34 -13
  505. package/dist/slices/style-preview/schema.js +13 -0
  506. package/dist/slices/style-preview/service.js +2 -1
  507. package/dist/slices/style-preview/settings.js +33 -5
  508. package/dist/slices/telemetry/collector-client.js +2 -4
  509. package/dist/slices/telemetry/flush.js +2 -4
  510. package/dist/slices/telemetry/model.js +0 -7
  511. package/dist/slices/telemetry/record.js +10 -3
  512. package/dist/slices/template-studio/anatomy-view.js +118 -0
  513. package/dist/slices/template-studio/anatomy.js +73 -0
  514. package/dist/slices/template-studio/bakeoff-make.js +225 -0
  515. package/dist/slices/template-studio/bakeoff-repo.js +83 -0
  516. package/dist/slices/template-studio/bakeoff.js +333 -0
  517. package/dist/slices/template-studio/budget.js +103 -0
  518. package/dist/slices/template-studio/checks.js +273 -0
  519. package/dist/slices/template-studio/document-sample.js +56 -0
  520. package/dist/slices/template-studio/edit.js +15 -0
  521. package/dist/slices/template-studio/for-all.js +161 -0
  522. package/dist/slices/template-studio/free-video.js +31 -0
  523. package/dist/slices/template-studio/free.js +176 -0
  524. package/dist/slices/template-studio/gate.js +40 -0
  525. package/dist/slices/template-studio/hidden.js +20 -0
  526. package/dist/slices/template-studio/jobs.js +79 -0
  527. package/dist/slices/template-studio/loudness.js +111 -0
  528. package/dist/slices/template-studio/make.js +40 -0
  529. package/dist/slices/template-studio/model.js +54 -0
  530. package/dist/slices/template-studio/pack-import.js +253 -0
  531. package/dist/slices/template-studio/pack-samples.js +60 -0
  532. package/dist/slices/template-studio/pack.js +205 -0
  533. package/dist/slices/template-studio/paid-view.js +66 -0
  534. package/dist/slices/template-studio/paid.js +348 -0
  535. package/dist/slices/template-studio/quote.js +148 -0
  536. package/dist/slices/template-studio/ready.js +104 -0
  537. package/dist/slices/template-studio/repo.js +134 -0
  538. package/dist/slices/template-studio/reviews-path.js +58 -0
  539. package/dist/slices/template-studio/runner.js +84 -0
  540. package/dist/slices/template-studio/save.js +236 -0
  541. package/dist/slices/template-studio/say-it-as.js +248 -0
  542. package/dist/slices/template-studio/schedule-gate.js +34 -0
  543. package/dist/slices/template-studio/schedule-price.js +30 -0
  544. package/dist/slices/template-studio/schedule-sample.js +87 -0
  545. package/dist/slices/template-studio/schema.js +218 -0
  546. package/dist/slices/template-studio/scope.js +124 -0
  547. package/dist/slices/template-studio/sections.js +176 -0
  548. package/dist/slices/template-studio/service.js +173 -0
  549. package/dist/slices/template-studio/status.js +174 -0
  550. package/dist/slices/template-studio/topic.js +223 -0
  551. package/dist/slices/trash/designs.js +76 -0
  552. package/dist/slices/trash/model.js +13 -4
  553. package/dist/slices/trash/service.js +52 -2
  554. package/dist/slices/tutorials/library.js +3 -2
  555. package/dist/slices/video/ass-text.js +17 -0
  556. package/dist/slices/video/audio-export.js +2 -64
  557. package/dist/slices/video/encoding.js +160 -0
  558. package/dist/slices/video/ffmpeg.js +23 -21
  559. package/dist/slices/video/figure-card.js +1 -15
  560. package/dist/slices/video/slideshow.js +43 -18
  561. package/dist/slices/voices/palette.js +0 -3
  562. package/dist/slices/youtube/answer.js +2 -15
  563. package/dist/slices/youtube/edits-repo.js +2 -11
  564. package/dist/tutorials/Agents-MCP.md +2 -1
  565. package/dist/tutorials/Assistant.md +42 -0
  566. package/dist/tutorials/Channels.md +2 -0
  567. package/dist/tutorials/Home-and-Projects.md +19 -0
  568. package/dist/tutorials/Install.md +1 -0
  569. package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
  570. package/dist/tutorials/Models.md +33 -1
  571. package/dist/tutorials/Notifications.md +6 -0
  572. package/dist/tutorials/Play-Images.md +4 -0
  573. package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
  574. package/dist/tutorials/Prompts.md +10 -6
  575. package/dist/tutorials/Remote-Access.md +63 -0
  576. package/dist/tutorials/Reviews-and-Checkpoints.md +13 -2
  577. package/dist/tutorials/Schedules.md +21 -1
  578. package/dist/tutorials/Settings-Reference.md +50 -8
  579. package/dist/tutorials/Template-Studio.md +125 -0
  580. package/dist/tutorials/Templates.md +3 -0
  581. package/dist/tutorials/_Sidebar.md +5 -0
  582. package/dist/updater/work-in-progress.js +42 -12
  583. package/dist/web/assets/index-CkAI_2E7.css +1 -0
  584. package/dist/web/assets/index-DcD0cdfo.js +334 -0
  585. package/dist/web/assets/{pdf-T7MCwjIv.js → pdf-TODRwF31.js} +1 -1
  586. package/dist/web/index.html +2 -2
  587. package/package.json +5 -1
  588. package/dist/slices/article/provided-entries.js +0 -66
  589. package/dist/slices/article/run.js +0 -145
  590. package/dist/slices/images/run.js +0 -234
  591. package/dist/slices/narration/legacy-plan.js +0 -58
  592. package/dist/slices/narration/run.js +0 -270
  593. package/dist/slices/rebuild/runtime-actions.js +0 -90
  594. package/dist/slices/research/run.js +0 -224
  595. package/dist/slices/subtitles/prepare.js +0 -194
  596. package/dist/slices/subtitles/transcript.js +0 -34
  597. package/dist/slices/thumbnail/run.js +0 -219
  598. package/dist/slices/video/audio-inputs.js +0 -33
  599. package/dist/slices/video/reuse-audio.js +0 -62
  600. package/dist/slices/video/run.js +0 -78
  601. package/dist/slices/video/write-export.js +0 -158
  602. package/dist/slices/video/write-subtitles.js +0 -59
  603. package/dist/web/assets/index-BadsoORk.css +0 -1
  604. package/dist/web/assets/index-D8LqNsCl.js +0 -326
@@ -0,0 +1,42 @@
1
+ /// <reference lib="esnext.temporal" />
2
+ import { validTimeZone } from "./calendar.js";
3
+ export function rowDate(row, dateField) {
4
+ const value = (row.values[dateField] ?? "").trim();
5
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value))
6
+ return undefined;
7
+ try {
8
+ return Temporal.PlainDate.from(value, { overflow: "reject" });
9
+ }
10
+ catch {
11
+ return undefined;
12
+ }
13
+ }
14
+ export function designOccurrences(rows, dateField, daysBefore, time, timeZone, now) {
15
+ if (!validTimeZone(timeZone))
16
+ return [];
17
+ const today = Temporal.Instant.fromEpochMilliseconds(now.valueOf())
18
+ .toZonedDateTimeISO(timeZone)
19
+ .toPlainDate();
20
+ const wanted = Temporal.PlainTime.from(time);
21
+ const found = [];
22
+ for (const [index, row] of rows.entries()) {
23
+ const date = rowDate(row, dateField);
24
+ if (date === undefined)
25
+ continue;
26
+ const over = Temporal.PlainDate.compare(date, today) < 0;
27
+ const planned = date
28
+ .subtract({ days: daysBefore })
29
+ .toPlainDateTime(wanted)
30
+ .toZonedDateTime(timeZone, { disambiguation: "compatible" }).epochMilliseconds;
31
+ found.push({
32
+ at: new Date(over ? now.valueOf() : Math.max(planned, now.valueOf())),
33
+ index,
34
+ over,
35
+ });
36
+ }
37
+ // Soonest first; rows due at the same moment keep their table order.
38
+ return found.toSorted((a, b) => a.at.valueOf() - b.at.valueOf() || a.index - b.index);
39
+ }
40
+ export function nextDesignOccurrence(rows, dateField, daysBefore, time, timeZone, now) {
41
+ return designOccurrences(rows, dateField, daysBefore, time, timeZone, now)[0] ?? null;
42
+ }
@@ -12,6 +12,11 @@ export const cadenceSchema = z.discriminatedUnion("kind", [
12
12
  days: z.array(z.number().int().min(0).max(6)).min(1).max(7).readonly(),
13
13
  })
14
14
  .strict(),
15
+ // A design schedule: each row of its table is made ahead of the date it holds, at this time
16
+ // (`by-date.ts`). Only design schedules use it, and `nextOccurrence` is never asked about it.
17
+ z
18
+ .object({ kind: z.literal("by-date"), time: z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/) })
19
+ .strict(),
15
20
  ]);
16
21
  export function validTimeZone(timeZone) {
17
22
  try {
@@ -0,0 +1,36 @@
1
+ import { designOccurrences } from "./by-date.js";
2
+ import { designPlanOf } from "./next-run.js";
3
+ // The calendar's runs of a design schedule: one per row still to make, on the day it is made,
4
+ // named by the row's title. A row whose date is over isn't shown; the scheduler skips it.
5
+ export function upcomingDesignRuns(db, schedule, now, from, to) {
6
+ if (schedule.cadence.kind !== "by-date")
7
+ return [];
8
+ const plan = designPlanOf(db, schedule.templateId);
9
+ if (plan === undefined)
10
+ return [];
11
+ return designOccurrences(schedule.items, plan.dateField, plan.daysBefore, schedule.cadence.time, schedule.timezone, now)
12
+ .filter((one) => !one.over && one.at >= from && one.at < to)
13
+ .map((one) => {
14
+ const row = schedule.items[one.index];
15
+ return {
16
+ at: one.at.toISOString(),
17
+ scheduleId: schedule.id,
18
+ scheduleName: schedule.name,
19
+ scheduleVersion: schedule.version,
20
+ paused: schedule.status === "paused",
21
+ templateId: schedule.templateId,
22
+ templateVersion: plan.readyVersion ?? plan.headVersion,
23
+ templateName: plan.name,
24
+ index: one.index,
25
+ topic: row?.title ?? null,
26
+ topicSource: "queued",
27
+ renderedTitle: row?.title ?? null,
28
+ prepared: null,
29
+ templateKind: "design",
30
+ timezone: schedule.timezone,
31
+ // A design template's readiness is the designs' own (runnableDesignVersion), not the
32
+ // template studio's.
33
+ notReady: false,
34
+ };
35
+ });
36
+ }
@@ -0,0 +1,41 @@
1
+ import { designFields } from "../designs/fields.js";
2
+ import { getTemplate } from "../designs/templates.js";
3
+ import { rowDate } from "./by-date.js";
4
+ import { designPlanOf } from "./next-run.js";
5
+ export function checkDesign(deps, input) {
6
+ const refuse = (message) => ({ ok: false, reason: "invalid-topics", message });
7
+ if (input.cadence.kind !== "by-date" ||
8
+ input.topicGeneration.mode !== "off" ||
9
+ input.topicKeyword !== null ||
10
+ input.releases.length > 0)
11
+ return {
12
+ ok: false,
13
+ reason: "invalid-input",
14
+ message: "A design schedule makes each row's piece ahead of its date: it has no cadence, topic generation or release days. Choose Ahead of each date.",
15
+ };
16
+ const template = getTemplate(deps.db, input.templateId);
17
+ if (template === undefined)
18
+ return { ok: false, reason: "missing-template" };
19
+ const plan = designPlanOf(deps.db, input.templateId);
20
+ if (plan === undefined)
21
+ return refuse(`The schedule wasn't saved. ${template.name} doesn't say which field holds each date. Open it in Library → Designs → Templates, choose the date field under Schedule, save it, then save the schedule again.`);
22
+ const fields = designFields(plan.document);
23
+ const named = fields.length === 0 ? "none" : fields.map((one) => `{{${one}}}`).join(", ");
24
+ const problems = [];
25
+ for (const keyword of Object.keys(input.values))
26
+ if (!fields.includes(keyword))
27
+ problems.push(`{{${keyword}}} (for every row) is not a field of this template (its fields are ${named}). Remove it.`);
28
+ for (const [index, row] of input.items.entries()) {
29
+ const where = `Row ${String(index + 1)} (${row.title})`;
30
+ for (const keyword of Object.keys(row.values))
31
+ if (!fields.includes(keyword))
32
+ problems.push(`${where} fills {{${keyword}}}, which this template doesn't use (its fields are ${named}). Remove that column.`);
33
+ if (rowDate(row, plan.dateField) === undefined)
34
+ problems.push(`${where} has no date in {{${plan.dateField}}}. Write it as YYYY-MM-DD, for example 2026-11-14.`);
35
+ }
36
+ if (problems.length === 0)
37
+ return { ok: true, value: template.headVersion };
38
+ const shown = problems.slice(0, 5);
39
+ const more = problems.length - shown.length;
40
+ return refuse(`The schedule wasn't saved. ${shown.join(" ")}${more > 0 ? ` And ${String(more)} more like these.` : ""}`);
41
+ }
@@ -0,0 +1,126 @@
1
+ /// <reference lib="esnext.temporal" />
2
+ import { transact } from "../../kernel/db/tx.js";
3
+ import { missingValues } from "../designs/fields.js";
4
+ import { makeFromTemplate, quoteDocument } from "../designs/template-make.js";
5
+ import { designOccurrences } from "./by-date.js";
6
+ import { nextOccurrence } from "./calendar.js";
7
+ import { designPlanOf, missedGraceMs, nextRunOf } from "./next-run.js";
8
+ import { insertRun, scheduleById, updateRun } from "./repo.js";
9
+ // One due run of a design schedule, all at once and in one transaction: it takes the row due
10
+ // soonest, makes its piece from the template's ready version and starts the artwork (the only
11
+ // paid step, made in the background by the design runner), removes the row and records the
12
+ // design on the run. Nothing here waits on a provider, so the tick moves on at once.
13
+ //
14
+ // A row whose date is over is removed with a skipped run that says so. A run that can't start
15
+ // (no ready version, a value missing, over the spend limit, no image provider) keeps its row,
16
+ // records why, and tries again at the same time the next day; marking a version ready tries
17
+ // again at once (`refreshDesignSchedules`). None of this reaches needs_attention: it shows on
18
+ // the schedule's runs.
19
+ export function claimDesignRun(deps, schedule, now) {
20
+ const designs = deps.designs?.();
21
+ transact(deps.db, () => {
22
+ const current = scheduleById(deps.db, schedule.id);
23
+ if (current === undefined ||
24
+ current.version !== schedule.version ||
25
+ current.nextRunAt !== schedule.nextRunAt ||
26
+ current.status !== "active" ||
27
+ current.cadence.kind !== "by-date")
28
+ return;
29
+ const time = current.cadence.time;
30
+ const plan = designPlanOf(deps.db, current.templateId);
31
+ const due = plan === undefined
32
+ ? undefined
33
+ : designOccurrences(current.items, plan.dateField, plan.daysBefore, time, current.timezone, now)[0];
34
+ // Rows edited meanwhile: nothing is due yet, so only the next run moves.
35
+ if (plan === undefined || due === undefined || due.at > now) {
36
+ setNext(deps, current, nextRunOf(deps.db, current, now), current.items, now);
37
+ return;
38
+ }
39
+ const row = current.items[due.index];
40
+ if (row === undefined)
41
+ return;
42
+ const run = (status, error) => ({
43
+ id: deps.uuid(),
44
+ scheduleId: current.id,
45
+ scheduledFor: schedule.nextRunAt ?? now.toISOString(),
46
+ status,
47
+ requestId: null,
48
+ projectIds: [],
49
+ designIds: [],
50
+ estimate: null,
51
+ startedAt: now.toISOString(),
52
+ endedAt: status === "running" ? null : now.toISOString(),
53
+ error,
54
+ });
55
+ const without = current.items.filter((_item, index) => index !== due.index);
56
+ const date = row.values[plan.dateField] ?? "";
57
+ if (due.over) {
58
+ insertRun(deps.db, run("skipped", `Skipped: ${row.title} on ${date} is already over.`));
59
+ setNext(deps, current, nextRunOf(deps.db, { ...current, items: without }, now), without, now);
60
+ return;
61
+ }
62
+ const tomorrow = () => {
63
+ const next = nextOccurrence({ kind: "daily", time }, current.timezone, now);
64
+ const soonest = nextRunOf(deps.db, current, new Date(now.valueOf() + 1000));
65
+ return next === null ? soonest : soonest === null || soonest < next ? next : soonest;
66
+ };
67
+ const keep = (status, error) => {
68
+ insertRun(deps.db, run(status, error));
69
+ setNext(deps, current, tomorrow(), current.items, now);
70
+ };
71
+ // A run Slopify wasn't open for, like a project schedule's: skipped when the schedule skips
72
+ // missed runs. The row stays and is tried again at the same time the next day.
73
+ const scheduledFor = schedule.nextRunAt === null ? now : new Date(schedule.nextRunAt);
74
+ if (current.missedPolicy === "skip" && now.valueOf() - scheduledFor.valueOf() > missedGraceMs)
75
+ return keep("skipped", `Skipped: Slopify wasn't open at ${time} when ${row.title}'s piece was due, and this schedule skips the runs it misses. It tries again at ${time} tomorrow; to make a missed piece as soon as Slopify opens, set Missed run to Run once when Slopify reopens in Library → Designs → Templates → ${plan.name} → Schedule.`);
76
+ if (designs === undefined)
77
+ return keep("failed", "Not started: designs aren't available in this copy of Slopify. Restart Slopify; if it keeps happening, reinstall it.");
78
+ if (plan.readyVersion === null)
79
+ return keep("skipped", `Not started: ${plan.name} has no version marked ready. Open it in Library → Designs → Templates and press Mark ready.`);
80
+ const missing = missingValues(plan.document, row.values);
81
+ if (missing.length > 0) {
82
+ const list = missing.map((name) => `{{${name}}}`).join(", ");
83
+ return keep("failed", `Not started: ${row.title} has no ${list} in its row. Fill ${missing.length === 1 ? "it" : "them"} in under Schedules → ${current.name}; the next try is at ${time}.`);
84
+ }
85
+ const quote = quoteDocument(designs.catalogue(), plan.document);
86
+ if (current.spendLimitCents !== null &&
87
+ (quote.unknown > 0 || quote.high * 100 > current.spendLimitCents))
88
+ return keep("failed", `Not started: ${row.title}'s piece costs up to $${quote.high.toFixed(2)}${quote.unknown > 0 ? " and some prices are unknown" : ""}, over this schedule's spend limit. Raise the spend limit or choose an image model with a known, lower price.`);
89
+ const started = run("running", null);
90
+ if (!insertRun(deps.db, started))
91
+ return;
92
+ const made = makeFromTemplate(designs, current.templateId, {
93
+ mutationId: `schedule-${started.id}`,
94
+ values: row.values,
95
+ acknowledgedHigh: quote.high,
96
+ // A schedule with no spend limit makes pieces whose price is unknown, as it always has.
97
+ acknowledgedUnknown: quote.unknown > 0,
98
+ version: plan.readyVersion,
99
+ name: row.title,
100
+ }, { scheduleId: current.id, scheduleRunId: started.id });
101
+ if (!made.ok) {
102
+ updateRun(deps.db, {
103
+ ...started,
104
+ status: "failed",
105
+ endedAt: now.toISOString(),
106
+ error: `Not started: ${made.message}`,
107
+ });
108
+ setNext(deps, current, tomorrow(), current.items, now);
109
+ return;
110
+ }
111
+ updateRun(deps.db, {
112
+ ...started,
113
+ status: "succeeded",
114
+ designIds: [made.value.id],
115
+ estimate: [quote],
116
+ endedAt: now.toISOString(),
117
+ });
118
+ setNext(deps, current, nextRunOf(deps.db, { ...current, items: without }, now), without, now);
119
+ });
120
+ }
121
+ // A design schedule stays active when its table empties: rows added later run as they come.
122
+ function setNext(deps, schedule, next, items, now) {
123
+ deps.db
124
+ .prepare("UPDATE schedules SET items_json=?, next_run_at=?, version=version+1, updated_at=? WHERE id=? AND version=?")
125
+ .run(JSON.stringify(items), next?.toISOString() ?? null, now.toISOString(), schedule.id, schedule.version);
126
+ }
@@ -0,0 +1,62 @@
1
+ import { runnableDesignVersion } from "../designs/gate.js";
2
+ import { getTemplate } from "../designs/templates.js";
3
+ import { nextDesignOccurrence } from "./by-date.js";
4
+ import { nextOccurrence } from "./calendar.js";
5
+ // How late a run may start and still count as on time; later, it was missed (Slopify was
6
+ // closed), and a schedule that skips missed runs skips it.
7
+ export const missedGraceMs = 60_000;
8
+ export function designPlanOf(db, templateId) {
9
+ const template = getTemplate(db, templateId);
10
+ if (template === undefined)
11
+ return undefined;
12
+ const ready = runnableDesignVersion(db, templateId);
13
+ const document = ready?.document ?? template.document;
14
+ const schedule = document.schedule;
15
+ if (schedule === undefined)
16
+ return undefined;
17
+ return {
18
+ name: ready?.name ?? template.name,
19
+ dateField: schedule.dateField,
20
+ daysBefore: schedule.daysBefore,
21
+ readyVersion: ready?.version ?? null,
22
+ headVersion: template.headVersion,
23
+ document,
24
+ };
25
+ }
26
+ export function nextRunOf(db, schedule, now) {
27
+ if (schedule.cadence.kind !== "by-date")
28
+ return nextOccurrence(schedule.cadence, schedule.timezone, now);
29
+ const plan = designPlanOf(db, schedule.templateId);
30
+ if (plan === undefined)
31
+ return null;
32
+ return (nextDesignOccurrence(schedule.items, plan.dateField, plan.daysBefore, schedule.cadence.time, schedule.timezone, now)?.at ?? null);
33
+ }
34
+ // Every active design schedule of a template takes its next run again, for when a version is
35
+ // marked ready or the template's dates change.
36
+ export function refreshDesignSchedules(db, templateId, now) {
37
+ const rows = db
38
+ .prepare(`SELECT id FROM schedules WHERE template_kind='design' AND template_id=? AND status='active' AND deleted_at IS NULL`)
39
+ .all(templateId)
40
+ .map((row) => String(row.id));
41
+ let changed = 0;
42
+ for (const id of rows) {
43
+ const raw = db
44
+ .prepare("SELECT cadence_json, timezone, items_json, next_run_at FROM schedules WHERE id=?")
45
+ .get(id);
46
+ if (raw === undefined)
47
+ continue;
48
+ const next = nextRunOf(db, {
49
+ templateKind: "design",
50
+ templateId,
51
+ timezone: String(raw.timezone),
52
+ cadence: JSON.parse(String(raw.cadence_json)),
53
+ items: JSON.parse(String(raw.items_json)),
54
+ }, now);
55
+ const at = next?.toISOString() ?? null;
56
+ if (at === raw.next_run_at)
57
+ continue;
58
+ db.prepare("UPDATE schedules SET next_run_at=?, version=version+1, updated_at=? WHERE id=?").run(at, now.toISOString(), id);
59
+ changed += 1;
60
+ }
61
+ return changed;
62
+ }
@@ -8,6 +8,7 @@ import { createDraft } from "../play-drafts/service.js";
8
8
  import { startPlayDraft } from "../play-drafts/start.js";
9
9
  import { freshTemplateDraft } from "../project-templates/setup.js";
10
10
  import { currentRevisionId } from "../revisions/repo.js";
11
+ import { notTemplateSample } from "../template-studio/repo.js";
11
12
  import { scheduleById } from "./repo.js";
12
13
  import { renderedTitle, scheduledValues } from "./topic-list.js";
13
14
  // The draft a schedule's run starts for one topic: the template as it is now, the topic in its
@@ -43,9 +44,19 @@ export async function prepareTopic(deps, input) {
43
44
  const schedule = scheduleById(deps.db, input.scheduleId);
44
45
  if (schedule === undefined)
45
46
  return { ok: false, reason: "not-found" };
47
+ // A design schedule's piece is made on its day; there is no video to hold back.
48
+ if (schedule.templateKind === "design")
49
+ return { ok: false, reason: "design" };
50
+ // A paused schedule makes nothing, ahead or on its day.
51
+ if (schedule.status === "paused")
52
+ return { ok: false, reason: "paused" };
46
53
  const topic = schedule.items.find((item) => item.title === input.title);
47
54
  if (topic === undefined)
48
55
  return { ok: false, reason: "not-found" };
56
+ // Prepared ahead is the schedule's run made early: it waits for a ready version too.
57
+ const notReady = deps.notReady?.(schedule.templateId);
58
+ if (notReady !== undefined)
59
+ return { ok: false, reason: "not-ready", detail: notReady };
49
60
  const document = scheduledDocument(deps, schedule, topic);
50
61
  if (document === undefined)
51
62
  return { ok: false, reason: "missing-template" };
@@ -104,9 +115,13 @@ const ended = new Set(["done", "partial", "failed", "canceled"]);
104
115
  // run the same title, so only a prepared project counts there.
105
116
  export function preparedProject(db, scheduleId, title, byTitle = true) {
106
117
  const live = "project_id NOT IN (SELECT project_id FROM project_trash)";
118
+ // A template studio sample is titled from the template's next queued topic, so it can have
119
+ // the run's title; it is the studio's alone and never the run's to continue.
107
120
  const prepared = db
108
121
  .prepare(`SELECT project_id, added_checkpoint FROM prepared_videos
109
- WHERE schedule_id=? AND title=? AND ${live} ORDER BY prepared_at DESC LIMIT 1`)
122
+ WHERE schedule_id=? AND title=? AND ${live}
123
+ AND ${notTemplateSample("prepared_videos", "project_id")}
124
+ ORDER BY prepared_at DESC LIMIT 1`)
110
125
  .get(scheduleId, title);
111
126
  // A prepared project canceled since is no video to continue: the day makes a new one.
112
127
  if (typeof prepared?.project_id === "string" &&
@@ -115,7 +130,8 @@ export function preparedProject(db, scheduleId, title, byTitle = true) {
115
130
  if (!byTitle)
116
131
  return undefined;
117
132
  for (const row of db
118
- .prepare("SELECT id FROM projects WHERE title=? AND id NOT IN (SELECT project_id FROM project_trash) ORDER BY created_at DESC")
133
+ .prepare(`SELECT id FROM projects WHERE title=? AND id NOT IN (SELECT project_id FROM project_trash)
134
+ AND ${notTemplateSample()} ORDER BY created_at DESC`)
119
135
  .all(title)) {
120
136
  const id = String(row.id);
121
137
  if (!ended.has(derive(stagesOf(db, id), projectPaused(db, id))))
@@ -8,6 +8,7 @@ import { scheduleRunSchema, scheduleSummarySchema, } from "./schema.js";
8
8
  const rowSchema = z.object({
9
9
  id: z.string(),
10
10
  name: z.string(),
11
+ template_kind: z.string(),
11
12
  template_id: z.string(),
12
13
  template_version: z.number(),
13
14
  cadence_json: z.string(),
@@ -33,12 +34,13 @@ const rowSchema = z.object({
33
34
  topics_failed_at: z.string().nullable(),
34
35
  topics_error: z.string().nullable(),
35
36
  releases_json: z.string().nullable(),
37
+ topic_scoring: z.string(),
36
38
  held_topics: z.number(),
37
39
  });
38
- const scheduleColumns = `id,name,template_id,template_version,cadence_json,timezone,missed_policy,
40
+ const scheduleColumns = `id,name,template_kind,template_id,template_version,cadence_json,timezone,missed_policy,
39
41
  overlap_policy,spend_limit_cents,items_json,topic_keyword,values_json,status,version,next_run_at,
40
42
  created_at,updated_at,deleted_at,brief,topic_mode,topic_min,topic_llm_json,topics_generating_at,
41
- topics_generated_at,topics_failed_at,topics_error,releases_json,
43
+ topics_generated_at,topics_failed_at,topics_error,releases_json,topic_scoring,
42
44
  (SELECT count(*) FROM schedule_topics AS held
43
45
  WHERE held.schedule_id=schedules.id AND held.state='held') AS held_topics`;
44
46
  export function scheduleById(db, id) {
@@ -66,11 +68,11 @@ export function dueSchedules(db, now) {
66
68
  }
67
69
  export function insertSchedule(db, schedule, creationHash) {
68
70
  db.prepare(`INSERT INTO schedules
69
- (id,name,template_id,template_version,cadence_json,timezone,missed_policy,overlap_policy,
70
- spend_limit_cents,items_json,topic_keyword,values_json,status,version,creation_hash,
71
- next_run_at,created_at,updated_at,deleted_at,brief,topic_mode,topic_min,topic_llm_json,
72
- releases_json)
73
- VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(schedule.id, schedule.name, schedule.templateId, schedule.templateVersion, JSON.stringify(schedule.cadence), schedule.timezone, schedule.missedPolicy, schedule.overlapPolicy, schedule.spendLimitCents, JSON.stringify(schedule.items), schedule.topicKeyword, JSON.stringify(schedule.values), schedule.status, schedule.version, creationHash, schedule.nextRunAt, schedule.createdAt, schedule.updatedAt, schedule.deletedAt, ...generationColumns(schedule));
71
+ (id,name,template_kind,template_id,template_version,cadence_json,timezone,missed_policy,
72
+ overlap_policy,spend_limit_cents,items_json,topic_keyword,values_json,status,version,
73
+ creation_hash,next_run_at,created_at,updated_at,deleted_at,brief,topic_mode,topic_min,
74
+ topic_llm_json,releases_json,topic_scoring)
75
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`).run(schedule.id, schedule.name, schedule.templateKind, schedule.templateId, schedule.templateVersion, JSON.stringify(schedule.cadence), schedule.timezone, schedule.missedPolicy, schedule.overlapPolicy, schedule.spendLimitCents, JSON.stringify(schedule.items), schedule.topicKeyword, JSON.stringify(schedule.values), schedule.status, schedule.version, creationHash, schedule.nextRunAt, schedule.createdAt, schedule.updatedAt, schedule.deletedAt, ...generationColumns(schedule));
74
76
  }
75
77
  function generationColumns(schedule) {
76
78
  const generation = schedule.topicGeneration;
@@ -80,18 +82,20 @@ function generationColumns(schedule) {
80
82
  generation.keepAtLeast,
81
83
  generation.llm === null ? null : JSON.stringify(generation.llm),
82
84
  schedule.releases.length === 0 ? null : JSON.stringify(schedule.releases),
85
+ schedule.topicScoring,
83
86
  ];
84
87
  }
85
88
  export function updateScheduleRow(db, schedule, mutationId, mutationHash, baseVersion) {
86
89
  const changed = db
87
- .prepare(`UPDATE schedules SET name=?,template_id=?,template_version=?,cadence_json=?,timezone=?,
90
+ .prepare(`UPDATE schedules SET name=?,template_kind=?,template_id=?,template_version=?,cadence_json=?,timezone=?,
88
91
  missed_policy=?,overlap_policy=?,spend_limit_cents=?,items_json=?,topic_keyword=?,
89
92
  values_json=?,status=?,version=?,
90
93
  next_run_at=?,updated_at=?,mutation_id=?,mutation_hash=?,
91
- brief=?,topic_mode=?,topic_min=?,topic_llm_json=?,releases_json=?,topics_failed_at=NULL,
94
+ brief=?,topic_mode=?,topic_min=?,topic_llm_json=?,releases_json=?,topic_scoring=?,
95
+ topics_failed_at=NULL,
92
96
  topics_error=NULL
93
97
  WHERE id=? AND version=? AND deleted_at IS NULL`)
94
- .run(schedule.name, schedule.templateId, schedule.templateVersion, JSON.stringify(schedule.cadence), schedule.timezone, schedule.missedPolicy, schedule.overlapPolicy, schedule.spendLimitCents, JSON.stringify(schedule.items), schedule.topicKeyword, JSON.stringify(schedule.values), schedule.status, schedule.version, schedule.nextRunAt, schedule.updatedAt, mutationId, mutationHash, ...generationColumns(schedule), schedule.id, baseVersion);
98
+ .run(schedule.name, schedule.templateKind, schedule.templateId, schedule.templateVersion, JSON.stringify(schedule.cadence), schedule.timezone, schedule.missedPolicy, schedule.overlapPolicy, schedule.spendLimitCents, JSON.stringify(schedule.items), schedule.topicKeyword, JSON.stringify(schedule.values), schedule.status, schedule.version, schedule.nextRunAt, schedule.updatedAt, mutationId, mutationHash, ...generationColumns(schedule), schedule.id, baseVersion);
95
99
  return Number(changed.changes) === 1;
96
100
  }
97
101
  export function tombstoneScheduleRow(db, id, version, deletedAt) {
@@ -111,8 +115,8 @@ export function setScheduleStatus(db, id, version, status, nextRunAt, updatedAt)
111
115
  export function insertRun(db, run) {
112
116
  try {
113
117
  db.prepare(`INSERT INTO schedule_runs
114
- (id,schedule_id,scheduled_for,status,request_id,project_ids_json,estimate_json,started_at,ended_at,error)
115
- VALUES (?,?,?,?,?,?,?,?,?,?)`).run(run.id, run.scheduleId, run.scheduledFor, run.status, run.requestId, JSON.stringify(run.projectIds), run.estimate === null ? null : JSON.stringify(run.estimate), run.startedAt, run.endedAt, run.error);
118
+ (id,schedule_id,scheduled_for,status,request_id,project_ids_json,design_ids_json,estimate_json,started_at,ended_at,error)
119
+ VALUES (?,?,?,?,?,?,?,?,?,?,?)`).run(run.id, run.scheduleId, run.scheduledFor, run.status, run.requestId, JSON.stringify(run.projectIds), JSON.stringify(run.designIds), run.estimate === null ? null : JSON.stringify(run.estimate), run.startedAt, run.endedAt, run.error);
116
120
  return true;
117
121
  }
118
122
  catch (error) {
@@ -122,8 +126,8 @@ export function insertRun(db, run) {
122
126
  }
123
127
  }
124
128
  export function updateRun(db, run) {
125
- db.prepare(`UPDATE schedule_runs SET status=?,request_id=?,project_ids_json=?,estimate_json=?,
126
- ended_at=?,error=? WHERE id=?`).run(run.status, run.requestId, JSON.stringify(run.projectIds), run.estimate === null ? null : JSON.stringify(run.estimate), run.endedAt, run.error, run.id);
129
+ db.prepare(`UPDATE schedule_runs SET status=?,request_id=?,project_ids_json=?,design_ids_json=?,
130
+ estimate_json=?,ended_at=?,error=? WHERE id=?`).run(run.status, run.requestId, JSON.stringify(run.projectIds), JSON.stringify(run.designIds), run.estimate === null ? null : JSON.stringify(run.estimate), run.endedAt, run.error, run.id);
127
131
  }
128
132
  export function recordRunStartIdentity(db, run) {
129
133
  if (run.requestId === null)
@@ -174,8 +178,8 @@ function consumeTopic(db, scheduleId, used, updatedAt) {
174
178
  }
175
179
  export function runsForSchedule(db, scheduleId) {
176
180
  return db
177
- .prepare(`SELECT id,schedule_id,scheduled_for,status,request_id,project_ids_json,estimate_json,
178
- started_at,ended_at,error FROM schedule_runs WHERE schedule_id=? ORDER BY started_at DESC,id DESC`)
181
+ .prepare(`SELECT id,schedule_id,scheduled_for,status,request_id,project_ids_json,design_ids_json,
182
+ estimate_json,started_at,ended_at,error FROM schedule_runs WHERE schedule_id=? ORDER BY started_at DESC,id DESC`)
179
183
  .all(scheduleId)
180
184
  .map(parseRun);
181
185
  }
@@ -288,6 +292,7 @@ function parseSchedule(row) {
288
292
  return scheduleSummarySchema.parse({
289
293
  id: value.id,
290
294
  name: value.name,
295
+ templateKind: value.template_kind,
291
296
  templateId: value.template_id,
292
297
  templateVersion: value.template_version,
293
298
  cadence: JSON.parse(value.cadence_json),
@@ -305,6 +310,7 @@ function parseSchedule(row) {
305
310
  llm: value.topic_llm_json === null ? null : JSON.parse(value.topic_llm_json),
306
311
  },
307
312
  releases: value.releases_json === null ? [] : JSON.parse(value.releases_json),
313
+ topicScoring: value.topic_scoring,
308
314
  topics: {
309
315
  held: value.held_topics,
310
316
  generatingSince: value.topics_generating_at,
@@ -329,6 +335,7 @@ function parseRun(row) {
329
335
  status: z.string(),
330
336
  request_id: z.string().nullable(),
331
337
  project_ids_json: z.string(),
338
+ design_ids_json: z.string(),
332
339
  estimate_json: z.string().nullable(),
333
340
  started_at: z.string(),
334
341
  ended_at: z.string().nullable(),
@@ -342,6 +349,7 @@ function parseRun(row) {
342
349
  status: value.status,
343
350
  requestId: value.request_id,
344
351
  projectIds: JSON.parse(value.project_ids_json),
352
+ designIds: JSON.parse(value.design_ids_json),
345
353
  estimate: value.estimate_json === null ? null : JSON.parse(value.estimate_json),
346
354
  startedAt: value.started_at,
347
355
  endedAt: value.ended_at,
@@ -0,0 +1,35 @@
1
+ import { transact } from "../../kernel/db/tx.js";
2
+ import { scheduleById } from "./repo.js";
3
+ import { rankedItems, saveScores, scoreTopics } from "./topic-scores.js";
4
+ import { heldTopics, knownTitles, rankHeld } from "./topics.js";
5
+ // Rescore: every queued and held topic scored again now, then the queue and the held list put
6
+ // in score order. Topics the person added or moved keep their places: one scored for the first
7
+ // time here is scored where it stands.
8
+ export async function rescoreTopics(deps, scheduleId, signal) {
9
+ const schedule = scheduleById(deps.db, scheduleId);
10
+ if (schedule === undefined || schedule.deletedAt !== null)
11
+ return { ok: false, reason: "not-found" };
12
+ if (schedule.topicScoring === "off")
13
+ return {
14
+ ok: false,
15
+ reason: "scoring-off",
16
+ message: "Topic ranking is off for this schedule. Choose how to rank topics under Edit → Topic generation → Rank topics, save, then rescore.",
17
+ };
18
+ const titles = [
19
+ ...schedule.items.map((item) => item.title),
20
+ ...heldTopics(deps, scheduleId).map((topic) => topic.title),
21
+ ];
22
+ const scores = await scoreTopics(deps, schedule.topicScoring, titles, knownTitles(deps, scheduleId), deps.template(schedule.templateId)?.document.form.language ?? "en", signal);
23
+ return transact(deps.db, () => {
24
+ const current = scheduleById(deps.db, scheduleId);
25
+ if (current === undefined || current.deletedAt !== null)
26
+ return { ok: false, reason: "not-found" };
27
+ const at = deps.clock.now().toISOString();
28
+ saveScores(deps.db, scheduleId, scores, at, true);
29
+ deps.db
30
+ .prepare("UPDATE schedules SET items_json=?,version=version+1,updated_at=? WHERE id=? AND version=?")
31
+ .run(JSON.stringify(rankedItems(deps.db, scheduleId, current.items)), at, scheduleId, current.version);
32
+ rankHeld(deps, scheduleId);
33
+ return { ok: true, value: scheduleById(deps.db, scheduleId) };
34
+ });
35
+ }
@@ -3,10 +3,11 @@ import { reviewDraft } from "../play-drafts/review.js";
3
3
  import { createDraft } from "../play-drafts/service.js";
4
4
  import { startPlayDraft } from "../play-drafts/start.js";
5
5
  import { nextOccurrence } from "./calendar.js";
6
+ import { claimDesignRun } from "./design-run.js";
7
+ import { missedGraceMs } from "./next-run.js";
6
8
  import { continuePrepared, preparedProject, scheduledDocument, scheduledTitle } from "./prepare.js";
7
9
  import { activeRun, dueSchedules, insertRun, recordRunDispatch, recordRunStartIdentity, recoverRunningRuns, scheduleById, scheduleRows, updateRun, } from "./repo.js";
8
10
  import { generateTopics, generationDue, releaseTopicLeases } from "./topics.js";
9
- const missedGraceMs = 60_000;
10
11
  export function createScheduleRunner(deps) {
11
12
  let ticking = false;
12
13
  // ceiling: one entry per schedule generating now.
@@ -76,6 +77,11 @@ export function createScheduleRunner(deps) {
76
77
  function claim(deps, schedule, now) {
77
78
  if (schedule.nextRunAt === null)
78
79
  return [];
80
+ // A design schedule's run makes its piece at once and never reaches `execute`.
81
+ if (schedule.templateKind === "design") {
82
+ claimDesignRun(deps, schedule, now);
83
+ return [];
84
+ }
79
85
  const scheduledFor = new Date(schedule.nextRunAt);
80
86
  const occurrence = schedule.missedPolicy === "skip" && now.valueOf() - scheduledFor.valueOf() > missedGraceMs;
81
87
  let next = nextOccurrence(schedule.cadence, schedule.timezone, new Date(scheduledFor.valueOf() + 1000));
@@ -94,7 +100,10 @@ function claim(deps, schedule, now) {
94
100
  const noTopic = current.topicGeneration.mode !== "off" && current.items.length === 0
95
101
  ? noTopicReason(current)
96
102
  : null;
97
- const skip = occurrence || overlapping || noTopic !== null;
103
+ // A template with no version marked ready (or saved before the studio) waits: the run is
104
+ // skipped, nothing is spent and no topic is used.
105
+ const notReady = noTopic === null ? (deps.notReady?.(current.templateId) ?? null) : null;
106
+ const skip = occurrence || overlapping || noTopic !== null || notReady !== null;
98
107
  const run = {
99
108
  id: deps.uuid(),
100
109
  scheduleId: schedule.id,
@@ -102,6 +111,7 @@ function claim(deps, schedule, now) {
102
111
  status: skip ? "skipped" : "running",
103
112
  requestId: null,
104
113
  projectIds: [],
114
+ designIds: [],
105
115
  estimate: null,
106
116
  startedAt: now.toISOString(),
107
117
  endedAt: skip ? now.toISOString() : null,
@@ -110,7 +120,7 @@ function claim(deps, schedule, now) {
110
120
  ? "Skipped because the previous run of this schedule was still going."
111
121
  : occurrence
112
122
  ? "Skipped because Slopify was not running at the scheduled time."
113
- : noTopic
123
+ : (noTopic ?? notReady)
114
124
  : null,
115
125
  };
116
126
  if (!insertRun(deps.db, run))