@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,118 @@
1
+ import { projectExists } from "../admission/repo.js";
2
+ import { templateById } from "../project-templates/repo.js";
3
+ import { currentRevisionId } from "../revisions/repo.js";
4
+ import { getRevisionView } from "../revisions/view.js";
5
+ import { promptAnatomy } from "./anatomy.js";
6
+ import { resolveSampleRun } from "./quote.js";
7
+ import { sampleOf } from "./repo.js";
8
+ import { sampleArticleInstruction, sampleDocument } from "./scope.js";
9
+ import { defaultSampleTopic } from "./service.js";
10
+ // The section a prompt is sent from, by its key in the run's rendered prompts.
11
+ export function sectionOfPrompt(key) {
12
+ if (key === "article" || key === "intro" || key === "outro")
13
+ return "script";
14
+ if (key === "narration")
15
+ return "voice";
16
+ if (key.startsWith("imagePrompts.") || key === "referencePrompt")
17
+ return "pictures";
18
+ if (key.startsWith("thumbnail"))
19
+ return "thumbnail";
20
+ if (key === "description")
21
+ return "upload";
22
+ if (key === "shorts" || key === "shortsImage")
23
+ return "shorts";
24
+ if (key.startsWith("review."))
25
+ return "reviews";
26
+ return undefined;
27
+ }
28
+ function labelOf(key, names) {
29
+ if (key === "article")
30
+ return "Article prompt";
31
+ if (key === "intro")
32
+ return "Intro";
33
+ if (key === "outro")
34
+ return "Outro";
35
+ if (key === "narration")
36
+ return "Narration prompt";
37
+ if (key === "referencePrompt")
38
+ return "Establishing image prompt";
39
+ if (key.startsWith("imagePrompts.")) {
40
+ const index = Number(key.slice("imagePrompts.".length));
41
+ return `Image prompt ${names[index] ?? String(index + 1)}`;
42
+ }
43
+ if (key.startsWith("thumbnail"))
44
+ return "Thumbnail prompt";
45
+ if (key === "description")
46
+ return "YouTube description prompt";
47
+ if (key === "shorts")
48
+ return "Shorts prompt";
49
+ if (key === "shortsImage")
50
+ return "Shorts picture prompt";
51
+ if (key.startsWith("review."))
52
+ return `Review prompt (${key.slice("review.".length)})`;
53
+ return key;
54
+ }
55
+ export async function getAnatomy(deps, id, section, item) {
56
+ const template = templateById(deps.db, id);
57
+ if (template === undefined)
58
+ return {
59
+ ok: false,
60
+ reason: "not-found",
61
+ message: "This template no longer exists; it may have been deleted. Go to Library → Templates to see your templates.",
62
+ };
63
+ const record = sampleOf(deps.db, id);
64
+ const fullScript = record?.fullScript ?? false;
65
+ const resolved = await resolveSampleRun(deps.review, sampleDocument(template.document, {
66
+ topic: record?.topic ?? defaultSampleTopic(deps.db),
67
+ fullScript,
68
+ }), fullScript);
69
+ const empty = (problem) => ({
70
+ ok: true,
71
+ value: { section, items: [], item: null, segments: [], fromSample: false, problem },
72
+ });
73
+ if (!resolved.ok)
74
+ return empty(resolved.problem);
75
+ const { run } = resolved;
76
+ const names = template.document.form.imagePrompts.map((prompt) => prompt.name);
77
+ const items = Object.keys(run.templates)
78
+ .filter((key) => sectionOfPrompt(key) === section)
79
+ .map((key) => ({ key, label: labelOf(key, names) }));
80
+ const chosen = items.find((one) => one.key === item) ?? items[0];
81
+ if (chosen === undefined)
82
+ return empty(null);
83
+ const body = run.templates[chosen.key] ?? "";
84
+ // What the sample sent, when its project still runs this very body.
85
+ let sent;
86
+ if (record !== undefined && projectExists(deps.db, record.projectId)) {
87
+ const revisionId = currentRevisionId(deps.db, record.projectId);
88
+ const view = revisionId === undefined
89
+ ? undefined
90
+ : getRevisionView({
91
+ db: deps.db,
92
+ paths: deps.paths,
93
+ log: deps.log,
94
+ ids: { next: () => "" },
95
+ clock: { now: () => new Date(), sleep: async () => undefined },
96
+ }, record.projectId, revisionId);
97
+ if (view?.revision.content.promptTemplates[chosen.key] === body)
98
+ sent = view.revision.config.rendered[chosen.key];
99
+ }
100
+ return {
101
+ ok: true,
102
+ value: {
103
+ section,
104
+ items,
105
+ item: chosen.key,
106
+ segments: promptAnatomy({
107
+ body,
108
+ sent: sent ?? run.rendered[chosen.key],
109
+ values: run.draft.values,
110
+ appended: chosen.key === "article" && !fullScript
111
+ ? [{ text: sampleArticleInstruction, by: "slopify" }]
112
+ : [],
113
+ }),
114
+ fromSample: sent !== undefined,
115
+ problem: null,
116
+ },
117
+ };
118
+ }
@@ -0,0 +1,73 @@
1
+ import { filledKeywords } from "../admission/substitute.js";
2
+ const slot = /\{\{([^{}\n]*)\}\}/gu;
3
+ function partsOf(body) {
4
+ const parts = [];
5
+ let last = 0;
6
+ for (const match of body.matchAll(slot)) {
7
+ const at = match.index;
8
+ if (at > last)
9
+ parts.push({ literal: body.slice(last, at) });
10
+ const name = (match[1] ?? "").trim();
11
+ parts.push(name === "" ? { literal: match[0] } : { name });
12
+ last = at + match[0].length;
13
+ }
14
+ if (last < body.length)
15
+ parts.push({ literal: body.slice(last) });
16
+ return parts;
17
+ }
18
+ const escapeRegex = (text) => text.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
19
+ // Each keyword's value as the sent prompt shows it: the body's own text around the slots is
20
+ // matched in the sent text, and what lies between is the value. Undefined when the sent prompt
21
+ // isn't this body filled in (the prompt was edited by hand, or it is another version's).
22
+ export function sentValues(body, sent) {
23
+ const parts = partsOf(body);
24
+ const names = [];
25
+ const pattern = parts
26
+ .map((part) => {
27
+ if (part.name === undefined)
28
+ return escapeRegex(part.literal ?? "");
29
+ names.push(part.name);
30
+ return "([\\s\\S]*?)";
31
+ })
32
+ .join("");
33
+ const match = new RegExp(`^${pattern}$`, "u").exec(sent);
34
+ if (match === null)
35
+ return undefined;
36
+ const values = Object.create(null);
37
+ names.forEach((name, index) => {
38
+ const value = match[index + 1] ?? "";
39
+ if (!Object.hasOwn(values, name))
40
+ values[name] = value;
41
+ });
42
+ return values;
43
+ }
44
+ export function promptAnatomy(input) {
45
+ const filled = input.filled ?? filledKeywords;
46
+ const read = input.sent === undefined ? undefined : sentValues(input.body, input.sent);
47
+ const filledValue = (name) => {
48
+ const shown = read?.[name];
49
+ // A slot the sent prompt still shows as written was never filled.
50
+ if (shown !== undefined && shown !== `{{${name}}}`)
51
+ return shown;
52
+ return Object.hasOwn(input.values, name) && input.values[name] !== ""
53
+ ? input.values[name]
54
+ : undefined;
55
+ };
56
+ const segments = [];
57
+ for (const part of partsOf(input.body)) {
58
+ if (part.name === undefined) {
59
+ const text = part.literal ?? "";
60
+ if (text !== "")
61
+ segments.push({ origin: "yours", text });
62
+ continue;
63
+ }
64
+ const value = filledValue(part.name);
65
+ const origin = filled.includes(part.name) ? "slopify" : "keyword";
66
+ segments.push(value === undefined
67
+ ? { origin, name: part.name, text: `{{${part.name}}}`, unfilled: true }
68
+ : { origin, name: part.name, text: value });
69
+ }
70
+ for (const extra of input.appended ?? [])
71
+ segments.push({ origin: extra.by, text: `\n\n${extra.text}` });
72
+ return segments;
73
+ }
@@ -0,0 +1,225 @@
1
+ import { internalError } from "../../kernel/errors.js";
2
+ import { derive } from "../../kernel/runner/graph.js";
3
+ import { projectExists, projectPaused, stagesOf } from "../admission/repo.js";
4
+ import { copyProject } from "../onboarding/copy.js";
5
+ import { templateById } from "../project-templates/repo.js";
6
+ import { previewRebuild, startRebuild } from "../rebuild/service.js";
7
+ import { saveRevision } from "../revisions/mutations.js";
8
+ import { currentRevisionId } from "../revisions/repo.js";
9
+ import { getRevisionView } from "../revisions/view.js";
10
+ import { withModel } from "./bakeoff.js";
11
+ import { bakeoffOf, clonesOf, setBakeoff, setClone, } from "./bakeoff-repo.js";
12
+ import { budgetRoom, budgetWords, fitsBudget } from "./budget.js";
13
+ import { sampleEdit } from "./edit.js";
14
+ import { removeHiddenProject } from "./hidden.js";
15
+ import { sectionLabel } from "./model.js";
16
+ import { refused, settled, studioWords } from "./paid.js";
17
+ import { resolveSampleRun } from "./quote.js";
18
+ import { sampleOf } from "./repo.js";
19
+ import { exceedsAcknowledged } from "./save.js";
20
+ import { sampleDocument } from "./scope.js";
21
+ import { sectionOfWork } from "./sections.js";
22
+ const money = (value) => `$${value.toFixed(2)}`;
23
+ export async function makeBakeoff(deps, job, signal) {
24
+ const { db } = deps.start;
25
+ const at = () => deps.start.clock.now().toISOString();
26
+ const row = bakeoffOf(db, job.templateId);
27
+ if (row === undefined || (row.state !== "queued" && row.state !== "making"))
28
+ return;
29
+ const stop = (state, sentence) => setBakeoff(db, row.id, state, sentence, at());
30
+ const template = templateById(db, row.templateId);
31
+ if (template === undefined)
32
+ return;
33
+ if (template.version !== row.templateVersion) {
34
+ stop("failed", "The template was saved again since the bake-off was priced, so it wasn't made and nothing was spent. Compare again on the new version.");
35
+ return;
36
+ }
37
+ const sample = sampleOf(db, row.templateId);
38
+ if (sample === undefined || !projectExists(db, sample.projectId)) {
39
+ stop("failed", "The template's sample is gone, so there is nothing to compare on. Press Make sample, then compare again.");
40
+ return;
41
+ }
42
+ // The copies are taken once the sample's own work has finished.
43
+ await settled(deps, sample.projectId, signal);
44
+ setBakeoff(db, row.id, "making", null, at());
45
+ const clones = clonesOf(db, row.id);
46
+ const prepared = [];
47
+ for (const clone of clones) {
48
+ if (signal.aborted)
49
+ return;
50
+ if (clone.state === "making" || clone.state === "done" || clone.state === "failed")
51
+ continue;
52
+ const ready = await prepare(deps, row, clone, sample, signal);
53
+ if (typeof ready === "string") {
54
+ setClone(db, row.id, clone.slot, { state: "failed", failure: ready, finishedAt: at() });
55
+ continue;
56
+ }
57
+ prepared.push(ready);
58
+ }
59
+ // The whole bake-off is held against what the person accepted, before anything starts.
60
+ if (prepared.length > 0) {
61
+ const high = prepared.reduce((sum, one) => sum + Math.max(one.high, one.clone.quotedHigh ?? 0), 0);
62
+ const unknown = prepared.reduce((sum, one) => sum + one.unknown, 0);
63
+ const usesPlan = prepared.some((one) => one.usesPlan);
64
+ const room = budgetRoom(db, deps.start.clock.now(), deps.timeZone);
65
+ const waiting = exceedsAcknowledged(high, row.ackHigh)
66
+ ? `Waiting: comparing now costs about ${money(high)}, more than the ${money(row.ackHigh)} you saw. Press Compare again to accept the new price.`
67
+ : unknown > 0 && !row.ackUnknown
68
+ ? `Waiting: ${String(unknown)} ${unknown === 1 ? "step has" : "steps have"} no known price. Press Compare again to accept that.`
69
+ : !fitsBudget(room, high, usesPlan)
70
+ ? `Waiting: ${budgetWords(room, { high, usesPlan }, "comparing")}, or compare tomorrow.`
71
+ : undefined;
72
+ if (waiting !== undefined) {
73
+ for (const one of prepared) {
74
+ // A copy that stays keeps its row, so it stays hidden and Discard removes it later.
75
+ if (removeHiddenProject(deps.rebuild, one.projectId).ok)
76
+ setClone(db, row.id, one.clone.slot, { state: "queued", projectId: null });
77
+ else
78
+ setClone(db, row.id, one.clone.slot, {
79
+ state: "failed",
80
+ failure: "This model's copy couldn't be removed while the bake-off waited, because its files are busy or in use. Press Discard in the bake-off once nothing uses Slopify's files, then Compare again.",
81
+ finishedAt: at(),
82
+ });
83
+ }
84
+ stop("held", waiting);
85
+ return;
86
+ }
87
+ }
88
+ for (const one of prepared) {
89
+ if (signal.aborted)
90
+ return;
91
+ const started = await startRebuild(deps.rebuild, {
92
+ projectId: one.projectId,
93
+ baseRevisionId: one.revisionId,
94
+ idempotencyKey: deps.start.uuid(),
95
+ previewId: one.previewId,
96
+ acknowledgeUnknownCosts: one.unknown === 0 || row.ackUnknown,
97
+ confirmedProvidedWorkKeys: one.provided,
98
+ });
99
+ if (!started.ok) {
100
+ setClone(db, row.id, one.clone.slot, {
101
+ state: "failed",
102
+ failure: refused(started.reason, started.fields),
103
+ finishedAt: at(),
104
+ });
105
+ continue;
106
+ }
107
+ setClone(db, row.id, one.clone.slot, { state: "making", startedAt: at() });
108
+ }
109
+ // Each copy finishes on its own; the slower ones are waited for in turn.
110
+ for (const clone of clonesOf(db, row.id)) {
111
+ if (clone.state !== "making" || clone.projectId === null)
112
+ continue;
113
+ await settled(deps, clone.projectId, signal);
114
+ const failure = failureOf(deps, clone.projectId);
115
+ setClone(db, row.id, clone.slot, {
116
+ state: failure === null ? "done" : "failed",
117
+ failure,
118
+ finishedAt: at(),
119
+ });
120
+ }
121
+ const finished = clonesOf(db, row.id);
122
+ setBakeoff(db, row.id, finished.some((clone) => clone.state === "done") ? "done" : "failed", finished.some((clone) => clone.state === "done")
123
+ ? null
124
+ : "No other model could make the sample: each one says why. Fix it, or pick other models, and compare again.", at());
125
+ }
126
+ // A copy of the sample with the model switched, priced for the section's own work. A string
127
+ // says why this model can't be compared.
128
+ async function prepare(deps, row, clone, sample, signal) {
129
+ const { db } = deps.start;
130
+ const template = templateById(db, row.templateId, row.templateVersion);
131
+ if (template === undefined)
132
+ return "The template's version is gone.";
133
+ const catalogue = deps.rebuild.catalogue.read();
134
+ const document = withModel(template.document, row.section, clone, catalogue);
135
+ const resolved = await resolveSampleRun(deps.start, sampleDocument(document, { topic: sample.topic, fullScript: sample.fullScript }), sample.fullScript);
136
+ if (!resolved.ok)
137
+ return resolved.problem;
138
+ if (signal.aborted)
139
+ return "Slopify stopped before this model's copy was made.";
140
+ let projectId = clone.projectId;
141
+ if (projectId === null || !projectExists(db, projectId)) {
142
+ // The copy's row names its project before the project exists, so it is hidden, and its
143
+ // folder kept in the data dir, from its very first file.
144
+ const reserved = deps.start.ids.next();
145
+ let given = false;
146
+ const ids = {
147
+ next: () => {
148
+ if (given)
149
+ return deps.start.ids.next();
150
+ given = true;
151
+ return reserved;
152
+ },
153
+ };
154
+ setClone(db, row.id, clone.slot, { projectId: reserved });
155
+ try {
156
+ const copied = copyProject({ ...deps.rebuild, ids, catalogue }, sample.projectId, `Bake-off: ${clone.model}`);
157
+ if (copied.projectId !== reserved)
158
+ throw new Error(internalError("the bake-off copy got another id than its row", "Compare again"));
159
+ }
160
+ catch (error) {
161
+ setClone(db, row.id, clone.slot, { projectId: null });
162
+ return `The sample couldn't be copied for ${clone.model}: ${error instanceof Error ? error.message : String(error)}`;
163
+ }
164
+ projectId = reserved;
165
+ // The copy's own spending only: the sample's calls it was copied with are the sample's.
166
+ db.prepare("DELETE FROM provider_usage WHERE project_id=?").run(projectId);
167
+ db.prepare("DELETE FROM plan_limit_readings WHERE project_id=?").run(projectId);
168
+ }
169
+ const base = getRevisionView(deps.rebuild, projectId, currentRevisionId(db, projectId) ?? "");
170
+ if (base === undefined)
171
+ return "The copy of the sample has no version to change.";
172
+ const saved = await saveRevision(deps.rebuild, {
173
+ projectId,
174
+ baseRevisionId: base.revision.id,
175
+ idempotencyKey: deps.start.uuid(),
176
+ edit: sampleEdit(deps.rebuild, base, resolved.run),
177
+ });
178
+ if (!saved.ok)
179
+ return refused(saved.reason, saved.fields);
180
+ const revisionId = saved.view.revision.id;
181
+ const all = await previewRebuild(deps.rebuild, {
182
+ projectId,
183
+ baseRevisionId: revisionId,
184
+ request: { kind: "allAffected" },
185
+ });
186
+ if (!all.ok)
187
+ return refused(all.reason, all.fields);
188
+ const keys = all.value.work
189
+ .filter((work) => (work.disposition === "generate" || work.disposition === "local") &&
190
+ sectionOfWork(work.key) === row.section)
191
+ .map((work) => work.key);
192
+ if (keys.length === 0)
193
+ return `Nothing in ${sectionLabel[row.section]} changes with ${clone.model}, so there is nothing to compare.`;
194
+ const preview = await previewRebuild(deps.rebuild, {
195
+ projectId,
196
+ baseRevisionId: revisionId,
197
+ request: { kind: "selected", workKeys: keys },
198
+ });
199
+ if (!preview.ok)
200
+ return refused(preview.reason, preview.fields);
201
+ return {
202
+ clone,
203
+ projectId,
204
+ revisionId,
205
+ previewId: preview.value.id,
206
+ high: preview.value.costs.high,
207
+ unknown: preview.value.costs.unknown,
208
+ usesPlan: preview.value.costs.rows.some((one) => one.onPlan === true),
209
+ provided: preview.value.providedReuseRequired,
210
+ };
211
+ }
212
+ // The failed step's own sentence, or null when the copy's work finished.
213
+ function failureOf(deps, projectId) {
214
+ const stages = stagesOf(deps.start.db, projectId);
215
+ const state = derive(stages, projectPaused(deps.start.db, projectId));
216
+ if (state === "failed") {
217
+ const reason = stages.find((stage) => stage.state === "failed")?.failureReason;
218
+ return reason === undefined || reason === null
219
+ ? "A step of this model's copy failed without saying why. Compare again; if it fails again, use Download diagnostics in Settings and report it."
220
+ : studioWords(reason, "Compare again", "");
221
+ }
222
+ if (state === "canceled" || state === "paused")
223
+ return "This model's copy stopped before it finished. Compare again to make it.";
224
+ return null;
225
+ }
@@ -0,0 +1,83 @@
1
+ import { z } from "zod";
2
+ // The bake-off's rows (`0074-template-bakeoffs.sql`): one per template, and one copy per model.
3
+ export const bakeoffSections = ["script", "voice", "pictures"];
4
+ export const bakeoffStates = ["queued", "making", "done", "held", "failed"];
5
+ export const cloneStates = ["queued", "making", "done", "failed"];
6
+ const bakeoffRow = z.object({
7
+ id: z.string(),
8
+ templateId: z.string(),
9
+ templateVersion: z.number().int().positive(),
10
+ section: z.enum(bakeoffSections),
11
+ ackHigh: z.number(),
12
+ ackUnknown: z.number(),
13
+ state: z.enum(bakeoffStates),
14
+ sentence: z.string().nullable(),
15
+ createdAt: z.string(),
16
+ updatedAt: z.string(),
17
+ });
18
+ const cloneRow = z.object({
19
+ slot: z.number().int(),
20
+ provider: z.string(),
21
+ model: z.string(),
22
+ projectId: z.string().nullable(),
23
+ state: z.enum(cloneStates),
24
+ quotedHigh: z.number().nullable(),
25
+ failure: z.string().nullable(),
26
+ startedAt: z.string().nullable(),
27
+ finishedAt: z.string().nullable(),
28
+ });
29
+ export function bakeoffOf(db, templateId) {
30
+ const row = db
31
+ .prepare(`SELECT id,template_id AS templateId,template_version AS templateVersion,section,ack_high AS ackHigh,
32
+ ack_unknown AS ackUnknown,state,sentence,created_at AS createdAt,updated_at AS updatedAt
33
+ FROM template_bakeoffs WHERE template_id=?`)
34
+ .get(templateId);
35
+ if (row === undefined)
36
+ return undefined;
37
+ const parsed = bakeoffRow.parse(row);
38
+ return { ...parsed, ackUnknown: parsed.ackUnknown === 1 };
39
+ }
40
+ export function clonesOf(db, bakeoffId) {
41
+ return db
42
+ .prepare(`SELECT slot,provider,model,project_id AS projectId,state,quoted_high AS quotedHigh,failure,
43
+ started_at AS startedAt,finished_at AS finishedAt
44
+ FROM template_bakeoff_clones WHERE bakeoff_id=? ORDER BY slot`)
45
+ .all(bakeoffId)
46
+ .map((row) => cloneRow.parse(row));
47
+ }
48
+ export function insertBakeoff(db, row, clones) {
49
+ db.prepare(`INSERT INTO template_bakeoffs (id,template_id,template_version,section,ack_high,ack_unknown,state,sentence,created_at,updated_at)
50
+ VALUES (?,?,?,?,?,?,'queued',NULL,?,?)`).run(row.id, row.templateId, row.templateVersion, row.section, row.ackHigh, row.ackUnknown ? 1 : 0, row.createdAt, row.createdAt);
51
+ const insert = db.prepare("INSERT INTO template_bakeoff_clones (bakeoff_id,slot,provider,model,state,quoted_high) VALUES (?,?,?,?,'queued',?)");
52
+ clones.forEach((clone, slot) => {
53
+ insert.run(row.id, slot, clone.provider, clone.model, clone.quotedHigh);
54
+ });
55
+ }
56
+ export function setBakeoff(db, id, state, sentence, at) {
57
+ db.prepare("UPDATE template_bakeoffs SET state=?,sentence=?,updated_at=? WHERE id=?").run(state, sentence, at, id);
58
+ }
59
+ // Records what one copy is now. A field left out keeps what it was.
60
+ export function setClone(db, bakeoffId, slot, change) {
61
+ const columns = {
62
+ state: change.state,
63
+ project_id: change.projectId,
64
+ quoted_high: change.quotedHigh,
65
+ failure: change.failure,
66
+ started_at: change.startedAt,
67
+ finished_at: change.finishedAt,
68
+ };
69
+ const set = Object.entries(columns).filter(([, value]) => value !== undefined);
70
+ if (set.length === 0)
71
+ return;
72
+ db.prepare(`UPDATE template_bakeoff_clones SET ${set.map(([column]) => `${column}=?`).join(",")} WHERE bakeoff_id=? AND slot=?`).run(...set.map(([, value]) => value ?? null), bakeoffId, slot);
73
+ }
74
+ export function deleteBakeoffRow(db, id) {
75
+ db.prepare("DELETE FROM template_bakeoffs WHERE id=?").run(id);
76
+ }
77
+ // A newer Save, topic or full script takes the place of a bake-off still waiting to start: the
78
+ // bake-off was priced on the version before it.
79
+ export function supersedeQueuedBakeoff(db, templateId, at) {
80
+ db.prepare(`UPDATE template_bakeoffs SET state='failed',updated_at=?,
81
+ sentence='A newer Save took its place before it started, so nothing was spent on it. Start the bake-off again on the new version.'
82
+ WHERE template_id=? AND state='queued'`).run(at, templateId);
83
+ }