@gentbajko/slopify 3.25.9 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (718) hide show
  1. package/dist/adapters/account-limits.js +30 -0
  2. package/dist/adapters/alignment/audio.js +1 -1
  3. package/dist/adapters/alignment/cache.js +4 -6
  4. package/dist/adapters/alignment/ctc.js +1 -2
  5. package/dist/adapters/alignment/lock.js +4 -3
  6. package/dist/adapters/alignment/multilingual.js +2 -4
  7. package/dist/adapters/alignment/prefetch.js +2 -1
  8. package/dist/adapters/alignment/runner.js +1 -1
  9. package/dist/adapters/alignment/worker.js +3 -2
  10. package/dist/adapters/explain.js +10 -12
  11. package/dist/adapters/ffmpeg.js +19 -1
  12. package/dist/adapters/host-cli/index.js +21 -4
  13. package/dist/adapters/host-cli/transport.js +2 -1
  14. package/dist/adapters/http-failure.js +53 -0
  15. package/dist/adapters/image/bytes.js +2 -1
  16. package/dist/adapters/image/codex.js +42 -9
  17. package/dist/adapters/image/fal.js +21 -53
  18. package/dist/adapters/image/google.js +33 -56
  19. package/dist/adapters/image/models.js +2 -2
  20. package/dist/adapters/image/openai.js +22 -48
  21. package/dist/adapters/image/reference.js +36 -0
  22. package/dist/adapters/image/replicate.js +21 -49
  23. package/dist/adapters/image/video.js +2 -1
  24. package/dist/adapters/interest/search-interest.js +113 -0
  25. package/dist/adapters/key-probes.js +54 -3
  26. package/dist/adapters/llm/antigravity-models.js +1 -1
  27. package/dist/adapters/llm/antigravity.js +11 -6
  28. package/dist/adapters/llm/assistant-cli.js +388 -0
  29. package/dist/adapters/llm/child-session.js +83 -0
  30. package/dist/adapters/llm/claude-code-models.js +52 -99
  31. package/dist/adapters/llm/claude-code.js +16 -4
  32. package/dist/adapters/llm/codex-limits.js +27 -68
  33. package/dist/adapters/llm/codex-models.js +1 -1
  34. package/dist/adapters/llm/codex-server-models.js +61 -109
  35. package/dist/adapters/llm/codex.js +12 -1
  36. package/dist/adapters/llm/document-workspace.js +3 -2
  37. package/dist/adapters/llm/image-workspace.js +3 -2
  38. package/dist/adapters/llm/openrouter.js +12 -48
  39. package/dist/adapters/llm/run-cli.js +9 -24
  40. package/dist/adapters/llm/sse-lines.js +5 -1
  41. package/dist/adapters/model-access.js +37 -0
  42. package/dist/adapters/tts/cartesia.js +15 -46
  43. package/dist/adapters/tts/elevenlabs.js +20 -52
  44. package/dist/adapters/tts/gemini.js +21 -41
  45. package/dist/adapters/tts/inworld-async.js +6 -2
  46. package/dist/adapters/tts/inworld.js +6 -2
  47. package/dist/adapters/tts/openai.js +20 -50
  48. package/dist/adapters/tts/system.js +2 -1
  49. package/dist/assets/models-lifecycle.yaml +6 -0
  50. package/dist/assistant-wiring.js +60 -0
  51. package/dist/autopilot-timers.js +59 -0
  52. package/dist/catalog/lifecycle.js +52 -0
  53. package/dist/catalog/propose.js +204 -0
  54. package/dist/catalog/registry.js +23 -14
  55. package/dist/catalog/schema.js +4 -1
  56. package/dist/catalog/store.js +39 -0
  57. package/dist/catalog/validate.js +5 -2
  58. package/dist/edge/autostart/native.js +3 -5
  59. package/dist/edge/autostart/prompt.js +2 -1
  60. package/dist/edge/autostart/service.js +3 -4
  61. package/dist/edge/cli-args.js +3 -4
  62. package/dist/edge/cli.js +2 -1
  63. package/dist/edge/docker-install/apply.js +11 -11
  64. package/dist/edge/docker-install/run.js +2 -1
  65. package/dist/edge/docker-install/state.js +4 -3
  66. package/dist/edge/docker-install/tree.js +2 -4
  67. package/dist/edge/docker-install/volume.js +3 -2
  68. package/dist/edge/docker.js +5 -4
  69. package/dist/edge/events/hub.js +5 -5
  70. package/dist/edge/http/actions.js +11 -32
  71. package/dist/edge/http/actor.js +5 -3
  72. package/dist/edge/http/app.js +86 -11
  73. package/dist/edge/http/assistant.js +129 -0
  74. package/dist/edge/http/audio-preview.js +4 -11
  75. package/dist/edge/http/auditions.js +1 -1
  76. package/dist/edge/http/autostart.js +5 -5
  77. package/dist/edge/http/backups.js +2 -4
  78. package/dist/edge/http/channel-memory.js +9 -22
  79. package/dist/edge/http/channels.js +14 -27
  80. package/dist/edge/http/checkpoints.js +39 -21
  81. package/dist/edge/http/design-templates.js +167 -0
  82. package/dist/edge/http/designs.js +178 -0
  83. package/dist/edge/http/diagnostics.js +5 -1
  84. package/dist/edge/http/document-themes.js +5 -14
  85. package/dist/edge/http/draft-files.js +1 -3
  86. package/dist/edge/http/draft-problem.js +5 -10
  87. package/dist/edge/http/drafts.js +3 -3
  88. package/dist/edge/http/entries.js +6 -9
  89. package/dist/edge/http/extension-auth.js +27 -0
  90. package/dist/edge/http/external-reviews.js +12 -11
  91. package/dist/edge/http/files.js +5 -11
  92. package/dist/edge/http/folder-location.js +1 -4
  93. package/dist/edge/http/fonts.js +0 -7
  94. package/dist/edge/http/home.js +47 -14
  95. package/dist/edge/http/host-cli.js +18 -8
  96. package/dist/edge/http/ids.js +8 -0
  97. package/dist/edge/http/keywords.js +35 -0
  98. package/dist/edge/http/model-checks.js +132 -0
  99. package/dist/edge/http/narration-peaks.js +5 -13
  100. package/dist/edge/http/onboarding.js +30 -26
  101. package/dist/edge/http/open-folder.js +5 -10
  102. package/dist/edge/http/outputs.js +7 -14
  103. package/dist/edge/http/patch-notes.js +6 -12
  104. package/dist/edge/http/planning.js +3 -7
  105. package/dist/edge/http/problem.js +2 -4
  106. package/dist/edge/http/project-create.js +2 -1
  107. package/dist/edge/http/project-templates.js +31 -19
  108. package/dist/edge/http/projects.js +24 -16
  109. package/dist/edge/http/prompts.js +9 -16
  110. package/dist/edge/http/pronunciations.js +1 -2
  111. package/dist/edge/http/providers.js +48 -34
  112. package/dist/edge/http/refusal.js +29 -0
  113. package/dist/edge/http/remote-access.js +40 -0
  114. package/dist/edge/http/remote-guard.js +71 -0
  115. package/dist/edge/http/request-guard.js +91 -0
  116. package/dist/edge/http/reviews.js +12 -25
  117. package/dist/edge/http/revision-files.js +6 -11
  118. package/dist/edge/http/revisions.js +14 -19
  119. package/dist/edge/http/run-cost.js +1 -2
  120. package/dist/edge/http/same-page.js +80 -0
  121. package/dist/edge/http/schedules.js +69 -40
  122. package/dist/edge/http/settings.js +27 -14
  123. package/dist/edge/http/social.js +283 -0
  124. package/dist/edge/http/staging.js +3 -5
  125. package/dist/edge/http/storage-files.js +5 -7
  126. package/dist/edge/http/storage.js +33 -25
  127. package/dist/edge/http/studio.js +94 -69
  128. package/dist/edge/http/style-preview.js +3 -6
  129. package/dist/edge/http/subtitles.js +3 -17
  130. package/dist/edge/http/template-studio.js +436 -0
  131. package/dist/edge/http/trash.js +11 -12
  132. package/dist/edge/http/tutorial.js +1 -2
  133. package/dist/edge/http/tutorials.js +5 -11
  134. package/dist/edge/http/update.js +7 -13
  135. package/dist/edge/http/waveform.js +3 -6
  136. package/dist/edge/http/youtube-edits.js +3 -4
  137. package/dist/edge/mcp/assistant.js +279 -0
  138. package/dist/edge/mcp/attribution.js +8 -2
  139. package/dist/edge/mcp/call-route.js +11 -2
  140. package/dist/edge/mcp/excluded-routes.js +29 -3
  141. package/dist/edge/mcp/http.js +11 -2
  142. package/dist/edge/mcp/instructions.js +6 -4
  143. package/dist/edge/mcp/library-tools.js +9 -5
  144. package/dist/edge/mcp/remake-tools.js +7 -4
  145. package/dist/edge/mcp/route-tool.js +35 -15
  146. package/dist/edge/mcp/server.js +13 -8
  147. package/dist/edge/mcp/tools-channels.js +11 -9
  148. package/dist/edge/mcp/tools-designs.js +165 -0
  149. package/dist/edge/mcp/tools-library.js +19 -7
  150. package/dist/edge/mcp/tools-planning.js +40 -21
  151. package/dist/edge/mcp/tools-projects.js +38 -11
  152. package/dist/edge/mcp/tools-publishing.js +9 -9
  153. package/dist/edge/mcp/tools-runs.js +23 -10
  154. package/dist/edge/mcp/tools-schedules.js +32 -8
  155. package/dist/edge/mcp/tools-setup.js +75 -11
  156. package/dist/edge/mcp/tools-social.js +47 -0
  157. package/dist/edge/mcp/tools-storage.js +11 -3
  158. package/dist/edge/mcp/tools-template-studio.js +166 -0
  159. package/dist/edge/mcp/tools.js +6 -0
  160. package/dist/edge/remote-access/cli.js +71 -0
  161. package/dist/edge/remote-access/model.js +32 -0
  162. package/dist/edge/remote-access/rules.js +207 -0
  163. package/dist/edge/remote-access/service.js +203 -0
  164. package/dist/edge/remote-access/store.js +44 -0
  165. package/dist/edge/remote-access/views.js +43 -0
  166. package/dist/extension/slopify-studio-chrome.zip +0 -0
  167. package/dist/extension/slopify-studio-firefox.zip +0 -0
  168. package/dist/host-cli/install.js +2 -2
  169. package/dist/host-cli/open-folder.js +2 -2
  170. package/dist/host-cli/paths.js +2 -4
  171. package/dist/host-cli/server.js +4 -4
  172. package/dist/host-cli/service.js +3 -3
  173. package/dist/host-cli/status.js +7 -7
  174. package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
  175. package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
  176. package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
  177. package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
  178. package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
  179. package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
  180. package/dist/kernel/db/migrations/0070-designs.sql +53 -0
  181. package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
  182. package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
  183. package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
  184. package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
  185. package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
  186. package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
  187. package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
  188. package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
  189. package/dist/kernel/db/tx.js +2 -4
  190. package/dist/kernel/errors.js +27 -1
  191. package/dist/kernel/json-answer.js +15 -0
  192. package/dist/kernel/lock.js +4 -9
  193. package/dist/kernel/paths.js +8 -0
  194. package/dist/kernel/pipeline.js +12 -0
  195. package/dist/kernel/ports/assistant-cli.js +4 -0
  196. package/dist/kernel/ports/host-cli.js +3 -0
  197. package/dist/kernel/ports/interest.js +4 -0
  198. package/dist/kernel/ports/languages.js +0 -3
  199. package/dist/kernel/ports/model.js +2 -0
  200. package/dist/kernel/ports/settings-places.js +31 -0
  201. package/dist/kernel/ports/system-speech.js +31 -3
  202. package/dist/kernel/runner/attempt.js +14 -4
  203. package/dist/kernel/runner/audition.js +3 -1
  204. package/dist/kernel/runner/checkpoint-authority.js +2 -1
  205. package/dist/kernel/runner/index.js +8 -10
  206. package/dist/kernel/runner/model-access.js +40 -0
  207. package/dist/kernel/runner/model-check.js +153 -0
  208. package/dist/kernel/runner/providers.js +18 -12
  209. package/dist/kernel/runner/standalone.js +11 -7
  210. package/dist/main.js +338 -21
  211. package/dist/model-catalog.js +20 -0
  212. package/dist/model-checks.js +166 -0
  213. package/dist/patch-notes/4.0.0.md +51 -0
  214. package/dist/patch-notes/4.1.0.md +42 -0
  215. package/dist/patch-notes/index.json +12 -0
  216. package/dist/slices/admission/heads.js +2 -1
  217. package/dist/slices/admission/listing-facts.js +95 -0
  218. package/dist/slices/admission/repo.js +11 -7
  219. package/dist/slices/admission/rules.js +50 -15
  220. package/dist/slices/admission/schema.js +8 -0
  221. package/dist/slices/admission/stage-writes.js +0 -3
  222. package/dist/slices/admission/start.js +48 -31
  223. package/dist/slices/admission/state-words.js +34 -5
  224. package/dist/slices/admission/substitute.js +7 -4
  225. package/dist/slices/agents/attention-posts.js +31 -0
  226. package/dist/slices/agents/attention-templates.js +33 -0
  227. package/dist/slices/agents/attention.js +10 -1
  228. package/dist/slices/agents/connection.js +2 -6
  229. package/dist/slices/agents/model.js +6 -3
  230. package/dist/slices/agents/repo.js +15 -7
  231. package/dist/slices/article/continuation.js +0 -63
  232. package/dist/slices/article/plain.js +3 -2
  233. package/dist/slices/article/segments.js +2 -62
  234. package/dist/slices/assistant/access.js +1 -0
  235. package/dist/slices/assistant/asks.js +80 -0
  236. package/dist/slices/assistant/cost.js +54 -0
  237. package/dist/slices/assistant/gate.js +222 -0
  238. package/dist/slices/assistant/model.js +86 -0
  239. package/dist/slices/assistant/names.js +23 -0
  240. package/dist/slices/assistant/prompt.js +74 -0
  241. package/dist/slices/assistant/repo.js +74 -0
  242. package/dist/slices/assistant/tokens.js +18 -0
  243. package/dist/slices/assistant/turn.js +344 -0
  244. package/dist/slices/autopilot/buffer.js +76 -0
  245. package/dist/slices/autopilot/model.js +14 -0
  246. package/dist/slices/autopilot/notify.js +27 -0
  247. package/dist/slices/autopilot/repo.js +34 -0
  248. package/dist/slices/autopilot/signals.js +194 -0
  249. package/dist/slices/autopilot/warnings.js +85 -0
  250. package/dist/slices/autopilot/weekly.js +100 -0
  251. package/dist/slices/backups/files.js +2 -6
  252. package/dist/slices/backups/repo.js +3 -15
  253. package/dist/slices/backups/service.js +8 -7
  254. package/dist/slices/channels/cast-images.js +3 -2
  255. package/dist/slices/channels/model.js +0 -1
  256. package/dist/slices/channels/rebrand.js +0 -3
  257. package/dist/slices/channels/repo.js +4 -0
  258. package/dist/slices/channels/schema.js +7 -1
  259. package/dist/slices/channels/service.js +10 -0
  260. package/dist/slices/channels/videos.js +3 -15
  261. package/dist/slices/checkpoints/index.js +0 -1
  262. package/dist/slices/control/providers.js +2 -28
  263. package/dist/slices/designs/artwork.js +66 -0
  264. package/dist/slices/designs/budget.js +23 -0
  265. package/dist/slices/designs/calls.js +124 -0
  266. package/dist/slices/designs/check-context.js +38 -0
  267. package/dist/slices/designs/check-text.js +43 -0
  268. package/dist/slices/designs/fields.js +88 -0
  269. package/dist/slices/designs/frames.js +34 -0
  270. package/dist/slices/designs/gate.js +130 -0
  271. package/dist/slices/designs/layout.js +293 -0
  272. package/dist/slices/designs/model.js +35 -0
  273. package/dist/slices/designs/pdf-job.js +23 -0
  274. package/dist/slices/designs/pdf-pages.js +30 -0
  275. package/dist/slices/designs/pdf-runner.js +68 -0
  276. package/dist/slices/designs/pdf-worker.js +24 -0
  277. package/dist/slices/designs/picture-size.js +79 -0
  278. package/dist/slices/designs/pictures.js +55 -0
  279. package/dist/slices/designs/quote.js +24 -0
  280. package/dist/slices/designs/render-args.js +36 -0
  281. package/dist/slices/designs/render-input.js +59 -0
  282. package/dist/slices/designs/render.js +215 -0
  283. package/dist/slices/designs/repo.js +101 -0
  284. package/dist/slices/designs/requests.js +80 -0
  285. package/dist/slices/designs/runner.js +239 -0
  286. package/dist/slices/designs/sample-repo.js +91 -0
  287. package/dist/slices/designs/sample.js +223 -0
  288. package/dist/slices/designs/schema.js +87 -0
  289. package/dist/slices/designs/sections.js +44 -0
  290. package/dist/slices/designs/service.js +233 -0
  291. package/dist/slices/designs/steps-repo.js +102 -0
  292. package/dist/slices/designs/studio-kind.js +39 -0
  293. package/dist/slices/designs/template-checks.js +44 -0
  294. package/dist/slices/designs/template-make.js +118 -0
  295. package/dist/slices/designs/templates.js +218 -0
  296. package/dist/slices/document/fonts.js +2 -1
  297. package/dist/slices/document/model.js +7 -4
  298. package/dist/slices/document/render.js +2 -1
  299. package/dist/slices/document/theme-schema.js +1 -1
  300. package/dist/slices/document/theme.js +49 -3
  301. package/dist/slices/episodes/summarize.js +6 -2
  302. package/dist/slices/estimate/index.js +72 -28
  303. package/dist/slices/estimate/requests.js +4 -4
  304. package/dist/slices/fixes/rules.js +3 -1
  305. package/dist/slices/fonts/catalog.js +5 -3
  306. package/dist/slices/fonts/coverage.js +2 -1
  307. package/dist/slices/fonts/discovery.js +3 -2
  308. package/dist/slices/fonts/files.js +2 -6
  309. package/dist/slices/fonts/index.js +0 -1
  310. package/dist/slices/fonts/sfnt.js +45 -10
  311. package/dist/slices/images/appearance.js +8 -16
  312. package/dist/slices/images/scenes.js +102 -28
  313. package/dist/slices/keywords/digest.js +85 -0
  314. package/dist/slices/keywords/facts.js +92 -0
  315. package/dist/slices/keywords/fill.js +80 -0
  316. package/dist/slices/keywords/model.js +75 -0
  317. package/dist/slices/keywords/rules.js +187 -0
  318. package/dist/slices/keywords/schema.js +28 -0
  319. package/dist/slices/keywords/specs.js +260 -0
  320. package/dist/slices/keywords/values.js +74 -0
  321. package/dist/slices/library/lint.js +29 -12
  322. package/dist/slices/library/model.js +2 -0
  323. package/dist/slices/library/photorealistic.js +4 -12
  324. package/dist/slices/library/rename.js +9 -7
  325. package/dist/slices/library/save.js +14 -10
  326. package/dist/slices/library/slots.js +37 -11
  327. package/dist/slices/library/transfer.js +5 -4
  328. package/dist/slices/library/used-by.js +25 -10
  329. package/dist/slices/loudness/loudnorm.js +53 -12
  330. package/dist/slices/loudness/model.js +3 -2
  331. package/dist/slices/loudness/sentence-level.js +2 -1
  332. package/dist/slices/model-checks/cost.js +61 -0
  333. package/dist/slices/model-checks/listing.js +124 -0
  334. package/dist/slices/model-checks/model.js +20 -0
  335. package/dist/slices/model-checks/record.js +32 -0
  336. package/dist/slices/model-checks/repo.js +120 -0
  337. package/dist/slices/model-checks/rules.js +125 -0
  338. package/dist/slices/model-checks/run.js +143 -0
  339. package/dist/slices/model-checks/service.js +198 -0
  340. package/dist/slices/model-upkeep/model.js +1 -1
  341. package/dist/slices/model-upkeep/switch.js +72 -27
  342. package/dist/slices/model-upkeep/usage.js +39 -13
  343. package/dist/slices/narration/breaths.js +3 -1
  344. package/dist/slices/narration/clean-pieces.js +3 -1
  345. package/dist/slices/narration/concat.js +2 -1
  346. package/dist/slices/narration/pauses-model.js +3 -2
  347. package/dist/slices/narration/peaks.js +3 -4
  348. package/dist/slices/narration/pronunciation-chunks.js +4 -3
  349. package/dist/slices/narration/pronunciation.js +6 -4
  350. package/dist/slices/narration/steering.js +4 -3
  351. package/dist/slices/notifications/notifier.js +4 -3
  352. package/dist/slices/notifications/rules.js +5 -2
  353. package/dist/slices/notifications/settings.js +4 -12
  354. package/dist/slices/notifications/subject.js +4 -3
  355. package/dist/slices/onboarding/copy.js +21 -3
  356. package/dist/slices/onboarding/first-run.js +16 -40
  357. package/dist/slices/onboarding/full-video.js +3 -2
  358. package/dist/slices/onboarding/install.js +6 -4
  359. package/dist/slices/onboarding/model.js +26 -37
  360. package/dist/slices/onboarding/packs.js +22 -22
  361. package/dist/slices/onboarding/preferred-model.js +14 -0
  362. package/dist/slices/onboarding/quick-short.js +105 -65
  363. package/dist/slices/onboarding/sample.js +4 -2
  364. package/dist/slices/onboarding/state.js +9 -11
  365. package/dist/slices/onboarding/template.js +8 -6
  366. package/dist/slices/outputs/add.js +3 -2
  367. package/dist/slices/outputs/service.js +2 -2
  368. package/dist/slices/patch-notes/library.js +4 -3
  369. package/dist/slices/play-drafts/convert.js +4 -0
  370. package/dist/slices/play-drafts/readiness.js +3 -3
  371. package/dist/slices/play-drafts/review-inputs.js +9 -3
  372. package/dist/slices/play-drafts/review.js +5 -4
  373. package/dist/slices/play-drafts/schema.js +4 -0
  374. package/dist/slices/play-drafts/service.js +17 -7
  375. package/dist/slices/project-templates/from-project.js +9 -2
  376. package/dist/slices/project-templates/next-chapter.js +2 -1
  377. package/dist/slices/project-templates/provider-defaults.js +22 -0
  378. package/dist/slices/project-templates/repo.js +6 -1
  379. package/dist/slices/project-templates/setup-sections.js +26 -0
  380. package/dist/slices/project-templates/setup.js +14 -1
  381. package/dist/slices/project-templates/stand-ins.js +22 -0
  382. package/dist/slices/rebuild/activity.js +2 -0
  383. package/dist/slices/rebuild/admission-repo.js +3 -2
  384. package/dist/slices/rebuild/narration-history.js +4 -5
  385. package/dist/slices/rebuild/narration-retry.js +2 -1
  386. package/dist/slices/rebuild/preview-details.js +32 -14
  387. package/dist/slices/rebuild/preview-plan.js +3 -8
  388. package/dist/slices/rebuild/recipe-build.js +8 -3
  389. package/dist/slices/rebuild/recipe-describe.js +3 -3
  390. package/dist/slices/rebuild/recipe-digest.js +58 -0
  391. package/dist/slices/rebuild/recipe-input-schema.js +10 -0
  392. package/dist/slices/rebuild/recipe-keywords.js +71 -0
  393. package/dist/slices/rebuild/recipe-legacy.js +5 -1
  394. package/dist/slices/rebuild/recipe-model.js +4 -0
  395. package/dist/slices/rebuild/recipe-narration-text.js +2 -1
  396. package/dist/slices/rebuild/recipe-preparation.js +4 -4
  397. package/dist/slices/rebuild/recipe-reference.js +8 -4
  398. package/dist/slices/rebuild/recipe-reviews.js +27 -7
  399. package/dist/slices/rebuild/recipe-save.js +8 -5
  400. package/dist/slices/rebuild/recipe-scenes.js +40 -11
  401. package/dist/slices/rebuild/recipe-shorts.js +8 -8
  402. package/dist/slices/rebuild/recipe-social.js +46 -0
  403. package/dist/slices/rebuild/recipe-text.js +64 -20
  404. package/dist/slices/rebuild/recipe-validation.js +102 -31
  405. package/dist/slices/rebuild/recipe-visual.js +55 -16
  406. package/dist/slices/rebuild/recipe-voices.js +3 -2
  407. package/dist/slices/rebuild/recipe-work.js +19 -7
  408. package/dist/slices/rebuild/recipe-youtube.js +4 -3
  409. package/dist/slices/rebuild/recovery-selection.js +3 -1
  410. package/dist/slices/rebuild/recovery.js +9 -8
  411. package/dist/slices/rebuild/remake-outdated.js +5 -5
  412. package/dist/slices/rebuild/repo.js +4 -3
  413. package/dist/slices/rebuild/review-promise.js +25 -0
  414. package/dist/slices/rebuild/review-redo.js +3 -2
  415. package/dist/slices/rebuild/runtime-admission.js +4 -3
  416. package/dist/slices/rebuild/runtime-agent-review.js +11 -5
  417. package/dist/slices/rebuild/runtime-animate.js +10 -9
  418. package/dist/slices/rebuild/runtime-article.js +7 -5
  419. package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
  420. package/dist/slices/rebuild/runtime-document.js +11 -13
  421. package/dist/slices/rebuild/runtime-export-bed.js +8 -12
  422. package/dist/slices/rebuild/runtime-export-edit.js +8 -16
  423. package/dist/slices/rebuild/runtime-export-inputs.js +12 -11
  424. package/dist/slices/rebuild/runtime-export-short.js +9 -5
  425. package/dist/slices/rebuild/runtime-export.js +38 -15
  426. package/dist/slices/rebuild/runtime-figure-card.js +2 -1
  427. package/dist/slices/rebuild/runtime-image.js +8 -12
  428. package/dist/slices/rebuild/runtime-instructions.js +2 -0
  429. package/dist/slices/rebuild/runtime-keywords.js +59 -0
  430. package/dist/slices/rebuild/runtime-lines.js +2 -11
  431. package/dist/slices/rebuild/runtime-local.js +17 -22
  432. package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
  433. package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
  434. package/dist/slices/rebuild/runtime-narration-text.js +13 -17
  435. package/dist/slices/rebuild/runtime-pictures.js +2 -4
  436. package/dist/slices/rebuild/runtime-piece-label.js +10 -6
  437. package/dist/slices/rebuild/runtime-plan.js +31 -5
  438. package/dist/slices/rebuild/runtime-provider.js +67 -25
  439. package/dist/slices/rebuild/runtime-publication.js +10 -9
  440. package/dist/slices/rebuild/runtime-review.js +39 -33
  441. package/dist/slices/rebuild/runtime-run.js +4 -1
  442. package/dist/slices/rebuild/runtime-shorts.js +31 -50
  443. package/dist/slices/rebuild/runtime-store.js +20 -10
  444. package/dist/slices/rebuild/runtime-subtitles.js +28 -25
  445. package/dist/slices/rebuild/runtime-voices.js +10 -16
  446. package/dist/slices/rebuild/runtime-youtube.js +14 -31
  447. package/dist/slices/rebuild/service-readiness.js +11 -3
  448. package/dist/slices/rebuild/transition-repo.js +6 -5
  449. package/dist/slices/rebuild/work-records.js +6 -0
  450. package/dist/slices/reruns/cascade.js +1 -2
  451. package/dist/slices/reruns/index.js +6 -9
  452. package/dist/slices/research/synthesis.js +3 -2
  453. package/dist/slices/reviews/external-model.js +4 -1
  454. package/dist/slices/reviews/external-repo.js +2 -1
  455. package/dist/slices/reviews/external-rows.js +2 -3
  456. package/dist/slices/reviews/holds.js +5 -4
  457. package/dist/slices/reviews/model.js +32 -11
  458. package/dist/slices/reviews/repo.js +2 -1
  459. package/dist/slices/reviews/rules.js +4 -3
  460. package/dist/slices/reviews/verdict.js +2 -1
  461. package/dist/slices/reviews/view.js +5 -2
  462. package/dist/slices/revisions/downloads.js +4 -5
  463. package/dist/slices/revisions/image-plan.js +1 -1
  464. package/dist/slices/revisions/mutation-assets.js +9 -5
  465. package/dist/slices/revisions/mutation-cues.js +2 -5
  466. package/dist/slices/revisions/mutations.js +3 -3
  467. package/dist/slices/revisions/repo.js +3 -1
  468. package/dist/slices/revisions/schema.js +1 -0
  469. package/dist/slices/revisions/view.js +20 -0
  470. package/dist/slices/run-cost/limits.js +5 -2
  471. package/dist/slices/run-cost/meter.js +12 -5
  472. package/dist/slices/run-cost/panel.js +8 -74
  473. package/dist/slices/run-cost/plan-readings.js +127 -0
  474. package/dist/slices/run-cost/plan-use.js +169 -0
  475. package/dist/slices/run-cost/pricing.js +3 -3
  476. package/dist/slices/run-cost/week.js +32 -4
  477. package/dist/slices/schedules/agenda.js +18 -7
  478. package/dist/slices/schedules/by-date.js +42 -0
  479. package/dist/slices/schedules/calendar.js +5 -0
  480. package/dist/slices/schedules/design-agenda.js +36 -0
  481. package/dist/slices/schedules/design-check.js +41 -0
  482. package/dist/slices/schedules/design-run.js +126 -0
  483. package/dist/slices/schedules/next-run.js +62 -0
  484. package/dist/slices/schedules/prepare.js +18 -2
  485. package/dist/slices/schedules/repo.js +30 -21
  486. package/dist/slices/schedules/rescore.js +35 -0
  487. package/dist/slices/schedules/scheduler.js +13 -3
  488. package/dist/slices/schedules/schema.js +57 -3
  489. package/dist/slices/schedules/score.js +107 -0
  490. package/dist/slices/schedules/service.js +57 -24
  491. package/dist/slices/schedules/topic-list.js +15 -0
  492. package/dist/slices/schedules/topic-scores.js +104 -0
  493. package/dist/slices/schedules/topics.js +53 -41
  494. package/dist/slices/settings/cli-paths.js +4 -6
  495. package/dist/slices/settings/first-run.js +8 -43
  496. package/dist/slices/settings/health.js +30 -15
  497. package/dist/slices/settings/key-test.js +1 -1
  498. package/dist/slices/settings/model-reach.js +3 -17
  499. package/dist/slices/settings/model.js +14 -2
  500. package/dist/slices/settings/playback.js +34 -23
  501. package/dist/slices/settings/probe-read.js +16 -0
  502. package/dist/slices/settings/repo.js +33 -0
  503. package/dist/slices/settings/tutorial.js +2 -2
  504. package/dist/slices/settings/voices.js +4 -12
  505. package/dist/slices/shorts/keep.js +2 -1
  506. package/dist/slices/shorts/pick.js +6 -18
  507. package/dist/slices/shorts/prompts.js +4 -14
  508. package/dist/slices/shorts/render.js +6 -2
  509. package/dist/slices/social/channel.js +44 -0
  510. package/dist/slices/social/defaults.js +17 -0
  511. package/dist/slices/social/due.js +36 -0
  512. package/dist/slices/social/extension.js +18 -0
  513. package/dist/slices/social/fit.js +115 -0
  514. package/dist/slices/social/limits.js +186 -0
  515. package/dist/slices/social/links.js +21 -0
  516. package/dist/slices/social/media.js +132 -0
  517. package/dist/slices/social/model.js +75 -0
  518. package/dist/slices/social/notice.js +19 -0
  519. package/dist/slices/social/pack.js +176 -0
  520. package/dist/slices/social/post-prompt.js +56 -0
  521. package/dist/slices/social/queue.js +31 -0
  522. package/dist/slices/social/repo.js +133 -0
  523. package/dist/slices/social/reshape.js +97 -0
  524. package/dist/slices/social/rules.js +5 -0
  525. package/dist/slices/social/schema.js +70 -0
  526. package/dist/slices/social/serve.js +51 -0
  527. package/dist/slices/social/service.js +129 -0
  528. package/dist/slices/social/settings.js +21 -0
  529. package/dist/slices/social/sources.js +114 -0
  530. package/dist/slices/social/state.js +110 -0
  531. package/dist/slices/social/text.js +149 -0
  532. package/dist/slices/storage/arrange.js +3 -1
  533. package/dist/slices/storage/assets.js +8 -10
  534. package/dist/slices/storage/backup-designs.js +74 -0
  535. package/dist/slices/storage/backup-export.js +8 -3
  536. package/dist/slices/storage/backup-format.js +10 -0
  537. package/dist/slices/storage/backup-import.js +22 -4
  538. package/dist/slices/storage/delete-project.js +6 -5
  539. package/dist/slices/storage/files-location.js +6 -8
  540. package/dist/slices/storage/layout.js +13 -2
  541. package/dist/slices/storage/model.js +3 -0
  542. package/dist/slices/storage/portable.js +17 -12
  543. package/dist/slices/storage/schema.js +2 -0
  544. package/dist/slices/storage/staging-refs.js +2 -1
  545. package/dist/slices/storage/staging.js +6 -9
  546. package/dist/slices/storage/trim.js +26 -9
  547. package/dist/slices/studio/calendar.js +7 -2
  548. package/dist/slices/studio/disclosure.js +4 -4
  549. package/dist/slices/studio/model.js +1 -1
  550. package/dist/slices/studio/pack.js +9 -8
  551. package/dist/slices/studio/pick.js +2 -11
  552. package/dist/slices/studio/plan.js +7 -16
  553. package/dist/slices/studio/queue.js +3 -14
  554. package/dist/slices/studio/releases.js +26 -0
  555. package/dist/slices/studio/settings.js +20 -57
  556. package/dist/slices/studio/videos.js +35 -4
  557. package/dist/slices/style-preview/render.js +37 -16
  558. package/dist/slices/style-preview/schema.js +14 -1
  559. package/dist/slices/style-preview/service.js +2 -1
  560. package/dist/slices/style-preview/settings.js +33 -5
  561. package/dist/slices/subtitles/captions.js +1 -1
  562. package/dist/slices/telemetry/collector-client.js +2 -4
  563. package/dist/slices/telemetry/flush.js +2 -4
  564. package/dist/slices/telemetry/model.js +0 -7
  565. package/dist/slices/telemetry/record.js +10 -3
  566. package/dist/slices/template-studio/anatomy-view.js +161 -0
  567. package/dist/slices/template-studio/anatomy.js +73 -0
  568. package/dist/slices/template-studio/bakeoff-make.js +225 -0
  569. package/dist/slices/template-studio/bakeoff-repo.js +83 -0
  570. package/dist/slices/template-studio/bakeoff.js +333 -0
  571. package/dist/slices/template-studio/budget.js +106 -0
  572. package/dist/slices/template-studio/cards.js +78 -0
  573. package/dist/slices/template-studio/checks.js +322 -0
  574. package/dist/slices/template-studio/document-sample.js +56 -0
  575. package/dist/slices/template-studio/edit.js +15 -0
  576. package/dist/slices/template-studio/for-all.js +161 -0
  577. package/dist/slices/template-studio/free-video.js +31 -0
  578. package/dist/slices/template-studio/free.js +176 -0
  579. package/dist/slices/template-studio/gate.js +40 -0
  580. package/dist/slices/template-studio/hidden.js +20 -0
  581. package/dist/slices/template-studio/jobs.js +79 -0
  582. package/dist/slices/template-studio/loudness.js +111 -0
  583. package/dist/slices/template-studio/make.js +40 -0
  584. package/dist/slices/template-studio/model.js +58 -0
  585. package/dist/slices/template-studio/pack-import.js +253 -0
  586. package/dist/slices/template-studio/pack-samples.js +60 -0
  587. package/dist/slices/template-studio/pack.js +207 -0
  588. package/dist/slices/template-studio/paid-view.js +66 -0
  589. package/dist/slices/template-studio/paid.js +355 -0
  590. package/dist/slices/template-studio/quote.js +155 -0
  591. package/dist/slices/template-studio/ready.js +104 -0
  592. package/dist/slices/template-studio/repo.js +134 -0
  593. package/dist/slices/template-studio/reviews-path.js +58 -0
  594. package/dist/slices/template-studio/runner.js +84 -0
  595. package/dist/slices/template-studio/save.js +236 -0
  596. package/dist/slices/template-studio/say-it-as.js +248 -0
  597. package/dist/slices/template-studio/schedule-gate.js +34 -0
  598. package/dist/slices/template-studio/schedule-price.js +32 -0
  599. package/dist/slices/template-studio/schedule-sample.js +91 -0
  600. package/dist/slices/template-studio/schema.js +243 -0
  601. package/dist/slices/template-studio/scope.js +124 -0
  602. package/dist/slices/template-studio/sections.js +176 -0
  603. package/dist/slices/template-studio/service.js +175 -0
  604. package/dist/slices/template-studio/status.js +191 -0
  605. package/dist/slices/template-studio/topic.js +223 -0
  606. package/dist/slices/thumbnail/by-llm.js +1 -1
  607. package/dist/slices/trash/designs.js +76 -0
  608. package/dist/slices/trash/model.js +13 -4
  609. package/dist/slices/trash/service.js +52 -2
  610. package/dist/slices/tutorials/library.js +3 -2
  611. package/dist/slices/uploads/repo.js +37 -1
  612. package/dist/slices/uploads/rules.js +3 -2
  613. package/dist/slices/video/ass-text.js +17 -0
  614. package/dist/slices/video/audio-export.js +2 -64
  615. package/dist/slices/video/edit-list.js +2 -2
  616. package/dist/slices/video/edit-settings.js +1 -1
  617. package/dist/slices/video/encoding.js +169 -0
  618. package/dist/slices/video/ffmpeg.js +23 -21
  619. package/dist/slices/video/figure-card.js +1 -15
  620. package/dist/slices/video/plan.js +2 -1
  621. package/dist/slices/video/slideshow.js +43 -18
  622. package/dist/slices/voices/attribution.js +3 -2
  623. package/dist/slices/voices/model.js +9 -8
  624. package/dist/slices/voices/palette.js +0 -3
  625. package/dist/slices/voices/script.js +2 -1
  626. package/dist/slices/youtube/answer.js +4 -16
  627. package/dist/slices/youtube/edits-repo.js +3 -12
  628. package/dist/tutorials/AI-CLIs.md +25 -25
  629. package/dist/tutorials/Agents-MCP.md +34 -33
  630. package/dist/tutorials/Assistant.md +42 -0
  631. package/dist/tutorials/Backups.md +7 -7
  632. package/dist/tutorials/Calendar.md +17 -25
  633. package/dist/tutorials/Cast-Library.md +19 -19
  634. package/dist/tutorials/Channels.md +42 -35
  635. package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
  636. package/dist/tutorials/Create-Article.md +114 -0
  637. package/dist/tutorials/Create-Extras.md +112 -0
  638. package/dist/tutorials/Create-Images.md +165 -0
  639. package/dist/tutorials/Create-Narration.md +178 -0
  640. package/dist/tutorials/Create-Overview.md +244 -0
  641. package/dist/tutorials/Create-Video-and-Style.md +144 -0
  642. package/dist/tutorials/Docker.md +3 -3
  643. package/dist/tutorials/Document-Themes.md +32 -32
  644. package/dist/tutorials/Editing-a-Project.md +94 -94
  645. package/dist/tutorials/FAQ.md +18 -18
  646. package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
  647. package/dist/tutorials/Home-and-Projects.md +115 -71
  648. package/dist/tutorials/Home.md +33 -33
  649. package/dist/tutorials/Install.md +14 -13
  650. package/dist/tutorials/Intros-and-Outros.md +33 -34
  651. package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
  652. package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
  653. package/dist/tutorials/Models.md +53 -21
  654. package/dist/tutorials/Multiple-Voices.md +41 -40
  655. package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
  656. package/dist/tutorials/Notifications.md +27 -17
  657. package/dist/tutorials/Other-Languages.md +15 -15
  658. package/dist/tutorials/PDF-Documents.md +38 -29
  659. package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
  660. package/dist/tutorials/Project-Page.md +118 -120
  661. package/dist/tutorials/Prompts-and-Templates.md +84 -0
  662. package/dist/tutorials/Prompts.md +48 -44
  663. package/dist/tutorials/Providers-and-Keys.md +105 -98
  664. package/dist/tutorials/Publishing-to-YouTube.md +31 -31
  665. package/dist/tutorials/Recovery-and-Retries.md +31 -31
  666. package/dist/tutorials/Remote-Access.md +63 -0
  667. package/dist/tutorials/Reviews-and-Checkpoints.md +98 -90
  668. package/dist/tutorials/Schedules.md +46 -27
  669. package/dist/tutorials/Settings-Reference.md +194 -174
  670. package/dist/tutorials/Shorts.md +34 -33
  671. package/dist/tutorials/Start-at-Login.md +3 -3
  672. package/dist/tutorials/Studio-Extension.md +22 -24
  673. package/dist/tutorials/Template-Studio.md +128 -0
  674. package/dist/tutorials/Templates.md +51 -77
  675. package/dist/tutorials/Trash.md +4 -4
  676. package/dist/tutorials/Troubleshooting.md +44 -44
  677. package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
  678. package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
  679. package/dist/tutorials/Video-Editing.md +34 -34
  680. package/dist/tutorials/Where-Your-Files-Live.md +10 -10
  681. package/dist/tutorials/YouTube-Description.md +26 -26
  682. package/dist/tutorials/Your-First-Short.md +35 -35
  683. package/dist/tutorials/_Sidebar.md +19 -14
  684. package/dist/updater/work-in-progress.js +42 -12
  685. package/dist/web/assets/index-BNftKQrA.css +1 -0
  686. package/dist/web/assets/index-Cpa58woP.js +459 -0
  687. package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
  688. package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
  689. package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
  690. package/dist/web/index.html +2 -2
  691. package/package.json +6 -2
  692. package/dist/slices/article/provided-entries.js +0 -66
  693. package/dist/slices/article/run.js +0 -145
  694. package/dist/slices/images/run.js +0 -234
  695. package/dist/slices/narration/legacy-plan.js +0 -58
  696. package/dist/slices/narration/run.js +0 -270
  697. package/dist/slices/rebuild/runtime-actions.js +0 -90
  698. package/dist/slices/research/run.js +0 -224
  699. package/dist/slices/subtitles/prepare.js +0 -194
  700. package/dist/slices/subtitles/transcript.js +0 -34
  701. package/dist/slices/thumbnail/run.js +0 -219
  702. package/dist/slices/video/audio-inputs.js +0 -33
  703. package/dist/slices/video/reuse-audio.js +0 -62
  704. package/dist/slices/video/run.js +0 -78
  705. package/dist/slices/video/write-export.js +0 -158
  706. package/dist/slices/video/write-subtitles.js +0 -59
  707. package/dist/tutorials/Library-Overview.md +0 -76
  708. package/dist/tutorials/Play-Images.md +0 -161
  709. package/dist/tutorials/Play-Narration.md +0 -167
  710. package/dist/tutorials/Play-Outputs.md +0 -109
  711. package/dist/tutorials/Play-Overview.md +0 -227
  712. package/dist/tutorials/Play-Title-and-Article.md +0 -136
  713. package/dist/tutorials/Play-Video-and-Style.md +0 -143
  714. package/dist/web/assets/index-BadsoORk.css +0 -1
  715. package/dist/web/assets/index-D8LqNsCl.js +0 -326
  716. package/dist/web/assets/pdf-T7MCwjIv.js +0 -54
  717. package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
  718. package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
