@gentbajko/slopify 3.25.9 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (718) hide show
  1. package/dist/adapters/account-limits.js +30 -0
  2. package/dist/adapters/alignment/audio.js +1 -1
  3. package/dist/adapters/alignment/cache.js +4 -6
  4. package/dist/adapters/alignment/ctc.js +1 -2
  5. package/dist/adapters/alignment/lock.js +4 -3
  6. package/dist/adapters/alignment/multilingual.js +2 -4
  7. package/dist/adapters/alignment/prefetch.js +2 -1
  8. package/dist/adapters/alignment/runner.js +1 -1
  9. package/dist/adapters/alignment/worker.js +3 -2
  10. package/dist/adapters/explain.js +10 -12
  11. package/dist/adapters/ffmpeg.js +19 -1
  12. package/dist/adapters/host-cli/index.js +21 -4
  13. package/dist/adapters/host-cli/transport.js +2 -1
  14. package/dist/adapters/http-failure.js +53 -0
  15. package/dist/adapters/image/bytes.js +2 -1
  16. package/dist/adapters/image/codex.js +42 -9
  17. package/dist/adapters/image/fal.js +21 -53
  18. package/dist/adapters/image/google.js +33 -56
  19. package/dist/adapters/image/models.js +2 -2
  20. package/dist/adapters/image/openai.js +22 -48
  21. package/dist/adapters/image/reference.js +36 -0
  22. package/dist/adapters/image/replicate.js +21 -49
  23. package/dist/adapters/image/video.js +2 -1
  24. package/dist/adapters/interest/search-interest.js +113 -0
  25. package/dist/adapters/key-probes.js +54 -3
  26. package/dist/adapters/llm/antigravity-models.js +1 -1
  27. package/dist/adapters/llm/antigravity.js +11 -6
  28. package/dist/adapters/llm/assistant-cli.js +388 -0
  29. package/dist/adapters/llm/child-session.js +83 -0
  30. package/dist/adapters/llm/claude-code-models.js +52 -99
  31. package/dist/adapters/llm/claude-code.js +16 -4
  32. package/dist/adapters/llm/codex-limits.js +27 -68
  33. package/dist/adapters/llm/codex-models.js +1 -1
  34. package/dist/adapters/llm/codex-server-models.js +61 -109
  35. package/dist/adapters/llm/codex.js +12 -1
  36. package/dist/adapters/llm/document-workspace.js +3 -2
  37. package/dist/adapters/llm/image-workspace.js +3 -2
  38. package/dist/adapters/llm/openrouter.js +12 -48
  39. package/dist/adapters/llm/run-cli.js +9 -24
  40. package/dist/adapters/llm/sse-lines.js +5 -1
  41. package/dist/adapters/model-access.js +37 -0
  42. package/dist/adapters/tts/cartesia.js +15 -46
  43. package/dist/adapters/tts/elevenlabs.js +20 -52
  44. package/dist/adapters/tts/gemini.js +21 -41
  45. package/dist/adapters/tts/inworld-async.js +6 -2
  46. package/dist/adapters/tts/inworld.js +6 -2
  47. package/dist/adapters/tts/openai.js +20 -50
  48. package/dist/adapters/tts/system.js +2 -1
  49. package/dist/assets/models-lifecycle.yaml +6 -0
  50. package/dist/assistant-wiring.js +60 -0
  51. package/dist/autopilot-timers.js +59 -0
  52. package/dist/catalog/lifecycle.js +52 -0
  53. package/dist/catalog/propose.js +204 -0
  54. package/dist/catalog/registry.js +23 -14
  55. package/dist/catalog/schema.js +4 -1
  56. package/dist/catalog/store.js +39 -0
  57. package/dist/catalog/validate.js +5 -2
  58. package/dist/edge/autostart/native.js +3 -5
  59. package/dist/edge/autostart/prompt.js +2 -1
  60. package/dist/edge/autostart/service.js +3 -4
  61. package/dist/edge/cli-args.js +3 -4
  62. package/dist/edge/cli.js +2 -1
  63. package/dist/edge/docker-install/apply.js +11 -11
  64. package/dist/edge/docker-install/run.js +2 -1
  65. package/dist/edge/docker-install/state.js +4 -3
  66. package/dist/edge/docker-install/tree.js +2 -4
  67. package/dist/edge/docker-install/volume.js +3 -2
  68. package/dist/edge/docker.js +5 -4
  69. package/dist/edge/events/hub.js +5 -5
  70. package/dist/edge/http/actions.js +11 -32
  71. package/dist/edge/http/actor.js +5 -3
  72. package/dist/edge/http/app.js +86 -11
  73. package/dist/edge/http/assistant.js +129 -0
  74. package/dist/edge/http/audio-preview.js +4 -11
  75. package/dist/edge/http/auditions.js +1 -1
  76. package/dist/edge/http/autostart.js +5 -5
  77. package/dist/edge/http/backups.js +2 -4
  78. package/dist/edge/http/channel-memory.js +9 -22
  79. package/dist/edge/http/channels.js +14 -27
  80. package/dist/edge/http/checkpoints.js +39 -21
  81. package/dist/edge/http/design-templates.js +167 -0
  82. package/dist/edge/http/designs.js +178 -0
  83. package/dist/edge/http/diagnostics.js +5 -1
  84. package/dist/edge/http/document-themes.js +5 -14
  85. package/dist/edge/http/draft-files.js +1 -3
  86. package/dist/edge/http/draft-problem.js +5 -10
  87. package/dist/edge/http/drafts.js +3 -3
  88. package/dist/edge/http/entries.js +6 -9
  89. package/dist/edge/http/extension-auth.js +27 -0
  90. package/dist/edge/http/external-reviews.js +12 -11
  91. package/dist/edge/http/files.js +5 -11
  92. package/dist/edge/http/folder-location.js +1 -4
  93. package/dist/edge/http/fonts.js +0 -7
  94. package/dist/edge/http/home.js +47 -14
  95. package/dist/edge/http/host-cli.js +18 -8
  96. package/dist/edge/http/ids.js +8 -0
  97. package/dist/edge/http/keywords.js +35 -0
  98. package/dist/edge/http/model-checks.js +132 -0
  99. package/dist/edge/http/narration-peaks.js +5 -13
  100. package/dist/edge/http/onboarding.js +30 -26
  101. package/dist/edge/http/open-folder.js +5 -10
  102. package/dist/edge/http/outputs.js +7 -14
  103. package/dist/edge/http/patch-notes.js +6 -12
  104. package/dist/edge/http/planning.js +3 -7
  105. package/dist/edge/http/problem.js +2 -4
  106. package/dist/edge/http/project-create.js +2 -1
  107. package/dist/edge/http/project-templates.js +31 -19
  108. package/dist/edge/http/projects.js +24 -16
  109. package/dist/edge/http/prompts.js +9 -16
  110. package/dist/edge/http/pronunciations.js +1 -2
  111. package/dist/edge/http/providers.js +48 -34
  112. package/dist/edge/http/refusal.js +29 -0
  113. package/dist/edge/http/remote-access.js +40 -0
  114. package/dist/edge/http/remote-guard.js +71 -0
  115. package/dist/edge/http/request-guard.js +91 -0
  116. package/dist/edge/http/reviews.js +12 -25
  117. package/dist/edge/http/revision-files.js +6 -11
  118. package/dist/edge/http/revisions.js +14 -19
  119. package/dist/edge/http/run-cost.js +1 -2
  120. package/dist/edge/http/same-page.js +80 -0
  121. package/dist/edge/http/schedules.js +69 -40
  122. package/dist/edge/http/settings.js +27 -14
  123. package/dist/edge/http/social.js +283 -0
  124. package/dist/edge/http/staging.js +3 -5
  125. package/dist/edge/http/storage-files.js +5 -7
  126. package/dist/edge/http/storage.js +33 -25
  127. package/dist/edge/http/studio.js +94 -69
  128. package/dist/edge/http/style-preview.js +3 -6
  129. package/dist/edge/http/subtitles.js +3 -17
  130. package/dist/edge/http/template-studio.js +436 -0
  131. package/dist/edge/http/trash.js +11 -12
  132. package/dist/edge/http/tutorial.js +1 -2
  133. package/dist/edge/http/tutorials.js +5 -11
  134. package/dist/edge/http/update.js +7 -13
  135. package/dist/edge/http/waveform.js +3 -6
  136. package/dist/edge/http/youtube-edits.js +3 -4
  137. package/dist/edge/mcp/assistant.js +279 -0
  138. package/dist/edge/mcp/attribution.js +8 -2
  139. package/dist/edge/mcp/call-route.js +11 -2
  140. package/dist/edge/mcp/excluded-routes.js +29 -3
  141. package/dist/edge/mcp/http.js +11 -2
  142. package/dist/edge/mcp/instructions.js +6 -4
  143. package/dist/edge/mcp/library-tools.js +9 -5
  144. package/dist/edge/mcp/remake-tools.js +7 -4
  145. package/dist/edge/mcp/route-tool.js +35 -15
  146. package/dist/edge/mcp/server.js +13 -8
  147. package/dist/edge/mcp/tools-channels.js +11 -9
  148. package/dist/edge/mcp/tools-designs.js +165 -0
  149. package/dist/edge/mcp/tools-library.js +19 -7
  150. package/dist/edge/mcp/tools-planning.js +40 -21
  151. package/dist/edge/mcp/tools-projects.js +38 -11
  152. package/dist/edge/mcp/tools-publishing.js +9 -9
  153. package/dist/edge/mcp/tools-runs.js +23 -10
  154. package/dist/edge/mcp/tools-schedules.js +32 -8
  155. package/dist/edge/mcp/tools-setup.js +75 -11
  156. package/dist/edge/mcp/tools-social.js +47 -0
  157. package/dist/edge/mcp/tools-storage.js +11 -3
  158. package/dist/edge/mcp/tools-template-studio.js +166 -0
  159. package/dist/edge/mcp/tools.js +6 -0
  160. package/dist/edge/remote-access/cli.js +71 -0
  161. package/dist/edge/remote-access/model.js +32 -0
  162. package/dist/edge/remote-access/rules.js +207 -0
  163. package/dist/edge/remote-access/service.js +203 -0
  164. package/dist/edge/remote-access/store.js +44 -0
  165. package/dist/edge/remote-access/views.js +43 -0
  166. package/dist/extension/slopify-studio-chrome.zip +0 -0
  167. package/dist/extension/slopify-studio-firefox.zip +0 -0
  168. package/dist/host-cli/install.js +2 -2
  169. package/dist/host-cli/open-folder.js +2 -2
  170. package/dist/host-cli/paths.js +2 -4
  171. package/dist/host-cli/server.js +4 -4
  172. package/dist/host-cli/service.js +3 -3
  173. package/dist/host-cli/status.js +7 -7
  174. package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
  175. package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
  176. package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
  177. package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
  178. package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
  179. package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
  180. package/dist/kernel/db/migrations/0070-designs.sql +53 -0
  181. package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
  182. package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
  183. package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
  184. package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
  185. package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
  186. package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
  187. package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
  188. package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
  189. package/dist/kernel/db/tx.js +2 -4
  190. package/dist/kernel/errors.js +27 -1
  191. package/dist/kernel/json-answer.js +15 -0
  192. package/dist/kernel/lock.js +4 -9
  193. package/dist/kernel/paths.js +8 -0
  194. package/dist/kernel/pipeline.js +12 -0
  195. package/dist/kernel/ports/assistant-cli.js +4 -0
  196. package/dist/kernel/ports/host-cli.js +3 -0
  197. package/dist/kernel/ports/interest.js +4 -0
  198. package/dist/kernel/ports/languages.js +0 -3
  199. package/dist/kernel/ports/model.js +2 -0
  200. package/dist/kernel/ports/settings-places.js +31 -0
  201. package/dist/kernel/ports/system-speech.js +31 -3
  202. package/dist/kernel/runner/attempt.js +14 -4
  203. package/dist/kernel/runner/audition.js +3 -1
  204. package/dist/kernel/runner/checkpoint-authority.js +2 -1
  205. package/dist/kernel/runner/index.js +8 -10
  206. package/dist/kernel/runner/model-access.js +40 -0
  207. package/dist/kernel/runner/model-check.js +153 -0
  208. package/dist/kernel/runner/providers.js +18 -12
  209. package/dist/kernel/runner/standalone.js +11 -7
  210. package/dist/main.js +338 -21
  211. package/dist/model-catalog.js +20 -0
  212. package/dist/model-checks.js +166 -0
  213. package/dist/patch-notes/4.0.0.md +51 -0
  214. package/dist/patch-notes/4.1.0.md +42 -0
  215. package/dist/patch-notes/index.json +12 -0
  216. package/dist/slices/admission/heads.js +2 -1
  217. package/dist/slices/admission/listing-facts.js +95 -0
  218. package/dist/slices/admission/repo.js +11 -7
  219. package/dist/slices/admission/rules.js +50 -15
  220. package/dist/slices/admission/schema.js +8 -0
  221. package/dist/slices/admission/stage-writes.js +0 -3
  222. package/dist/slices/admission/start.js +48 -31
  223. package/dist/slices/admission/state-words.js +34 -5
  224. package/dist/slices/admission/substitute.js +7 -4
  225. package/dist/slices/agents/attention-posts.js +31 -0
  226. package/dist/slices/agents/attention-templates.js +33 -0
  227. package/dist/slices/agents/attention.js +10 -1
  228. package/dist/slices/agents/connection.js +2 -6
  229. package/dist/slices/agents/model.js +6 -3
  230. package/dist/slices/agents/repo.js +15 -7
  231. package/dist/slices/article/continuation.js +0 -63
  232. package/dist/slices/article/plain.js +3 -2
  233. package/dist/slices/article/segments.js +2 -62
  234. package/dist/slices/assistant/access.js +1 -0
  235. package/dist/slices/assistant/asks.js +80 -0
  236. package/dist/slices/assistant/cost.js +54 -0
  237. package/dist/slices/assistant/gate.js +222 -0
  238. package/dist/slices/assistant/model.js +86 -0
  239. package/dist/slices/assistant/names.js +23 -0
  240. package/dist/slices/assistant/prompt.js +74 -0
  241. package/dist/slices/assistant/repo.js +74 -0
  242. package/dist/slices/assistant/tokens.js +18 -0
  243. package/dist/slices/assistant/turn.js +344 -0
  244. package/dist/slices/autopilot/buffer.js +76 -0
  245. package/dist/slices/autopilot/model.js +14 -0
  246. package/dist/slices/autopilot/notify.js +27 -0
  247. package/dist/slices/autopilot/repo.js +34 -0
  248. package/dist/slices/autopilot/signals.js +194 -0
  249. package/dist/slices/autopilot/warnings.js +85 -0
  250. package/dist/slices/autopilot/weekly.js +100 -0
  251. package/dist/slices/backups/files.js +2 -6
  252. package/dist/slices/backups/repo.js +3 -15
  253. package/dist/slices/backups/service.js +8 -7
  254. package/dist/slices/channels/cast-images.js +3 -2
  255. package/dist/slices/channels/model.js +0 -1
  256. package/dist/slices/channels/rebrand.js +0 -3
  257. package/dist/slices/channels/repo.js +4 -0
  258. package/dist/slices/channels/schema.js +7 -1
  259. package/dist/slices/channels/service.js +10 -0
  260. package/dist/slices/channels/videos.js +3 -15
  261. package/dist/slices/checkpoints/index.js +0 -1
  262. package/dist/slices/control/providers.js +2 -28
  263. package/dist/slices/designs/artwork.js +66 -0
  264. package/dist/slices/designs/budget.js +23 -0
  265. package/dist/slices/designs/calls.js +124 -0
  266. package/dist/slices/designs/check-context.js +38 -0
  267. package/dist/slices/designs/check-text.js +43 -0
  268. package/dist/slices/designs/fields.js +88 -0
  269. package/dist/slices/designs/frames.js +34 -0
  270. package/dist/slices/designs/gate.js +130 -0
  271. package/dist/slices/designs/layout.js +293 -0
  272. package/dist/slices/designs/model.js +35 -0
  273. package/dist/slices/designs/pdf-job.js +23 -0
  274. package/dist/slices/designs/pdf-pages.js +30 -0
  275. package/dist/slices/designs/pdf-runner.js +68 -0
  276. package/dist/slices/designs/pdf-worker.js +24 -0
  277. package/dist/slices/designs/picture-size.js +79 -0
  278. package/dist/slices/designs/pictures.js +55 -0
  279. package/dist/slices/designs/quote.js +24 -0
  280. package/dist/slices/designs/render-args.js +36 -0
  281. package/dist/slices/designs/render-input.js +59 -0
  282. package/dist/slices/designs/render.js +215 -0
  283. package/dist/slices/designs/repo.js +101 -0
  284. package/dist/slices/designs/requests.js +80 -0
  285. package/dist/slices/designs/runner.js +239 -0
  286. package/dist/slices/designs/sample-repo.js +91 -0
  287. package/dist/slices/designs/sample.js +223 -0
  288. package/dist/slices/designs/schema.js +87 -0
  289. package/dist/slices/designs/sections.js +44 -0
  290. package/dist/slices/designs/service.js +233 -0
  291. package/dist/slices/designs/steps-repo.js +102 -0
  292. package/dist/slices/designs/studio-kind.js +39 -0
  293. package/dist/slices/designs/template-checks.js +44 -0
  294. package/dist/slices/designs/template-make.js +118 -0
  295. package/dist/slices/designs/templates.js +218 -0
  296. package/dist/slices/document/fonts.js +2 -1
  297. package/dist/slices/document/model.js +7 -4
  298. package/dist/slices/document/render.js +2 -1
  299. package/dist/slices/document/theme-schema.js +1 -1
  300. package/dist/slices/document/theme.js +49 -3
  301. package/dist/slices/episodes/summarize.js +6 -2
  302. package/dist/slices/estimate/index.js +72 -28
  303. package/dist/slices/estimate/requests.js +4 -4
  304. package/dist/slices/fixes/rules.js +3 -1
  305. package/dist/slices/fonts/catalog.js +5 -3
  306. package/dist/slices/fonts/coverage.js +2 -1
  307. package/dist/slices/fonts/discovery.js +3 -2
  308. package/dist/slices/fonts/files.js +2 -6
  309. package/dist/slices/fonts/index.js +0 -1
  310. package/dist/slices/fonts/sfnt.js +45 -10
  311. package/dist/slices/images/appearance.js +8 -16
  312. package/dist/slices/images/scenes.js +102 -28
  313. package/dist/slices/keywords/digest.js +85 -0
  314. package/dist/slices/keywords/facts.js +92 -0
  315. package/dist/slices/keywords/fill.js +80 -0
  316. package/dist/slices/keywords/model.js +75 -0
  317. package/dist/slices/keywords/rules.js +187 -0
  318. package/dist/slices/keywords/schema.js +28 -0
  319. package/dist/slices/keywords/specs.js +260 -0
  320. package/dist/slices/keywords/values.js +74 -0
  321. package/dist/slices/library/lint.js +29 -12
  322. package/dist/slices/library/model.js +2 -0
  323. package/dist/slices/library/photorealistic.js +4 -12
  324. package/dist/slices/library/rename.js +9 -7
  325. package/dist/slices/library/save.js +14 -10
  326. package/dist/slices/library/slots.js +37 -11
  327. package/dist/slices/library/transfer.js +5 -4
  328. package/dist/slices/library/used-by.js +25 -10
  329. package/dist/slices/loudness/loudnorm.js +53 -12
  330. package/dist/slices/loudness/model.js +3 -2
  331. package/dist/slices/loudness/sentence-level.js +2 -1
  332. package/dist/slices/model-checks/cost.js +61 -0
  333. package/dist/slices/model-checks/listing.js +124 -0
  334. package/dist/slices/model-checks/model.js +20 -0
  335. package/dist/slices/model-checks/record.js +32 -0
  336. package/dist/slices/model-checks/repo.js +120 -0
  337. package/dist/slices/model-checks/rules.js +125 -0
  338. package/dist/slices/model-checks/run.js +143 -0
  339. package/dist/slices/model-checks/service.js +198 -0
  340. package/dist/slices/model-upkeep/model.js +1 -1
  341. package/dist/slices/model-upkeep/switch.js +72 -27
  342. package/dist/slices/model-upkeep/usage.js +39 -13
  343. package/dist/slices/narration/breaths.js +3 -1
  344. package/dist/slices/narration/clean-pieces.js +3 -1
  345. package/dist/slices/narration/concat.js +2 -1
  346. package/dist/slices/narration/pauses-model.js +3 -2
  347. package/dist/slices/narration/peaks.js +3 -4
  348. package/dist/slices/narration/pronunciation-chunks.js +4 -3
  349. package/dist/slices/narration/pronunciation.js +6 -4
  350. package/dist/slices/narration/steering.js +4 -3
  351. package/dist/slices/notifications/notifier.js +4 -3
  352. package/dist/slices/notifications/rules.js +5 -2
  353. package/dist/slices/notifications/settings.js +4 -12
  354. package/dist/slices/notifications/subject.js +4 -3
  355. package/dist/slices/onboarding/copy.js +21 -3
  356. package/dist/slices/onboarding/first-run.js +16 -40
  357. package/dist/slices/onboarding/full-video.js +3 -2
  358. package/dist/slices/onboarding/install.js +6 -4
  359. package/dist/slices/onboarding/model.js +26 -37
  360. package/dist/slices/onboarding/packs.js +22 -22
  361. package/dist/slices/onboarding/preferred-model.js +14 -0
  362. package/dist/slices/onboarding/quick-short.js +105 -65
  363. package/dist/slices/onboarding/sample.js +4 -2
  364. package/dist/slices/onboarding/state.js +9 -11
  365. package/dist/slices/onboarding/template.js +8 -6
  366. package/dist/slices/outputs/add.js +3 -2
  367. package/dist/slices/outputs/service.js +2 -2
  368. package/dist/slices/patch-notes/library.js +4 -3
  369. package/dist/slices/play-drafts/convert.js +4 -0
  370. package/dist/slices/play-drafts/readiness.js +3 -3
  371. package/dist/slices/play-drafts/review-inputs.js +9 -3
  372. package/dist/slices/play-drafts/review.js +5 -4
  373. package/dist/slices/play-drafts/schema.js +4 -0
  374. package/dist/slices/play-drafts/service.js +17 -7
  375. package/dist/slices/project-templates/from-project.js +9 -2
  376. package/dist/slices/project-templates/next-chapter.js +2 -1
  377. package/dist/slices/project-templates/provider-defaults.js +22 -0
  378. package/dist/slices/project-templates/repo.js +6 -1
  379. package/dist/slices/project-templates/setup-sections.js +26 -0
  380. package/dist/slices/project-templates/setup.js +14 -1
  381. package/dist/slices/project-templates/stand-ins.js +22 -0
  382. package/dist/slices/rebuild/activity.js +2 -0
  383. package/dist/slices/rebuild/admission-repo.js +3 -2
  384. package/dist/slices/rebuild/narration-history.js +4 -5
  385. package/dist/slices/rebuild/narration-retry.js +2 -1
  386. package/dist/slices/rebuild/preview-details.js +32 -14
  387. package/dist/slices/rebuild/preview-plan.js +3 -8
  388. package/dist/slices/rebuild/recipe-build.js +8 -3
  389. package/dist/slices/rebuild/recipe-describe.js +3 -3
  390. package/dist/slices/rebuild/recipe-digest.js +58 -0
  391. package/dist/slices/rebuild/recipe-input-schema.js +10 -0
  392. package/dist/slices/rebuild/recipe-keywords.js +71 -0
  393. package/dist/slices/rebuild/recipe-legacy.js +5 -1
  394. package/dist/slices/rebuild/recipe-model.js +4 -0
  395. package/dist/slices/rebuild/recipe-narration-text.js +2 -1
  396. package/dist/slices/rebuild/recipe-preparation.js +4 -4
  397. package/dist/slices/rebuild/recipe-reference.js +8 -4
  398. package/dist/slices/rebuild/recipe-reviews.js +27 -7
  399. package/dist/slices/rebuild/recipe-save.js +8 -5
  400. package/dist/slices/rebuild/recipe-scenes.js +40 -11
  401. package/dist/slices/rebuild/recipe-shorts.js +8 -8
  402. package/dist/slices/rebuild/recipe-social.js +46 -0
  403. package/dist/slices/rebuild/recipe-text.js +64 -20
  404. package/dist/slices/rebuild/recipe-validation.js +102 -31
  405. package/dist/slices/rebuild/recipe-visual.js +55 -16
  406. package/dist/slices/rebuild/recipe-voices.js +3 -2
  407. package/dist/slices/rebuild/recipe-work.js +19 -7
  408. package/dist/slices/rebuild/recipe-youtube.js +4 -3
  409. package/dist/slices/rebuild/recovery-selection.js +3 -1
  410. package/dist/slices/rebuild/recovery.js +9 -8
  411. package/dist/slices/rebuild/remake-outdated.js +5 -5
  412. package/dist/slices/rebuild/repo.js +4 -3
  413. package/dist/slices/rebuild/review-promise.js +25 -0
  414. package/dist/slices/rebuild/review-redo.js +3 -2
  415. package/dist/slices/rebuild/runtime-admission.js +4 -3
  416. package/dist/slices/rebuild/runtime-agent-review.js +11 -5
  417. package/dist/slices/rebuild/runtime-animate.js +10 -9
  418. package/dist/slices/rebuild/runtime-article.js +7 -5
  419. package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
  420. package/dist/slices/rebuild/runtime-document.js +11 -13
  421. package/dist/slices/rebuild/runtime-export-bed.js +8 -12
  422. package/dist/slices/rebuild/runtime-export-edit.js +8 -16
  423. package/dist/slices/rebuild/runtime-export-inputs.js +12 -11
  424. package/dist/slices/rebuild/runtime-export-short.js +9 -5
  425. package/dist/slices/rebuild/runtime-export.js +38 -15
  426. package/dist/slices/rebuild/runtime-figure-card.js +2 -1
  427. package/dist/slices/rebuild/runtime-image.js +8 -12
  428. package/dist/slices/rebuild/runtime-instructions.js +2 -0
  429. package/dist/slices/rebuild/runtime-keywords.js +59 -0
  430. package/dist/slices/rebuild/runtime-lines.js +2 -11
  431. package/dist/slices/rebuild/runtime-local.js +17 -22
  432. package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
  433. package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
  434. package/dist/slices/rebuild/runtime-narration-text.js +13 -17
  435. package/dist/slices/rebuild/runtime-pictures.js +2 -4
  436. package/dist/slices/rebuild/runtime-piece-label.js +10 -6
  437. package/dist/slices/rebuild/runtime-plan.js +31 -5
  438. package/dist/slices/rebuild/runtime-provider.js +67 -25
  439. package/dist/slices/rebuild/runtime-publication.js +10 -9
  440. package/dist/slices/rebuild/runtime-review.js +39 -33
  441. package/dist/slices/rebuild/runtime-run.js +4 -1
  442. package/dist/slices/rebuild/runtime-shorts.js +31 -50
  443. package/dist/slices/rebuild/runtime-store.js +20 -10
  444. package/dist/slices/rebuild/runtime-subtitles.js +28 -25
  445. package/dist/slices/rebuild/runtime-voices.js +10 -16
  446. package/dist/slices/rebuild/runtime-youtube.js +14 -31
  447. package/dist/slices/rebuild/service-readiness.js +11 -3
  448. package/dist/slices/rebuild/transition-repo.js +6 -5
  449. package/dist/slices/rebuild/work-records.js +6 -0
  450. package/dist/slices/reruns/cascade.js +1 -2
  451. package/dist/slices/reruns/index.js +6 -9
  452. package/dist/slices/research/synthesis.js +3 -2
  453. package/dist/slices/reviews/external-model.js +4 -1
  454. package/dist/slices/reviews/external-repo.js +2 -1
  455. package/dist/slices/reviews/external-rows.js +2 -3
  456. package/dist/slices/reviews/holds.js +5 -4
  457. package/dist/slices/reviews/model.js +32 -11
  458. package/dist/slices/reviews/repo.js +2 -1
  459. package/dist/slices/reviews/rules.js +4 -3
  460. package/dist/slices/reviews/verdict.js +2 -1
  461. package/dist/slices/reviews/view.js +5 -2
  462. package/dist/slices/revisions/downloads.js +4 -5
  463. package/dist/slices/revisions/image-plan.js +1 -1
  464. package/dist/slices/revisions/mutation-assets.js +9 -5
  465. package/dist/slices/revisions/mutation-cues.js +2 -5
  466. package/dist/slices/revisions/mutations.js +3 -3
  467. package/dist/slices/revisions/repo.js +3 -1
  468. package/dist/slices/revisions/schema.js +1 -0
  469. package/dist/slices/revisions/view.js +20 -0
  470. package/dist/slices/run-cost/limits.js +5 -2
  471. package/dist/slices/run-cost/meter.js +12 -5
  472. package/dist/slices/run-cost/panel.js +8 -74
  473. package/dist/slices/run-cost/plan-readings.js +127 -0
  474. package/dist/slices/run-cost/plan-use.js +169 -0
  475. package/dist/slices/run-cost/pricing.js +3 -3
  476. package/dist/slices/run-cost/week.js +32 -4
  477. package/dist/slices/schedules/agenda.js +18 -7
  478. package/dist/slices/schedules/by-date.js +42 -0
  479. package/dist/slices/schedules/calendar.js +5 -0
  480. package/dist/slices/schedules/design-agenda.js +36 -0
  481. package/dist/slices/schedules/design-check.js +41 -0
  482. package/dist/slices/schedules/design-run.js +126 -0
  483. package/dist/slices/schedules/next-run.js +62 -0
  484. package/dist/slices/schedules/prepare.js +18 -2
  485. package/dist/slices/schedules/repo.js +30 -21
  486. package/dist/slices/schedules/rescore.js +35 -0
  487. package/dist/slices/schedules/scheduler.js +13 -3
  488. package/dist/slices/schedules/schema.js +57 -3
  489. package/dist/slices/schedules/score.js +107 -0
  490. package/dist/slices/schedules/service.js +57 -24
  491. package/dist/slices/schedules/topic-list.js +15 -0
  492. package/dist/slices/schedules/topic-scores.js +104 -0
  493. package/dist/slices/schedules/topics.js +53 -41
  494. package/dist/slices/settings/cli-paths.js +4 -6
  495. package/dist/slices/settings/first-run.js +8 -43
  496. package/dist/slices/settings/health.js +30 -15
  497. package/dist/slices/settings/key-test.js +1 -1
  498. package/dist/slices/settings/model-reach.js +3 -17
  499. package/dist/slices/settings/model.js +14 -2
  500. package/dist/slices/settings/playback.js +34 -23
  501. package/dist/slices/settings/probe-read.js +16 -0
  502. package/dist/slices/settings/repo.js +33 -0
  503. package/dist/slices/settings/tutorial.js +2 -2
  504. package/dist/slices/settings/voices.js +4 -12
  505. package/dist/slices/shorts/keep.js +2 -1
  506. package/dist/slices/shorts/pick.js +6 -18
  507. package/dist/slices/shorts/prompts.js +4 -14
  508. package/dist/slices/shorts/render.js +6 -2
  509. package/dist/slices/social/channel.js +44 -0
  510. package/dist/slices/social/defaults.js +17 -0
  511. package/dist/slices/social/due.js +36 -0
  512. package/dist/slices/social/extension.js +18 -0
  513. package/dist/slices/social/fit.js +115 -0
  514. package/dist/slices/social/limits.js +186 -0
  515. package/dist/slices/social/links.js +21 -0
  516. package/dist/slices/social/media.js +132 -0
  517. package/dist/slices/social/model.js +75 -0
  518. package/dist/slices/social/notice.js +19 -0
  519. package/dist/slices/social/pack.js +176 -0
  520. package/dist/slices/social/post-prompt.js +56 -0
  521. package/dist/slices/social/queue.js +31 -0
  522. package/dist/slices/social/repo.js +133 -0
  523. package/dist/slices/social/reshape.js +97 -0
  524. package/dist/slices/social/rules.js +5 -0
  525. package/dist/slices/social/schema.js +70 -0
  526. package/dist/slices/social/serve.js +51 -0
  527. package/dist/slices/social/service.js +129 -0
  528. package/dist/slices/social/settings.js +21 -0
  529. package/dist/slices/social/sources.js +114 -0
  530. package/dist/slices/social/state.js +110 -0
  531. package/dist/slices/social/text.js +149 -0
  532. package/dist/slices/storage/arrange.js +3 -1
  533. package/dist/slices/storage/assets.js +8 -10
  534. package/dist/slices/storage/backup-designs.js +74 -0
  535. package/dist/slices/storage/backup-export.js +8 -3
  536. package/dist/slices/storage/backup-format.js +10 -0
  537. package/dist/slices/storage/backup-import.js +22 -4
  538. package/dist/slices/storage/delete-project.js +6 -5
  539. package/dist/slices/storage/files-location.js +6 -8
  540. package/dist/slices/storage/layout.js +13 -2
  541. package/dist/slices/storage/model.js +3 -0
  542. package/dist/slices/storage/portable.js +17 -12
  543. package/dist/slices/storage/schema.js +2 -0
  544. package/dist/slices/storage/staging-refs.js +2 -1
  545. package/dist/slices/storage/staging.js +6 -9
  546. package/dist/slices/storage/trim.js +26 -9
  547. package/dist/slices/studio/calendar.js +7 -2
  548. package/dist/slices/studio/disclosure.js +4 -4
  549. package/dist/slices/studio/model.js +1 -1
  550. package/dist/slices/studio/pack.js +9 -8
  551. package/dist/slices/studio/pick.js +2 -11
  552. package/dist/slices/studio/plan.js +7 -16
  553. package/dist/slices/studio/queue.js +3 -14
  554. package/dist/slices/studio/releases.js +26 -0
  555. package/dist/slices/studio/settings.js +20 -57
  556. package/dist/slices/studio/videos.js +35 -4
  557. package/dist/slices/style-preview/render.js +37 -16
  558. package/dist/slices/style-preview/schema.js +14 -1
  559. package/dist/slices/style-preview/service.js +2 -1
  560. package/dist/slices/style-preview/settings.js +33 -5
  561. package/dist/slices/subtitles/captions.js +1 -1
  562. package/dist/slices/telemetry/collector-client.js +2 -4
  563. package/dist/slices/telemetry/flush.js +2 -4
  564. package/dist/slices/telemetry/model.js +0 -7
  565. package/dist/slices/telemetry/record.js +10 -3
  566. package/dist/slices/template-studio/anatomy-view.js +161 -0
  567. package/dist/slices/template-studio/anatomy.js +73 -0
  568. package/dist/slices/template-studio/bakeoff-make.js +225 -0
  569. package/dist/slices/template-studio/bakeoff-repo.js +83 -0
  570. package/dist/slices/template-studio/bakeoff.js +333 -0
  571. package/dist/slices/template-studio/budget.js +106 -0
  572. package/dist/slices/template-studio/cards.js +78 -0
  573. package/dist/slices/template-studio/checks.js +322 -0
  574. package/dist/slices/template-studio/document-sample.js +56 -0
  575. package/dist/slices/template-studio/edit.js +15 -0
  576. package/dist/slices/template-studio/for-all.js +161 -0
  577. package/dist/slices/template-studio/free-video.js +31 -0
  578. package/dist/slices/template-studio/free.js +176 -0
  579. package/dist/slices/template-studio/gate.js +40 -0
  580. package/dist/slices/template-studio/hidden.js +20 -0
  581. package/dist/slices/template-studio/jobs.js +79 -0
  582. package/dist/slices/template-studio/loudness.js +111 -0
  583. package/dist/slices/template-studio/make.js +40 -0
  584. package/dist/slices/template-studio/model.js +58 -0
  585. package/dist/slices/template-studio/pack-import.js +253 -0
  586. package/dist/slices/template-studio/pack-samples.js +60 -0
  587. package/dist/slices/template-studio/pack.js +207 -0
  588. package/dist/slices/template-studio/paid-view.js +66 -0
  589. package/dist/slices/template-studio/paid.js +355 -0
  590. package/dist/slices/template-studio/quote.js +155 -0
  591. package/dist/slices/template-studio/ready.js +104 -0
  592. package/dist/slices/template-studio/repo.js +134 -0
  593. package/dist/slices/template-studio/reviews-path.js +58 -0
  594. package/dist/slices/template-studio/runner.js +84 -0
  595. package/dist/slices/template-studio/save.js +236 -0
  596. package/dist/slices/template-studio/say-it-as.js +248 -0
  597. package/dist/slices/template-studio/schedule-gate.js +34 -0
  598. package/dist/slices/template-studio/schedule-price.js +32 -0
  599. package/dist/slices/template-studio/schedule-sample.js +91 -0
  600. package/dist/slices/template-studio/schema.js +243 -0
  601. package/dist/slices/template-studio/scope.js +124 -0
  602. package/dist/slices/template-studio/sections.js +176 -0
  603. package/dist/slices/template-studio/service.js +175 -0
  604. package/dist/slices/template-studio/status.js +191 -0
  605. package/dist/slices/template-studio/topic.js +223 -0
  606. package/dist/slices/thumbnail/by-llm.js +1 -1
  607. package/dist/slices/trash/designs.js +76 -0
  608. package/dist/slices/trash/model.js +13 -4
  609. package/dist/slices/trash/service.js +52 -2
  610. package/dist/slices/tutorials/library.js +3 -2
  611. package/dist/slices/uploads/repo.js +37 -1
  612. package/dist/slices/uploads/rules.js +3 -2
  613. package/dist/slices/video/ass-text.js +17 -0
  614. package/dist/slices/video/audio-export.js +2 -64
  615. package/dist/slices/video/edit-list.js +2 -2
  616. package/dist/slices/video/edit-settings.js +1 -1
  617. package/dist/slices/video/encoding.js +169 -0
  618. package/dist/slices/video/ffmpeg.js +23 -21
  619. package/dist/slices/video/figure-card.js +1 -15
  620. package/dist/slices/video/plan.js +2 -1
  621. package/dist/slices/video/slideshow.js +43 -18
  622. package/dist/slices/voices/attribution.js +3 -2
  623. package/dist/slices/voices/model.js +9 -8
  624. package/dist/slices/voices/palette.js +0 -3
  625. package/dist/slices/voices/script.js +2 -1
  626. package/dist/slices/youtube/answer.js +4 -16
  627. package/dist/slices/youtube/edits-repo.js +3 -12
  628. package/dist/tutorials/AI-CLIs.md +25 -25
  629. package/dist/tutorials/Agents-MCP.md +34 -33
  630. package/dist/tutorials/Assistant.md +42 -0
  631. package/dist/tutorials/Backups.md +7 -7
  632. package/dist/tutorials/Calendar.md +17 -25
  633. package/dist/tutorials/Cast-Library.md +19 -19
  634. package/dist/tutorials/Channels.md +42 -35
  635. package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
  636. package/dist/tutorials/Create-Article.md +114 -0
  637. package/dist/tutorials/Create-Extras.md +112 -0
  638. package/dist/tutorials/Create-Images.md +165 -0
  639. package/dist/tutorials/Create-Narration.md +178 -0
  640. package/dist/tutorials/Create-Overview.md +244 -0
  641. package/dist/tutorials/Create-Video-and-Style.md +144 -0
  642. package/dist/tutorials/Docker.md +3 -3
  643. package/dist/tutorials/Document-Themes.md +32 -32
  644. package/dist/tutorials/Editing-a-Project.md +94 -94
  645. package/dist/tutorials/FAQ.md +18 -18
  646. package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
  647. package/dist/tutorials/Home-and-Projects.md +115 -71
  648. package/dist/tutorials/Home.md +33 -33
  649. package/dist/tutorials/Install.md +14 -13
  650. package/dist/tutorials/Intros-and-Outros.md +33 -34
  651. package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
  652. package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
  653. package/dist/tutorials/Models.md +53 -21
  654. package/dist/tutorials/Multiple-Voices.md +41 -40
  655. package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
  656. package/dist/tutorials/Notifications.md +27 -17
  657. package/dist/tutorials/Other-Languages.md +15 -15
  658. package/dist/tutorials/PDF-Documents.md +38 -29
  659. package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
  660. package/dist/tutorials/Project-Page.md +118 -120
  661. package/dist/tutorials/Prompts-and-Templates.md +84 -0
  662. package/dist/tutorials/Prompts.md +48 -44
  663. package/dist/tutorials/Providers-and-Keys.md +105 -98
  664. package/dist/tutorials/Publishing-to-YouTube.md +31 -31
  665. package/dist/tutorials/Recovery-and-Retries.md +31 -31
  666. package/dist/tutorials/Remote-Access.md +63 -0
  667. package/dist/tutorials/Reviews-and-Checkpoints.md +98 -90
  668. package/dist/tutorials/Schedules.md +46 -27
  669. package/dist/tutorials/Settings-Reference.md +194 -174
  670. package/dist/tutorials/Shorts.md +34 -33
  671. package/dist/tutorials/Start-at-Login.md +3 -3
  672. package/dist/tutorials/Studio-Extension.md +22 -24
  673. package/dist/tutorials/Template-Studio.md +128 -0
  674. package/dist/tutorials/Templates.md +51 -77
  675. package/dist/tutorials/Trash.md +4 -4
  676. package/dist/tutorials/Troubleshooting.md +44 -44
  677. package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
  678. package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
  679. package/dist/tutorials/Video-Editing.md +34 -34
  680. package/dist/tutorials/Where-Your-Files-Live.md +10 -10
  681. package/dist/tutorials/YouTube-Description.md +26 -26
  682. package/dist/tutorials/Your-First-Short.md +35 -35
  683. package/dist/tutorials/_Sidebar.md +19 -14
  684. package/dist/updater/work-in-progress.js +42 -12
  685. package/dist/web/assets/index-BNftKQrA.css +1 -0
  686. package/dist/web/assets/index-Cpa58woP.js +459 -0
  687. package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
  688. package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
  689. package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
  690. package/dist/web/index.html +2 -2
  691. package/package.json +6 -2
  692. package/dist/slices/article/provided-entries.js +0 -66
  693. package/dist/slices/article/run.js +0 -145
  694. package/dist/slices/images/run.js +0 -234
  695. package/dist/slices/narration/legacy-plan.js +0 -58
  696. package/dist/slices/narration/run.js +0 -270
  697. package/dist/slices/rebuild/runtime-actions.js +0 -90
  698. package/dist/slices/research/run.js +0 -224
  699. package/dist/slices/subtitles/prepare.js +0 -194
  700. package/dist/slices/subtitles/transcript.js +0 -34
  701. package/dist/slices/thumbnail/run.js +0 -219
  702. package/dist/slices/video/audio-inputs.js +0 -33
  703. package/dist/slices/video/reuse-audio.js +0 -62
  704. package/dist/slices/video/run.js +0 -78
  705. package/dist/slices/video/write-export.js +0 -158
  706. package/dist/slices/video/write-subtitles.js +0 -59
  707. package/dist/tutorials/Library-Overview.md +0 -76
  708. package/dist/tutorials/Play-Images.md +0 -161
  709. package/dist/tutorials/Play-Narration.md +0 -167
  710. package/dist/tutorials/Play-Outputs.md +0 -109
  711. package/dist/tutorials/Play-Overview.md +0 -227
  712. package/dist/tutorials/Play-Title-and-Article.md +0 -136
  713. package/dist/tutorials/Play-Video-and-Style.md +0 -143
  714. package/dist/web/assets/index-BadsoORk.css +0 -1
  715. package/dist/web/assets/index-D8LqNsCl.js +0 -326
  716. package/dist/web/assets/pdf-T7MCwjIv.js +0 -54
  717. package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
  718. package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
