@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
@@ -255,7 +255,7 @@ config) {
255
255
  model: typeof llmModel === "string" ? llmModel : "",
256
256
  inputCharacters: (typeof style === "string" ? style.length : 0) + 3000,
257
257
  outputCharacters: 2400,
258
- detail: "One LLM call per short writes its image prompts; its length is estimated.",
258
+ detail: "One AI call per short writes its image prompts; its length is estimated.",
259
259
  })),
260
260
  ...Array.from({ length: images }, () => ({
261
261
  kind: "image",
@@ -285,7 +285,9 @@ export function priceRecipe(work, value, config) {
285
285
  (input.operation === "image-scene" ||
286
286
  input.operation === "image-scenes" ||
287
287
  input.operation === "thumbnail-scenes" ||
288
- input.operation === "image-appearance")) {
288
+ input.operation === "image-appearance" ||
289
+ input.operation === "keyword-digest" ||
290
+ input.operation === "social-post")) {
289
291
  const choice = config === undefined ? undefined : recipeProviderChoice(value, config);
290
292
  if (choice !== undefined && input.operation === "image-scene")
291
293
  return { kind: "image", stage: work.key, provider: choice.provider, model: choice.model };
@@ -296,7 +298,13 @@ export function priceRecipe(work, value, config) {
296
298
  provider: choice.provider,
297
299
  model: choice.model,
298
300
  inputCharacters: 90000,
299
- outputCharacters: input.operation === "image-appearance" ? 6000 : 4000,
301
+ outputCharacters: input.operation === "image-appearance"
302
+ ? 6000
303
+ : input.operation === "keyword-digest"
304
+ ? 2000
305
+ : input.operation === "social-post"
306
+ ? 600
307
+ : 4000,
300
308
  detail: "The article is read when the step runs; its length is estimated. Retries are excluded.",
301
309
  };
302
310
  }
@@ -304,13 +312,13 @@ export function priceRecipe(work, value, config) {
304
312
  return {
305
313
  kind: "unknown",
306
314
  stage: work.key,
307
- detail: "Narration Preparation: one LLM call per future logical chunk or entry; source length is not yet known.",
315
+ detail: "Narration preparation: one AI call per narration piece or intro or outro; how many is known once the text is written.",
308
316
  };
309
317
  if (input.kind === "deferred" && input.operation === "narration-description")
310
318
  return {
311
319
  kind: "unknown",
312
320
  stage: work.key,
313
- detail: "Narration descriptions: one LLM call per table, figure, equation or code block in the article; how many is known once the article is written.",
321
+ detail: "Narration descriptions: one AI call per table, figure, equation or code block in the article; how many is known once the article is written.",
314
322
  };
315
323
  if (input.kind === "llm")
316
324
  return {
@@ -320,7 +328,11 @@ export function priceRecipe(work, value, config) {
320
328
  model: input.model,
321
329
  inputCharacters: input.messages.reduce((sum, message) => sum + message.content.length, 0) +
322
330
  (input.documents ?? []).reduce((sum, document) => sum + document.content.length, 0),
323
- outputCharacters: work.key === "article:body" ? 9000 : input.describe !== undefined ? 600 : 2400,
331
+ outputCharacters: work.key === "article:body"
332
+ ? 9000
333
+ : input.describe !== undefined || input.social !== undefined
334
+ ? 600
335
+ : 2400,
324
336
  detail: "Actual saved request input; output length is estimated. Retries and tools are excluded.",
325
337
  };
326
338
  if (input.kind === "tts")
@@ -409,7 +421,7 @@ function cliRequest(work, value, config) {
409
421
  detail: preparation
410
422
  ? value.input.operation === "narration-description"
411
423
  ? "Runs on your CLI plan, so it adds no charge. Narration descriptions make one call per table, figure, equation or code block; how many is known once the article is written, so no API figure is given."
412
- : "Runs on your CLI plan, so it adds no charge. Narration Preparation makes one call per logical chunk or entry; how many is known when the step runs, so no API figure is given."
424
+ : "Runs on your CLI plan, so it adds no charge. Narration preparation makes one call per narration piece or intro or outro; how many is known when the step runs, so no API figure is given."
413
425
  : "Runs on your CLI plan, so it adds no charge. The request is built when the step runs, so its API figure uses an estimated length.",
414
426
  };
415
427
  }
@@ -1,7 +1,7 @@
1
1
  import { subjectOf } from "../admission/model.js";
2
2
  import { usesYoutubeDescription } from "../admission/rules.js";
3
3
  import { recipe, resourceIdentity, } from "./recipe-model.js";
4
- import { renderedPrompt } from "./recipe-text.js";
4
+ import { promptOf } from "./recipe-text.js";
5
5
  // The YouTube description is written from the word timing, so it waits for
6
6
  // `subtitles:timing` and nothing else: it runs beside the render, and a change to the
7
7
  // motion, zoom, images or captions' look leaves it current. The transcript is only known once
@@ -12,6 +12,7 @@ export function youtubeRecipes(context, exports) {
12
12
  const timing = exports.find((value) => value.key === "subtitles:timing");
13
13
  if (!usesYoutubeDescription(config) || timing === undefined)
14
14
  return [];
15
+ const prompt = config.descriptionPrompt?.trim() ? promptOf(context, "description") : undefined;
15
16
  return [
16
17
  recipe(context, "youtube:description", "video", {
17
18
  kind: "local",
@@ -24,12 +25,12 @@ export function youtubeRecipes(context, exports) {
24
25
  config.llm?.thinking ?? null,
25
26
  // Blank means the built-in prompt; the step fills it in, so a new built-in wording
26
27
  // ships as a new operation version rather than a silent change here.
27
- config.descriptionPrompt?.trim() ? renderedPrompt(context, "description") : "",
28
+ prompt?.text ?? "",
28
29
  subjectOf(config),
29
30
  // The project language, only when it is not English, so English keeps its fingerprint.
30
31
  ...(config.language === undefined || config.language === "en" ? [] : [config.language]),
31
32
  ],
32
- }, [timing.key],
33
+ }, [timing.key, ...(prompt?.dependsOn ?? [])],
33
34
  // A paid LLM call: readiness, the charge warning and the estimate treat it like one.
34
35
  { kind: "provider" }),
35
36
  ];
@@ -1,5 +1,6 @@
1
1
  import { readmitted } from "../../kernel/runner/graph.js";
2
2
  import { narrationRegenerationKey } from "../narration/plan.js";
3
+ import { promiseItemKey } from "../reviews/model.js";
3
4
  export function sectionRoots(view, plan, stage) {
4
5
  if (stage === "article" &&
5
6
  (view.revision.config.sources.article !== "generate" || view.revision.content.articleEdited))
@@ -35,7 +36,8 @@ export function redoTarget(view, plan, item) {
35
36
  };
36
37
  if (item === "narration")
37
38
  return section("audio");
38
- if (item === "article:body")
39
+ // The promise check sends the article back: its opening is what broke the promise.
40
+ if (item === "article:body" || item === promiseItemKey)
39
41
  return section("article");
40
42
  const own = (roots) => ({
41
43
  roots,
@@ -1,4 +1,5 @@
1
1
  import { transact } from "../../kernel/db/tx.js";
2
+ import { internalError } from "../../kernel/errors.js";
2
3
  import { stagesOf } from "../admission/repo.js";
3
4
  import { withProjectControl } from "../control/lock.js";
4
5
  import { requestHash } from "../revisions/mutation-request.js";
@@ -78,7 +79,7 @@ options = {}) {
78
79
  field: "stage",
79
80
  message: input.action.kind === "redo"
80
81
  ? "This item is no longer made by the project (it was removed, or its source changed), so it can't be made again. Reload the project page."
81
- : "This section has no generated work to rerun. Use Edit project to change its source.",
82
+ : "This section has nothing made by AI to make again. Change its source in Edit settings.",
82
83
  },
83
84
  ],
84
85
  };
@@ -93,7 +94,7 @@ options = {}) {
93
94
  if (record.edit !== null) {
94
95
  const prior = retainedPreviewPlan(deps, base, deps.catalogue.read());
95
96
  if (input.action.kind !== "rerun" && input.action.kind !== "redo")
96
- throw new Error("Slopify hit an internal error (a recovery edit has nothing to re-run). Try again; if it happens again, use Download diagnostics in Settings and report it.");
97
+ throw new Error(internalError("a recovery edit has nothing to re-run"));
97
98
  const affected = dependentClosure(prior.recipes, rootsOf(base, prior));
98
99
  const savedIntent = deps.db
99
100
  .prepare("SELECT result_revision_id FROM revision_mutations WHERE project_id=? AND idempotency_key=?")
@@ -120,7 +121,7 @@ options = {}) {
120
121
  {
121
122
  field: "stage",
122
123
  message: late === "running"
123
- ? "Wait for this section to finish, or Pause the project before rerunning it."
124
+ ? "Wait for this section to finish, or Pause the project before making it again."
124
125
  : acceptedJobMessage,
125
126
  },
126
127
  ],
@@ -153,7 +154,7 @@ options = {}) {
153
154
  fields: [
154
155
  {
155
156
  field: "stage",
156
- message: "This section has no enabled work. Use Edit project to change its source.",
157
+ message: "This section is switched off. Change its source in Edit settings.",
157
158
  },
158
159
  ],
159
160
  });
@@ -166,7 +167,7 @@ options = {}) {
166
167
  reason: "review-required",
167
168
  fields: preview.value.preview.providedReuseRequired.map((key) => ({
168
169
  field: key,
169
- message: "Review changed supplied content or manual captions in Edit project or Advanced rebuild review.",
170
+ message: "Look over the changed content you supplied, or the captions you edited, in Edit settings or in Choose what to make again.",
170
171
  })),
171
172
  });