@@ -0,0 +1,333 @@
1
+ import { z } from "zod";
2
+ import { transact } from "../../kernel/db/tx.js";
3
+ import { projectExists } from "../admission/repo.js";
4
+ import { keepThinking } from "../model-upkeep/switch.js";
5
+ import { templateById } from "../project-templates/repo.js";
6
+ import { currentRevisionId } from "../revisions/repo.js";
7
+ import { getRevisionView, isReadyOutput } from "../revisions/view.js";
8
+ import { runCostOf } from "../run-cost/panel.js";
9
+ import { bakeoffOf, bakeoffSections, clonesOf, deleteBakeoffRow, insertBakeoff, } from "./bakeoff-repo.js";
10
+ import { budgetRoom, budgetWords, fitsBudget } from "./budget.js";
11
+ import { removeHiddenProject } from "./hidden.js";
12
+ import { enqueueJob, queuedJob, runningJob } from "./jobs.js";
13
+ import { sectionLabel } from "./model.js";
14
+ import { quoteSample } from "./quote.js";
15
+ import { sampleOf, sampleVersions } from "./repo.js";
16
+ import { exceedsAcknowledged } from "./save.js";
17
+ import { sectionOfWork } from "./sections.js";
18
+ // Compare models: one section's sample made again on one or two other models, each on a hidden
19
+ // copy of the template's sample (`onboarding/copy.ts`), so its cost and speed sit beside the
20
+ // model the template uses now. Only that section's work runs on each copy. Nothing about the
21
+ // template changes: "Use this model" is a normal Save, and the copies are discarded after.
22
+ export const bakeoffModelSchema = z
23
+ .object({
24
+ provider: z.string().trim().min(1).max(100),
25
+ model: z.string().trim().min(1).max(200),
26
+ })
27
+ .strict();
28
+ export const bakeoffQuoteSchema = z
29
+ .object({
30
+ section: z.enum(bakeoffSections),
31
+ // The models to compare with the one the template uses now: one or two.
32
+ models: z.array(bakeoffModelSchema).min(1).max(2),
33
+ })
34
+ .strict();
35
+ export const bakeoffStartSchema = bakeoffQuoteSchema
36
+ .extend({
37
+ // The total high estimate the quote showed, and that steps with no price are accepted.
38
+ acknowledgedHigh: z.number().finite().min(0).max(10_000),
39
+ acknowledgedUnknown: z.boolean().optional(),
40
+ })
41
+ .strict();
42
+ // The stage each section's model works in, which its time is read from.
43
+ export const bakeoffStage = {
44
+ script: "article",
45
+ voice: "audio",
46
+ pictures: "images",
47
+ };
48
+ // The model a section is made with now, or undefined when no model makes it.
49
+ export function sectionModel(document, section) {
50
+ const { form } = document;
51
+ const pick = (choice) => choice.provider === "" || choice.model === ""
52
+ ? undefined
53
+ : { provider: choice.provider, model: choice.model };
54
+ switch (section) {
55
+ case "script":
56
+ return form.sources.article === "generate" ? pick(form.llm) : undefined;
57
+ case "voice":
58
+ return form.sources.audio === "generate" ? pick(form.audio) : undefined;
59
+ case "pictures":
60
+ return form.sources.images === "generate" ? pick(form.images) : undefined;
61
+ }
62
+ }
63
+ // The template's setup with the section made with `model` and nothing else changed.
64
+ export function withModel(document, section, model, catalogue) {
65
+ const { form } = document;
66
+ switch (section) {
67
+ case "script": {
68
+ const { thinking, ...rest } = form.llm;
69
+ return {
70
+ ...document,
71
+ form: {
72
+ ...form,
73
+ llm: {
74
+ ...rest,
75
+ provider: model.provider,
76
+ model: model.model,
77
+ ...keepThinking(catalogue, model.provider, model.model, thinking),
78
+ },
79
+ },
80
+ };
81
+ }
82
+ case "voice":
83
+ return { ...document, form: { ...form, audio: { ...form.audio, model: model.model } } };
84
+ case "pictures":
85
+ return {
86
+ ...document,
87
+ form: { ...form, images: { ...form.images, provider: model.provider, model: model.model } },
88
+ };
89
+ }
90
+ }
91
+ const refuse = (reason, message) => ({
92
+ ok: false,
93
+ reason,
94
+ message,
95
+ });
96
+ const missingTemplate = "This template no longer exists; it may have been deleted. Go to Templates to see your templates.";
97
+ // What the bake-off is made on: the template's newest version, with a current paid sample.
98
+ function basis(deps, templateId, section, models) {
99
+ const template = templateById(deps.db, templateId);
100
+ if (template === undefined)
101
+ return refuse("not-found", missingTemplate);
102
+ const label = sectionLabel[section];
103
+ const current = sectionModel(template.document, section);
104
+ if (current === undefined)
105
+ return refuse("invalid-input", `No model makes ${label} in this template, so there is nothing to compare. Choose a model in ${label} and press Save first.`);
106
+ const sample = sampleOf(deps.db, templateId);
107
+ const made = sampleVersions(deps.db, templateId).find((one) => one.templateVersion === template.version);
108
+ if (sample === undefined || !projectExists(deps.db, sample.projectId) || made?.state !== "done")
109
+ return refuse("not-ready", `Compare models runs on the template's current sample, and version ${String(template.version)} has none yet. Press Make sample, wait for it, then compare.`);
110
+ const seen = new Set();
111
+ for (const model of models) {
112
+ const key = `${model.provider}:${model.model}`;
113
+ if (model.provider === current.provider && model.model === current.model)
114
+ return refuse("invalid-input", `${model.model} is the model ${label} uses now; its figures come from the current sample. Pick another model to compare it with.`);
115
+ if (seen.has(key))
116
+ return refuse("invalid-input", `${model.model} is picked twice. Pick each model once.`);
117
+ seen.add(key);
118
+ if (section === "voice" && model.provider !== current.provider)
119
+ return refuse("invalid-input", "A voice belongs to its voice service, so voice models are compared within the template's voice service. Pick models of that service, or change the voice in Narration first.");
120
+ }
121
+ return { ok: true, document: template.document, version: template.version, current };
122
+ }
123
+ export async function quoteBakeoff(deps, templateId, input) {
124
+ const base = basis(deps, templateId, input.section, input.models);
125
+ if (!base.ok)
126
+ return base;
127
+ const catalogue = deps.review.catalogue.read();
128
+ const models = [];
129
+ for (const model of input.models) {
130
+ const quoted = await quoteSample(deps, templateId, {
131
+ document: withModel(base.document, input.section, model, catalogue),
132
+ sections: [input.section],
133
+ });
134
+ if (!quoted.ok)
135
+ return quoted;
136
+ models.push({
137
+ ...model,
138
+ high: quoted.value.high,
139
+ unknown: quoted.value.unknown,
140
+ onPlan: quoted.value.onPlan,
141
+ usesPlan: quoted.value.usesPlan,
142
+ problem: quoted.value.problem,
143
+ });
144
+ }
145
+ const high = models.reduce((sum, one) => sum + one.high, 0);
146
+ const usesPlan = models.some((one) => one.usesPlan);
147
+ const budget = budgetRoom(deps.db, deps.clock.now(), deps.timeZone);
148
+ return {
149
+ ok: true,
150
+ value: {
151
+ version: base.version,
152
+ section: input.section,
153
+ current: base.current,
154
+ models,
155
+ high,
156
+ unknown: models.reduce((sum, one) => sum + one.unknown, 0),
157
+ usesPlan,
158
+ budget,
159
+ fits: fitsBudget(budget, high, usesPlan),
160
+ problem: models.find((one) => one.problem !== null)?.problem ?? null,
161
+ },
162
+ };
163
+ }
164
+ // Compare: priced again first; a higher total, an unknown price not accepted or a total past
165
+ // today's budget is refused with the new quote, and nothing is spent.
166
+ export async function startBakeoff(deps, templateId, input) {
167
+ const existing = bakeoffOf(deps.db, templateId);
168
+ if (existing !== undefined && (existing.state === "queued" || existing.state === "making"))
169
+ return refuse("conflict", "A bake-off of this template is still being made. Wait for it to finish, or discard it, then compare again.");
170
+ if (queuedJob(deps.db, templateId) !== undefined ||
171
+ runningJob(deps.db)?.templateId === templateId)
172
+ return refuse("conflict", "A sample of this template is being made. Compare models once it is done: the bake-off runs on it.");
173
+ const quoted = await quoteBakeoff(deps, templateId, input);
174
+ if (!quoted.ok)
175
+ return quoted;
176
+ const quote = quoted.value;
177
+ if (quote.problem !== null)
178
+ return { ...refuse("invalid-input", quote.problem), quote };
179
+ const money = (value) => `$${value.toFixed(2)}`;
180
+ if (exceedsAcknowledged(quote.high, input.acknowledgedHigh))
181
+ return {
182
+ ...refuse("cost-changed", `Comparing now costs about ${money(quote.high)}, more than the ${money(input.acknowledgedHigh)} you saw. Press Compare again to accept the new price.`),
183
+ quote,
184
+ };
185
+ if (quote.unknown > 0 && input.acknowledgedUnknown !== true)
186
+ return {
187
+ ...refuse("cost-changed", `${String(quote.unknown)} ${quote.unknown === 1 ? "step has" : "steps have"} no known price. Press Compare again to accept that.`),
188
+ quote,
189
+ };
190
+ if (!quote.fits)
191
+ return {
192
+ ...refuse("over-budget", `${budgetWords(quote.budget, quote, "Comparing")}, or compare tomorrow.`),
193
+ quote,
194
+ };
195
+ if (existing !== undefined) {
196
+ const cleared = discardBakeoff(deps, templateId);
197
+ if (!cleared.ok)
198
+ return cleared;
199
+ }
200
+ const id = deps.uuid();
201
+ const at = deps.clock.now().toISOString();
202
+ transact(deps.db, () => {
203
+ insertBakeoff(deps.db, {
204
+ id,
205
+ templateId,
206
+ templateVersion: quote.version,
207
+ section: input.section,
208
+ // The person's figure: the quarter-and-five-cents leeway is applied once, at make time.
209
+ ackHigh: input.acknowledgedHigh,
210
+ ackUnknown: quote.unknown > 0,
211
+ createdAt: at,
212
+ }, quote.models.map((model) => ({
213
+ provider: model.provider,
214
+ model: model.model,
215
+ quotedHigh: model.high,
216
+ })));
217
+ enqueueJob(deps.db, {
218
+ templateId,
219
+ templateVersion: quote.version,
220
+ ackHigh: input.acknowledgedHigh,
221
+ kind: "bakeoff",
222
+ requestedAt: at,
223
+ });
224
+ });
225
+ return { ok: true, value: { id, version: quote.version } };
226
+ }
227
+ // Discard: every copy goes, with its files. What the copies were charged today still counts
228
+ // against the sample budget. Refused while a copy still has work going.
229
+ export function discardBakeoff(deps, templateId) {
230
+ const row = bakeoffOf(deps.db, templateId);
231
+ if (row === undefined)
232
+ return { ok: true, value: { removed: 0 } };
233
+ if (row.state === "making" ||
234
+ (row.state === "queued" && runningJob(deps.db)?.templateId === templateId))
235
+ return refuse("conflict", "The bake-off is still being made, and work already going is never stopped. Discard it once it finishes.");
236
+ let removed = 0;
237
+ for (const clone of clonesOf(deps.db, row.id)) {
238
+ if (clone.projectId === null || !projectExists(deps.db, clone.projectId))
239
+ continue;
240
+ const gone = removeHiddenProject(deps, clone.projectId);
241
+ if (!gone.ok)
242
+ return refuse("conflict", gone.reason === "running"
243
+ ? "A model's copy still has work going. Discard the bake-off once it finishes."
244
+ : "A model's copy couldn't be removed from disk. Close any program using Slopify's files, then press Discard again.");
245
+ removed += 1;
246
+ }
247
+ deleteBakeoffRow(deps.db, row.id);
248
+ // A queued bake-off job has nothing left to make.
249
+ if (row.state === "queued")
250
+ deps.db
251
+ .prepare("DELETE FROM template_sample_jobs WHERE template_id=? AND state='queued' AND kind='bakeoff'")
252
+ .run(templateId);
253
+ return { ok: true, value: { removed } };
254
+ }
255
+ const openingChars = 1200;
256
+ function madeOn(deps, projectId, section) {
257
+ const revisionId = currentRevisionId(deps.db, projectId);
258
+ if (revisionId === undefined)
259
+ return { outputs: [], article: null };
260
+ const view = getRevisionView({ ...deps, ids: { next: () => "" }, clock: { now: () => new Date(), sleep: async () => { } } }, projectId, revisionId);
261
+ if (view === undefined)
262
+ return { outputs: [], article: null };
263
+ const outputs = view.outputs.flatMap((row) => isReadyOutput(row) && sectionOfWork(row.workKey) === section
264
+ ? [
265
+ {
266
+ role: row.output.role,
267
+ url: `/files/${encodeURIComponent(projectId)}/revisions/${encodeURIComponent(revisionId)}/${encodeURIComponent(row.recordId)}`,
268
+ name: row.output.path.split("/").pop() ?? row.output.path,
269
+ },
270
+ ]
271
+ : []);
272
+ return {
273
+ outputs: section === "script" ? [] : outputs,
274
+ article: section === "script" && view.articleMarkdown !== null
275
+ ? view.articleMarkdown.slice(0, openingChars)
276
+ : null,
277
+ };
278
+ }
279
+ const secondsOf = (from, to) => from === null || to === null ? null : Math.max(0, (Date.parse(to) - Date.parse(from)) / 1000);
280
+ // The bake-off as the studio shows it: the model in use now (from the template's current
281
+ // sample), then each other model's copy, with what it made, cost and took.
282
+ export function bakeoffView(deps, templateId) {
283
+ const row = bakeoffOf(deps.db, templateId);
284
+ if (row === undefined)
285
+ return null;
286
+ const head = templateById(deps.db, templateId);
287
+ const version = templateById(deps.db, templateId, row.templateVersion);
288
+ const current = version === undefined ? undefined : sectionModel(version.document, row.section);
289
+ const sample = sampleOf(deps.db, templateId);
290
+ const entries = [];
291
+ if (current !== undefined && sample !== undefined && projectExists(deps.db, sample.projectId)) {
292
+ const cost = runCostOf(deps.db, sample.projectId);
293
+ const used = cost.byModel.filter((one) => one.provider === current.provider && one.model === current.model);
294
+ const wall = cost.byStage.find((one) => one.stage === bakeoffStage[row.section])?.wallMs ?? null;
295
+ entries.push({
296
+ ...current,
297
+ slot: null,
298
+ state: "current",
299
+ quotedHigh: null,
300
+ cost: used.length === 0 ? null : used.reduce((sum, one) => sum + one.cost, 0),
301
+ seconds: wall === null ? null : wall / 1000,
302
+ failure: null,
303
+ ...madeOn(deps, sample.projectId, row.section),
304
+ });
305
+ }
306
+ for (const clone of clonesOf(deps.db, row.id)) {
307
+ const exists = clone.projectId !== null && projectExists(deps.db, clone.projectId);
308
+ entries.push({
309
+ provider: clone.provider,
310
+ model: clone.model,
311
+ slot: clone.slot,
312
+ state: clone.state,
313
+ quotedHigh: clone.quotedHigh,
314
+ cost: exists && clone.projectId !== null && clone.state !== "queued"
315
+ ? runCostOf(deps.db, clone.projectId).cost
316
+ : null,
317
+ seconds: secondsOf(clone.startedAt, clone.finishedAt),
318
+ failure: clone.failure,
319
+ ...(exists && clone.projectId !== null && clone.state === "done"
320
+ ? madeOn(deps, clone.projectId, row.section)
321
+ : { outputs: [], article: null }),
322
+ });
323
+ }
324
+ return {
325
+ id: row.id,
326
+ section: row.section,
327
+ version: row.templateVersion,
328
+ stale: head !== undefined && head.version !== row.templateVersion,
329
+ state: row.state,
330
+ sentence: row.sentence,
331
+ entries,
332
+ };
333
+ }
@@ -0,0 +1,106 @@
1
+ import { z } from "zod";
2
+ import { dailySampleBudget, dailySampleBudgetKey } from "../designs/budget.js";
3
+ import { readJsonSetting, writeSetting } from "../settings/repo.js";
4
+ // Settings → Production defaults: the most the studio's samples may spend in one day, in dollars,
5
+ // and whether they may use a CLI plan at all. Plan usage has no dollar price, so the budget
6
+ // can't hold it back: samples that run on a CLI plan wait until the person turns that on. By
7
+ // default ($2 a day, plans off) samples spend at most $2 a day and never a plan; at $0 nothing
8
+ // spends money. A sample that would go over either waits, saying so, until the next day, a
9
+ // higher budget or plans allowed. The designed pieces' samples have their own daily budget
10
+ // (`designs/budget.ts`), set here too, and follow the same plan switch.
11
+ export const dailyBudgetKey = "templateStudio.dailyBudget";
12
+ export const samplesUsePlansKey = "templateStudio.samplesUsePlans";
13
+ export const defaultDailyBudget = 2;
14
+ export const dailyBudgetMax = 1000;
15
+ // Each field left out keeps what is stored.
16
+ export const studioSettingsSchema = z
17
+ .object({
18
+ dailyBudget: z.number().finite().min(0).max(dailyBudgetMax).optional(),
19
+ samplesUsePlans: z.boolean().optional(),
20
+ designDailyBudget: z.number().finite().min(0).max(dailyBudgetMax).optional(),
21
+ })
22
+ .strict()
23
+ .readonly();
24
+ export function readStudioSettings(db) {
25
+ return {
26
+ dailyBudget: readJsonSetting(db, dailyBudgetKey, z.number().finite().min(0).max(dailyBudgetMax), defaultDailyBudget),
27
+ samplesUsePlans: readJsonSetting(db, samplesUsePlansKey, z.boolean(), false),
28
+ designDailyBudget: dailySampleBudget(db),
29
+ };
30
+ }
31
+ export function writeStudioSettings(db, settings) {
32
+ const cents = (dollars) => JSON.stringify(Math.round(dollars * 100) / 100);
33
+ if (settings.dailyBudget !== undefined)
34
+ writeSetting(db, dailyBudgetKey, cents(settings.dailyBudget));
35
+ if (settings.designDailyBudget !== undefined)
36
+ writeSetting(db, dailySampleBudgetKey, cents(settings.designDailyBudget));
37
+ if (settings.samplesUsePlans !== undefined)
38
+ writeSetting(db, samplesUsePlansKey, JSON.stringify(settings.samplesUsePlans));
39
+ return readStudioSettings(db);
40
+ }
41
+ // The instant today began on this computer's clock, in `timeZone`.
42
+ export function localMidnight(now, timeZone) {
43
+ const day = Temporal.Instant.fromEpochMilliseconds(now.valueOf())
44
+ .toZonedDateTimeISO(timeZone)
45
+ .startOfDay();
46
+ return new Date(day.epochMilliseconds);
47
+ }
48
+ export function systemTimeZone() {
49
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
50
+ }
51
+ // What the studio's samples were charged since local midnight: the priced calls of every
52
+ // template's sample project and every bake-off copy, billed per use (a CLI plan's calls add
53
+ // nothing), and what such a project spent before it was removed. Other projects' calls never
54
+ // count.
55
+ export function spentToday(db, now, timeZone = systemTimeZone()) {
56
+ const since = localMidnight(now, timeZone).toISOString();
57
+ const row = db
58
+ .prepare(`SELECT COALESCE((SELECT SUM(u.cost) FROM provider_usage u
59
+ WHERE u.project_id IN (SELECT project_id FROM template_hidden_projects)
60
+ AND u.on_plan = 0 AND u.created_at >= ?), 0)
61
+ + COALESCE((SELECT SUM(cost) FROM template_studio_spend WHERE created_at >= ?), 0) AS spent`)
62
+ .get(since, since);
63
+ return z.object({ spent: z.number() }).parse(row).spent;
64
+ }
65
+ // Today's sample calls billed per use whose price no one knows: they add nothing to `spentToday`,
66
+ // so they are counted and said beside it rather than read as free.
67
+ export function unpricedToday(db, now, timeZone = systemTimeZone()) {
68
+ const row = db
69
+ .prepare(`SELECT count(*) AS n FROM provider_usage u
70
+ WHERE u.project_id IN (SELECT project_id FROM template_hidden_projects)
71
+ AND u.on_plan = 0 AND u.cost IS NULL AND u.created_at >= ?`)
72
+ .get(localMidnight(now, timeZone).toISOString());
73
+ return z.object({ n: z.number() }).parse(row).n;
74
+ }
75
+ export function budgetRoom(db, now, timeZone = systemTimeZone()) {
76
+ const { dailyBudget, samplesUsePlans } = readStudioSettings(db);
77
+ const spent = spentToday(db, now, timeZone);
78
+ return {
79
+ budget: dailyBudget,
80
+ spent,
81
+ unpriced: unpricedToday(db, now, timeZone),
82
+ left: Math.max(0, dailyBudget - spent),
83
+ plans: samplesUsePlans,
84
+ };
85
+ }
86
+ // Whether a sample of about `high` dollars, `usesPlan` when a step runs on a CLI plan, may
87
+ // start on what is left of today's budget.
88
+ export function fitsBudget(room, high, usesPlan = false) {
89
+ if (usesPlan && !room.plans)
90
+ return false;
91
+ return high <= room.left + 1e-9;
92
+ }
93
+ const money = (value) => `$${value.toFixed(2)}`;
94
+ // Settings → Production defaults' switch by its name on screen (web `budget-words.ts`
95
+ // plansLabel), so a sentence that says to turn it on names what the person will find.
96
+ export const plansSwitch = "Let samples use my Claude Code or Codex plan";
97
+ // Why a sample that doesn't fit (`fitsBudget`) waits, and what lets it start, as one sentence
98
+ // (no full stop) about `subject`: "This sample", "Comparing".
99
+ export function budgetWords(room, cost, subject) {
100
+ if (cost.usesPlan && !room.plans)
101
+ return `${subject} runs on your Claude Code or Codex plan, and samples may not use it. Turn on ${plansSwitch} in Settings → Production defaults`;
102
+ const unpriced = room.unpriced === 0
103
+ ? ""
104
+ : ` (samples spent ${money(room.spent)} today plus ${String(room.unpriced)} ${room.unpriced === 1 ? "call" : "calls"} with no known price)`;
105
+ return `${subject} costs about ${money(cost.high)} and ${money(room.left)} of today's ${money(room.budget)} sample budget is left${unpriced}. Raise the budget in Settings → Production defaults`;
106
+ }
@@ -0,0 +1,78 @@
1
+ import { projectExists } from "../admission/repo.js";
2
+ import { topicKeywords } from "../project-templates/one-off.js";
3
+ import { templateById, templateSummaries } from "../project-templates/repo.js";
4
+ import { currentRevisionId } from "../revisions/repo.js";
5
+ import { getRevisionView } from "../revisions/view.js";
6
+ import { listVoices } from "../settings/repo.js";
7
+ import { packSamples } from "./pack-samples.js";
8
+ import { sampleOf } from "./repo.js";
9
+ import { templateSchedules } from "./service.js";
10
+ const formats = new Set(["16:9", "9:16", "1:1"]);
11
+ export function cardFacts(document, voices) {
12
+ const { form } = document;
13
+ const voiced = form.sources.audio === "generate" && form.audio.voice.trim() !== "";
14
+ const saved = voices.find((one) => one.provider === form.audio.provider && one.voiceId === form.audio.voice);
15
+ const words = Number.parseInt(document.expectedWords, 10);
16
+ const shorts = Number.parseInt(form.shorts?.count ?? "0", 10);
17
+ return {
18
+ format: formats.has(form.format) ? form.format : "16:9",
19
+ video: form.sources.video !== "off" && form.sources.images !== "off",
20
+ words: form.sources.article === "off" || !Number.isFinite(words) ? null : Math.max(0, words),
21
+ voice: voiced
22
+ ? {
23
+ provider: form.audio.provider,
24
+ voiceId: form.audio.voice,
25
+ name: saved?.name.trim() ? saved.name : form.audio.voice,
26
+ }
27
+ : null,
28
+ captions: form.subtitles.mode,
29
+ shorts: form.shorts?.enabled === true && Number.isFinite(shorts) ? Math.max(0, shorts) : 0,
30
+ pdf: form.sources.document === "generate",
31
+ asks: [...topicKeywords(form.title)],
32
+ };
33
+ }
34
+ // The sample's thumbnail or first picture, as the project's file route serves it.
35
+ function sampleStill(deps, templateId) {
36
+ const sample = sampleOf(deps.db, templateId);
37
+ if (sample === undefined || !projectExists(deps.db, sample.projectId))
38
+ return null;
39
+ const revisionId = currentRevisionId(deps.db, sample.projectId);
40
+ if (revisionId === undefined)
41
+ return null;
42
+ const revision = getRevisionView({
43
+ db: deps.db,
44
+ paths: deps.paths,
45
+ log: deps.log,
46
+ ids: { next: () => "" },
47
+ clock: { now: () => new Date(), sleep: async () => undefined },
48
+ }, sample.projectId, revisionId);
49
+ const shown = (role) => revision?.outputs.find((row) => row.output.role === role && row.selected && row.available && row.state === "ready");
50
+ const row = shown("thumbnail") ?? shown("image");
51
+ return row === undefined
52
+ ? null
53
+ : `/files/${encodeURIComponent(sample.projectId)}/revisions/${encodeURIComponent(revisionId)}/${encodeURIComponent(row.recordId)}`;
54
+ }
55
+ function packStill(deps, templateId) {
56
+ const samples = packSamples(deps.paths, templateId);
57
+ const picture = samples.find((one) => one.role === "thumbnail") ??
58
+ samples.find((one) => one.role === "picture");
59
+ return picture === undefined
60
+ ? null
61
+ : `/api/template-studio/${templateId}/pack-samples/${picture.file}`;
62
+ }
63
+ export function templateCards(deps) {
64
+ const voices = listVoices(deps.db);
65
+ return templateSummaries(deps.db).flatMap((summary) => {
66
+ const template = templateById(deps.db, summary.id);
67
+ if (template === undefined)
68
+ return [];
69
+ return [
70
+ {
71
+ id: template.id,
72
+ still: sampleStill(deps, template.id) ?? packStill(deps, template.id),
73
+ ...cardFacts(template.document, voices),
74
+ schedules: templateSchedules(deps.db, template.id).length,
75
+ },
76
+ ];
77
+ });
78
+ }