@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
@@ -6,8 +6,8 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1" />
7
7
  <meta name="color-scheme" content="dark light" />
8
8
  <title>Slopify</title>
9
- <script type="module" crossorigin src="/assets/index-D8LqNsCl.js"></script>
10
- <link rel="stylesheet" crossorigin href="/assets/index-BadsoORk.css">
9
+ <script type="module" crossorigin src="/assets/index-DcD0cdfo.js"></script>
10
+ <link rel="stylesheet" crossorigin href="/assets/index-CkAI_2E7.css">
11
11
  </head>
12
12
  <body>
13
13
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gentbajko/slopify",
3
- "version": "3.25.8",
3
+ "version": "4.0.0",
4
4
  "description": "Turn a prompt into a finished video, locally, with your own provider keys",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Gent Bajko",
@@ -45,5 +45,9 @@
45
45
  "ulid": "^3.0.2",
46
46
  "yaml": "^2.9.1",
47
47
  "zod": "^4.5.4"
48
+ },
49
+ "devDependencies": {
50
+ "@types/mdast": "^4.0.4",
51
+ "esbuild": "^0.28.1"
48
52
  }
49
53
  }
@@ -1,66 +0,0 @@
1
- import { readFileSync } from "node:fs";
2
- import { piecesOf } from "../../kernel/runner/piece-repo.js";
3
- import { projectById, stagesOf } from "../admission/repo.js";
4
- import { outputPath } from "../storage/layout.js";
5
- import { outputsOf } from "../storage/repo.js";
6
- import { storeText } from "../storage/staging.js";
7
- import { categories, instructionsText, keepSegment, writeSegment } from "./segments.js";
8
- // A provided Article never runs its writer. Prepare its selected entries as part
9
- // of Audio's cancellable work, retaining Article ownership of the resulting text.
10
- export async function prepareProvidedArticleSegments(deps, audioContext, providers) {
11
- const { projectId } = audioContext.stage;
12
- const project = projectById(deps.db, projectId);
13
- if (!project)
14
- throw new Error("This project no longer exists; it may have been deleted while it was running.");
15
- const { config } = project;
16
- if (config.sources.article !== "provide" || config.sources.audio !== "generate")
17
- return "done";
18
- if (!config.intro && !config.outro)
19
- return "done";
20
- audioContext.signal.throwIfAborted();
21
- const article = stagesOf(deps.db, projectId).find((stage) => stage.kind === "article");
22
- if (!article)
23
- throw new Error("Slopify hit an internal error (the project has no article stage). Try again; if it happens again, use Download diagnostics in Settings and report it.");
24
- const outputs = outputsOf(deps.db, projectId);
25
- const plain = outputs.find((output) => output.role === "article_txt");
26
- if (!plain)
27
- throw new Error("The article text you provided is missing, so the intro and outro can't be written from it. Paste the article again in Edit project → Article, then Try again.");
28
- const narration = readFileSync(outputPath(deps.paths, projectId, plain.path), "utf8");
29
- const saved = outputs.find((output) => output.stageKind === "article" && output.role === "instructions");
30
- let instructions = saved
31
- ? readFileSync(outputPath(deps.paths, projectId, saved.path), "utf8")
32
- : "";
33
- const completed = piecesOf(deps.db, article.id, "segment");
34
- for (const [index, category] of categories.entries()) {
35
- audioContext.signal.throwIfAborted();
36
- if (completed.some((piece) => piece.idx === index + 1 && piece.state === "done"))
37
- continue;
38
- const sent = [];
39
- const result = await writeSegment(providers, config.llm, config, category, narration, sent);
40
- audioContext.signal.throwIfAborted();
41
- if (!result.ok)
42
- return "held";
43
- const segment = result.value;
44
- if (!segment)
45
- continue;
46
- if (sent.length > 0) {
47
- instructions += `${instructions === "" ? "" : "\n"}${instructionsText(sent)}`;
48
- storeText(deps, {
49
- projectId,
50
- stageKind: "article",
51
- role: "instructions",
52
- text: instructions,
53
- });
54
- }
55
- keepSegment(deps, { stage: article }, segment, index + 1);
56
- deps.count("stage.completed", {
57
- stage: "article",
58
- segment: category,
59
- ...(segment.mode === "llm" && config.llm
60
- ? { provider: config.llm.provider, model: config.llm.model }
61
- : {}),
62
- ...segment.tokens,
63
- });
64
- }
65
- return "done";
66
- }
@@ -1,145 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { z } from "zod";
3
- import { messageRoles } from "../../kernel/ports/llm.js";
4
- import { insertPiece, piecesOf, setPiece } from "../../kernel/runner/piece-repo.js";
5
- import { projectById } from "../admission/repo.js";
6
- import { withEarlierEpisodes } from "../episodes/related.js";
7
- import { outputPath } from "../storage/layout.js";
8
- import { outputsOf } from "../storage/repo.js";
9
- import { storeText } from "../storage/staging.js";
10
- import { writeArticle } from "./continuation.js";
11
- import { categories, instructionsText, keepSegment, writeSegment } from "./segments.js";
12
- import { storeArticleText } from "./store.js";
13
- export async function runArticle(deps, context, providers) {
14
- const { projectId } = context.stage;
15
- const project = projectById(deps.db, projectId);
16
- if (project === undefined) {
17
- throw new Error("This project no longer exists; it may have been deleted while it was running.");
18
- }
19
- const choice = project.config.llm;
20
- const articlePrompt = project.config.rendered.article;
21
- if (choice === undefined || articlePrompt === undefined) {
22
- // Admission refuses a run whose article is Generate without both, so
23
- // reaching here is a bug in admission rather than something the user did.
24
- throw new Error("No AI model or article prompt is set for writing the article. Choose a model in Edit project → Providers and check Edit project → Prompts, then Try again.");
25
- }
26
- const notes = researchNotes(deps, projectId);
27
- const brief = {
28
- articlePrompt: withEarlierEpisodes(articlePrompt, project.config.earlierEpisodes),
29
- ...(notes === undefined ? {} : { notes }),
30
- };
31
- const result = await articleBody(deps, context, providers, choice, brief);
32
- if (!result.ok)
33
- return "held";
34
- const completed = result.value;
35
- const { narration } = completed;
36
- const sent = [...completed.sent];
37
- for (const [index, category] of categories.entries()) {
38
- if (project.config.sources.audio !== "generate")
39
- break;
40
- if (completed.resumed &&
41
- piecesOf(deps.db, context.stage.id, "segment").some((piece) => piece.idx === index + 1 && piece.state === "done"))
42
- continue;
43
- const result = await writeSegment(providers, choice, project.config, category, narration, sent);
44
- if (!result.ok)
45
- return "held";
46
- const segment = result.value;
47
- if (segment !== undefined) {
48
- keepSegment(deps, context, segment, index + 1);
49
- checkpointArticle(deps, context, sent);
50
- // One event per intro/outro text, named by its segment. A text-mode entry is
51
- // rendered rather than written, so it made no call, names no provider and reports
52
- // zero tokens rather than an estimate.
53
- deps.count("stage.completed", {
54
- stage: "article",
55
- segment: category,
56
- ...(segment.mode === "llm" ? { provider: choice.provider, model: choice.model } : {}),
57
- ...segment.tokens,
58
- });
59
- }
60
- }
61
- // The exact messages sent, the continuations and the entry calls among them.
62
- storeText(deps, {
63
- projectId,
64
- stageKind: "article",
65
- role: "instructions",
66
- text: instructionsText(sent),
67
- });
68
- deps.log.write("info", "article.done", {
69
- projectId,
70
- stage: "article",
71
- detail: `${String(narration.length)} characters to narrate`,
72
- });
73
- return "done";
74
- }
75
- // Once the article is stored, a pause during end matter resumes that end matter
76
- // instead of buying and replacing the article again. Re-run clears this checkpoint.
77
- const articleCheckpoint = z.object({
78
- sent: z.array(z.object({
79
- label: z.string(),
80
- messages: z.array(z.object({ role: z.enum(messageRoles), content: z.string() })),
81
- })),
82
- });
83
- async function articleBody(deps, context, providers, choice, brief) {
84
- const { projectId } = context.stage;
85
- const saved = piecesOf(deps.db, context.stage.id, "article_written")[0];
86
- const outputs = outputsOf(deps.db, projectId);
87
- const plain = outputs.find((output) => output.role === "article_txt");
88
- const markdown = outputs.find((output) => output.role === "article_md");
89
- if (saved?.payload !== null &&
90
- saved?.payload !== undefined &&
91
- plain &&
92
- markdown &&
93
- existsSync(outputPath(deps.paths, projectId, plain.path)) &&
94
- existsSync(outputPath(deps.paths, projectId, markdown.path))) {
95
- return {
96
- ok: true,
97
- value: {
98
- narration: readFileSync(outputPath(deps.paths, projectId, plain.path), "utf8"),
99
- sent: articleCheckpoint.parse(JSON.parse(saved.payload)).sent,
100
- resumed: true,
101
- },
102
- };
103
- }
104
- const result = await writeArticle(providers, choice, brief, (text) => {
105
- context.emit({ type: "article.delta", projectId, text });
106
- });
107
- if (!result.ok)
108
- return result;
109
- const written = result.value;
110
- storeText(deps, { projectId, stageKind: "article", role: "article_md", text: written.markdown });
111
- const narration = storeArticleText(deps, { projectId, markdown: written.markdown });
112
- checkpointArticle(deps, context, written.sent);
113
- deps.count("stage.completed", {
114
- stage: "article",
115
- provider: choice.provider,
116
- model: choice.model,
117
- ...written.tokens,
118
- });
119
- return { ok: true, value: { narration, sent: written.sent, resumed: false } };
120
- }
121
- function checkpointArticle(deps, context, sent) {
122
- const existing = piecesOf(deps.db, context.stage.id, "article_written")[0];
123
- const payload = JSON.stringify({ sent });
124
- if (existing)
125
- setPiece(deps.db, existing.id, "done", payload);
126
- else
127
- insertPiece(deps.db, {
128
- id: deps.ids.next(),
129
- stageId: context.stage.id,
130
- kind: "article_written",
131
- idx: 1,
132
- state: "done",
133
- payload,
134
- });
135
- }
136
- // Research writes its notes as an output of its own, and a provided research stage stores the
137
- // pasted text the same way, so one lookup covers both. No row means research was Off or
138
- // skipped, and the article is written from the prompt alone.
139
- function researchNotes(deps, projectId) {
140
- const notes = outputsOf(deps.db, projectId).find((output) => output.role === "notes");
141
- if (notes === undefined) {
142
- return undefined;
143
- }
144
- return readFileSync(outputPath(deps.paths, projectId, notes.path), "utf8");
145
- }
@@ -1,234 +0,0 @@
1
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
- import { dirname } from "node:path";
3
- import { z } from "zod";
4
- import { transact } from "../../kernel/db/tx.js";
5
- import { insertPiece, piecesOf, setPiece } from "../../kernel/runner/piece-repo.js";
6
- import { projectById } from "../admission/repo.js";
7
- import { setStageProgress } from "../admission/stage-writes.js";
8
- import { outputFileName, outputPath } from "../storage/layout.js";
9
- import { insertOutput, outputsOf } from "../storage/repo.js";
10
- import { imageCountsOf } from "./scale.js";
11
- // What an image piece carries between runs: what was asked for, and the file it came back
12
- // as once the provider answered. That is the whole of the resume.
13
- const imagePayload = z.object({
14
- promptName: z.string(),
15
- prompt: z.string(),
16
- // Which ticked prompt this send belongs to, and which send of that prompt it is. Both
17
- // are stored rather than derived, because the user can delete an image and the pieces
18
- // that are left must still say where each one came from.
19
- promptIndex: z.number(),
20
- indexInPrompt: z.number(),
21
- file: z.string().optional(),
22
- });
23
- export async function runImages(deps, context, providers) {
24
- const { projectId } = context.stage;
25
- const project = projectById(deps.db, projectId);
26
- if (project === undefined) {
27
- throw new Error("This project no longer exists; it may have been deleted while it was running.");
28
- }
29
- const choice = project.config.images;
30
- if (choice === undefined) {
31
- // Admission refuses a run whose images are Generate without a provider and a model, so
32
- // reaching here is a bug in admission rather than the user's.
33
- throw new Error("No image model is set for this project. Choose one in Edit project → Providers, then Try again.");
34
- }
35
- const pieces = plan(deps, context, project.config);
36
- if (pieces.length === 0) {
37
- // Admission makes an image source mandatory and puts the Number at one or more, so an
38
- // empty plan is a bug upstream rather than a run with no pictures.
39
- throw new Error("Slopify hit an internal error (no image prompt was selected). Try again; if it happens again, use Download diagnostics in Settings and report it.");
40
- }
41
- // The run's own frame. The adapter turns it into whatever its provider spells the
42
- // closest supported size, and the render crops whatever is left over.
43
- const result = await sendAll(deps, context, providers, choice, pieces, project.format);
44
- if (!result.ok)
45
- return "held";
46
- const made = result.value;
47
- // Images made means images stored, and only the ones this run stored: a resume does not
48
- // count an image the previous run made, and a regenerated image counts again.
49
- //
50
- // ceiling: a run that fails partway records nothing, so the images it did store are
51
- // counted by no event and the resume counts only its own. One event is written when the
52
- // stage completes; the upgrade, if the drift ever matters, is an event per image.
53
- deps.count("stage.completed", {
54
- stage: "images",
55
- provider: choice.provider,
56
- model: choice.model,
57
- images: made,
58
- });
59
- deps.log.write("info", "images.done", {
60
- projectId,
61
- stage: "images",
62
- detail: `${String(pieces.length)} images from ${String(project.config.imagePrompts.length)} prompts`,
63
- });
64
- return "done";
65
- }
66
- // For each ticked image prompt, its rendered text is sent Number times as independent
67
- // parallel calls. The plan is made once and kept, so a retry finds the rows the first run
68
- // wrote and sends only what did not land.
69
- //
70
- // `idx` is the slideshow order - prompts in selection order, then the index within each
71
- // prompt - so the order is fixed here and never depends on which image arrives first.
72
- function plan(deps, context, config) {
73
- const existing = piecesOf(deps.db, context.stage.id, "image");
74
- if (existing.length > 0) {
75
- return existing;
76
- }
77
- const planned = [];
78
- // Each prompt's Number, or more when the run scales its images (`scale.ts`).
79
- const counts = imageCountsOf(config);
80
- for (const [at, picked] of config.imagePrompts.entries()) {
81
- // `slices/library/slots.ts` names the rendered body after the draft field that picked
82
- // it, so the run carries the substituted text under this key.
83
- const prompt = config.rendered[`imagePrompts.${String(at)}`];
84
- if (prompt === undefined) {
85
- throw new Error(`Slopify hit an internal error (the image prompt ${picked.name} was never filled in). Try again; if it happens again, use Download diagnostics in Settings and report it.`);
86
- }
87
- for (let send = 1; send <= (counts[at] ?? picked.number); send += 1) {
88
- planned.push({
89
- id: deps.ids.next(),
90
- stageId: context.stage.id,
91
- kind: "image",
92
- idx: planned.length + 1,
93
- state: "pending",
94
- payload: JSON.stringify({
95
- promptName: picked.name,
96
- prompt,
97
- promptIndex: at + 1,
98
- indexInPrompt: send,
99
- }),
100
- });
101
- }
102
- }
103
- transact(deps.db, () => {
104
- for (const piece of planned) {
105
- insertPiece(deps.db, piece);
106
- }
107
- });
108
- return planned;
109
- }
110
- // An image a previous run stored is not made again, and one that fails takes down the
111
- // whole stage while its siblings finish and keep their images for the next resume. A
112
- // refusal is the wrapper's to make terminal; nothing here counts attempts.
113
- async function sendAll(deps, context, providers, choice, pieces, format) {
114
- const { projectId } = context.stage;
115
- // Read once, before anything is written: a piece counts as landed only when its row and
116
- // its file both survived, and the parallel sends below each add one of each.
117
- const stored = outputsOf(deps.db, projectId);
118
- const total = pieces.length;
119
- let done = pieces.filter((piece) => landed(deps, projectId, piece, stored)).length;
120
- report(deps, context, done, total);
121
- const outcomes = await Promise.all(pieces.map(async (piece) => {
122
- const asked = payloadOf(piece);
123
- if (landed(deps, projectId, piece, stored)) {
124
- return { ok: true, made: false };
125
- }
126
- setPiece(deps.db, piece.id, "running", piece.payload);
127
- try {
128
- const result = await providers.forPiece(piece.id).image({
129
- provider: choice.provider,
130
- model: choice.model,
131
- prompt: asked.prompt,
132
- aspect: format,
133
- });
134
- if (!result.ok) {
135
- setPiece(deps.db, piece.id, "pending", piece.payload);
136
- return result;
137
- }
138
- const made = result.value;
139
- const file = keep(deps, projectId, piece.idx, made);
140
- // The prompt text, the prompt name, the index within the prompt, the
141
- // provider and the model travel with the image.
142
- const output = record(deps, projectId, piece, asked, file, made, choice);
143
- // The row and the file are both there before the piece says so: a crash between
144
- // them leaves a piece that is not `done`, which the next run simply sends again.
145
- setPiece(deps.db, piece.id, "done", JSON.stringify({ ...asked, file }));
146
- done += 1;
147
- // The project page fills in as each one arrives.
148
- context.emit({ type: "image.landed", projectId, outputId: output.id, index: piece.idx });
149
- report(deps, context, done, total);
150
- return { ok: true, made: true };
151
- }
152
- catch (error) {
153
- // A cancel is not this image failing: an aborted call counts as nothing, and the
154
- // resume runs a `pending` image exactly as a failed one.
155
- setPiece(deps.db, piece.id, context.signal.aborted ? "pending" : "failed", piece.payload);
156
- return { ok: false, error };
157
- }
158
- }));
159
- let made = 0;
160
- for (const outcome of outcomes) {
161
- if (!outcome.ok) {
162
- if ("reason" in outcome)
163
- return outcome;
164
- throw outcome.error;
165
- }
166
- made += outcome.made ? 1 : 0;
167
- }
168
- return { ok: true, value: made };
169
- }
170
- // An image counts as landed only when its row and its file are both still there: they are
171
- // written one after the other, the boot reconcile can remove a file whose row survived,
172
- // and the user can delete one on purpose. Answering "done" for a missing file would hand
173
- // the render a path to nothing.
174
- function landed(deps, projectId, piece, stored) {
175
- const file = payloadOf(piece).file;
176
- if (file === undefined) {
177
- return false;
178
- }
179
- if (!stored.some((output) => output.role === "image" && output.path === file)) {
180
- return false;
181
- }
182
- return existsSync(outputPath(deps.paths, projectId, file));
183
- }
184
- function keep(deps, projectId, idx, made) {
185
- // Stored as received, png or jpg. The adapter read the mime off the bytes,
186
- // so the extension is what the file actually is rather than what a header claimed.
187
- const name = outputFileName("image", idx, made.mime === "image/png" ? ".png" : ".jpg", "images");
188
- const target = outputPath(deps.paths, projectId, name);
189
- mkdirSync(dirname(target), { recursive: true, mode: 0o700 });
190
- writeFileSync(target, made.bytes, { mode: 0o600 });
191
- return name;
192
- }
193
- function record(deps, projectId, piece, asked, file, made, choice) {
194
- const output = {
195
- id: deps.ids.next(),
196
- projectId,
197
- stageKind: "images",
198
- role: "image",
199
- path: file,
200
- originalFilename: null,
201
- bytes: made.bytes.byteLength,
202
- durationMs: null,
203
- // `index` is the slideshow place the render sorts on, and it is the piece's own `idx`
204
- // rather than the order the images came back in.
205
- meta: {
206
- index: piece.idx,
207
- promptName: asked.promptName,
208
- prompt: asked.prompt,
209
- provider: choice.provider,
210
- model: choice.model,
211
- },
212
- createdAt: deps.clock.now().toISOString(),
213
- };
214
- insertOutput(deps.db, output);
215
- return output;
216
- }
217
- // K of N images made. Written as well as emitted, so a page opened mid-stage reads the count
218
- // off the row rather than waiting for the next image.
219
- function report(deps, context, done, total) {
220
- setStageProgress(deps.db, context.stage.id, done, total);
221
- context.emit({
222
- type: "stage.progress",
223
- projectId: context.stage.projectId,
224
- stage: "images",
225
- current: done,
226
- total,
227
- });
228
- }
229
- function payloadOf(piece) {
230
- if (piece.payload === null) {
231
- throw new Error("Slopify hit an internal error (a saved image step is empty). Try again; if it happens again, use Download diagnostics in Settings and report it.");
232
- }
233
- return imagePayload.parse(JSON.parse(piece.payload));
234
- }
@@ -1,58 +0,0 @@
1
- import { z } from "zod";
2
- import { transact } from "../../kernel/db/tx.js";
3
- import { splitText } from "../../kernel/ports/text.js";
4
- import { insertPiece, piecesOf } from "../../kernel/runner/piece-repo.js";
5
- const payload = z.object({ text: z.string(), file: z.string().optional() });
6
- // Old whole-text plans can exceed a newly known account limit. Preserve finished
7
- // pieces and their paths, and split only unfinished work before any request starts.
8
- export function planLegacyNarration(deps, stageId, texts, maxCharacters, finished) {
9
- const old = piecesOf(deps.db, stageId, "chunk");
10
- const source = old.length
11
- ? old
12
- : texts.map((text, idx) => ({
13
- id: deps.ids.next(),
14
- stageId,
15
- kind: "chunk",
16
- idx: idx + 1,
17
- state: "pending",
18
- payload: JSON.stringify({ text }),
19
- }));
20
- const planned = [];
21
- for (const piece of source) {
22
- const data = payload.parse(JSON.parse(piece.payload ?? "null"));
23
- if (finished(piece)) {
24
- planned.push({ ...piece, idx: planned.length + 1 });
25
- continue;
26
- }
27
- for (const [part, text] of splitText(data.text, maxCharacters).entries())
28
- planned.push({
29
- ...piece,
30
- id: part === 0 ? piece.id : deps.ids.next(),
31
- idx: planned.length + 1,
32
- state: "pending",
33
- payload: JSON.stringify({ text }),
34
- });
35
- }
36
- if (old.length &&
37
- planned.length === old.length &&
38
- planned.every((p, i) => p.id === old[i]?.id &&
39
- payload.parse(JSON.parse(p.payload ?? "null")).text ===
40
- payload.parse(JSON.parse(old[i]?.payload ?? "null")).text))
41
- return old;
42
- transact(deps.db, () => {
43
- // Negative temporary indices avoid colliding with a retained completed piece.
44
- deps.db
45
- .prepare("UPDATE stage_pieces SET idx=-idx WHERE stage_id=? AND kind='chunk'")
46
- .run(stageId);
47
- const known = new Set(old.map((p) => p.id));
48
- for (const piece of planned) {
49
- if (known.has(piece.id))
50
- deps.db
51
- .prepare("UPDATE stage_pieces SET idx=?,state=?,payload=? WHERE id=?")
52
- .run(piece.idx, piece.state, piece.payload, piece.id);
53
- else
54
- insertPiece(deps.db, piece);
55
- }
56
- });
57
- return planned;
58
- }