172
173
  const blocked = preview.value.preview.work.filter((row) => row.disposition === "blocked");
@@ -186,11 +187,11 @@ options = {}) {
186
187
  input.action.stage === "video"
187
188
  ? {
188
189
  field: "video",
189
- message: "Source media is incomplete. Use Continue the run to recover it before rerunning the export.",
190
+ message: "Some of what the video is made from isn't finished. Use Continue the run to finish it before making the video again.",
190
191
  }
191
192
  : {
192
193
  field: "document",
193
- message: "The article or thumbnail the document is made from isn't finished. Use Continue the run to finish it, then More → make it again in its section on Document.",
194
+ message: "The article or thumbnail the document is made from isn't finished. Use Continue the run to finish it, then press Make the PDF again in the project's PDF section.",
194
195
  },
195
196
  ],
196
197
  });
@@ -200,7 +201,7 @@ options = {}) {
200
201
  storePreview(deps, preview.value.preview, preview.value.execution);
201
202
  const stored = previewById(deps.db, projectId, preview.value.preview.id);
202
203
  if (stored === undefined)
203
- throw new Error("Slopify hit an internal error (the saved recovery preview is missing). Try again; if it happens again, use Download diagnostics in Settings and report it.");
204
+ throw new Error(internalError("the saved recovery preview is missing"));
204
205
  return {
205
206
  plan: { preview: stored, execution: preview.value.execution },
206
207
  view,
@@ -3,19 +3,19 @@ export function remadeWork(work) {
3
3
  }
4
4
  export function remakeBlocker(status, sample) {
5
5
  if (status === "running")
6
- return "It is running now. Remake it once the run has finished.";
6
+ return "It is running now. Make its outdated parts again once the run has finished.";
7
7
  if (sample)
8
- return "It is a sample project, which stays as it came with Slopify. Open it, press Make my own copy at the top of its page, then remake the copy.";
8
+ return "It is a sample project, which stays as it came with Slopify. Open it, press Make my own copy at the top of its page, then change the copy.";
9
9
  return undefined;
10
10
  }
11
11
  export function previewBlocker(preview, label) {
12
12
  if (remadeWork(preview.work).length === 0)
13
- return "Nothing in it is outdated, so there is nothing to remake.";
13
+ return "Nothing in it is outdated, so there is nothing to make again.";
14
14
  const blocked = preview.work.find((work) => work.disposition === "blocked");
15
15
  if (blocked !== undefined)
16
- return `${label(blocked.key)} can't run: ${blocked.reason.trim() || "no reason was given."} Open the project and press Choose what to remake to see what to fix.`;
16
+ return `${label(blocked.key)} can't run: ${blocked.reason.trim() || "no reason was given."} Open the project and press Choose what to make again to see what to fix.`;
17
17
  if (preview.providedReuseRequired.length > 0)
18
- return "It uses content you supplied, which you confirm on the project itself: open it and press Choose what to remake.";
18
+ return "It uses content you supplied, which you confirm on the project itself: open it and press Choose what to make again.";
19
19
  return undefined;
20
20
  }
21
21
  export function remakeTotal(costs) {
@@ -1,4 +1,5 @@
1
1
  import { transact } from "../../kernel/db/tx.js";
2
+ import { internalError } from "../../kernel/errors.js";
2
3
  import { workExists } from "../../kernel/runner/work-authority.js";
3
4
  import { currentRevisionId, revisionById } from "../revisions/repo.js";
4
5
  import { rebuildPreviewSchema } from "./model.js";
@@ -7,7 +8,7 @@ export { transitionRevisionWork } from "./transition-repo.js";
7
8
  export function publicationTargets(db, publication, workKey, workFingerprint) {
8
9
  const { work, pieceId, publicationId } = publication;
9
10
  if (publicationId !== (pieceId ?? work.workId))
10
- throw new Error("Slopify hit an internal error (a finished result is filed under the wrong step). Try again; if it happens again, use Download diagnostics in Settings and report it.");
11
+ throw new Error(internalError("a finished result is filed under the wrong step"));
11
12
  if (!workExists(db, work))
12
13
  return [];
13
14
  if (pieceId !== null) {
@@ -15,9 +16,9 @@ export function publicationTargets(db, publication, workKey, workFingerprint) {
15
16
  .prepare("SELECT work_key,fingerprint FROM revision_work_pieces WHERE id=? AND work_id=?")
16
17
  .get(pieceId, work.workId);
17
18
  if (piece === undefined)
18
- throw new Error("Slopify hit an internal error (a finished result belongs to a different step). Try again; if it happens again, use Download diagnostics in Settings and report it.");
19
+ throw new Error(internalError("a finished result belongs to a different step"));
19
20
  if (piece.work_key !== workKey || piece.fingerprint !== workFingerprint)
20
- throw new Error("Slopify hit an internal error (a finished result doesn't match its saved step). Try again; if it happens again, use Download diagnostics in Settings and report it.");
21
+ throw new Error(internalError("a finished result doesn't match its saved step"));
21
22
  }
22
23
  const currentId = currentRevisionId(db, work.projectId);
23
24
  const owns = (revisionId) => {
@@ -0,0 +1,25 @@
1
+ import { plainText } from "../article/plain.js";
2
+ import { splitEndMatter } from "../article/split.js";
3
+ import { spokenWordsPerMinute } from "../images/scale.js";
4
+ import { normalizeNarrationText } from "../narration/plan.js";
5
+ // How long the opening the promise check reads lasts: the span in which a viewer decides
6
+ // whether the video is what its title and thumbnail said.
7
+ export const promiseOpeningSeconds = 30;
8
+ // The article as the voice would say it (no Markdown, no end matter: what `recipe-text.ts`
9
+ // hands the narration), so the reviewer reads what the viewer will hear.
10
+ export function spokenArticle(markdown) {
11
+ return normalizeNarrationText(plainText(splitEndMatter(markdown).body));
12
+ }
13
+ // The spoken text cut after the words said in the opening seconds, its own line breaks kept.
14
+ export function openingOf(spoken, seconds = promiseOpeningSeconds, wordsPerMinute = spokenWordsPerMinute) {
15
+ const words = Math.round((seconds * wordsPerMinute) / 60);
16
+ let end = 0;
17
+ let count = 0;
18
+ for (const match of spoken.matchAll(/\S+/g)) {
19
+ if (count === words)
20
+ break;
21
+ count += 1;
22
+ end = match.index + match[0].length;
23
+ }
24
+ return spoken.slice(0, end);
25
+ }
@@ -1,4 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { errorText } from "../../kernel/errors.js";
2
3
  import { reviewKey } from "../reviews/model.js";
3
4
  import { pendingRedos, setRedoState } from "../reviews/repo.js";
4
5
  import { currentRevisionId } from "../revisions/repo.js";
@@ -49,7 +50,7 @@ export function createReviewRedos() {
49
50
  .catch((error) => {
50
51
  deps.log.write("error", "review.redo", {
51
52
  projectId: verdict.projectId,
52
- detail: error instanceof Error ? error.message : String(error),
53
+ detail: errorText(error),
53
54
  });
54
55
  setRedoState(deps.db, verdict.id, "failed", "Slopify hit an internal error while making this item again. Use Redo beside it; if it happens again, use Download diagnostics in Settings and report it.");
55
56
  })
@@ -127,7 +128,7 @@ export function redoRefusal(result) {
127
128
  case "running":
128
129
  return "Slopify couldn't make this item again automatically because work that depends on it was already running. Use Redo beside it once the run has finished.";
129
130
  case "readiness":
130
- return `Slopify couldn't make this item again automatically: ${detail ?? "a provider isn't ready"}. Fix that in Settings → Providers, then use Redo beside it.`;
131
+ return `Slopify couldn't make this item again automatically: ${detail ?? "a provider isn't ready"}. Fix that in Settings → Keys & services, then use Redo beside it.`;
131
132
  case "conflict":
132
133
  case "control-changed":
133
134
  return "Slopify couldn't make this item again automatically because the project changed at the same moment (an edit, Pause or Cancel). Use Redo beside it.";
@@ -1,4 +1,5 @@
1
1
  import { transact } from "../../kernel/db/tx.js";
2
+ import { internalError } from "../../kernel/errors.js";
2
3
  import { narrationRegenerationToken } from "../narration/plan.js";
3
4
  import { currentRevisionId } from "../revisions/repo.js";
4
5
  import { bindNarrationReuse, narrationOrdinal } from "./runtime-narration-reuse.js";
@@ -25,7 +26,7 @@ export function admitInitialRevision(deps, view, catalogue) {
25
26
  if (deps.db
26
27
  .prepare("SELECT 1 FROM revision_work WHERE project_id=? LIMIT 1")
27
28
  .get(view.revision.projectId) !== undefined)
28
- throw new Error("Slopify hit an internal error (this project was started twice). Try again; if it happens again, use Download diagnostics in Settings and report it.");
29
+ throw new Error(internalError("this project was started twice"));
29
30
  const snapshot = executionCatalogue(catalogue, view.revision.config);
30
31
  const plan = executionPlan(deps, view, snapshot);
31
32
  for (const recipe of plan.recipes) {
@@ -35,7 +36,7 @@ export function admitInitialRevision(deps, view, catalogue) {
35
36
  const logicalKey = recipe.input.kind === "tts" ? `${recipe.input.logicalKey}:1` : recipe.key;
36
37
  const anchor = view.revision.fingerprints[logicalKey] ?? desired;
37
38
  if (anchor === undefined)
38
- throw new Error(`Slopify hit an internal error (step ${recipe.key} has no saved starting point). Try again; if it happens again, use Download diagnostics in Settings and report it.`);
39
+ throw new Error(internalError(`step ${recipe.key} has no saved starting point`));
39
40
  const reuse = plan.work.find((row) => row.key === recipe.key)?.disposition === "reuse";
40
41
  if (reuse)
41
42
  bindNarrationReuse(deps, view, recipe, narrationOrdinal(plan.recipes, recipe.key));
@@ -49,7 +50,7 @@ export function insertInvocation(deps, view, recipe, catalogue, anchor, complete
49
50
  .prepare("SELECT id FROM stages WHERE project_id=? AND kind=?")
50
51
  .get(projectId, recipe.stage);
51
52
  if (typeof stage?.id !== "string")
52
- throw new Error("Slopify hit an internal error (a step has no matching stage). Try again; if it happens again, use Download diagnostics in Settings and report it.");
53
+ throw new Error(internalError("a step has no matching stage"));
53
54
  const work = {
54
55
  projectId,
55
56
  revisionId,
@@ -1,4 +1,6 @@
1
1
  import { z } from "zod";
2
+ import { internalError } from "../../kernel/errors.js";
3
+ import { fillLateKeywords, mentionsLateKeyword } from "../keywords/fill.js";
2
4
  import { externalReviewWaitMs } from "../reviews/external-model.js";
3
5
  import { openExternalReview } from "../reviews/external-repo.js";
4
6
  import { externalReviewByFingerprint } from "../reviews/external-rows.js";
@@ -6,8 +8,10 @@ import { reviewStages } from "../reviews/model.js";
6
8
  import { nextAttempt, reviewOutcome } from "../reviews/outcome.js";
7
9
  import { latestVerdict, saveVerdict } from "../reviews/repo.js";
8
10
  import { exportSnapshot } from "./runtime-export-inputs.js";
11
+ import { lateValuesOf } from "./runtime-keywords.js";
9
12
  import { publishResult } from "./runtime-publication.js";
10
13
  import { reviewMaterial } from "./runtime-review.js";
14
+ import { pieceAlreadyDone } from "./work-records.js";
11
15
  // What `recipe-reviews.ts` saves for a review an external agent answers, by position.
12
16
  const valuesSchema = z.tuple([
13
17
  z.enum(reviewStages),
@@ -21,16 +25,18 @@ const valuesSchema = z.tuple([
21
25
  // agent's verdict through MCP. Waiting is not "held": the stage's other reviews still open
22
26
  // theirs in the same pass, and `agentReviewHold` keeps the runner from claiming it again.
23
27
  export async function executeAgentReviewRecipe(deps, context, piece) {
24
- if (deps.db
25
- .prepare("SELECT state FROM revision_work_pieces WHERE id=? AND work_id=?")
26
- .get(piece.id, context.work.workId)?.state === "done")
28
+ if (pieceAlreadyDone(deps.db, context.work.workId, piece.id))
27
29
  return "done";
28
30
  if (!context.maySubmit(piece.id))
29
31
  return "held";
30
32
  const values = piece.input.kind === "local" ? valuesSchema.safeParse(piece.input.values) : undefined;
31
33
  if (values === undefined || !values.success)
32
- throw new Error("Slopify hit an internal error (a review step was set up wrongly). Retry stage; if it happens again, use Download diagnostics in Settings and report it.");
33
- const [stage, itemKey, , prompt, mode, retries] = values.data;
34
+ throw new Error(internalError("a review step was set up wrongly"));
35
+ const [stage, itemKey, , planned, mode, retries] = values.data;
36
+ // The release date and the length are filled as the review opens, like a request a model is sent.
37
+ const prompt = mentionsLateKeyword(planned)
38
+ ? fillLateKeywords(planned, await lateValuesOf(deps, context))
39
+ : planned;
34
40
  const projectId = context.work.projectId;
35
41
  const known = externalReviewByFingerprint(deps.db, projectId, piece.fingerprint);
36
42
  if (known === undefined || known.state === "superseded" || known.state === "canceled") {
@@ -1,10 +1,13 @@
1
1
  import { mkdtempSync, readFileSync, rmSync } from "node:fs";
2
2
  import { join } from "node:path";
3
+ import { errorText, internalError } from "../../kernel/errors.js";
4
+ import { isReadyOutput } from "../revisions/view.js";
3
5
  import { discardPreparedAssets, writeAsset } from "../storage/assets.js";
4
6
  import { outputPath, projectDir } from "../storage/layout.js";
5
7
  import { runFfmpeg } from "../video/ffmpeg.js";
6
8
  import { executionView } from "./runtime-plan.js";
7
9
  import { preparedResult, publishResult } from "./runtime-publication.js";
10
+ import { pieceAlreadyDone } from "./work-records.js";
8
11
  // Animate images: one still of the slideshow sent to the image provider's image-to-video
9
12
  // model, and the clip it makes saved beside the image. The still goes up as a small JPEG, so
10
13
  // the request stays well under what either provider takes inline.
@@ -16,17 +19,15 @@ import { preparedResult, publishResult } from "./runtime-publication.js";
16
19
  // for, and keeps a JPEG to a few hundred KB.
17
20
  const sentWidth = 1280;
18
21
  export async function executeAnimateRecipe(deps, context, providers, piece) {
19
- if (deps.db
20
- .prepare("SELECT state FROM revision_work_pieces WHERE id=? AND work_id=?")
21
- .get(piece.id, context.work.workId)?.state === "done")
22
+ if (pieceAlreadyDone(deps.db, context.work.workId, piece.id))
22
23
  return "done";
23
24
  const input = piece.input;
24
25
  if (input.kind !== "image" || input.animate === undefined)
25
- throw new Error("Slopify hit an internal error (an animated image was set up wrongly). Use Try again; if it happens again, use Download diagnostics in Settings and report it.");
26
+ throw new Error(internalError("an animated image was set up wrongly"));
26
27
  const imageKey = piece.key.slice("animate:".length);
27
28
  const view = executionView(deps, context.work.projectId, context.work.revisionId);
28
29
  const index = (view?.revision.content.imageOrder.indexOf(imageKey) ?? -1) + 1;
29
- const still = view?.outputs.find((row) => row.workKey === `image:${imageKey}` && row.selected && row.available && row.state === "ready");
30
+ const still = view?.outputs.find((row) => row.workKey === `image:${imageKey}` && isReadyOutput(row));
30
31
  const fallback = async (reason) => {
31
32
  deps.log.write("warn", "video.animate.fallback", { detail: reason });
32
33
  await publishResult(deps, context, piece, [], {
@@ -35,10 +36,10 @@ export async function executeAnimateRecipe(deps, context, providers, piece) {
35
36
  return "done";
36
37
  };
37
38
  if (still === undefined)
38
- return fallback("its image wasn't ready to animate. Use More → Render the video again in the Video section after the image is made.");
39
+ return fallback("its image wasn't ready to animate. Press Make the video again in the project's Video section after the image is made.");
39
40
  const animate = providers.forPiece(piece.id).animate;
40
41
  if (animate === undefined)
41
- throw new Error("Slopify hit an internal error (animating images isn't wired up in this build). Use Try again; if it happens again, use Download diagnostics in Settings and report it.");
42
+ throw new Error(internalError("animating images isn't wired up in this build"));
42
43
  if (!context.maySubmit(piece.id))
43
44
  return "held";
44
45
  let made;
@@ -55,7 +56,7 @@ export async function executeAnimateRecipe(deps, context, providers, piece) {
55
56
  catch (error) {
56
57
  if (context.signal.aborted)
57
58
  throw error;
58
- return fallback(`${error instanceof Error ? error.message : String(error)} To try again, use More → Render the video again in the Video section.`);
59
+ return fallback(`${errorText(error)} To try again, press Make the video again in the project's Video section.`);
59
60
  }
60
61
  if (!made.ok)
61
62
  return "held";
@@ -73,7 +74,7 @@ export async function executeAnimateRecipe(deps, context, providers, piece) {
73
74
  stage: context.work.kind,
74
75
  provider: input.provider,
75
76
  model: input.model,
76
- });
77
+ }, context.work.projectId);
77
78
  }
78
79
  finally {
79
80
  discardPreparedAssets(deps, [asset]);
@@ -1,5 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { transact } from "../../kernel/db/tx.js";
3
+ import { internalError } from "../../kernel/errors.js";
4
+ import { editSettings } from "../../kernel/ports/settings-places.js";
3
5
  import { continuationLimit, continuationMessages } from "../article/continuation.js";
4
6
  import { currentRevisionId, revisionById } from "../revisions/repo.js";
5
7
  import { recipe } from "./recipe-model.js";
@@ -12,14 +14,14 @@ const answerSchema = z.object({
12
14
  });
13
15
  export async function executeArticleRequests(deps, context, providers, initial) {
14
16
  if (initial.input.kind !== "llm")
15
- throw new Error("Slopify hit an internal error (the article step has no AI request). Try again; if it happens again, use Download diagnostics in Settings and report it.");
17
+ throw new Error(internalError("the article step has no AI request"));
16
18
  let piece = initial;
17
19
  let text = "";
18
20
  let inputTokens = 0;
19
21
  let outputTokens = 0;
20
22
  for (let part = 0; part <= continuationLimit; part += 1) {
21
23
  if (piece.input.kind !== "llm")
22
- throw new Error("Slopify hit an internal error (an article continuation has no AI request). Try again; if it happens again, use Download diagnostics in Settings and report it.");
24
+ throw new Error(internalError("an article continuation has no AI request"));
23
25
  const saved = deps.db
24
26
  .prepare("SELECT result_json FROM revision_work_pieces WHERE id=? AND work_id=?")
25
27
  .get(piece.id, context.work.workId);
@@ -38,9 +40,9 @@ export async function executeArticleRequests(deps, context, providers, initial)
38
40
  webSearch: input.webSearch,
39
41
  previewLabel: part === 0 ? "Article" : `Continuation ${part}`,
40
42
  check: (value) => value.text.trim() === ""
41
- ? "The AI model returned an empty article. Try again; if it keeps happening, choose a different model in Edit project → Providers."
43
+ ? `The AI model returned an empty article. Try again; if it keeps happening, choose a different model in ${editSettings.writer}.`
42
44
  : part === continuationLimit && value.finishReason === "length"
43
- ? `The article was still unfinished after ${continuationLimit} continuations because the AI model kept stopping at its length limit. Ask for a shorter article in Edit project → Prompts, or choose a model with a larger output limit in Edit project → Providers, then Try again.`
45
+ ? `The article was still unfinished after ${continuationLimit} continuations because the AI model kept stopping at its length limit. Ask for a shorter article in the article prompt in ${editSettings.article}, or choose a model with a larger output limit under Written by there, then Try again.`
44
46
  : undefined,
45
47
  }, (event) => {
46
48
  if (event.type === "delta")
@@ -72,7 +74,7 @@ export async function executeArticleRequests(deps, context, providers, initial)
72
74
  return { ok: false, reason: "held" };
73
75
  piece = next;
74
76
  }
75
- throw new Error(`The article was still unfinished after ${continuationLimit} continuations because the AI model kept stopping at its length limit. Ask for a shorter article in Edit project → Prompts, or choose a model with a larger output limit in Edit project → Providers, then Try again.`);
77
+ throw new Error(`The article was still unfinished after ${continuationLimit} continuations because the AI model kept stopping at its length limit. Ask for a shorter article in the article prompt in ${editSettings.article}, or choose a model with a larger output limit under Written by there, then Try again.`);
76
78
  }
77
79
  function continuationPiece(deps, context, initial, part, text) {
78
80
  return transact(deps.db, () => {
@@ -1,3 +1,4 @@
1
+ import { internalError } from "../../kernel/errors.js";
1
2
  import { checkpointClosure, checkpointFingerprint } from "../checkpoints/fingerprint.js";
2
3
  import { saveCheckpointSet } from "../checkpoints/repo.js";
3
4
  import { currentRevisionId } from "../revisions/repo.js";
@@ -11,14 +12,14 @@ export function admitReviewedCheckpoints(deps, projectIds, reviewed, catalogue)
11
12
  const revisionId = currentRevisionId(deps.db, projectId);
12
13
  const view = revisionId === undefined ? undefined : getRevisionView(deps, projectId, revisionId);
13
14
  if (!view)
14
- throw new Error("Slopify hit an internal error (the project version to review is missing). Try again; if it happens again, use Download diagnostics in Settings and report it.");
15
+ throw new Error(internalError("the project version to review is missing"));
15
16
  const plan = executionPlan(deps, view, executionCatalogue(catalogue, view.revision.config));
16
17
  const checkpoints = gates.map((gate) => {
17
18
  const work = deps.db
18
19
  .prepare("SELECT id FROM revision_work WHERE project_id=? AND revision_id=? AND kind=? ORDER BY id LIMIT 1")
19
20
  .get(projectId, view.revision.id, gate.stage);
20
21
  if (typeof work?.id !== "string")
21
- throw new Error("Slopify hit an internal error (a review checkpoint has no matching stage). Try again; if it happens again, use Download diagnostics in Settings and report it.");
22
+ throw new Error(internalError("a review checkpoint has no matching stage"));
22
23
  return {
23
24
  checkpointId: gate.checkpointId,
24
25
  stage: gate.stage,
@@ -34,11 +35,11 @@ export function admitReviewedCheckpoints(deps, projectIds, reviewed, catalogue)
34
35
  createdAt: deps.clock.now().toISOString(),
35
36
  });
36
37
  if (!saved.ok)
37
- throw new Error("Slopify hit an internal error (the review checkpoints could not be saved). Try again; if it happens again, use Download diagnostics in Settings and report it.");
38
+ throw new Error(internalError("the review checkpoints could not be saved"));
38
39
  return saved.value.map((row) => {
39
40
  const gate = gates.find((gate) => gate.checkpointId === row.checkpointId);
40
41
  if (!gate)
41
- throw new Error("Slopify hit an internal error (a saved review checkpoint could not be matched). Try again; if it happens again, use Download diagnostics in Settings and report it.");
42
+ throw new Error(internalError("a saved review checkpoint could not be matched"));
42
43
  return { ...row, reviewedFingerprint: gate.fingerprint };
43
44
  });
44
45
  });
@@ -1,16 +1,18 @@
1
1
  import { readFileSync } from "node:fs";
2
+ import { errorText, internalError } from "../../kernel/errors.js";
3
+ import { editSettings } from "../../kernel/ports/settings-places.js";
2
4
  import { readDocumentAssets } from "../document/fonts.js";
3
5
  import { renderDocument } from "../document/render.js";
4
6
  import { resolvedDocumentTheme } from "../document/theme.js";
7
+ import { readyOutput } from "../revisions/view.js";
5
8
  import { writeAsset } from "../storage/assets.js";
6
9
  import { outputPath } from "../storage/layout.js";
7
10
  import { executionPlan, executionView, savedCatalogue } from "./runtime-plan.js";
8
11
  import { preparedResult, publishResult } from "./runtime-publication.js";
12
+ import { pieceAlreadyDone } from "./work-records.js";
9
13
  // Lays the saved article out as a PDF. Local and quick: no provider, no charge.
10
14
  export async function executeDocumentRecipe(deps, context, piece) {
11
- if (deps.db
12
- .prepare("SELECT state FROM revision_work_pieces WHERE id=? AND work_id=?")
13
- .get(piece.id, context.work.workId)?.state === "done")
15
+ if (pieceAlreadyDone(deps.db, context.work.workId, piece.id))
14
16
  return "done";
15
17
  if (!context.maySubmit(piece.id))
16
18
  return "held";
@@ -28,7 +30,7 @@ export async function executeDocumentRecipe(deps, context, piece) {
28
30
  ? view.articleMarkdown
29
31
  : text("article_md", "article:body");
30
32
  if (article === null)
31
- throw new Error("The article isn't finished yet, so there's nothing to make the document from. Let the Article stage finish (Resume, or Try again on Article), then use Try again on Document.");
33
+ throw new Error("The article isn't finished yet, so there's nothing to make the document from. Let the Article stage finish (Continue the run, or Try again on Article), then use Try again on PDF.");
32
34
  const thumbnail = ready(view, "thumbnail", "thumbnail:image");
33
35
  let cover = null;
34
36
  if (config.sources.thumbnail !== "off" && thumbnail !== undefined) {
@@ -36,7 +38,7 @@ export async function executeDocumentRecipe(deps, context, piece) {
36
38
  cover = new Uint8Array(readFileSync(outputPath(deps.paths, projectId, thumbnail.output.path)));
37
39
  }
38
40
  catch (error) {
39
- throw new Error(`The document's cover is the project's thumbnail, and its file can't be read (${error instanceof Error ? error.message : String(error)}). Regenerate or upload the thumbnail again (More → make it again in its section on Thumbnail, or Edit project → Thumbnail), then use Try again on Document.`, { cause: error });
41
+ throw new Error(`The document's cover is the project's thumbnail, and its file can't be read (${errorText(error)}). Make the thumbnail again in the project's Images section, or upload it again in ${editSettings.extras}, then use Try again on PDF.`, { cause: error });
40
42
  }
41
43
  }
42
44
  const rendered = renderDocument({
@@ -60,7 +62,7 @@ export async function executeDocumentRecipe(deps, context, piece) {
60
62
  const asset = writeAsset(deps, projectId, "document.pdf", rendered.bytes);
61
63
  // publishResult discards the file itself when the publication doesn't commit.
62
64
  await publishResult(deps, context, piece, [preparedResult(deps, context, piece, "document_pdf", asset)], { pages: rendered.pages, words: rendered.words, cover: rendered.cover });
63
- deps.count?.("stage.completed", { stage: "document" });
65
+ deps.count?.("stage.completed", { stage: "document" }, context.work.projectId);
64
66
  return "done";
65
67
  }
66
68
  function documentView(deps, context, piece) {
@@ -69,16 +71,12 @@ function documentView(deps, context, piece) {
69
71
  .prepare("SELECT recipe_context FROM revision_work WHERE id=?")
70
72
  .get(context.work.workId);
71
73
  if (view === undefined || row === undefined)
72
- throw new Error("Slopify hit an internal error (the project version the document belongs to is missing). Use Try again on Document; if it happens again, use Download diagnostics in Settings and report it.");
74
+ throw new Error(internalError("the project version the document belongs to is missing", "Use Try again on PDF"));
73
75
  const recipe = executionPlan(deps, view, savedCatalogue(row.recipe_context)).recipes.find((one) => one.key === piece.key && one.fingerprint === piece.fingerprint);
74
76
  if (recipe === undefined || recipe.unresolved)
75
- throw new Error("The project changed after this document was queued, so it no longer matches the saved article. Use Choose what to remake (in the project's More menu) (or Try again on Document) to make it from the current version.");
77
+ throw new Error("The project changed after this document was queued, so it no longer matches the saved article. Use Choose what to make again (in the project's More menu) (or Try again on PDF) to make it from the current version.");
76
78
  return view;
77
79
  }
78
80
  function ready(view, role, workKey) {
79
- return view.outputs.find((row) => row.selected &&
80
- row.available &&
81
- row.state === "ready" &&
82
- row.workKey === workKey &&
83
- row.output.role === role);
81
+ return readyOutput(view, { workKey, role });
84
82
  }