@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,273 @@
1
+ import { detectSlots, filledKeywords } from "../admission/substitute.js";
2
+ import { isReserved } from "../keywords/model.js";
3
+ import { topicKeywords } from "../project-templates/one-off.js";
4
+ import { usesPostPrompt } from "../social/rules.js";
5
+ import { sectionLabel } from "./model.js";
6
+ export const freeCheckIds = [
7
+ "keywords",
8
+ "providers",
9
+ "voice",
10
+ "release-slots",
11
+ "monthly-cost",
12
+ "answerers",
13
+ ];
14
+ const nameOf = (schedule) => schedule.paused === true ? `${schedule.name} (paused)` : schedule.name;
15
+ export const studioHref = (templateId, section) => `/templates/${encodeURIComponent(templateId)}?section=${section}`;
16
+ const scheduleHref = (id) => `/calendar?tab=schedules&schedule=${encodeURIComponent(id)}`;
17
+ const weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
18
+ const agentWindowMs = 7 * 24 * 60 * 60 * 1000;
19
+ export function freeChecks(input) {
20
+ return [
21
+ keywordsCheck(input),
22
+ providersCheck(input),
23
+ voiceCheck(input),
24
+ releaseSlotsCheck(input),
25
+ monthlyCostCheck(input),
26
+ answerersCheck(input),
27
+ ];
28
+ }
29
+ function list(names) {
30
+ if (names.length <= 1)
31
+ return names.join("");
32
+ return `${names.slice(0, -1).join(", ")} and ${names.at(-1) ?? ""}`;
33
+ }
34
+ // A keyword is filled when it has a value, is the topic a schedule fills each run, or is one
35
+ // Slopify fills itself ({{Scene}}, {{Appearance}} and every {{Slopify_…}} name).
36
+ function keywordsCheck(input) {
37
+ const { form } = input.document;
38
+ const topics = new Set([
39
+ ...topicKeywords(form.title),
40
+ ...input.schedules.flatMap((schedule) => schedule.topicKeyword === null ? [] : [schedule.topicKeyword]),
41
+ ]);
42
+ const names = new Set([form.title, ...input.bodies].flatMap((body) => detectSlots(body).names));
43
+ const empty = [...names].filter((name) => !topics.has(name) &&
44
+ !filledKeywords.includes(name) &&
45
+ // The keywords registry's: an unknown Slopify_ name is refused when the prompt is saved.
46
+ !isReserved(name) &&
47
+ (form.values[name] ?? "").trim() === "");
48
+ if (empty.length === 0)
49
+ return {
50
+ id: "keywords",
51
+ ok: true,
52
+ sentence: "Every keyword has a value or is filled per video.",
53
+ };
54
+ return {
55
+ id: "keywords",
56
+ ok: false,
57
+ sentence: `${empty.length === 1 ? "A keyword is" : "Keywords are"} empty: ${list(empty.map((name) => `{{${name}}}`))}. A run would send the prompt with nothing in ${empty.length === 1 ? "its place" : "their place"}.`,
58
+ fix: {
59
+ label: "Fill the keywords in Subject & research",
60
+ href: studioHref(input.templateId, "subject"),
61
+ },
62
+ };
63
+ }
64
+ function usedProviders(document) {
65
+ const { form } = document;
66
+ const generates = (source) => source !== undefined && source !== "off" && source !== "provide";
67
+ const text = generates(form.sources.research) ||
68
+ generates(form.sources.article) ||
69
+ form.sources.thumbnail === "prompt_by_llm" ||
70
+ form.youtubeDescription === true ||
71
+ usesPostPrompt(form) ||
72
+ form.shorts?.enabled === true;
73
+ const reviews = form.reviews !== undefined &&
74
+ (form.reviews.reviewer ?? "model") === "model" &&
75
+ Object.values(form.reviews.stages).some((stage) => stage.mode !== "off");
76
+ return [
77
+ ...(text
78
+ ? [
79
+ {
80
+ family: "llm",
81
+ provider: form.llm.provider,
82
+ section: "script",
83
+ what: "text model",
84
+ },
85
+ ]
86
+ : []),
87
+ ...(generates(form.sources.audio)
88
+ ? [
89
+ {
90
+ family: "tts",
91
+ provider: form.audio.provider,
92
+ section: "voice",
93
+ what: "voice",
94
+ },
95
+ ]
96
+ : []),
97
+ ...(generates(form.sources.images) || generates(form.sources.thumbnail)
98
+ ? [
99
+ {
100
+ family: "image",
101
+ provider: form.images.provider,
102
+ section: "pictures",
103
+ what: "picture model",
104
+ },
105
+ ]
106
+ : []),
107
+ ...(reviews && form.reviews !== undefined
108
+ ? [
109
+ {
110
+ family: "llm",
111
+ provider: form.reviews.provider,
112
+ section: "reviews",
113
+ what: "reviewer model",
114
+ },
115
+ ]
116
+ : []),
117
+ ];
118
+ }
119
+ function providersCheck(input) {
120
+ const used = usedProviders(input.document);
121
+ const unchosen = used.find((one) => one.provider === "");
122
+ if (unchosen !== undefined)
123
+ return {
124
+ id: "providers",
125
+ ok: false,
126
+ sentence: `No ${unchosen.what} is chosen, so the run can't start.`,
127
+ fix: {
128
+ label: `Choose one in ${sectionLabel[unchosen.section]}`,
129
+ href: studioHref(input.templateId, unchosen.section),
130
+ },
131
+ };
132
+ const missing = used.find((one) => input.providers.get(one.provider)?.ready !== true);
133
+ if (missing === undefined)
134
+ return { id: "providers", ok: true, sentence: "Every provider this template uses is set up." };
135
+ const name = input.providers.get(missing.provider)?.name ?? missing.provider;
136
+ return {
137
+ id: "providers",
138
+ ok: false,
139
+ sentence: `${name} (the ${missing.what}) isn't set up on this computer: no key is stored or its program wasn't found.`,
140
+ fix: { label: "Set it up in Settings → Providers", href: "/settings?section=providers" },
141
+ };
142
+ }
143
+ // The narration's voice (and each speaker's) is chosen and is one of the voices this computer
144
+ // keeps in Settings → Voices: an imported pack's voice may be someone else's.
145
+ function voiceCheck(input) {
146
+ const { form } = input.document;
147
+ const voiced = form.sources.audio === "generate";
148
+ const fix = { label: "Choose a voice in Voice", href: studioHref(input.templateId, "voice") };
149
+ if (!voiced)
150
+ return { id: "voice", ok: true, sentence: "The narration isn't voiced by Slopify." };
151
+ const picks = [
152
+ { who: "The narration's", provider: form.audio.provider, voice: form.audio.voice },
153
+ ...(form.voices?.speakers ?? []).map((speaker) => ({
154
+ who: `${speaker.name.trim() === "" ? "A speaker" : speaker.name}'s`,
155
+ provider: speaker.voice.provider,
156
+ voice: speaker.voice.voice,
157
+ })),
158
+ ];
159
+ if (form.audio.voice.trim() === "" && form.voices === undefined)
160
+ return {
161
+ id: "voice",
162
+ ok: false,
163
+ sentence: "No voice is chosen for the narration, so the run can't start.",
164
+ fix,
165
+ };
166
+ const known = input.voices;
167
+ const unknown = known === undefined
168
+ ? undefined
169
+ : picks.find((pick) => pick.voice.trim() !== "" &&
170
+ !known.some((one) => one.provider === pick.provider && one.voiceId === pick.voice));
171
+ if (unknown !== undefined)
172
+ return {
173
+ id: "voice",
174
+ ok: false,
175
+ sentence: `${unknown.who} voice (ID ${unknown.voice}) isn't one of your voices in Settings → Voices. Add it there under that ID, or choose one of yours.`,
176
+ fix,
177
+ };
178
+ return { id: "voice", ok: true, sentence: "The narration's voice is one of your voices." };
179
+ }
180
+ function releaseSlotsCheck(input) {
181
+ const shorts = input.document.form.shorts;
182
+ const wanted = shorts?.enabled === true ? Math.max(0, Number.parseInt(shorts.count, 10) || 0) : 0;
183
+ for (const schedule of input.schedules) {
184
+ if (schedule.releases.length === 0)
185
+ continue;
186
+ const missing = schedule.runDays.filter((day) => !schedule.releases.some((release) => release.day === day));
187
+ if (missing.length > 0)
188
+ return {
189
+ id: "release-slots",
190
+ ok: false,
191
+ sentence: `${nameOf(schedule)} runs on ${list(missing.map((day) => weekdays[day] ?? String(day)))} but has no release time for ${missing.length === 1 ? "that day" : "those days"}.`,
192
+ fix: {
193
+ label: `Add the release times in ${schedule.name}`,
194
+ href: scheduleHref(schedule.id),
195
+ },
196
+ };
197
+ const short = schedule.releases.find((release) => release.shorts < wanted);
198
+ if (short !== undefined)
199
+ return {
200
+ id: "release-slots",
201
+ ok: false,
202
+ sentence: `This template makes ${String(wanted)} shorts a video, but ${nameOf(schedule)} gives ${weekdays[short.day] ?? ""}'s run release times for ${String(short.shorts)}.`,
203
+ fix: {
204
+ label: `Add short release times in ${schedule.name}`,
205
+ href: scheduleHref(schedule.id),
206
+ },
207
+ };
208
+ }
209
+ return {
210
+ id: "release-slots",
211
+ ok: true,
212
+ sentence: input.schedules.length === 0
213
+ ? "No schedule runs this template yet."
214
+ : "Every run has a release time for the video and its shorts.",
215
+ };
216
+ }
217
+ function monthlyCostCheck(input) {
218
+ if (input.monthlyCost === null)
219
+ return {
220
+ id: "monthly-cost",
221
+ ok: true,
222
+ sentence: "No schedule runs this template, so it costs nothing a month.",
223
+ };
224
+ const paused = input.monthlyCost.paused?.schedules ?? 0;
225
+ const resumed = `up to about $${(input.monthlyCost.paused?.high ?? 0).toFixed(2)} a month when resumed`;
226
+ const many = (n) => `${String(n)} paused ${n === 1 ? "schedule" : "schedules"}`;
227
+ if (input.monthlyCost.unknown === 0) {
228
+ const activeCost = `Its schedules cost up to about $${input.monthlyCost.high.toFixed(2)} a month`;
229
+ return {
230
+ id: "monthly-cost",
231
+ ok: true,
232
+ sentence: paused === 0
233
+ ? `${activeCost}.`
234
+ : input.monthlyCost.high === 0 && (input.monthlyCost.runs ?? 0) === 0
235
+ ? `${many(paused)} ${paused === 1 ? "uses" : "use"} this template: ${paused === 1 ? "it costs" : "they cost"} nothing while paused, and ${resumed}.`
236
+ : `${activeCost}; ${many(paused)} would add ${resumed}.`,
237
+ };
238
+ }
239
+ return {
240
+ id: "monthly-cost",
241
+ ok: false,
242
+ sentence: input.monthlyCost.problem ??
243
+ `The monthly cost isn't known: ${String(input.monthlyCost.unknown)} ${input.monthlyCost.unknown === 1 ? "step has" : "steps have"} no price in the model list.`,
244
+ fix: { label: "See which in Schedule", href: studioHref(input.templateId, "schedule") },
245
+ };
246
+ }
247
+ function answerersCheck(input) {
248
+ const { form } = input.document;
249
+ const asks = (form.checkpoints?.length ?? 0) > 0 ||
250
+ (form.reviews?.reviewer === "agent" &&
251
+ Object.values(form.reviews.stages).some((stage) => stage.mode !== "off"));
252
+ if (!asks)
253
+ return { id: "answerers", ok: true, sentence: "Nothing in a run waits for an answer." };
254
+ const agent = input.agentSeenAt !== null &&
255
+ input.now.getTime() - new Date(input.agentSeenAt).getTime() <= agentWindowMs;
256
+ if (input.notificationUrl || agent)
257
+ return {
258
+ id: "answerers",
259
+ ok: true,
260
+ sentence: agent
261
+ ? "An agent connected this week answers the checkpoints."
262
+ : "You're notified when a checkpoint waits.",
263
+ };
264
+ return {
265
+ id: "answerers",
266
+ ok: false,
267
+ sentence: "A run stops at a checkpoint and nobody would know: no notification address is set and no agent connected in the last 7 days.",
268
+ fix: {
269
+ label: "Set a notification address in Settings → Notifications",
270
+ href: "/settings?section=notifications",
271
+ },
272
+ };
273
+ }
@@ -0,0 +1,56 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { mkdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { draftDocumentThemeOf } from "../document/model.js";
5
+ import { renderSampleDocument } from "../document/sample.js";
6
+ import { resolvedDocumentTheme } from "../document/theme.js";
7
+ import { stableJson } from "../style-preview/settings.js";
8
+ // The Document (PDF) sample: the Library theme editor's sample article laid out in the
9
+ // template's theme. Local and free.
10
+ export function documentThemeOfTemplate(document) {
11
+ const settings = document.form.document;
12
+ return resolvedDocumentTheme({
13
+ theme: draftDocumentThemeOf(settings),
14
+ ...(settings?.custom === undefined ? {} : { custom: settings.custom }),
15
+ });
16
+ }
17
+ export function documentHash(theme) {
18
+ return createHash("sha256")
19
+ .update(stableJson({ version: 1, theme }))
20
+ .digest("hex");
21
+ }
22
+ const hashPattern = /^[a-f0-9]{64}$/;
23
+ export function createDocumentSamples(deps) {
24
+ const render = deps.render ?? ((theme) => renderSampleDocument(theme).bytes);
25
+ const pathOf = (hash) => join(deps.dir, `${hash}.pdf`);
26
+ const file = (hash) => {
27
+ if (!hashPattern.test(hash))
28
+ return undefined;
29
+ try {
30
+ const stats = statSync(pathOf(hash));
31
+ return stats.isFile() && stats.size > 0
32
+ ? { path: pathOf(hash), bytes: stats.size }
33
+ : undefined;
34
+ }
35
+ catch {
36
+ return undefined;
37
+ }
38
+ };
39
+ return {
40
+ file,
41
+ make: (theme) => {
42
+ const hash = documentHash(theme);
43
+ if (file(hash) !== undefined)
44
+ return;
45
+ mkdirSync(deps.dir, { recursive: true, mode: 0o700 });
46
+ const part = join(deps.dir, `${hash}.${randomUUID()}.part`);
47
+ try {
48
+ writeFileSync(part, render(theme), { mode: 0o600 });
49
+ renameSync(part, pathOf(hash));
50
+ }
51
+ finally {
52
+ rmSync(part, { force: true });
53
+ }
54
+ },
55
+ };
56
+ }
@@ -0,0 +1,15 @@
1
+ import { configOf } from "../admission/start.js";
2
+ // The sample project's next revision for a template's newer setup: the config a fresh run of it
3
+ // would start with (`configOf`, so aliases and rules are copied as they are now) and the
4
+ // current content with each prompt's template body replaced, so a changed prompt is sent as
5
+ // written now. Saving it outdates exactly what the change touches; the rebuild makes only that.
6
+ export function sampleEdit(deps, base, run) {
7
+ const config = configOf(deps, run.draft, run.rendered, deps.clock.now(), run.templates, base.revision.projectId);
8
+ return {
9
+ config,
10
+ content: {
11
+ ...base.revision.content,
12
+ promptTemplates: Object.fromEntries(Object.keys(config.rendered).map((key) => [key, run.templates[key] ?? null])),
13
+ },
14
+ };
15
+ }
@@ -0,0 +1,161 @@
1
+ import { setImmediate as yieldTurn } from "node:timers/promises";
2
+ import { z } from "zod";
3
+ import { transact } from "../../kernel/db/tx.js";
4
+ import { templateById, templateSummaries } from "../project-templates/repo.js";
5
+ import { budgetRoom, budgetWords, fitsBudget } from "./budget.js";
6
+ import { enqueueJob } from "./jobs.js";
7
+ import { quoteSample } from "./quote.js";
8
+ import { sampleVersions, setSampleVersion } from "./repo.js";
9
+ import { exceedsAcknowledged } from "./save.js";
10
+ import { affectedSections } from "./sections.js";
11
+ import { paidSections } from "./status.js";
12
+ const money = (value) => `$${value.toFixed(2)}`;
13
+ // The sections a template's newest version has no sample of: every one before its first
14
+ // sample, the ones changed since the last one made, none when it is made or on its way.
15
+ function wanted(deps, templateId) {
16
+ const head = templateById(deps.db, templateId);
17
+ if (head === undefined)
18
+ return "none";
19
+ const versions = sampleVersions(deps.db, templateId);
20
+ const row = versions.find((one) => one.templateVersion === head.version);
21
+ if (row !== undefined && ["done", "queued", "making"].includes(row.state))
22
+ return "none";
23
+ const done = versions.find((one) => one.state === "done" && one.templateVersion <= head.version);
24
+ const from = done === undefined ? undefined : templateById(deps.db, templateId, done.templateVersion);
25
+ if (from === undefined)
26
+ return "all";
27
+ const paid = new Set(paidSections);
28
+ const changed = affectedSections(from.document, head.document).filter((one) => paid.has(one));
29
+ return changed.length === 0 ? "none" : changed;
30
+ }
31
+ export async function quoteSamplesForAll(deps) {
32
+ const room = budgetRoom(deps.db, deps.clock.now(), deps.timeZone);
33
+ const items = [];
34
+ let used = 0;
35
+ for (const template of templateSummaries(deps.db)) {
36
+ const sections = wanted(deps, template.id);
37
+ if (sections === "none")
38
+ continue;
39
+ // Each price resolves a draft through Play's review: the server stays answering between them.
40
+ await yieldTurn();
41
+ const quoted = await quoteSample(deps, template.id, { sections });
42
+ if (!quoted.ok)
43
+ continue;
44
+ const { high, unknown, problem, usesPlan } = quoted.value;
45
+ const fits = problem === null && fitsBudget(room, used + high, usesPlan);
46
+ if (fits)
47
+ used += high;
48
+ items.push({
49
+ templateId: template.id,
50
+ name: template.name,
51
+ version: quoted.value.version,
52
+ high: problem === null ? high : 0,
53
+ unknown: problem === null ? unknown : 0,
54
+ usesPlan: problem === null && usesPlan,
55
+ fits,
56
+ problem,
57
+ });
58
+ }
59
+ const makeable = items.filter((item) => item.problem === null);
60
+ const total = makeable.reduce((sum, item) => sum + item.high, 0);
61
+ const fitting = makeable.filter((item) => item.fits).length;
62
+ return {
63
+ items,
64
+ total,
65
+ fitting,
66
+ budget: room,
67
+ sentence: sentenceOf(makeable, room),
68
+ };
69
+ }
70
+ function sentenceOf(makeable, room) {
71
+ const count = makeable.length;
72
+ if (count === 0)
73
+ return "Every template's sample is made for its newest version. Nothing to make.";
74
+ const total = makeable.reduce((sum, item) => sum + item.high, 0);
75
+ const fitting = makeable.filter((item) => item.fits).length;
76
+ const head = `${String(count)} ${count === 1 ? "template needs" : "templates need"} a sample: about ${money(total)} in all.`;
77
+ if (fitting === count)
78
+ return head;
79
+ const waiting = count - fitting;
80
+ const onPlan = makeable.filter((item) => !item.fits && item.usesPlan && !room.plans).length;
81
+ const why = onPlan === waiting
82
+ ? ": they run on your CLI plan, and samples may not use CLI plans (turn on Samples may use my CLI plans in Settings → Template studio)"
83
+ : onPlan > 0
84
+ ? `: ${String(onPlan)} run on your CLI plan, which samples may not use (Samples may use my CLI plans in Settings → Template studio), and the rest wait for tomorrow or a higher budget`
85
+ : " for tomorrow or a higher budget in Settings → Template studio";
86
+ return `${head} ${String(fitting)} of them ${fitting === 1 ? "fits" : "fit"} today's budget; the other ${String(waiting)} wait${why}.`;
87
+ }
88
+ export const samplesForAllSchema = z
89
+ .object({
90
+ // The total the button showed.
91
+ acknowledgedTotal: z.number().finite().min(0).max(100_000),
92
+ // That some steps have no price, and the person accepts it.
93
+ acknowledgedUnknown: z.boolean().optional(),
94
+ })
95
+ .strict()
96
+ .readonly();
97
+ const budgetHeld = "Waiting: today's sample budget is used by the other templates' samples. Press Make sample tomorrow, or raise the budget in Settings → Template studio.";
98
+ export async function makeSamplesForAll(deps, raw) {
99
+ const parsed = samplesForAllSchema.safeParse(raw);
100
+ if (!parsed.success)
101
+ return {
102
+ ok: false,
103
+ reason: "invalid-input",
104
+ message: "Settings sent a request Slopify couldn't read. Reload the page and press Make samples for all again.",
105
+ };
106
+ const quote = await quoteSamplesForAll(deps);
107
+ if (exceedsAcknowledged(quote.total, parsed.data.acknowledgedTotal))
108
+ return {
109
+ ok: false,
110
+ reason: "cost-changed",
111
+ message: `Making them now costs about ${money(quote.total)}, more than the ${money(parsed.data.acknowledgedTotal)} you saw. Press Make samples for all again to accept the new price.`,
112
+ quote,
113
+ };
114
+ const at = deps.clock.now().toISOString();
115
+ // Each sample's share of the total the person saw: its leeway is applied once, at make time.
116
+ const seenShare = quote.total > 0 ? Math.min(1, parsed.data.acknowledgedTotal / quote.total) : 1;
117
+ const queued = [];
118
+ const held = [];
119
+ transact(deps.db, () => {
120
+ for (const item of quote.items) {
121
+ if (item.problem !== null)
122
+ continue;
123
+ const head = templateById(deps.db, item.templateId);
124
+ // Saved again meanwhile: its own Save made (or skipped) that version's sample.
125
+ if (head === undefined || head.version !== item.version)
126
+ continue;
127
+ const unpriced = item.unknown > 0 && parsed.data.acknowledgedUnknown !== true;
128
+ if (!item.fits || unpriced) {
129
+ setSampleVersion(deps.db, item.templateId, item.version, {
130
+ state: "held",
131
+ at,
132
+ quotedHigh: item.high,
133
+ heldReason: unpriced
134
+ ? `Waiting: ${String(item.unknown)} ${item.unknown === 1 ? "step of this sample has" : "steps of this sample have"} no known price. Press Make sample to accept that and make it.`
135
+ : item.usesPlan && !quote.budget.plans
136
+ ? `Waiting: ${budgetWords(quote.budget, item, "this sample")}, then press Make sample.`
137
+ : budgetHeld,
138
+ });
139
+ held.push(item.templateId);
140
+ continue;
141
+ }
142
+ // Its unknown prices were accepted above, or its quote priced every step.
143
+ deps.acks.accept(item.templateId, item.version);
144
+ setSampleVersion(deps.db, item.templateId, item.version, {
145
+ state: "queued",
146
+ at,
147
+ quotedHigh: item.high,
148
+ heldReason: null,
149
+ });
150
+ enqueueJob(deps.db, {
151
+ templateId: item.templateId,
152
+ templateVersion: item.version,
153
+ ackHigh: item.high * seenShare,
154
+ kind: "save",
155
+ requestedAt: at,
156
+ });
157
+ queued.push(item.templateId);
158
+ }
159
+ });
160
+ return { ok: true, value: { queued, held, quote } };
161
+ }
@@ -0,0 +1,31 @@
1
+ import { defaultImageSeconds, defaultMotionStyle, defaultZoomPercent } from "../admission/rules.js";
2
+ // The Video & captions sample: 30 seconds made by the style preview's renderer from the
3
+ // template's frame, captions, Look and picture timing, on the bundled sample's pictures and
4
+ // narration. Local and free; no provider is called.
5
+ export const videoSampleSeconds = 30;
6
+ function number(raw, fallback, min, max) {
7
+ const value = Number(raw);
8
+ return raw === undefined || raw.trim() === "" || !Number.isFinite(value)
9
+ ? fallback
10
+ : Math.min(max, Math.max(min, value));
11
+ }
12
+ export function videoSampleRequest(document) {
13
+ const { form } = document;
14
+ return {
15
+ format: form.format,
16
+ subtitles: {
17
+ mode: form.subtitles.mode,
18
+ fontId: /^[A-Za-z0-9_-]+$/.test(form.subtitles.fontId) ? form.subtitles.fontId : "default",
19
+ fontSize: number(form.subtitles.fontSize, 48, 16, 120),
20
+ position: form.subtitles.position,
21
+ },
22
+ ...(form.videoEdit === undefined ? {} : { videoEdit: form.videoEdit }),
23
+ previewText: document.previewText.slice(0, 200),
24
+ seconds: videoSampleSeconds,
25
+ timing: {
26
+ imageSeconds: number(form.imageSeconds, defaultImageSeconds, 1, 120),
27
+ zoomPercent: number(form.zoomPercent, defaultZoomPercent, 0, 100),
28
+ motionStyle: form.motionStyle ?? defaultMotionStyle,
29
+ },
30
+ };
31
+ }