@@ -1,6 +1,8 @@
1
1
  import { rmSync, statSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { z } from "zod";
4
+ import { internalError } from "../../kernel/errors.js";
5
+ import { editSettings } from "../../kernel/ports/settings-places.js";
4
6
  import { referenceKey, thumbnailVariant } from "../admission/model.js";
5
7
  import { plainText } from "../article/plain.js";
6
8
  import { splitEndMatter } from "../article/split.js";
@@ -9,6 +11,8 @@ import { levelSentences } from "../loudness/sentence-level.js";
9
11
  import { cleanPieces } from "../narration/clean-pieces.js";
10
12
  import { joinNarration } from "../narration/concat.js";
11
13
  import { applyPauses, planPieces } from "../narration/pauses.js";
14
+ import { assetPath } from "../revisions/mutation-assets.js";
15
+ import { isDonePiece } from "../revisions/view.js";
12
16
  import { allocateAsset, discardPreparedAssets, sealAsset } from "../storage/assets.js";
13
17
  import { outputPath } from "../storage/layout.js";
14
18
  import { probeDurationMs, runFfmpeg } from "../video/ffmpeg.js";
@@ -17,19 +21,18 @@ import { breathsAsked, deEssAsked } from "./recipe-breaths.js";
17
21
  import { levelOperation, sentencesAsked } from "./recipe-loudness.js";
18
22
  import { executeFigureCard } from "./runtime-figure-card.js";
19
23
  import { publishNarrationText } from "./runtime-narration-text.js";
20
- import { executionPlan, executionView, savedCatalogue } from "./runtime-plan.js";
24
+ import { executionPlan, executionView, workCatalogue } from "./runtime-plan.js";
21
25
  import { preparedResult, preparedText, preparedTexts, publishResult, } from "./runtime-publication.js";
26
+ import { pieceAlreadyDone } from "./work-records.js";
22
27
  export async function executeLocalRecipe(deps, context, piece) {
23
- if (deps.db
24
- .prepare("SELECT state FROM revision_work_pieces WHERE id=? AND work_id=?")
25
- .get(piece.id, context.work.workId)?.state === "done")
28
+ if (pieceAlreadyDone(deps.db, context.work.workId, piece.id))
26
29
  return "done";
27
30
  if (!context.maySubmit(piece.id))
28
31
  return "held";
29
32
  const input = piece.input;
30
33
  if (input.kind === "provided") {
31
34
  if (input.assetId === null)
32
- throw new Error("A file you uploaded for this project is missing. Upload it again in Edit project, then Try again.");
35
+ throw new Error("A file you uploaded for this project is missing. Upload it again in Edit settings, then Try again.");
33
36
  const row = z
34
37
  .object({ id: z.string(), project_id: z.string(), path: z.string(), created_at: z.string() })
35
38
  .parse(deps.db
@@ -62,7 +65,7 @@ export async function executeLocalRecipe(deps, context, piece) {
62
65
  return "done";
63
66
  }
64
67
  if (input.kind !== "local")
65
- throw new Error("Slopify hit an internal error (a local step was set up wrongly). Try again; if it happens again, use Download diagnostics in Settings and report it.");
68
+ throw new Error(internalError("a local step was set up wrongly"));
66
69
  if (input.operation === "figure-card-v1")
67
70
  return executeFigureCard(deps, context, piece);
68
71
  if (input.operation === "narration-files-v1") {
@@ -98,31 +101,23 @@ export async function executeLocalRecipe(deps, context, piece) {
98
101
  });
99
102
  return "done";
100
103
  }
101
- throw new Error(`Slopify hit an internal error (no handler for the step "${input.operation}"). Try again; if it happens again, use Download diagnostics in Settings and report it.`);
104
+ throw new Error(internalError(`no handler for the step "${input.operation}"`));
102
105
  }
103
106
  async function concatenate(deps, context, piece) {
104
107
  const view = executionView(deps, context.work.projectId, context.work.revisionId);
105
108
  if (view === undefined)
106
- throw new Error("Slopify hit an internal error (the project version being built is missing). Try again; if it happens again, use Download diagnostics in Settings and report it.");
107
- const row = deps.db
108
- .prepare("SELECT recipe_context FROM revision_work WHERE id=?")
109
- .get(context.work.workId);
110
- const plan = executionPlan(deps, view, savedCatalogue(row?.recipe_context));
109
+ throw new Error(internalError("the project version being built is missing"));
110
+ const plan = executionPlan(deps, view, workCatalogue(deps.db, context.work.workId));
111
111
  const recipe = plan.recipes.find((candidate) => candidate.key === piece.key && candidate.fingerprint === piece.fingerprint);
112
112
  if (recipe === undefined)
113
- throw new Error("Slopify hit an internal error (the narration chunks to join no longer match the project's saved inputs). Try again; if it happens again, use Download diagnostics in Settings and report it.");
113
+ throw new Error(internalError("the narration chunks to join no longer match the project's saved inputs"));
114
114
  const files = recipe.dependsOn.map((key) => {
115
115
  const input = view.pieces.find((candidate) => candidate.key === key &&
116
- candidate.selected &&
117
- candidate.available &&
118
- candidate.piece.state === "done" &&
116
+ isDonePiece(candidate) &&
119
117
  candidate.fingerprint === plan.recipes.find((value) => value.key === key)?.fingerprint);
120
118
  if (input?.assetId === null || input === undefined)
121
- throw new Error("One narration chunk has no saved audio, so the narration can't be joined together. Regenerate the missing chunk in Edit project → Narration, then Try again.");
122
- const asset = deps.db
123
- .prepare("SELECT path FROM project_assets WHERE id=? AND project_id=?")
124
- .get(input.assetId, context.work.projectId);
125
- return outputPath(deps.paths, context.work.projectId, z.string().parse(asset?.path));
119
+ throw new Error(`One narration chunk has no saved audio, so the narration can't be joined together. Make the missing chunk again in ${editSettings.narration}, then Try again.`);
120
+ return outputPath(deps.paths, context.work.projectId, assetPath(deps, context.work.projectId, input.assetId));
126
121
  });
127
122
  // Level the volume repeats the join its recipe names, from the same pieces, each levelled
128
123
  // first (`recipe-loudness.ts`).
@@ -295,7 +290,7 @@ export async function joinTurns(run, files, values, output) {
295
290
  .rest(z.unknown())
296
291
  .parse(values)[1];
297
292
  if (layout.length !== files.length || files.length === 0)
298
- throw new Error("Slopify hit an internal error (the speaker turns to join don't match their audio). Try again; if it happens again, use Download diagnostics in Settings and report it.");
293
+ throw new Error(internalError("the speaker turns to join don't match their audio"));
299
294
  await runFfmpeg({
300
295
  bin: run.bin,
301
296
  args: turnJoinArgs(files.map((path, index) => ({
@@ -2,7 +2,7 @@ import { z } from "zod";
2
2
  import { projectSelected } from "../revisions/projection.js";
3
3
  import { getRevisionView } from "../revisions/view.js";
4
4
  import { bindNarrationReuse, narrationOrdinal } from "./runtime-narration-reuse.js";
5
- import { executionPlan, savedCatalogue } from "./runtime-plan.js";
5
+ import { executionPlan, workCatalogue } from "./runtime-plan.js";
6
6
  export function rebindPublishedNarration(deps, work, piece) {
7
7
  if (piece.input.kind !== "tts")
8
8
  return;
@@ -11,10 +11,7 @@ export function rebindPublishedNarration(deps, work, piece) {
11
11
  .all(work.projectId, piece.id, piece.key, work.revisionId);
12
12
  if (targets.length === 0)
13
13
  return;
14
- const row = deps.db
15
- .prepare("SELECT recipe_context FROM revision_work WHERE id=?")
16
- .get(work.workId);
17
- const catalogue = savedCatalogue(row?.recipe_context);
14
+ const catalogue = workCatalogue(deps.db, work.workId);
18
15
  for (const target of targets) {
19
16
  const view = getRevisionView(deps, work.projectId, z.string().parse(target.revision_id));
20
17
  if (view === undefined)
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { insertManifestOutput, insertManifestPiece, selectOutputRecord, selectPieceRecord, } from "../revisions/manifest-repo.js";
3
+ import { assetPathOrUndefined } from "../revisions/mutation-assets.js";
4
+ import { isDonePiece } from "../revisions/view.js";
3
5
  import { retainedNarrationPieces } from "./narration-history.js";
4
6
  import { matchingNarrationPiece } from "./narration-reuse.js";
5
7
  export function bindNarrationReuse(deps, view, recipe, ordinal) {
@@ -30,17 +32,14 @@ export function bindNarrationReuse(deps, view, recipe, ordinal) {
30
32
  return;
31
33
  }
32
34
  if (recipe.input.kind === "provided" && /^audio:(body:.+|intro|outro):[0-9]+$/.test(recipe.key)) {
33
- if (view.pieces.some((one) => one.selected &&
34
- one.available &&
35
- one.key === recipe.key &&
35
+ if (view.pieces.some((one) => isDonePiece(one, recipe.key) &&
36
36
  one.fingerprint === recipe.fingerprint &&
37
- one.piece.state === "done" &&
38
37
  one.piece.idx === ordinal))
39
38
  return;
40
- const asset = deps.db
41
- .prepare("SELECT path FROM project_assets WHERE id=? AND project_id=?")
42
- .get(recipe.input.assetId, view.revision.projectId);
43
- if (asset === undefined)
39
+ const file = recipe.input.assetId === null
40
+ ? undefined
41
+ : assetPathOrUndefined(deps, view.revision.projectId, recipe.input.assetId);
42
+ if (file === undefined)
44
43
  return;
45
44
  const semantic = z
46
45
  .tuple([z.string(), z.array(z.string().nullable())])
@@ -67,7 +66,7 @@ export function bindNarrationReuse(deps, view, recipe, ordinal) {
67
66
  state: "done",
68
67
  payload: JSON.stringify({
69
68
  provided: true,
70
- file: asset.path,
69
+ file,
71
70
  logicalKey: recipe.key.slice(0, recipe.key.lastIndexOf(":")),
72
71
  logicalText: semantic[0],
73
72
  text: semantic[0],
@@ -85,11 +84,8 @@ export function bindNarrationReuse(deps, view, recipe, ordinal) {
85
84
  if (recipe.input.kind !== "tts")
86
85
  return;
87
86
  const input = recipe.input;
88
- if (view.pieces.some((one) => one.selected &&
89
- one.available &&
90
- one.key === recipe.key &&
87
+ if (view.pieces.some((one) => isDonePiece(one, recipe.key) &&
91
88
  one.fingerprint === recipe.fingerprint &&
92
- one.piece.state === "done" &&
93
89
  one.piece.idx === ordinal &&
94
90
  narrationMetadataMatches(one.piece.payload, input)))
95
91
  return;
@@ -1,5 +1,8 @@
1
1
  import { z } from "zod";
2
- import { executionPlan, executionView, savedCatalogue } from "./runtime-plan.js";
2
+ import { internalError } from "../../kernel/errors.js";
3
+ import { editSettings } from "../../kernel/ports/settings-places.js";
4
+ import { isDonePiece } from "../revisions/view.js";
5
+ import { executionPlan, executionView, savedCatalogue, workCatalogue } from "./runtime-plan.js";
3
6
  import { preparedTexts, publishResult } from "./runtime-publication.js";
4
7
  export function joinedNarration(parts) {
5
8
  return parts
@@ -9,16 +12,12 @@ export function joinedNarration(parts) {
9
12
  export function narrationTextParts(view, plan, segment) {
10
13
  const concat = plan.recipes.find((row) => row.key === (segment === "body" ? "audio:body:concat" : `audio:${segment}`));
11
14
  if (concat === undefined)
12
- throw new Error(`Slopify hit an internal error (the ${segment} narration is missing from the project plan). Try again; if it happens again, use Download diagnostics in Settings and report it.`);
15
+ throw new Error(internalError(`the ${segment} narration is missing from the project plan`));
13
16
  return concat.dependsOn.map((key) => {
14
17
  const recipe = plan.recipes.find((row) => row.key === key);
15
- const selected = view.pieces.find((row) => row.key === key &&
16
- row.selected &&
17
- row.available &&
18
- row.piece.state === "done" &&
19
- row.fingerprint === recipe?.fingerprint);
18
+ const selected = view.pieces.find((row) => row.key === key && isDonePiece(row) && row.fingerprint === recipe?.fingerprint);
20
19
  if (selected === undefined || recipe === undefined)
21
- throw new Error("Some narration chunks aren't finished, so the full narration text isn't available. Let the Narration stage finish (Resume, or Try again on it), or regenerate the missing chunk in Edit project → Narration.");
20
+ throw new Error(`Some narration chunks aren't finished, so the full narration text isn't available. Let the Narration stage finish (Continue the run, or Try again on Narration), or make the missing chunk again in ${editSettings.narration}.`);
22
21
  const input = recipe.input;
23
22
  if (input.kind === "provided" &&
24
23
  Array.isArray(input.semantic) &&
@@ -29,13 +28,13 @@ export function narrationTextParts(view, plan, segment) {
29
28
  requestText: null,
30
29
  };
31
30
  if (input.kind !== "tts")
32
- throw new Error("Slopify hit an internal error (a narration chunk's text was never worked out). Try again; if it happens again, use Download diagnostics in Settings and report it.");
31
+ throw new Error(internalError("a narration chunk's text was never worked out"));
33
32
  const payload = z
34
33
  .object({ text: z.string().optional(), spokenText: z.string().optional() })
35
34
  .parse(JSON.parse(selected.piece.payload ?? "{}"));
36
35
  if (input.spokenText !== undefined &&
37
36
  (payload.spokenText !== input.spokenText || payload.text !== input.text))
38
- throw new Error("A narration chunk's audio no longer matches its prepared text. Regenerate that chunk in Edit project → Narration, then Try again.");
37
+ throw new Error(`A narration chunk's audio no longer matches its prepared text. Make that chunk again in ${editSettings.narration}, then Try again.`);
39
38
  return {
40
39
  logicalKey: input.logicalKey,
41
40
  spokenText: input.spokenText === undefined ? (payload.text ?? input.text) : (payload.spokenText ?? ""),
@@ -45,19 +44,16 @@ export function narrationTextParts(view, plan, segment) {
45
44
  }
46
45
  export async function publishNarrationText(deps, context, piece) {
47
46
  if (piece.input.kind !== "local")
48
- throw new Error("Slopify hit an internal error (the narration text file step was set up wrongly). Try again; if it happens again, use Download diagnostics in Settings and report it.");
47
+ throw new Error(internalError("the narration text file step was set up wrongly"));
49
48
  const { segment } = z
50
49
  .object({ segment: z.enum(["body", "intro", "outro"]) })
51
50
  .parse(piece.input.values);
52
51
  const view = executionView(deps, context.work.projectId, context.work.revisionId);
53
- const row = deps.db
54
- .prepare("SELECT recipe_context FROM revision_work WHERE id=?")
55
- .get(context.work.workId);
56
52
  if (view === undefined)
57
- throw new Error("Slopify hit an internal error (the project version being narrated is missing). Try again; if it happens again, use Download diagnostics in Settings and report it.");
58
- const plan = executionPlan(deps, view, savedCatalogue(row?.recipe_context));
53
+ throw new Error(internalError("the project version being narrated is missing"));
54
+ const plan = executionPlan(deps, view, workCatalogue(deps.db, context.work.workId));
59
55
  if (!plan.recipes.some((recipe) => recipe.key === piece.key && recipe.fingerprint === piece.fingerprint))
60
- throw new Error("Slopify hit an internal error (the narration text no longer matches the project's saved inputs). Try again; if it happens again, use Download diagnostics in Settings and report it.");
56
+ throw new Error(internalError("the narration text no longer matches the project's saved inputs"));
61
57
  const parts = narrationTextParts(view, plan, segment);
62
58
  const outputs = preparedTexts(deps, context, piece, [
63
59
  ["narration_txt", `${segment}-narration.txt`, joinedNarration(parts)],
@@ -1,5 +1,6 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { basename } from "node:path";
3
+ import { assetPathOrUndefined } from "../revisions/mutation-assets.js";
3
4
  import { outputPath } from "../storage/layout.js";
4
5
  // The file behind a picture the article names (`![alt](maps/relief.png)`): an image uploaded
5
6
  // to the project under that file name. An article's pictures are otherwise web addresses
@@ -14,10 +15,7 @@ export function articlePicture(deps, view, named) {
14
15
  for (const image of Object.values(view.revision.content.imageDefinitions)) {
15
16
  if (image.source !== "provide" || image.assetId === null)
16
17
  continue;
17
- const row = deps.db
18
- .prepare("SELECT path FROM project_assets WHERE id=? AND project_id=?")
19
- .get(image.assetId, view.revision.projectId);
20
- const path = typeof row?.path === "string" ? row.path : undefined;
18
+ const path = assetPathOrUndefined(deps, view.revision.projectId, image.assetId);
21
19
  if (path === undefined || basename(path).toLowerCase() !== name)
22
20
  continue;
23
21
  const file = outputPath(deps.paths, view.revision.projectId, path);
@@ -1,4 +1,5 @@
1
- import { executionPlan, executionView, savedCatalogue } from "./runtime-plan.js";
1
+ import { platformLabels, socialPlatforms } from "../social/model.js";
2
+ import { executionPlan, executionView, workCatalogueIfSaved } from "./runtime-plan.js";
2
3
  // What a failed step is called on screen, so its error says which image, chunk or topic to
3
4
  // fix. Worked out only after a failure: numbering a narration chunk means building the plan.
4
5
  // Undefined for steps that name their own place (captions, export) or have no single one.
@@ -17,6 +18,9 @@ export function pieceLabel(deps, context, piece) {
17
18
  return "Document";
18
19
  if (key === "youtube:description")
19
20
  return "YouTube description";
21
+ const post = /^social:post:([a-z]+)$/.exec(key);
22
+ if (post !== null)
23
+ return `${platformLabels[socialPlatforms.find((one) => one === post[1]) ?? "x"]} post`;
20
24
  if (key.startsWith("review:")) {
21
25
  const item = key.slice("review:".length);
22
26
  const itemLabel = item === "narration"
@@ -47,6 +51,8 @@ export function pieceLabel(deps, context, piece) {
47
51
  return "Animated images";
48
52
  if (key === "images:scenes")
49
53
  return "Image scenes";
54
+ if (key === "article:digest")
55
+ return "Keyword digest";
50
56
  const short = /^shorts:(\d+):(prompts|image:(\d+)|render)$/.exec(key);
51
57
  if (short !== null)
52
58
  return short[2] === "prompts"
@@ -84,13 +90,11 @@ export function pieceLabel(deps, context, piece) {
84
90
  return narrationChunk(deps, context, segment, key, prefix) ?? prefix;
85
91
  }
86
92
  function narrationChunk(deps, context, segment, key, prefix) {
87
- const row = deps.db
88
- .prepare("SELECT recipe_context FROM revision_work WHERE id=?")
89
- .get(context.work.workId);
93
+ const catalogue = workCatalogueIfSaved(deps.db, context.work.workId);
90
94
  const view = executionView(deps, context.work.projectId, context.work.revisionId);
91
- if (row?.recipe_context === null || row === undefined || view === undefined)
95
+ if (catalogue === undefined || view === undefined)
92
96
  return undefined;
93
- const plan = executionPlan(deps, view, savedCatalogue(row.recipe_context));
97
+ const plan = executionPlan(deps, view, catalogue);
94
98
  const concat = plan.recipes.find((recipe) => recipe.key === (segment === "body" ? "audio:body:concat" : `audio:${segment}`));
95
99
  if (concat === undefined)
96
100
  return undefined;
@@ -1,7 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { z } from "zod";
3
3
  import { catalogueSchema } from "../../catalog/schema.js";
4
- import { getRevisionView, withEarlierJoins } from "../revisions/view.js";
4
+ import { getRevisionView, readyOutput, withEarlierJoins } from "../revisions/view.js";
5
5
  import { outputPath } from "../storage/layout.js";
6
6
  import { referencedAssetsAvailable, retainedNarrationPieces } from "./narration-history.js";
7
7
  import { applyProvidedReviews } from "./provided-review.js";
@@ -22,12 +22,38 @@ export function executionCatalogue(catalogue, config) {
22
22
  export function savedCatalogue(value) {
23
23
  return catalogueSchema.parse(JSON.parse(z.string().parse(value)));
24
24
  }
25
+ function savedContext(db, workId) {
26
+ return db.prepare("SELECT recipe_context FROM revision_work WHERE id=?").get(workId)
27
+ ?.recipe_context;
28
+ }
29
+ // The catalogue a work was admitted with, saved beside it; a work without one is a bug.
30
+ export function workCatalogue(db, workId) {
31
+ return savedCatalogue(savedContext(db, workId));
32
+ }
33
+ // The same, or undefined for a work (or a missing one) that has no catalogue saved.
34
+ export function workCatalogueIfSaved(db, workId) {
35
+ const context = savedContext(db, workId);
36
+ return context === null || context === undefined ? undefined : savedCatalogue(context);
37
+ }
38
+ // A step's LLM call on its work's saved catalogue: the chosen model with the thinking settings
39
+ // the catalogue holds for its level, no web search, labelled with the step. The catalogue is
40
+ // read once, as the builder is made.
41
+ export function workLlm(db, workId, choice, label) {
42
+ const catalogued = workCatalogue(db, workId).llm.find((one) => one.provider === choice.provider && one.id === choice.model);
43
+ const { thinking } = choice;
44
+ return (call) => ({
45
+ provider: choice.provider,
46
+ model: choice.model,
47
+ ...(thinking === undefined ? {} : { thinking }),
48
+ thinkingConfig: thinking === undefined ? null : (catalogued?.llm.thinking?.[thinking] ?? null),
49
+ webSearch: false,
50
+ previewLabel: label,
51
+ ...call,
52
+ });
53
+ }
25
54
  export function executionPlan(deps, view, catalogue) {
26
55
  const textOutput = (role) => {
27
- const row = view.outputs.find((output) => output.selected &&
28
- output.available &&
29
- output.state === "ready" &&
30
- output.output.role === role);
56
+ const row = readyOutput(view, { role });
31
57
  return row === undefined
32
58
  ? null
33
59
  : readFileSync(outputPath(deps.paths, view.revision.projectId, row.output.path), "utf8");
@@ -1,9 +1,12 @@
1
1
  import { basename } from "node:path";
2
+ import { internalError } from "../../kernel/errors.js";
3
+ import { editSettings } from "../../kernel/ports/settings-places.js";
2
4
  import { referenceKey, thumbnailVariant } from "../admission/model.js";
3
5
  import { plainText } from "../article/plain.js";
4
6
  import { splitEndMatter } from "../article/split.js";
5
7
  import { checkAppearance } from "../images/appearance.js";
6
8
  import { checkScenes, sceneCountOf } from "../images/scenes.js";
9
+ import { checkDigest } from "../keywords/digest.js";
7
10
  import { spokenPassage } from "../narration/describe.js";
8
11
  import { observeNarration } from "../narration/live.js";
9
12
  import { validatePreparation } from "../narration/preparation.js";
@@ -11,24 +14,25 @@ import { prepareRequests } from "../narration/steering.js";
11
14
  import { chaptersFrom } from "../research/planner.js";
12
15
  import { sourcedAnswer } from "../research/synthesis.js";
13
16
  import { imageReviewers } from "../reviews/model.js";
17
+ import { checkPost, postText } from "../social/post-prompt.js";
14
18
  import { discardPreparedAssets, writeAsset } from "../storage/assets.js";
15
19
  import { outputPath } from "../storage/layout.js";
16
20
  import { probeDurationMs } from "../video/ffmpeg.js";
17
21
  import { parseAttribution } from "../voices/attribution.js";
18
22
  import { parseScript } from "../voices/script.js";
19
23
  import { imageAppearanceKey } from "./recipe-appearance.js";
24
+ import { digestKey } from "./recipe-digest.js";
20
25
  import { imageScenesKey, thumbnailScenesKey } from "./recipe-scenes.js";
21
26
  import { executeArticleRequests } from "./runtime-article.js";
22
27
  import { imageCall } from "./runtime-image.js";
23
28
  import { frozenInstructions } from "./runtime-instructions.js";
24
29
  import { articlePicture } from "./runtime-pictures.js";
25
- import { executionPlan, executionView, savedCatalogue } from "./runtime-plan.js";
30
+ import { executionPlan, executionView, workCatalogue, workCatalogueIfSaved, } from "./runtime-plan.js";
26
31
  import { preparedResult, preparedTexts, publishResult } from "./runtime-publication.js";
27
32
  import { clearSoftening, softenedPrompt, softeningRequested, softenMessages } from "./soften.js";
33
+ import { pieceAlreadyDone } from "./work-records.js";
28
34
  export async function executeProviderRecipe(deps, context, providers, piece) {
29
- if (deps.db
30
- .prepare("SELECT state FROM revision_work_pieces WHERE id=? AND work_id=?")
31
- .get(piece.id, context.work.workId)?.state === "done")
35
+ if (pieceAlreadyDone(deps.db, context.work.workId, piece.id))
32
36
  return "done";
33
37
  const input = piece.input;
34
38
  const wrapped = providers.forPiece(piece.id);
@@ -64,7 +68,7 @@ export async function executeProviderRecipe(deps, context, providers, piece) {
64
68
  ...(segment === undefined ? {} : { segment }),
65
69
  tokensIn: answer.value.usage?.inputTokens ?? 0,
66
70
  tokensOut: answer.value.usage?.outputTokens ?? 0,
67
- });
71
+ }, context.work.projectId);
68
72
  return "done";
69
73
  }
70
74
  if (input.kind === "tts") {
@@ -116,7 +120,7 @@ export async function executeProviderRecipe(deps, context, providers, piece) {
116
120
  provider: input.provider,
117
121
  model: input.model,
118
122
  ...(durationMs === undefined ? {} : { audioSeconds: durationMs / 1000 }),
119
- });
123
+ }, context.work.projectId);
120
124
  }
121
125
  finally {
122
126
  discardPreparedAssets(deps, [asset]);
@@ -164,10 +168,10 @@ export async function executeProviderRecipe(deps, context, providers, piece) {
164
168
  provider: input.provider,
165
169
  model: input.model,
166
170
  ...(variant !== undefined ? { thumbnails: 1 } : { images: 1 }),
167
- });
171
+ }, context.work.projectId);
168
172
  return "done";
169
173
  }
170
- throw new Error("Slopify hit an internal error (this step has no provider request to run). Use Try again; if it happens again, use Download diagnostics in Settings and report it.");
174
+ throw new Error(internalError("this step has no provider request to run"));
171
175
  }
172
176
  // Soften and retry (`soften.ts`): the project's AI model rewords a refused image prompt
173
177
  // before the image is drawn again. Undefined when nobody asked, or the project has no model.
@@ -186,17 +190,17 @@ export async function softenIfAsked(deps, context, providers, piece, prompt, lab
186
190
  messages: softenMessages(prompt),
187
191
  previewLabel: `${label}: softened prompt`,
188
192
  check: (value) => softenedPrompt(value.text) === ""
189
- ? "The AI model sent back an empty prompt while softening it. Use Soften and retry again, or reword the prompt yourself in Edit project → Images."
193
+ ? `The AI model sent back an empty prompt while softening it. Use Soften and retry again, or reword the prompt yourself in ${editSettings.images}.`
190
194
  : undefined,
191
195
  });
192
196
  return answer.ok ? softenedPrompt(answer.value.text) : "held";
193
197
  }
194
198
  function checkAnswer(piece, answer) {
195
199
  if (answer.text.trim() === "")
196
- return "The AI model sent back an empty answer. Use Try again; if it keeps happening, choose another model in the Providers section of Edit project.";
200
+ return `The AI model sent back an empty answer. Use Try again; if it keeps happening, choose another model in ${editSettings.writer}.`;
197
201
  if (piece.input.kind === "llm" && piece.input.describe !== undefined)
198
202
  return spokenPassage(answer.text) === ""
199
- ? "The AI model's description had no words a narrator could say. Use Try again; if it keeps happening, choose another model in the Providers section of Edit project, or turn off Describe tables and figures there."
203
+ ? `The AI model's description had no words a narrator could say. Use Try again; if it keeps happening, choose another model in ${editSettings.writer}, or turn off Describe tables and figures in ${editSettings.narration}.`
200
204
  : undefined;
201
205
  // Scenes from the article: one scene per image, as many as the request lists.
202
206
  if ((piece.key === imageScenesKey || piece.key === thumbnailScenesKey) &&
@@ -209,9 +213,17 @@ function checkAnswer(piece, answer) {
209
213
  const checked = checkAppearance(answer.text);
210
214
  return checked.ok ? undefined : checked.reason;
211
215
  }
216
+ // The keyword digest: every part written.
217
+ if (piece.key === digestKey && piece.input.kind === "llm") {
218
+ const checked = checkDigest(answer.text);
219
+ return checked.ok ? undefined : checked.reason;
220
+ }
221
+ // A post for another site: within its limit.
222
+ if (piece.input.kind === "llm" && piece.input.social !== undefined)
223
+ return checkPost(answer.text, piece.input.social);
212
224
  if (piece.key === "research:planner")
213
225
  return chaptersFrom(answer.text).length === 0
214
- ? "The AI model's research plan listed no chapters, so research could not go on. Use Try again; if it keeps happening, choose another model in the Providers section of Edit project."
226
+ ? `The AI model's research plan listed no chapters, so research could not go on. Use Try again; if it keeps happening, choose another model in ${editSettings.writer}.`
215
227
  : undefined;
216
228
  if (piece.key === "research:notes" || piece.key.startsWith("research:chapter:"))
217
229
  return sourcedAnswer(piece.key, answer.text);
@@ -225,7 +237,7 @@ function checkAnswer(piece, answer) {
225
237
  const checked = parseScript(answer.text, piece.input.script.speakers);
226
238
  return checked.ok
227
239
  ? undefined
228
- : `The conversation the text model wrote can't be read as a script: ${checked.reason}`;
240
+ : `The conversation the AI model wrote can't be read as a script: ${checked.reason}`;
229
241
  }
230
242
  return undefined;
231
243
  }
@@ -240,7 +252,11 @@ async function publishText(deps, context, piece, answer) {
240
252
  throw new Error(checked.reason);
241
253
  await publishResult(deps, context, piece, preparedTexts(deps, context, piece, [
242
254
  ["instructions", "instructions.md", frozenInstructions(deps, context, piece)],
243
- ]), { scenes: checked.scenes, text: answer.text });
255
+ ]), {
256
+ scenes: checked.scenes,
257
+ ...(checked.details === undefined ? {} : { details: checked.details }),
258
+ text: answer.text,
259
+ });
244
260
  return;
245
261
  }
246
262
  if (piece.key === imageAppearanceKey && piece.input.kind === "llm") {
@@ -252,6 +268,37 @@ async function publishText(deps, context, piece, answer) {
252
268
  ]), { appearance: checked.appearance, text: answer.text });
253
269
  return;
254
270
  }
271
+ if (piece.input.kind === "llm" && piece.input.social !== undefined) {
272
+ const target = piece.input.social;
273
+ const problem = checkPost(answer.text, target);
274
+ if (problem !== undefined)
275
+ throw new Error(problem);
276
+ const text = postText(answer.text);
277
+ const asset = writeAsset(deps, context.work.projectId, `post-${target.platform}.txt`, Buffer.from(text));
278
+ let outputs;
279
+ try {
280
+ outputs = [
281
+ preparedResult(deps, context, piece, "social_post", asset, null, {
282
+ platform: target.platform,
283
+ }),
284
+ ];
285
+ }
286
+ catch (error) {
287
+ discardPreparedAssets(deps, [asset]);
288
+ throw error;
289
+ }
290
+ await publishResult(deps, context, piece, outputs, { text });
291
+ return;
292
+ }
293
+ if (piece.key === digestKey && piece.input.kind === "llm") {
294
+ const checked = checkDigest(answer.text);
295
+ if (!checked.ok)
296
+ throw new Error(checked.reason);
297
+ await publishResult(deps, context, piece, preparedTexts(deps, context, piece, [
298
+ ["instructions", "instructions.md", frozenInstructions(deps, context, piece)],
299
+ ]), { digest: checked.digest, text: answer.text });
300
+ return;
301
+ }
255
302
  if (piece.input.kind === "llm" && piece.input.preparation !== undefined) {
256
303
  const checked = validatePreparation(answer.text, piece.input.preparation.source);
257
304
  if (!checked.ok)
@@ -276,7 +323,7 @@ async function publishText(deps, context, piece, answer) {
276
323
  if (piece.input.kind === "llm" && piece.input.script !== undefined) {
277
324
  const checked = parseScript(parts.body, piece.input.script.speakers);
278
325
  if (!checked.ok)
279
- throw new Error(`The text model's script can't be read: ${checked.reason} Try again to have it written again, or fix it in Edit project → Article.`);
326
+ throw new Error(`The AI model's script can't be read: ${checked.reason} Try again to have it written again, or fix it in ${editSettings.article}.`);
280
327
  }
281
328
  await publishResult(deps, context, piece, preparedTexts(deps, context, piece, [
282
329
  ["instructions", "instructions.md", frozenInstructions(deps, context, piece)],
@@ -314,7 +361,7 @@ async function publishText(deps, context, piece, answer) {
314
361
  : [];
315
362
  const title = titles[Number(piece.key.split(":").at(-1)) - 1];
316
363
  if (typeof title !== "string")
317
- throw new Error("Slopify hit an internal error (a research chapter has no title in the research plan). Use Try again; if it happens again, use Download diagnostics in Settings and report it.");
364
+ throw new Error(internalError("a research chapter has no title in the research plan"));
318
365
  const asset = writeAsset(deps, context.work.projectId, `research-${piece.key.split(":").at(-1)}.md`, Buffer.from(answer.text));
319
366
  await publishResult(deps, context, piece, [], { title, notes: answer.text }, asset);
320
367
  return;
@@ -328,13 +375,11 @@ function narrationLabel(deps, context, piece) {
328
375
  return "Narration";
329
376
  const name = piece.input.segment === "body" ? "Body" : piece.input.segment === "intro" ? "Intro" : "Outro";
330
377
  const view = executionView(deps, context.work.projectId, context.work.revisionId);
331
- const row = deps.db
332
- .prepare("SELECT recipe_context FROM revision_work WHERE id=?")
333
- .get(context.work.workId);
334
- if (view === undefined || row?.recipe_context === undefined || row.recipe_context === null)
378
+ const catalogue = workCatalogueIfSaved(deps.db, context.work.workId);
379
+ if (view === undefined || catalogue === undefined)
335
380
  return name;
336
381
  const segment = piece.input.segment;
337
- const parts = executionPlan(deps, view, savedCatalogue(row.recipe_context)).recipes.filter((recipe) => recipe.input.kind === "tts" && recipe.input.segment === segment);
382
+ const parts = executionPlan(deps, view, catalogue).recipes.filter((recipe) => recipe.input.kind === "tts" && recipe.input.segment === segment);
338
383
  const index = parts.findIndex((recipe) => recipe.key === piece.key);
339
384
  return parts.length > 1 && index >= 0 ? `${name} part ${index + 1} of ${parts.length}` : name;
340
385
  }
@@ -345,10 +390,7 @@ function checkPreparation(deps, context, piece, answer) {
345
390
  const checked = validatePreparation(answer.text, source);
346
391
  if (!checked.ok)
347
392
  return checked.reason;
348
- const row = deps.db
349
- .prepare("SELECT recipe_context FROM revision_work WHERE id=?")
350
- .get(context.work.workId);
351
- const model = savedCatalogue(row?.recipe_context).tts.find((model) => model.provider === "inworld" && model.id === "inworld-tts-2");
393
+ const model = workCatalogue(deps.db, context.work.workId).tts.find((model) => model.provider === "inworld" && model.id === "inworld-tts-2");
352
394
  const prepared = prepareRequests(source, checked.cues, model?.tts.maxCharacters ?? 4000);
353
395
  return prepared.ok ? undefined : prepared.reason;
354
396
  }
@@ -1,11 +1,12 @@
1
1
  import { transact } from "../../kernel/db/tx.js";
2
+ import { internalError } from "../../kernel/errors.js";
2
3
  import { fingerprint } from "../../kernel/runner/work.js";
3
4
  import { publicationAuthority } from "../revisions/publication-rules.js";
4
5
  import { commitRevisionOutputs } from "../revisions/publish.js";
5
6
  import { insertAsset, insertManifestOutput, revisionById } from "../revisions/repo.js";
6
7
  import { discardPreparedAssets, writeAsset } from "../storage/assets.js";
7
8
  import { rebindPublishedNarration } from "./runtime-narration-publication.js";
8
- import { executionPlan, executionView, savedCatalogue } from "./runtime-plan.js";
9
+ import { executionPlan, executionView, workCatalogueIfSaved } from "./runtime-plan.js";
9
10
  export function preparedResult(deps, context, piece, role, asset, durationMs = null, meta = {}) {
10
11
  return {
11
12
  // A project holds many images, and one video and several images per short.
@@ -15,6 +16,8 @@ export function preparedResult(deps, context, piece, role, asset, durationMs = n
15
16
  role === "animated_image" ||
16
17
  // Level the volume: one levelled narration per segment.
17
18
  role === "audio_levelled" ||
19
+ // A post per site.
20
+ role === "social_post" ||
18
21
  // The second and third thumbnails; the first keeps the slot it always had.
19
22
  (role === "thumbnail" && piece.key !== "thumbnail:image")
20
23
  ? piece.key
@@ -39,7 +42,7 @@ export function preparedResult(deps, context, piece, role, asset, durationMs = n
39
42
  export function preparedText(deps, context, piece, role, filename, text) {
40
43
  const output = preparedTexts(deps, context, piece, [[role, filename, text]])[0];
41
44
  if (output === undefined)
42
- throw new Error("Slopify hit an internal error (a text file could not be prepared). Try again; if it happens again, use Download diagnostics in Settings and report it.");
45
+ throw new Error(internalError("a text file could not be prepared"));
43
46
  return output;
44
47
  }
45
48
  export function preparedTexts(deps, context, piece, texts) {
@@ -173,11 +176,9 @@ function pieceIndex(deps, context, piece) {
173
176
  if (localIndex >= 0)
174
177
  return localIndex + 1;
175
178
  const view = executionView(deps, context.work.projectId, context.work.revisionId);
176
- const row = deps.db
177
- .prepare("SELECT recipe_context FROM revision_work WHERE id=?")
178
- .get(context.work.workId);
179
- if (view !== undefined && row?.recipe_context !== null && row?.recipe_context !== undefined) {
180
- const keys = executionPlan(deps, view, savedCatalogue(row.recipe_context)).recipes.filter((recipe) => recipe.stage === context.work.kind &&
179
+ const catalogue = workCatalogueIfSaved(deps.db, context.work.workId);
180
+ if (view !== undefined && catalogue !== undefined) {
181
+ const keys = executionPlan(deps, view, catalogue).recipes.filter((recipe) => recipe.stage === context.work.kind &&
181
182
  (piece.input.kind !== "llm" ||
182
183
  piece.input.preparation?.segment !== "body" ||
183
184
  (recipe.input.kind === "llm" && recipe.input.preparation?.segment === "body")) &&
@@ -206,10 +207,10 @@ export function retainPartialArticle(deps, context, piece, text) {
206
207
  if (authority === undefined)
207
208
  return;
208
209
  if (authority.key !== piece.key || authority.fingerprint !== piece.fingerprint)
209
- throw new Error("Slopify hit an internal error (a partly written article doesn't match its saved step). Try again; if it happens again, use Download diagnostics in Settings and report it.");
210
+ throw new Error(internalError("a partly written article doesn't match its saved step"));
210
211
  const revision = revisionById(deps.db, context.work.projectId, context.work.revisionId);
211
212
  if (revision === undefined)
212
- throw new Error("Slopify hit an internal error (the project version for a partly written article is missing). Try again; if it happens again, use Download diagnostics in Settings and report it.");
213
+ throw new Error(internalError("the project version for a partly written article is missing"));
213
214
  insertAsset(deps.db, result.asset);
214
215
  insertManifestOutput(deps.db, revision, {
215
216
  slot: `article:partial:${piece.id}`,