@gentbajko/slopify 3.25.9 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (718) hide show
  1. package/dist/adapters/account-limits.js +30 -0
  2. package/dist/adapters/alignment/audio.js +1 -1
  3. package/dist/adapters/alignment/cache.js +4 -6
  4. package/dist/adapters/alignment/ctc.js +1 -2
  5. package/dist/adapters/alignment/lock.js +4 -3
  6. package/dist/adapters/alignment/multilingual.js +2 -4
  7. package/dist/adapters/alignment/prefetch.js +2 -1
  8. package/dist/adapters/alignment/runner.js +1 -1
  9. package/dist/adapters/alignment/worker.js +3 -2
  10. package/dist/adapters/explain.js +10 -12
  11. package/dist/adapters/ffmpeg.js +19 -1
  12. package/dist/adapters/host-cli/index.js +21 -4
  13. package/dist/adapters/host-cli/transport.js +2 -1
  14. package/dist/adapters/http-failure.js +53 -0
  15. package/dist/adapters/image/bytes.js +2 -1
  16. package/dist/adapters/image/codex.js +42 -9
  17. package/dist/adapters/image/fal.js +21 -53
  18. package/dist/adapters/image/google.js +33 -56
  19. package/dist/adapters/image/models.js +2 -2
  20. package/dist/adapters/image/openai.js +22 -48
  21. package/dist/adapters/image/reference.js +36 -0
  22. package/dist/adapters/image/replicate.js +21 -49
  23. package/dist/adapters/image/video.js +2 -1
  24. package/dist/adapters/interest/search-interest.js +113 -0
  25. package/dist/adapters/key-probes.js +54 -3
  26. package/dist/adapters/llm/antigravity-models.js +1 -1
  27. package/dist/adapters/llm/antigravity.js +11 -6
  28. package/dist/adapters/llm/assistant-cli.js +388 -0
  29. package/dist/adapters/llm/child-session.js +83 -0
  30. package/dist/adapters/llm/claude-code-models.js +52 -99
  31. package/dist/adapters/llm/claude-code.js +16 -4
  32. package/dist/adapters/llm/codex-limits.js +27 -68
  33. package/dist/adapters/llm/codex-models.js +1 -1
  34. package/dist/adapters/llm/codex-server-models.js +61 -109
  35. package/dist/adapters/llm/codex.js +12 -1
  36. package/dist/adapters/llm/document-workspace.js +3 -2
  37. package/dist/adapters/llm/image-workspace.js +3 -2
  38. package/dist/adapters/llm/openrouter.js +12 -48
  39. package/dist/adapters/llm/run-cli.js +9 -24
  40. package/dist/adapters/llm/sse-lines.js +5 -1
  41. package/dist/adapters/model-access.js +37 -0
  42. package/dist/adapters/tts/cartesia.js +15 -46
  43. package/dist/adapters/tts/elevenlabs.js +20 -52
  44. package/dist/adapters/tts/gemini.js +21 -41
  45. package/dist/adapters/tts/inworld-async.js +6 -2
  46. package/dist/adapters/tts/inworld.js +6 -2
  47. package/dist/adapters/tts/openai.js +20 -50
  48. package/dist/adapters/tts/system.js +2 -1
  49. package/dist/assets/models-lifecycle.yaml +6 -0
  50. package/dist/assistant-wiring.js +60 -0
  51. package/dist/autopilot-timers.js +59 -0
  52. package/dist/catalog/lifecycle.js +52 -0
  53. package/dist/catalog/propose.js +204 -0
  54. package/dist/catalog/registry.js +23 -14
  55. package/dist/catalog/schema.js +4 -1
  56. package/dist/catalog/store.js +39 -0
  57. package/dist/catalog/validate.js +5 -2
  58. package/dist/edge/autostart/native.js +3 -5
  59. package/dist/edge/autostart/prompt.js +2 -1
  60. package/dist/edge/autostart/service.js +3 -4
  61. package/dist/edge/cli-args.js +3 -4
  62. package/dist/edge/cli.js +2 -1
  63. package/dist/edge/docker-install/apply.js +11 -11
  64. package/dist/edge/docker-install/run.js +2 -1
  65. package/dist/edge/docker-install/state.js +4 -3
  66. package/dist/edge/docker-install/tree.js +2 -4
  67. package/dist/edge/docker-install/volume.js +3 -2
  68. package/dist/edge/docker.js +5 -4
  69. package/dist/edge/events/hub.js +5 -5
  70. package/dist/edge/http/actions.js +11 -32
  71. package/dist/edge/http/actor.js +5 -3
  72. package/dist/edge/http/app.js +86 -11
  73. package/dist/edge/http/assistant.js +129 -0
  74. package/dist/edge/http/audio-preview.js +4 -11
  75. package/dist/edge/http/auditions.js +1 -1
  76. package/dist/edge/http/autostart.js +5 -5
  77. package/dist/edge/http/backups.js +2 -4
  78. package/dist/edge/http/channel-memory.js +9 -22
  79. package/dist/edge/http/channels.js +14 -27
  80. package/dist/edge/http/checkpoints.js +39 -21
  81. package/dist/edge/http/design-templates.js +167 -0
  82. package/dist/edge/http/designs.js +178 -0
  83. package/dist/edge/http/diagnostics.js +5 -1
  84. package/dist/edge/http/document-themes.js +5 -14
  85. package/dist/edge/http/draft-files.js +1 -3
  86. package/dist/edge/http/draft-problem.js +5 -10
  87. package/dist/edge/http/drafts.js +3 -3
  88. package/dist/edge/http/entries.js +6 -9
  89. package/dist/edge/http/extension-auth.js +27 -0
  90. package/dist/edge/http/external-reviews.js +12 -11
  91. package/dist/edge/http/files.js +5 -11
  92. package/dist/edge/http/folder-location.js +1 -4
  93. package/dist/edge/http/fonts.js +0 -7
  94. package/dist/edge/http/home.js +47 -14
  95. package/dist/edge/http/host-cli.js +18 -8
  96. package/dist/edge/http/ids.js +8 -0
  97. package/dist/edge/http/keywords.js +35 -0
  98. package/dist/edge/http/model-checks.js +132 -0
  99. package/dist/edge/http/narration-peaks.js +5 -13
  100. package/dist/edge/http/onboarding.js +30 -26
  101. package/dist/edge/http/open-folder.js +5 -10
  102. package/dist/edge/http/outputs.js +7 -14
  103. package/dist/edge/http/patch-notes.js +6 -12
  104. package/dist/edge/http/planning.js +3 -7
  105. package/dist/edge/http/problem.js +2 -4
  106. package/dist/edge/http/project-create.js +2 -1
  107. package/dist/edge/http/project-templates.js +31 -19
  108. package/dist/edge/http/projects.js +24 -16
  109. package/dist/edge/http/prompts.js +9 -16
  110. package/dist/edge/http/pronunciations.js +1 -2
  111. package/dist/edge/http/providers.js +48 -34
  112. package/dist/edge/http/refusal.js +29 -0
  113. package/dist/edge/http/remote-access.js +40 -0
  114. package/dist/edge/http/remote-guard.js +71 -0
  115. package/dist/edge/http/request-guard.js +91 -0
  116. package/dist/edge/http/reviews.js +12 -25
  117. package/dist/edge/http/revision-files.js +6 -11
  118. package/dist/edge/http/revisions.js +14 -19
  119. package/dist/edge/http/run-cost.js +1 -2
  120. package/dist/edge/http/same-page.js +80 -0
  121. package/dist/edge/http/schedules.js +69 -40
  122. package/dist/edge/http/settings.js +27 -14
  123. package/dist/edge/http/social.js +283 -0
  124. package/dist/edge/http/staging.js +3 -5
  125. package/dist/edge/http/storage-files.js +5 -7
  126. package/dist/edge/http/storage.js +33 -25
  127. package/dist/edge/http/studio.js +94 -69
  128. package/dist/edge/http/style-preview.js +3 -6
  129. package/dist/edge/http/subtitles.js +3 -17
  130. package/dist/edge/http/template-studio.js +436 -0
  131. package/dist/edge/http/trash.js +11 -12
  132. package/dist/edge/http/tutorial.js +1 -2
  133. package/dist/edge/http/tutorials.js +5 -11
  134. package/dist/edge/http/update.js +7 -13
  135. package/dist/edge/http/waveform.js +3 -6
  136. package/dist/edge/http/youtube-edits.js +3 -4
  137. package/dist/edge/mcp/assistant.js +279 -0
  138. package/dist/edge/mcp/attribution.js +8 -2
  139. package/dist/edge/mcp/call-route.js +11 -2
  140. package/dist/edge/mcp/excluded-routes.js +29 -3
  141. package/dist/edge/mcp/http.js +11 -2
  142. package/dist/edge/mcp/instructions.js +6 -4
  143. package/dist/edge/mcp/library-tools.js +9 -5
  144. package/dist/edge/mcp/remake-tools.js +7 -4
  145. package/dist/edge/mcp/route-tool.js +35 -15
  146. package/dist/edge/mcp/server.js +13 -8
  147. package/dist/edge/mcp/tools-channels.js +11 -9
  148. package/dist/edge/mcp/tools-designs.js +165 -0
  149. package/dist/edge/mcp/tools-library.js +19 -7
  150. package/dist/edge/mcp/tools-planning.js +40 -21
  151. package/dist/edge/mcp/tools-projects.js +38 -11
  152. package/dist/edge/mcp/tools-publishing.js +9 -9
  153. package/dist/edge/mcp/tools-runs.js +23 -10
  154. package/dist/edge/mcp/tools-schedules.js +32 -8
  155. package/dist/edge/mcp/tools-setup.js +75 -11
  156. package/dist/edge/mcp/tools-social.js +47 -0
  157. package/dist/edge/mcp/tools-storage.js +11 -3
  158. package/dist/edge/mcp/tools-template-studio.js +166 -0
  159. package/dist/edge/mcp/tools.js +6 -0
  160. package/dist/edge/remote-access/cli.js +71 -0
  161. package/dist/edge/remote-access/model.js +32 -0
  162. package/dist/edge/remote-access/rules.js +207 -0
  163. package/dist/edge/remote-access/service.js +203 -0
  164. package/dist/edge/remote-access/store.js +44 -0
  165. package/dist/edge/remote-access/views.js +43 -0
  166. package/dist/extension/slopify-studio-chrome.zip +0 -0
  167. package/dist/extension/slopify-studio-firefox.zip +0 -0
  168. package/dist/host-cli/install.js +2 -2
  169. package/dist/host-cli/open-folder.js +2 -2
  170. package/dist/host-cli/paths.js +2 -4
  171. package/dist/host-cli/server.js +4 -4
  172. package/dist/host-cli/service.js +3 -3
  173. package/dist/host-cli/status.js +7 -7
  174. package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
  175. package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
  176. package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
  177. package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
  178. package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
  179. package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
  180. package/dist/kernel/db/migrations/0070-designs.sql +53 -0
  181. package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
  182. package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
  183. package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
  184. package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
  185. package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
  186. package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
  187. package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
  188. package/dist/kernel/db/migrations/0078-uploaded-from-links.sql +7 -0
  189. package/dist/kernel/db/tx.js +2 -4
  190. package/dist/kernel/errors.js +27 -1
  191. package/dist/kernel/json-answer.js +15 -0
  192. package/dist/kernel/lock.js +4 -9
  193. package/dist/kernel/paths.js +8 -0
  194. package/dist/kernel/pipeline.js +12 -0
  195. package/dist/kernel/ports/assistant-cli.js +4 -0
  196. package/dist/kernel/ports/host-cli.js +3 -0
  197. package/dist/kernel/ports/interest.js +4 -0
  198. package/dist/kernel/ports/languages.js +0 -3
  199. package/dist/kernel/ports/model.js +2 -0
  200. package/dist/kernel/ports/settings-places.js +31 -0
  201. package/dist/kernel/ports/system-speech.js +31 -3
  202. package/dist/kernel/runner/attempt.js +14 -4
  203. package/dist/kernel/runner/audition.js +3 -1
  204. package/dist/kernel/runner/checkpoint-authority.js +2 -1
  205. package/dist/kernel/runner/index.js +8 -10
  206. package/dist/kernel/runner/model-access.js +40 -0
  207. package/dist/kernel/runner/model-check.js +153 -0
  208. package/dist/kernel/runner/providers.js +18 -12
  209. package/dist/kernel/runner/standalone.js +11 -7
  210. package/dist/main.js +338 -21
  211. package/dist/model-catalog.js +20 -0
  212. package/dist/model-checks.js +166 -0
  213. package/dist/patch-notes/4.0.0.md +51 -0
  214. package/dist/patch-notes/4.1.0.md +42 -0
  215. package/dist/patch-notes/index.json +12 -0
  216. package/dist/slices/admission/heads.js +2 -1
  217. package/dist/slices/admission/listing-facts.js +95 -0
  218. package/dist/slices/admission/repo.js +11 -7
  219. package/dist/slices/admission/rules.js +50 -15
  220. package/dist/slices/admission/schema.js +8 -0
  221. package/dist/slices/admission/stage-writes.js +0 -3
  222. package/dist/slices/admission/start.js +48 -31
  223. package/dist/slices/admission/state-words.js +34 -5
  224. package/dist/slices/admission/substitute.js +7 -4
  225. package/dist/slices/agents/attention-posts.js +31 -0
  226. package/dist/slices/agents/attention-templates.js +33 -0
  227. package/dist/slices/agents/attention.js +10 -1
  228. package/dist/slices/agents/connection.js +2 -6
  229. package/dist/slices/agents/model.js +6 -3
  230. package/dist/slices/agents/repo.js +15 -7
  231. package/dist/slices/article/continuation.js +0 -63
  232. package/dist/slices/article/plain.js +3 -2
  233. package/dist/slices/article/segments.js +2 -62
  234. package/dist/slices/assistant/access.js +1 -0
  235. package/dist/slices/assistant/asks.js +80 -0
  236. package/dist/slices/assistant/cost.js +54 -0
  237. package/dist/slices/assistant/gate.js +222 -0
  238. package/dist/slices/assistant/model.js +86 -0
  239. package/dist/slices/assistant/names.js +23 -0
  240. package/dist/slices/assistant/prompt.js +74 -0
  241. package/dist/slices/assistant/repo.js +74 -0
  242. package/dist/slices/assistant/tokens.js +18 -0
  243. package/dist/slices/assistant/turn.js +344 -0
  244. package/dist/slices/autopilot/buffer.js +76 -0
  245. package/dist/slices/autopilot/model.js +14 -0
  246. package/dist/slices/autopilot/notify.js +27 -0
  247. package/dist/slices/autopilot/repo.js +34 -0
  248. package/dist/slices/autopilot/signals.js +194 -0
  249. package/dist/slices/autopilot/warnings.js +85 -0
  250. package/dist/slices/autopilot/weekly.js +100 -0
  251. package/dist/slices/backups/files.js +2 -6
  252. package/dist/slices/backups/repo.js +3 -15
  253. package/dist/slices/backups/service.js +8 -7
  254. package/dist/slices/channels/cast-images.js +3 -2
  255. package/dist/slices/channels/model.js +0 -1
  256. package/dist/slices/channels/rebrand.js +0 -3
  257. package/dist/slices/channels/repo.js +4 -0
  258. package/dist/slices/channels/schema.js +7 -1
  259. package/dist/slices/channels/service.js +10 -0
  260. package/dist/slices/channels/videos.js +3 -15
  261. package/dist/slices/checkpoints/index.js +0 -1
  262. package/dist/slices/control/providers.js +2 -28
  263. package/dist/slices/designs/artwork.js +66 -0
  264. package/dist/slices/designs/budget.js +23 -0
  265. package/dist/slices/designs/calls.js +124 -0
  266. package/dist/slices/designs/check-context.js +38 -0
  267. package/dist/slices/designs/check-text.js +43 -0
  268. package/dist/slices/designs/fields.js +88 -0
  269. package/dist/slices/designs/frames.js +34 -0
  270. package/dist/slices/designs/gate.js +130 -0
  271. package/dist/slices/designs/layout.js +293 -0
  272. package/dist/slices/designs/model.js +35 -0
  273. package/dist/slices/designs/pdf-job.js +23 -0
  274. package/dist/slices/designs/pdf-pages.js +30 -0
  275. package/dist/slices/designs/pdf-runner.js +68 -0
  276. package/dist/slices/designs/pdf-worker.js +24 -0
  277. package/dist/slices/designs/picture-size.js +79 -0
  278. package/dist/slices/designs/pictures.js +55 -0
  279. package/dist/slices/designs/quote.js +24 -0
  280. package/dist/slices/designs/render-args.js +36 -0
  281. package/dist/slices/designs/render-input.js +59 -0
  282. package/dist/slices/designs/render.js +215 -0
  283. package/dist/slices/designs/repo.js +101 -0
  284. package/dist/slices/designs/requests.js +80 -0
  285. package/dist/slices/designs/runner.js +239 -0
  286. package/dist/slices/designs/sample-repo.js +91 -0
  287. package/dist/slices/designs/sample.js +223 -0
  288. package/dist/slices/designs/schema.js +87 -0
  289. package/dist/slices/designs/sections.js +44 -0
  290. package/dist/slices/designs/service.js +233 -0
  291. package/dist/slices/designs/steps-repo.js +102 -0
  292. package/dist/slices/designs/studio-kind.js +39 -0
  293. package/dist/slices/designs/template-checks.js +44 -0
  294. package/dist/slices/designs/template-make.js +118 -0
  295. package/dist/slices/designs/templates.js +218 -0
  296. package/dist/slices/document/fonts.js +2 -1
  297. package/dist/slices/document/model.js +7 -4
  298. package/dist/slices/document/render.js +2 -1
  299. package/dist/slices/document/theme-schema.js +1 -1
  300. package/dist/slices/document/theme.js +49 -3
  301. package/dist/slices/episodes/summarize.js +6 -2
  302. package/dist/slices/estimate/index.js +72 -28
  303. package/dist/slices/estimate/requests.js +4 -4
  304. package/dist/slices/fixes/rules.js +3 -1
  305. package/dist/slices/fonts/catalog.js +5 -3
  306. package/dist/slices/fonts/coverage.js +2 -1
  307. package/dist/slices/fonts/discovery.js +3 -2
  308. package/dist/slices/fonts/files.js +2 -6
  309. package/dist/slices/fonts/index.js +0 -1
  310. package/dist/slices/fonts/sfnt.js +45 -10
  311. package/dist/slices/images/appearance.js +8 -16
  312. package/dist/slices/images/scenes.js +102 -28
  313. package/dist/slices/keywords/digest.js +85 -0
  314. package/dist/slices/keywords/facts.js +92 -0
  315. package/dist/slices/keywords/fill.js +80 -0
  316. package/dist/slices/keywords/model.js +75 -0
  317. package/dist/slices/keywords/rules.js +187 -0
  318. package/dist/slices/keywords/schema.js +28 -0
  319. package/dist/slices/keywords/specs.js +260 -0
  320. package/dist/slices/keywords/values.js +74 -0
  321. package/dist/slices/library/lint.js +29 -12
  322. package/dist/slices/library/model.js +2 -0
  323. package/dist/slices/library/photorealistic.js +4 -12
  324. package/dist/slices/library/rename.js +9 -7
  325. package/dist/slices/library/save.js +14 -10
  326. package/dist/slices/library/slots.js +37 -11
  327. package/dist/slices/library/transfer.js +5 -4
  328. package/dist/slices/library/used-by.js +25 -10
  329. package/dist/slices/loudness/loudnorm.js +53 -12
  330. package/dist/slices/loudness/model.js +3 -2
  331. package/dist/slices/loudness/sentence-level.js +2 -1
  332. package/dist/slices/model-checks/cost.js +61 -0
  333. package/dist/slices/model-checks/listing.js +124 -0
  334. package/dist/slices/model-checks/model.js +20 -0
  335. package/dist/slices/model-checks/record.js +32 -0
  336. package/dist/slices/model-checks/repo.js +120 -0
  337. package/dist/slices/model-checks/rules.js +125 -0
  338. package/dist/slices/model-checks/run.js +143 -0
  339. package/dist/slices/model-checks/service.js +198 -0
  340. package/dist/slices/model-upkeep/model.js +1 -1
  341. package/dist/slices/model-upkeep/switch.js +72 -27
  342. package/dist/slices/model-upkeep/usage.js +39 -13
  343. package/dist/slices/narration/breaths.js +3 -1
  344. package/dist/slices/narration/clean-pieces.js +3 -1
  345. package/dist/slices/narration/concat.js +2 -1
  346. package/dist/slices/narration/pauses-model.js +3 -2
  347. package/dist/slices/narration/peaks.js +3 -4
  348. package/dist/slices/narration/pronunciation-chunks.js +4 -3
  349. package/dist/slices/narration/pronunciation.js +6 -4
  350. package/dist/slices/narration/steering.js +4 -3
  351. package/dist/slices/notifications/notifier.js +4 -3
  352. package/dist/slices/notifications/rules.js +5 -2
  353. package/dist/slices/notifications/settings.js +4 -12
  354. package/dist/slices/notifications/subject.js +4 -3
  355. package/dist/slices/onboarding/copy.js +21 -3
  356. package/dist/slices/onboarding/first-run.js +16 -40
  357. package/dist/slices/onboarding/full-video.js +3 -2
  358. package/dist/slices/onboarding/install.js +6 -4
  359. package/dist/slices/onboarding/model.js +26 -37
  360. package/dist/slices/onboarding/packs.js +22 -22
  361. package/dist/slices/onboarding/preferred-model.js +14 -0
  362. package/dist/slices/onboarding/quick-short.js +105 -65
  363. package/dist/slices/onboarding/sample.js +4 -2
  364. package/dist/slices/onboarding/state.js +9 -11
  365. package/dist/slices/onboarding/template.js +8 -6
  366. package/dist/slices/outputs/add.js +3 -2
  367. package/dist/slices/outputs/service.js +2 -2
  368. package/dist/slices/patch-notes/library.js +4 -3
  369. package/dist/slices/play-drafts/convert.js +4 -0
  370. package/dist/slices/play-drafts/readiness.js +3 -3
  371. package/dist/slices/play-drafts/review-inputs.js +9 -3
  372. package/dist/slices/play-drafts/review.js +5 -4
  373. package/dist/slices/play-drafts/schema.js +4 -0
  374. package/dist/slices/play-drafts/service.js +17 -7
  375. package/dist/slices/project-templates/from-project.js +9 -2
  376. package/dist/slices/project-templates/next-chapter.js +2 -1
  377. package/dist/slices/project-templates/provider-defaults.js +22 -0
  378. package/dist/slices/project-templates/repo.js +6 -1
  379. package/dist/slices/project-templates/setup-sections.js +26 -0
  380. package/dist/slices/project-templates/setup.js +14 -1
  381. package/dist/slices/project-templates/stand-ins.js +22 -0
  382. package/dist/slices/rebuild/activity.js +2 -0
  383. package/dist/slices/rebuild/admission-repo.js +3 -2
  384. package/dist/slices/rebuild/narration-history.js +4 -5
  385. package/dist/slices/rebuild/narration-retry.js +2 -1
  386. package/dist/slices/rebuild/preview-details.js +32 -14
  387. package/dist/slices/rebuild/preview-plan.js +3 -8
  388. package/dist/slices/rebuild/recipe-build.js +8 -3
  389. package/dist/slices/rebuild/recipe-describe.js +3 -3
  390. package/dist/slices/rebuild/recipe-digest.js +58 -0
  391. package/dist/slices/rebuild/recipe-input-schema.js +10 -0
  392. package/dist/slices/rebuild/recipe-keywords.js +71 -0
  393. package/dist/slices/rebuild/recipe-legacy.js +5 -1
  394. package/dist/slices/rebuild/recipe-model.js +4 -0
  395. package/dist/slices/rebuild/recipe-narration-text.js +2 -1
  396. package/dist/slices/rebuild/recipe-preparation.js +4 -4
  397. package/dist/slices/rebuild/recipe-reference.js +8 -4
  398. package/dist/slices/rebuild/recipe-reviews.js +27 -7
  399. package/dist/slices/rebuild/recipe-save.js +8 -5
  400. package/dist/slices/rebuild/recipe-scenes.js +40 -11
  401. package/dist/slices/rebuild/recipe-shorts.js +8 -8
  402. package/dist/slices/rebuild/recipe-social.js +46 -0
  403. package/dist/slices/rebuild/recipe-text.js +64 -20
  404. package/dist/slices/rebuild/recipe-validation.js +102 -31
  405. package/dist/slices/rebuild/recipe-visual.js +55 -16
  406. package/dist/slices/rebuild/recipe-voices.js +3 -2
  407. package/dist/slices/rebuild/recipe-work.js +19 -7
  408. package/dist/slices/rebuild/recipe-youtube.js +4 -3
  409. package/dist/slices/rebuild/recovery-selection.js +3 -1
  410. package/dist/slices/rebuild/recovery.js +9 -8
  411. package/dist/slices/rebuild/remake-outdated.js +5 -5
  412. package/dist/slices/rebuild/repo.js +4 -3
  413. package/dist/slices/rebuild/review-promise.js +25 -0
  414. package/dist/slices/rebuild/review-redo.js +3 -2
  415. package/dist/slices/rebuild/runtime-admission.js +4 -3
  416. package/dist/slices/rebuild/runtime-agent-review.js +11 -5
  417. package/dist/slices/rebuild/runtime-animate.js +10 -9
  418. package/dist/slices/rebuild/runtime-article.js +7 -5
  419. package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
  420. package/dist/slices/rebuild/runtime-document.js +11 -13
  421. package/dist/slices/rebuild/runtime-export-bed.js +8 -12
  422. package/dist/slices/rebuild/runtime-export-edit.js +8 -16
  423. package/dist/slices/rebuild/runtime-export-inputs.js +12 -11
  424. package/dist/slices/rebuild/runtime-export-short.js +9 -5
  425. package/dist/slices/rebuild/runtime-export.js +38 -15
  426. package/dist/slices/rebuild/runtime-figure-card.js +2 -1
  427. package/dist/slices/rebuild/runtime-image.js +8 -12
  428. package/dist/slices/rebuild/runtime-instructions.js +2 -0
  429. package/dist/slices/rebuild/runtime-keywords.js +59 -0
  430. package/dist/slices/rebuild/runtime-lines.js +2 -11
  431. package/dist/slices/rebuild/runtime-local.js +17 -22
  432. package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
  433. package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
  434. package/dist/slices/rebuild/runtime-narration-text.js +13 -17
  435. package/dist/slices/rebuild/runtime-pictures.js +2 -4
  436. package/dist/slices/rebuild/runtime-piece-label.js +10 -6
  437. package/dist/slices/rebuild/runtime-plan.js +31 -5
  438. package/dist/slices/rebuild/runtime-provider.js +67 -25
  439. package/dist/slices/rebuild/runtime-publication.js +10 -9
  440. package/dist/slices/rebuild/runtime-review.js +39 -33
  441. package/dist/slices/rebuild/runtime-run.js +4 -1
  442. package/dist/slices/rebuild/runtime-shorts.js +31 -50
  443. package/dist/slices/rebuild/runtime-store.js +20 -10
  444. package/dist/slices/rebuild/runtime-subtitles.js +28 -25
  445. package/dist/slices/rebuild/runtime-voices.js +10 -16
  446. package/dist/slices/rebuild/runtime-youtube.js +14 -31
  447. package/dist/slices/rebuild/service-readiness.js +11 -3
  448. package/dist/slices/rebuild/transition-repo.js +6 -5
  449. package/dist/slices/rebuild/work-records.js +6 -0
  450. package/dist/slices/reruns/cascade.js +1 -2
  451. package/dist/slices/reruns/index.js +6 -9
  452. package/dist/slices/research/synthesis.js +3 -2
  453. package/dist/slices/reviews/external-model.js +4 -1
  454. package/dist/slices/reviews/external-repo.js +2 -1
  455. package/dist/slices/reviews/external-rows.js +2 -3
  456. package/dist/slices/reviews/holds.js +5 -4
  457. package/dist/slices/reviews/model.js +32 -11
  458. package/dist/slices/reviews/repo.js +2 -1
  459. package/dist/slices/reviews/rules.js +4 -3
  460. package/dist/slices/reviews/verdict.js +2 -1
  461. package/dist/slices/reviews/view.js +5 -2
  462. package/dist/slices/revisions/downloads.js +4 -5
  463. package/dist/slices/revisions/image-plan.js +1 -1
  464. package/dist/slices/revisions/mutation-assets.js +9 -5
  465. package/dist/slices/revisions/mutation-cues.js +2 -5
  466. package/dist/slices/revisions/mutations.js +3 -3
  467. package/dist/slices/revisions/repo.js +3 -1
  468. package/dist/slices/revisions/schema.js +1 -0
  469. package/dist/slices/revisions/view.js +20 -0
  470. package/dist/slices/run-cost/limits.js +5 -2
  471. package/dist/slices/run-cost/meter.js +12 -5
  472. package/dist/slices/run-cost/panel.js +8 -74
  473. package/dist/slices/run-cost/plan-readings.js +127 -0
  474. package/dist/slices/run-cost/plan-use.js +169 -0
  475. package/dist/slices/run-cost/pricing.js +3 -3
  476. package/dist/slices/run-cost/week.js +32 -4
  477. package/dist/slices/schedules/agenda.js +18 -7
  478. package/dist/slices/schedules/by-date.js +42 -0
  479. package/dist/slices/schedules/calendar.js +5 -0
  480. package/dist/slices/schedules/design-agenda.js +36 -0
  481. package/dist/slices/schedules/design-check.js +41 -0
  482. package/dist/slices/schedules/design-run.js +126 -0
  483. package/dist/slices/schedules/next-run.js +62 -0
  484. package/dist/slices/schedules/prepare.js +18 -2
  485. package/dist/slices/schedules/repo.js +30 -21
  486. package/dist/slices/schedules/rescore.js +35 -0
  487. package/dist/slices/schedules/scheduler.js +13 -3
  488. package/dist/slices/schedules/schema.js +57 -3
  489. package/dist/slices/schedules/score.js +107 -0
  490. package/dist/slices/schedules/service.js +57 -24
  491. package/dist/slices/schedules/topic-list.js +15 -0
  492. package/dist/slices/schedules/topic-scores.js +104 -0
  493. package/dist/slices/schedules/topics.js +53 -41
  494. package/dist/slices/settings/cli-paths.js +4 -6
  495. package/dist/slices/settings/first-run.js +8 -43
  496. package/dist/slices/settings/health.js +30 -15
  497. package/dist/slices/settings/key-test.js +1 -1
  498. package/dist/slices/settings/model-reach.js +3 -17
  499. package/dist/slices/settings/model.js +14 -2
  500. package/dist/slices/settings/playback.js +34 -23
  501. package/dist/slices/settings/probe-read.js +16 -0
  502. package/dist/slices/settings/repo.js +33 -0
  503. package/dist/slices/settings/tutorial.js +2 -2
  504. package/dist/slices/settings/voices.js +4 -12
  505. package/dist/slices/shorts/keep.js +2 -1
  506. package/dist/slices/shorts/pick.js +6 -18
  507. package/dist/slices/shorts/prompts.js +4 -14
  508. package/dist/slices/shorts/render.js +6 -2
  509. package/dist/slices/social/channel.js +44 -0
  510. package/dist/slices/social/defaults.js +17 -0
  511. package/dist/slices/social/due.js +36 -0
  512. package/dist/slices/social/extension.js +18 -0
  513. package/dist/slices/social/fit.js +115 -0
  514. package/dist/slices/social/limits.js +186 -0
  515. package/dist/slices/social/links.js +21 -0
  516. package/dist/slices/social/media.js +132 -0
  517. package/dist/slices/social/model.js +75 -0
  518. package/dist/slices/social/notice.js +19 -0
  519. package/dist/slices/social/pack.js +176 -0
  520. package/dist/slices/social/post-prompt.js +56 -0
  521. package/dist/slices/social/queue.js +31 -0
  522. package/dist/slices/social/repo.js +133 -0
  523. package/dist/slices/social/reshape.js +97 -0
  524. package/dist/slices/social/rules.js +5 -0
  525. package/dist/slices/social/schema.js +70 -0
  526. package/dist/slices/social/serve.js +51 -0
  527. package/dist/slices/social/service.js +129 -0
  528. package/dist/slices/social/settings.js +21 -0
  529. package/dist/slices/social/sources.js +114 -0
  530. package/dist/slices/social/state.js +110 -0
  531. package/dist/slices/social/text.js +149 -0
  532. package/dist/slices/storage/arrange.js +3 -1
  533. package/dist/slices/storage/assets.js +8 -10
  534. package/dist/slices/storage/backup-designs.js +74 -0
  535. package/dist/slices/storage/backup-export.js +8 -3
  536. package/dist/slices/storage/backup-format.js +10 -0
  537. package/dist/slices/storage/backup-import.js +22 -4
  538. package/dist/slices/storage/delete-project.js +6 -5
  539. package/dist/slices/storage/files-location.js +6 -8
  540. package/dist/slices/storage/layout.js +13 -2
  541. package/dist/slices/storage/model.js +3 -0
  542. package/dist/slices/storage/portable.js +17 -12
  543. package/dist/slices/storage/schema.js +2 -0
  544. package/dist/slices/storage/staging-refs.js +2 -1
  545. package/dist/slices/storage/staging.js +6 -9
  546. package/dist/slices/storage/trim.js +26 -9
  547. package/dist/slices/studio/calendar.js +7 -2
  548. package/dist/slices/studio/disclosure.js +4 -4
  549. package/dist/slices/studio/model.js +1 -1
  550. package/dist/slices/studio/pack.js +9 -8
  551. package/dist/slices/studio/pick.js +2 -11
  552. package/dist/slices/studio/plan.js +7 -16
  553. package/dist/slices/studio/queue.js +3 -14
  554. package/dist/slices/studio/releases.js +26 -0
  555. package/dist/slices/studio/settings.js +20 -57
  556. package/dist/slices/studio/videos.js +35 -4
  557. package/dist/slices/style-preview/render.js +37 -16
  558. package/dist/slices/style-preview/schema.js +14 -1
  559. package/dist/slices/style-preview/service.js +2 -1
  560. package/dist/slices/style-preview/settings.js +33 -5
  561. package/dist/slices/subtitles/captions.js +1 -1
  562. package/dist/slices/telemetry/collector-client.js +2 -4
  563. package/dist/slices/telemetry/flush.js +2 -4
  564. package/dist/slices/telemetry/model.js +0 -7
  565. package/dist/slices/telemetry/record.js +10 -3
  566. package/dist/slices/template-studio/anatomy-view.js +161 -0
  567. package/dist/slices/template-studio/anatomy.js +73 -0
  568. package/dist/slices/template-studio/bakeoff-make.js +225 -0
  569. package/dist/slices/template-studio/bakeoff-repo.js +83 -0
  570. package/dist/slices/template-studio/bakeoff.js +333 -0
  571. package/dist/slices/template-studio/budget.js +106 -0
  572. package/dist/slices/template-studio/cards.js +78 -0
  573. package/dist/slices/template-studio/checks.js +322 -0
  574. package/dist/slices/template-studio/document-sample.js +56 -0
  575. package/dist/slices/template-studio/edit.js +15 -0
  576. package/dist/slices/template-studio/for-all.js +161 -0
  577. package/dist/slices/template-studio/free-video.js +31 -0
  578. package/dist/slices/template-studio/free.js +176 -0
  579. package/dist/slices/template-studio/gate.js +40 -0
  580. package/dist/slices/template-studio/hidden.js +20 -0
  581. package/dist/slices/template-studio/jobs.js +79 -0
  582. package/dist/slices/template-studio/loudness.js +111 -0
  583. package/dist/slices/template-studio/make.js +40 -0
  584. package/dist/slices/template-studio/model.js +58 -0
  585. package/dist/slices/template-studio/pack-import.js +253 -0
  586. package/dist/slices/template-studio/pack-samples.js +60 -0
  587. package/dist/slices/template-studio/pack.js +207 -0
  588. package/dist/slices/template-studio/paid-view.js +66 -0
  589. package/dist/slices/template-studio/paid.js +355 -0
  590. package/dist/slices/template-studio/quote.js +155 -0
  591. package/dist/slices/template-studio/ready.js +104 -0
  592. package/dist/slices/template-studio/repo.js +134 -0
  593. package/dist/slices/template-studio/reviews-path.js +58 -0
  594. package/dist/slices/template-studio/runner.js +84 -0
  595. package/dist/slices/template-studio/save.js +236 -0
  596. package/dist/slices/template-studio/say-it-as.js +248 -0
  597. package/dist/slices/template-studio/schedule-gate.js +34 -0
  598. package/dist/slices/template-studio/schedule-price.js +32 -0
  599. package/dist/slices/template-studio/schedule-sample.js +91 -0
  600. package/dist/slices/template-studio/schema.js +243 -0
  601. package/dist/slices/template-studio/scope.js +124 -0
  602. package/dist/slices/template-studio/sections.js +176 -0
  603. package/dist/slices/template-studio/service.js +175 -0
  604. package/dist/slices/template-studio/status.js +191 -0
  605. package/dist/slices/template-studio/topic.js +223 -0
  606. package/dist/slices/thumbnail/by-llm.js +1 -1
  607. package/dist/slices/trash/designs.js +76 -0
  608. package/dist/slices/trash/model.js +13 -4
  609. package/dist/slices/trash/service.js +52 -2
  610. package/dist/slices/tutorials/library.js +3 -2
  611. package/dist/slices/uploads/repo.js +37 -1
  612. package/dist/slices/uploads/rules.js +3 -2
  613. package/dist/slices/video/ass-text.js +17 -0
  614. package/dist/slices/video/audio-export.js +2 -64
  615. package/dist/slices/video/edit-list.js +2 -2
  616. package/dist/slices/video/edit-settings.js +1 -1
  617. package/dist/slices/video/encoding.js +169 -0
  618. package/dist/slices/video/ffmpeg.js +23 -21
  619. package/dist/slices/video/figure-card.js +1 -15
  620. package/dist/slices/video/plan.js +2 -1
  621. package/dist/slices/video/slideshow.js +43 -18
  622. package/dist/slices/voices/attribution.js +3 -2
  623. package/dist/slices/voices/model.js +9 -8
  624. package/dist/slices/voices/palette.js +0 -3
  625. package/dist/slices/voices/script.js +2 -1
  626. package/dist/slices/youtube/answer.js +4 -16
  627. package/dist/slices/youtube/edits-repo.js +3 -12
  628. package/dist/tutorials/AI-CLIs.md +25 -25
  629. package/dist/tutorials/Agents-MCP.md +34 -33
  630. package/dist/tutorials/Assistant.md +42 -0
  631. package/dist/tutorials/Backups.md +7 -7
  632. package/dist/tutorials/Calendar.md +17 -25
  633. package/dist/tutorials/Cast-Library.md +19 -19
  634. package/dist/tutorials/Channels.md +42 -35
  635. package/dist/tutorials/Costs-and-Run-Cost.md +38 -40
  636. package/dist/tutorials/Create-Article.md +114 -0
  637. package/dist/tutorials/Create-Extras.md +112 -0
  638. package/dist/tutorials/Create-Images.md +165 -0
  639. package/dist/tutorials/Create-Narration.md +178 -0
  640. package/dist/tutorials/Create-Overview.md +244 -0
  641. package/dist/tutorials/Create-Video-and-Style.md +144 -0
  642. package/dist/tutorials/Docker.md +3 -3
  643. package/dist/tutorials/Document-Themes.md +32 -32
  644. package/dist/tutorials/Editing-a-Project.md +94 -94
  645. package/dist/tutorials/FAQ.md +18 -18
  646. package/dist/tutorials/First-Launch-and-Welcome.md +50 -64
  647. package/dist/tutorials/Home-and-Projects.md +115 -71
  648. package/dist/tutorials/Home.md +33 -33
  649. package/dist/tutorials/Install.md +14 -13
  650. package/dist/tutorials/Intros-and-Outros.md +33 -34
  651. package/dist/tutorials/Keyboard-Shortcuts-and-Command-Palette.md +62 -58
  652. package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
  653. package/dist/tutorials/Models.md +53 -21
  654. package/dist/tutorials/Multiple-Voices.md +41 -40
  655. package/dist/tutorials/Narration-Aliases-and-Glossary.md +14 -14
  656. package/dist/tutorials/Notifications.md +27 -17
  657. package/dist/tutorials/Other-Languages.md +15 -15
  658. package/dist/tutorials/PDF-Documents.md +38 -29
  659. package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
  660. package/dist/tutorials/Project-Page.md +118 -120
  661. package/dist/tutorials/Prompts-and-Templates.md +84 -0
  662. package/dist/tutorials/Prompts.md +48 -44
  663. package/dist/tutorials/Providers-and-Keys.md +105 -98
  664. package/dist/tutorials/Publishing-to-YouTube.md +31 -31
  665. package/dist/tutorials/Recovery-and-Retries.md +31 -31
  666. package/dist/tutorials/Remote-Access.md +63 -0
  667. package/dist/tutorials/Reviews-and-Checkpoints.md +98 -90
  668. package/dist/tutorials/Schedules.md +46 -27
  669. package/dist/tutorials/Settings-Reference.md +194 -174
  670. package/dist/tutorials/Shorts.md +34 -33
  671. package/dist/tutorials/Start-at-Login.md +3 -3
  672. package/dist/tutorials/Studio-Extension.md +22 -24
  673. package/dist/tutorials/Template-Studio.md +128 -0
  674. package/dist/tutorials/Templates.md +51 -77
  675. package/dist/tutorials/Trash.md +4 -4
  676. package/dist/tutorials/Troubleshooting.md +44 -44
  677. package/dist/tutorials/Uninstalling-and-Moving.md +5 -5
  678. package/dist/tutorials/Updating-and-Patch-Notes.md +18 -18
  679. package/dist/tutorials/Video-Editing.md +34 -34
  680. package/dist/tutorials/Where-Your-Files-Live.md +10 -10
  681. package/dist/tutorials/YouTube-Description.md +26 -26
  682. package/dist/tutorials/Your-First-Short.md +35 -35
  683. package/dist/tutorials/_Sidebar.md +19 -14
  684. package/dist/updater/work-in-progress.js +42 -12
  685. package/dist/web/assets/index-BNftKQrA.css +1 -0
  686. package/dist/web/assets/index-Cpa58woP.js +459 -0
  687. package/dist/web/assets/pdf-BKh8f7R6.js +56 -0
  688. package/dist/web/assets/pdf.worker.min-BmVo14Nb.mjs +28 -0
  689. package/dist/web/assets/pdf.worker.min-D7i8o3wR.js +1 -0
  690. package/dist/web/index.html +2 -2
  691. package/package.json +6 -2
  692. package/dist/slices/article/provided-entries.js +0 -66
  693. package/dist/slices/article/run.js +0 -145
  694. package/dist/slices/images/run.js +0 -234
  695. package/dist/slices/narration/legacy-plan.js +0 -58
  696. package/dist/slices/narration/run.js +0 -270
  697. package/dist/slices/rebuild/runtime-actions.js +0 -90
  698. package/dist/slices/research/run.js +0 -224
  699. package/dist/slices/subtitles/prepare.js +0 -194
  700. package/dist/slices/subtitles/transcript.js +0 -34
  701. package/dist/slices/thumbnail/run.js +0 -219
  702. package/dist/slices/video/audio-inputs.js +0 -33
  703. package/dist/slices/video/reuse-audio.js +0 -62
  704. package/dist/slices/video/run.js +0 -78
  705. package/dist/slices/video/write-export.js +0 -158
  706. package/dist/slices/video/write-subtitles.js +0 -59
  707. package/dist/tutorials/Library-Overview.md +0 -76
  708. package/dist/tutorials/Play-Images.md +0 -161
  709. package/dist/tutorials/Play-Narration.md +0 -167
  710. package/dist/tutorials/Play-Outputs.md +0 -109
  711. package/dist/tutorials/Play-Overview.md +0 -227
  712. package/dist/tutorials/Play-Title-and-Article.md +0 -136
  713. package/dist/tutorials/Play-Video-and-Style.md +0 -143
  714. package/dist/web/assets/index-BadsoORk.css +0 -1
  715. package/dist/web/assets/index-D8LqNsCl.js +0 -326
  716. package/dist/web/assets/pdf-T7MCwjIv.js +0 -54
  717. package/dist/web/assets/pdf.worker.min-Dswkl-cV.mjs +0 -29
  718. package/dist/web/assets/pdf.worker.min-zC6nfbxG.js +0 -1
@@ -0,0 +1,132 @@
1
+ import { zValidator } from "@hono/zod-validator";
2
+ import { Hono } from "hono";
3
+ import { z } from "zod";
4
+ import { errorText } from "../../kernel/errors.js";
5
+ import { providerFamilies } from "../../kernel/ports/model.js";
6
+ import { autoModes } from "../../slices/model-checks/model.js";
7
+ import { accountOf, markNoticesSeen, writeAuto } from "../../slices/model-checks/repo.js";
8
+ import { costPhrase, dollarsText } from "../../slices/model-checks/rules.js";
9
+ import { providerById, providerIds } from "../../slices/settings/model.js";
10
+ import { onInvalid, problem } from "./problem.js";
11
+ const providerParam = z.object({ id: z.enum(providerIds) });
12
+ const modelList = z.string().min(1).max(200);
13
+ const estimateQuery = z.object({ models: z.string().max(10_000).optional() });
14
+ export const checkBody = z
15
+ .object({
16
+ models: z.array(modelList).max(300).optional(),
17
+ confirmedDollars: z.number().finite().nonnegative().optional(),
18
+ })
19
+ .strict();
20
+ const dismissBody = z
21
+ .object({
22
+ keys: z
23
+ .array(z
24
+ .object({
25
+ provider: z.string().min(1).max(64),
26
+ family: z.enum(providerFamilies),
27
+ model: modelList,
28
+ })
29
+ .strict())
30
+ .max(500),
31
+ })
32
+ .strict();
33
+ const autoBody = z.object({ auto: z.enum(autoModes) }).strict();
34
+ const notReady = "Model checks are not ready yet because Slopify is still starting. Wait a moment, reload the page and try again.";
35
+ export function estimateOf(plan) {
36
+ return {
37
+ count: plan.targets.length,
38
+ totalDollars: plan.totalDollars,
39
+ unpriced: plan.unpriced,
40
+ planAccounts: plan.planAccounts,
41
+ text: dollarsText(plan.totalDollars, plan.unpriced),
42
+ skipped: plan.skipped.map((one) => ({ model: one.model.model, reason: one.reason })),
43
+ };
44
+ }
45
+ function unavailable(c) {
46
+ return problem(c, { status: 503, detail: notReady });
47
+ }
48
+ function noAccount(c, id) {
49
+ const { displayName, auth } = providerById(id);
50
+ return problem(c, {
51
+ status: 400,
52
+ detail: auth === "key"
53
+ ? `No ${displayName} key is saved, so its models can't be checked. Paste a key in Settings → Keys & services → ${displayName} and choose Save, then choose Check models in Settings → Models.`
54
+ : `${displayName} is not set up, so its models can't be checked. Set it up in Settings → Keys & services, then choose Check models in Settings → Models.`,
55
+ });
56
+ }
57
+ // The provider-scoped half: its estimate and its Check models button.
58
+ export function providerCheckRoutes(deps) {
59
+ const checks = () => deps.modelChecks;
60
+ const models = (raw) => raw === undefined || raw.trim() === ""
61
+ ? undefined
62
+ : raw
63
+ .split(",")
64
+ .map((one) => one.trim())
65
+ .filter(Boolean);
66
+ return new Hono()
67
+ .get("/:id/models/check/estimate", zValidator("param", providerParam, onInvalid), zValidator("query", estimateQuery, onInvalid), async (c) => {
68
+ const service = checks();
69
+ if (service === undefined)
70
+ return unavailable(c);
71
+ const { id } = c.req.valid("param");
72
+ if (accountOf(deps.db, id) === undefined)
73
+ return noAccount(c, id);
74
+ c.header("Cache-Control", "no-store");
75
+ const plan = await service.plan({
76
+ trigger: "manual",
77
+ provider: id,
78
+ models: models(c.req.valid("query").models),
79
+ });
80
+ return c.json({ provider: id, ...estimateOf(plan) });
81
+ })
82
+ .post("/:id/models/check", zValidator("param", providerParam, onInvalid), zValidator("json", checkBody, onInvalid), async (c) => {
83
+ const service = checks();
84
+ if (service === undefined)
85
+ return unavailable(c);
86
+ const { id } = c.req.valid("param");
87
+ if (accountOf(deps.db, id) === undefined)
88
+ return noAccount(c, id);
89
+ const body = c.req.valid("json");
90
+ const name = providerById(id).displayName;
91
+ const answer = await service.start({ trigger: "manual", provider: id, models: body.models }, body.confirmedDollars);
92
+ if (!answer.ok && answer.reason === "running")
93
+ return problem(c, {
94
+ status: 409,
95
+ detail: `Slopify is already checking ${name}'s models. Wait for it to finish, then choose Check models again in Settings → Models.`,
96
+ });
97
+ if (!answer.ok) {
98
+ const estimate = estimateOf(answer.plan);
99
+ return problem(c, {
100
+ status: 409,
101
+ detail: `Checking ${String(estimate.count)} ${name} model${estimate.count === 1 ? "" : "s"} costs ${costPhrase(estimate.totalDollars, estimate.unpriced)}, and nothing was sent yet. Choose Check models in Settings → Models again and confirm the estimate to go ahead.`,
102
+ extensions: { estimate },
103
+ });
104
+ }
105
+ void answer.done.catch((error) => {
106
+ deps.log.write("warn", "model-checks", {
107
+ detail: `${id}: ${errorText(error)}`,
108
+ });
109
+ });
110
+ return c.json({ provider: id, started: true, ...estimateOf(answer.plan) }, 202);
111
+ });
112
+ }
113
+ // Settings → Models: what each provider's checks found, New for you, and Automatic checks.
114
+ export function modelCheckRoutes(deps) {
115
+ return new Hono()
116
+ .get("/", (c) => {
117
+ const service = deps.modelChecks;
118
+ if (service === undefined)
119
+ return unavailable(c);
120
+ c.header("Cache-Control", "no-store");
121
+ return c.json(service.overview());
122
+ })
123
+ .post("/notices/dismiss", zValidator("json", dismissBody, onInvalid), (c) => {
124
+ markNoticesSeen(deps.db, c.req.valid("json").keys);
125
+ return c.body(null, 204);
126
+ })
127
+ .put("/auto", zValidator("json", autoBody, onInvalid), (c) => {
128
+ const { auto } = c.req.valid("json");
129
+ writeAuto(deps.db, auto);
130
+ return c.json({ auto });
131
+ });
132
+ }
@@ -1,20 +1,14 @@
1
1
  import { zValidator } from "@hono/zod-validator";
2
2
  import { Hono } from "hono";
3
- import { z } from "zod";
3
+ import { errorText } from "../../kernel/errors.js";
4
4
  import { narrationAudio } from "../../slices/narration/peaks.js";
5
5
  import { assetPath } from "../../slices/revisions/mutation-assets.js";
6
6
  import { currentRevisionId } from "../../slices/revisions/repo.js";
7
7
  import { getRevisionView } from "../../slices/revisions/view.js";
8
8
  import { outputPath } from "../../slices/storage/layout.js";
9
9
  import { projectTitle } from "../../slices/storage/repo.js";
10
- import { onInvalid, problem, titleOf } from "./problem.js";
11
- const projectParam = z.object({
12
- projectId: z
13
- .string()
14
- .min(1)
15
- .max(64)
16
- .regex(/^[0-9A-Za-z_-]+$/),
17
- });
10
+ import { projectIdParam } from "./ids.js";
11
+ import { onInvalid, problem } from "./problem.js";
18
12
  // ceiling: a few projects' worth of pieces. An asset never changes, so a cached row is never
19
13
  // stale; the oldest goes first.
20
14
  const cachedPieces = 400;
@@ -22,12 +16,11 @@ const cachedPieces = 400;
22
16
  // version, fetched again each time a `narration.piece` event says one landed.
23
17
  export function narrationPeakRoutes(deps) {
24
18
  const cache = new Map();
25
- return new Hono().get("/:projectId/narration/peaks", zValidator("param", projectParam, onInvalid), async (c) => {
19
+ return new Hono().get("/:projectId/narration/peaks", zValidator("param", projectIdParam, onInvalid), async (c) => {
26
20
  const { projectId } = c.req.valid("param");
27
21
  if (projectTitle(deps.db, projectId) === undefined)
28
22
  return problem(c, {
29
23
  status: 404,
30
- title: titleOf(404),
31
24
  detail: "This project no longer exists. Go back to Projects to pick another.",
32
25
  });
33
26
  c.header("Cache-Control", "no-store");
@@ -43,7 +36,6 @@ export function narrationPeakRoutes(deps) {
43
36
  if (decode === undefined)
44
37
  return problem(c, {
45
38
  status: 503,
46
- title: titleOf(503),
47
39
  detail: "Slopify can't draw the narration waveform because ffmpeg isn't available. Restart Slopify; if it keeps happening, use Download diagnostics in Settings and report it.",
48
40
  });
49
41
  const audio = narrationAudio(view);
@@ -58,7 +50,7 @@ export function narrationPeakRoutes(deps) {
58
50
  deps.log.write("warn", "narration.peaks", {
59
51
  projectId,
60
52
  stage: "audio",
61
- detail: error instanceof Error ? error.message : String(error),
53
+ detail: errorText(error),
62
54
  });
63
55
  continue;
64
56
  }
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { zValidator } from "@hono/zod-validator";
3
3
  import { Hono } from "hono";
4
4
  import { z } from "zod";
5
- import { defaultSpeechVoice, detectSpeechCached, primaryLanguage, } from "../../kernel/ports/system-speech.js";
5
+ import { defaultSpeechVoice, detectSpeechCached, forgetDetectedSpeech, primaryLanguage, speechInstall, } from "../../kernel/ports/system-speech.js";
6
6
  import { loudnessOfDefault } from "../../slices/loudness/model.js";
7
7
  import { firstRunView } from "../../slices/onboarding/first-run.js";
8
8
  import { fullVideoDraft } from "../../slices/onboarding/full-video.js";
@@ -15,10 +15,11 @@ import { dismissFirstRun, recordShortRequest, shortRequestProject, } from "../..
15
15
  import { systemVoiceProvider } from "../../slices/settings/model.js";
16
16
  import { readSettings } from "../../slices/settings/playback.js";
17
17
  import { providerStatuses } from "../../slices/settings/readiness.js";
18
- import { listVoices } from "../../slices/settings/repo.js";
18
+ import { listVoices, writeSetting } from "../../slices/settings/repo.js";
19
19
  import { addVoice } from "../../slices/settings/voices.js";
20
20
  import { projectTitle } from "../../slices/storage/repo.js";
21
- import { onInvalid, problem, titleOf } from "./problem.js";
21
+ import { autostartAnsweredKey } from "../autostart/model.js";
22
+ import { onInvalid, problem } from "./problem.js";
22
23
  import { createProject } from "./project-create.js";
23
24
  const packParam = z.object({ id: z.string().min(1).max(40) });
24
25
  // The first five minutes: the first-run screen's state, starter packs, "Make a 60-second
@@ -30,7 +31,16 @@ export function onboardingRoutes(deps) {
30
31
  hostCliStatus: deps.hostCliStatus,
31
32
  host: deps.speechHost,
32
33
  });
33
- const speech = () => detectSpeechCached(deps.probe, deps.speechHost ?? process);
34
+ const host = deps.speechHost ?? process;
35
+ const speech = () => detectSpeechCached(deps.probe, host);
36
+ const view = async () => firstRunView(deps.db, await statuses(), speechInstall(host));
37
+ // Done with the first-run screen (Skip, Done, a first short, or a project made elsewhere):
38
+ // it also answers "Start Slopify when I log in" as No, so a fresh install is never asked it
39
+ // in a dialog over Home. The screen's own row and Settings → General still turn it on.
40
+ const doneWithFirstRun = () => {
41
+ dismissFirstRun(deps.db, deps.clock.now().toISOString());
42
+ writeSetting(deps.db, autostartAnsweredKey, "1");
43
+ };
34
44
  // The best speech program found and its English voice, for a short made without a voice key.
35
45
  const systemVoicePick = async () => {
36
46
  const engine = (await speech()).engines[0];
@@ -53,10 +63,16 @@ export function onboardingRoutes(deps) {
53
63
  return new Hono()
54
64
  .get("/", async (c) => {
55
65
  c.header("Cache-Control", "no-store");
56
- return c.json(firstRunView(deps.db, await statuses()));
66
+ return c.json(await view());
67
+ })
68
+ .post("/check", async (c) => {
69
+ // The checklist's Check again: looks for a speech program afresh instead of answering
70
+ // from the last minute's look, so a program installed a moment ago is found.
71
+ forgetDetectedSpeech(deps.probe);
72
+ return c.json(await view());
57
73
  })
58
74
  .post("/dismiss", (c) => {
59
- dismissFirstRun(deps.db, deps.clock.now().toISOString());
75
+ doneWithFirstRun();
60
76
  return c.json({ dismissed: true });
61
77
  })
62
78
  .post("/packs/:id", zValidator("param", packParam, onInvalid), (c) => {
@@ -64,8 +80,7 @@ export function onboardingRoutes(deps) {
64
80
  if (!installed.ok)
65
81
  return problem(c, {
66
82
  status: 404,
67
- title: titleOf(404),
68
- detail: "Slopify doesn't have that starter pack. Reload the page and pick one of the packs listed.",
83
+ detail: "Slopify doesn't have that starter template. Reload the page and pick one of the templates listed.",
69
84
  });
70
85
  return c.json(installed.value);
71
86
  })
@@ -78,14 +93,12 @@ export function onboardingRoutes(deps) {
78
93
  if (pack === undefined)
79
94
  return problem(c, {
80
95
  status: 404,
81
- title: titleOf(404),
82
- detail: "Slopify doesn't have that starter pack. Reload the page and pick one of the packs listed.",
96
+ detail: "Slopify doesn't have that starter template. Reload the page and pick one of the templates listed.",
83
97
  });
84
98
  const modelsFor = deps.modelsFor;
85
99
  if (modelsFor === undefined)
86
100
  return problem(c, {
87
101
  status: 503,
88
- title: titleOf(503),
89
102
  detail: "Slopify can't list the models on this machine right now. Restart Slopify and try again.",
90
103
  });
91
104
  const plan = await planShortProviders({
@@ -94,11 +107,11 @@ export function onboardingRoutes(deps) {
94
107
  modelsFor,
95
108
  suggested: pack.voice,
96
109
  systemVoice: await systemVoicePick(),
110
+ install: speechInstall(host),
97
111
  });
98
112
  if (!plan.ok)
99
113
  return problem(c, {
100
114
  status: 409,
101
- title: titleOf(409),
102
115
  detail: plan.gaps.map((gap) => gap.message).join(" "),
103
116
  extensions: { gaps: plan.gaps },
104
117
  });
@@ -106,8 +119,7 @@ export function onboardingRoutes(deps) {
106
119
  if (!installed.ok)
107
120
  return problem(c, {
108
121
  status: 404,
109
- title: titleOf(404),
110
- detail: "Slopify doesn't have that starter pack. Reload the page and pick one of the packs listed.",
122
+ detail: "Slopify doesn't have that starter template. Reload the page and pick one of the templates listed.",
111
123
  });
112
124
  // The computer's voice is saved like any other, so Play and a later rebuild offer it.
113
125
  const audio = plan.providers.audio;
@@ -135,13 +147,12 @@ export function onboardingRoutes(deps) {
135
147
  if (!created.ok)
136
148
  return problem(c, {
137
149
  status: created.status,
138
- title: titleOf(created.status),
139
150
  detail: `${created.detail} ${created.fields.map((field) => field.message).join(" ")}`.trim(),
140
151
  ...(created.fields.length === 0 ? {} : { extensions: { fields: created.fields } }),
141
152
  });
142
153
  recordShortRequest(deps.db, input.requestId, created.project.id);
143
154
  // A real project now exists, so the first-run screen is done with.
144
- dismissFirstRun(deps.db, deps.clock.now().toISOString());
155
+ doneWithFirstRun();
145
156
  return c.json({ projectId: created.project.id, replayed: false }, 201);
146
157
  })
147
158
  .post("/full-video", zValidator("json", fullVideoInputSchema, onInvalid), (c) => {
@@ -151,19 +162,16 @@ export function onboardingRoutes(deps) {
151
162
  if (made.reason === "not-found")
152
163
  return problem(c, {
153
164
  status: 404,
154
- title: titleOf(404),
155
- detail: "This short or its starter pack is no longer here, so Play couldn't be set up from it. Open Play and pick a template yourself.",
165
+ detail: "This short or its starter template is no longer here, so Create couldn't be set up from it. Open Create and pick a template yourself.",
156
166
  });
157
167
  if (made.reason === "not-short")
158
168
  return problem(c, {
159
169
  status: 409,
160
- title: titleOf(409),
161
- detail: "This project is already a long video. Open Play to start another one on a new topic.",
170
+ detail: "This project is already a long video. Open Create to start another one on a new topic.",
162
171
  });
163
172
  return problem(c, {
164
173
  status: 409,
165
- title: titleOf(409),
166
- detail: "Slopify couldn't open a Play draft for the full video. Press Make the full video on this topic again; if it keeps failing, open Play and pick the pack's template in Library → Templates.",
174
+ detail: "Slopify couldn't open a draft on Create for the full video. Press Make the full video on this topic again; if it keeps failing, press Make a video on the starter template in Templates.",
167
175
  extensions: { reason: made.reason },
168
176
  });
169
177
  })
@@ -176,7 +184,6 @@ export function onboardingRoutes(deps) {
176
184
  if (!restored.ok)
177
185
  return problem(c, {
178
186
  status: restored.status,
179
- title: titleOf(restored.status),
180
187
  detail: restored.detail,
181
188
  });
182
189
  return c.json({ projectId: restored.samples.library, samples: restored.samples });
@@ -188,7 +195,6 @@ export function onboardingRoutes(deps) {
188
195
  if (!input.success)
189
196
  return problem(c, {
190
197
  status: 400,
191
- title: titleOf(400),
192
198
  detail: "Slopify couldn't tell which sample to copy. Reload the page and try again.",
193
199
  });
194
200
  const catalogue = deps.catalogue;
@@ -196,14 +202,12 @@ export function onboardingRoutes(deps) {
196
202
  if (catalogue === undefined || id === undefined)
197
203
  return problem(c, {
198
204
  status: 404,
199
- title: titleOf(404),
200
205
  detail: "The sample project isn't here. Bring it back with Settings → Backup & storage → Restore samples, then press Make my own copy.",
201
206
  });
202
207
  const copied = copySample({ ...sample, catalogue: catalogue.read() }, id);
203
208
  if (!copied.ok)
204
209
  return problem(c, {
205
210
  status: copied.status,
206
- title: titleOf(copied.status),
207
211
  detail: copied.detail,
208
212
  });
209
213
  deps.hub.emitGlobal({ type: "project.updated", projectId: copied.projectId });
@@ -4,25 +4,21 @@ import { z } from "zod";
4
4
  import { assetOf, findDownload } from "../../slices/storage/downloads.js";
5
5
  import { outputsOf } from "../../slices/storage/repo.js";
6
6
  import { replyForFolder } from "./folder-location.js";
7
- import { onInvalid, problem, titleOf } from "./problem.js";
7
+ import { idString } from "./ids.js";
8
+ import { onInvalid, problem } from "./problem.js";
9
+ import { fromSlopifyPage } from "./same-page.js";
8
10
  export function openFolderRoutes(deps) {
9
11
  return new Hono().post("/:id/open-folder", zValidator("param", z.object({
10
- id: z
11
- .string()
12
- .min(1)
13
- .max(64)
14
- .regex(/^[0-9A-Za-z_-]+$/),
12
+ id: idString,
15
13
  }), onInvalid), zValidator("json", z.object({
16
14
  asset: z
17
15
  .string()
18
16
  .max(64)
19
17
  .regex(/^(?:[a-z0-9-]+|images\.zip)$/),
20
18
  }), onInvalid), async (c) => {
21
- const origin = c.req.header("origin");
22
- if (origin !== undefined && origin !== new URL(c.req.url).origin) {
19
+ if (!fromSlopifyPage(c, deps.remoteAccess?.remoteHost)) {
23
20
  return problem(c, {
24
21
  status: 403,
25
- title: titleOf(403),
26
22
  detail: "For your safety, folders can only be opened from the Slopify page itself. Open Slopify and try again there.",
27
23
  });
28
24
  }
@@ -40,7 +36,6 @@ export function openFolderRoutes(deps) {
40
36
  if (download === undefined || !download.ok) {
41
37
  return problem(c, {
42
38
  status: 404,
43
- title: titleOf(404),
44
39
  detail: "This output's file was deleted or moved. Use More → make it again in its section on the project page to make it again.",
45
40
  });
46
41
  }
@@ -1,17 +1,11 @@
1
1
  import { zValidator } from "@hono/zod-validator";
2
2
  import { Hono } from "hono";
3
- import { z } from "zod";
3
+ import { editSettings } from "../../kernel/ports/settings-places.js";
4
4
  import { addOutputPreviewRequestSchema, addOutputRequestSchema, } from "../../slices/outputs/model.js";
5
5
  import { addOutput, previewAddedOutput, } from "../../slices/outputs/service.js";
6
6
  import { currentRevisionId } from "../../slices/revisions/repo.js";
7
- import { onInvalid, problem, titleOf } from "./problem.js";
8
- const projectParam = z.object({
9
- id: z
10
- .string()
11
- .min(1)
12
- .max(64)
13
- .regex(/^[0-9A-Za-z_-]+$/),
14
- });
7
+ import { idParam } from "./ids.js";
8
+ import { onInvalid, problem } from "./problem.js";
15
9
  const statuses = {
16
10
  "no-project": 404,
17
11
  "no-revision": 404,
@@ -28,10 +22,10 @@ const details = {
28
22
  "no-revision": "This saved version of the project no longer exists. Reload the page, then open Add another output again.",
29
23
  conflict: "This project changed while you were choosing. Reload the page, then open Add another output again.",
30
24
  "idempotency-conflict": "This output was already requested with different details. Reload the page, then try again.",
31
- "invalid-edit": "This project is missing a choice the new output needs. Set the fields listed in this project's Settings, save, then add the output again.",
25
+ "invalid-edit": "This project is missing a choice the new output needs. Set the fields listed in Edit settings, save, then add the output again.",
32
26
  already: "This project already makes that output. Find it in its section on the left.",
33
27
  "needs-article": "That output is made from the article, which this project does not have yet. Wait for the Article step to finish, then add it.",
34
- "narration-taken": "This project already has narration, and a project has one. Keep it, or change its format under Speakers in this project's Settings → Providers.",
28
+ "narration-taken": `This project already has narration, and a project has one. Keep it, or change its format under Speakers in ${editSettings.narration}.`,
35
29
  "adaptation-not-accepted": 'This output rewrites your article as a conversation. Tick "Adapt my article into a conversation" in Add another output, then add it.',
36
30
  };
37
31
  // Add another output: what it reuses, makes and costs, then the revision that switches it on.
@@ -41,7 +35,6 @@ export function outputRoutes(deps) {
41
35
  const status = statuses[value.reason];
42
36
  return problem(c, {
43
37
  status,
44
- title: titleOf(status),
45
38
  detail: value.message ?? details[value.reason],
46
39
  extensions: {
47
40
  reason: value.reason,
@@ -51,12 +44,12 @@ export function outputRoutes(deps) {
51
44
  });
52
45
  };
53
46
  return new Hono()
54
- .post("/:id/outputs/preview", zValidator("param", projectParam, onInvalid), zValidator("json", addOutputPreviewRequestSchema, onInvalid), (c) => {
47
+ .post("/:id/outputs/preview", zValidator("param", idParam, onInvalid), zValidator("json", addOutputPreviewRequestSchema, onInvalid), (c) => {
55
48
  const projectId = c.req.valid("param").id;
56
49
  const result = previewAddedOutput(service, { projectId, ...c.req.valid("json") });
57
50
  return result.ok ? c.json(result.value) : refused(c, projectId, result);
58
51
  })
59
- .post("/:id/outputs", zValidator("param", projectParam, onInvalid), zValidator("json", addOutputRequestSchema, onInvalid), async (c) => {
52
+ .post("/:id/outputs", zValidator("param", idParam, onInvalid), zValidator("json", addOutputRequestSchema, onInvalid), async (c) => {
60
53
  const projectId = c.req.valid("param").id;
61
54
  const result = await addOutput(service, { projectId, ...c.req.valid("json") });
62
55
  if (!result.ok)
@@ -1,14 +1,9 @@
1
1
  import { Hono } from "hono";
2
2
  import { bundledPatchNotesDir, PatchNotesMissing, readPatchNote, } from "../../slices/patch-notes/library.js";
3
3
  import { markPatchNotesSeen, readPatchNotes } from "../../slices/patch-notes/seen.js";
4
- import { problem, titleOf } from "./problem.js";
5
- // A build without its notes says so in plain words; anything else is the app's error handler's.
6
- function missing(c, error) {
7
- if (!(error instanceof PatchNotesMissing))
8
- throw error;
9
- return problem(c, { status: 500, title: titleOf(500), detail: error.message });
10
- }
11
- // Settings → Patch notes: the list (with which note is due to open by itself), one note's
4
+ import { problem } from "./problem.js";
5
+ import { bundleMissing } from "./refusal.js";
6
+ // Settings → What's new: the list (with which note is due to open by itself), one note's
12
7
  // Markdown, and recording that the note that opened by itself was closed.
13
8
  // Preserve Hono's inferred route types for the web client.
14
9
  export function patchNotesRoutes(deps) {
@@ -19,7 +14,7 @@ export function patchNotesRoutes(deps) {
19
14
  return c.json(await readPatchNotes(deps.db, dir, deps.version));
20
15
  }
21
16
  catch (error) {
22
- return missing(c, error);
17
+ return bundleMissing(c, error, PatchNotesMissing);
23
18
  }
24
19
  })
25
20
  .post("/seen", (c) => {
@@ -32,13 +27,12 @@ export function patchNotesRoutes(deps) {
32
27
  markdown = await readPatchNote(dir, c.req.param("id"));
33
28
  }
34
29
  catch (error) {
35
- return missing(c, error);
30
+ return bundleMissing(c, error, PatchNotesMissing);
36
31
  }
37
32
  if (markdown === undefined)
38
33
  return problem(c, {
39
34
  status: 404,
40
- title: titleOf(404),
41
- detail: "These patch notes are not in this version of Slopify. Open Settings → Patch notes and pick one from the list.",
35
+ detail: "These patch notes are not in this version of Slopify. Open Settings → What's new and pick one from the list.",
42
36
  });
43
37
  return c.body(markdown, 200, { "content-type": "text/markdown; charset=utf-8" });
44
38
  });
@@ -10,7 +10,7 @@ import { estimateRun } from "../../slices/estimate/index.js";
10
10
  import { resolveFont } from "../../slices/fonts/index.js";
11
11
  import { pickTemplates, renderPicked } from "../../slices/library/slots.js";
12
12
  import { stagedFiles } from "../../slices/storage/repo.js";
13
- import { onInvalid, problem, titleOf } from "./problem.js";
13
+ import { onInvalid, problem } from "./problem.js";
14
14
  const planningBody = z.object({
15
15
  draft: runDraftSchema,
16
16
  expectedWords: z.number().int().min(1).max(100000).default(1500),
@@ -42,6 +42,7 @@ export function planningRoutes(deps) {
42
42
  draft: picked.draft,
43
43
  staged: stagedFiles(deps.db),
44
44
  requiredSlots: picked.requiredSlots,
45
+ keywordUses: picked.keywordUses,
45
46
  });
46
47
  const accepted = admitted.ok ? admitted.draft : picked.draft;
47
48
  const fields = [
@@ -69,7 +70,6 @@ export function planningRoutes(deps) {
69
70
  return c.json({ queue: result.queue });
70
71
  return problem(c, {
71
72
  status: 409,
72
- title: titleOf(409),
73
73
  detail: result.reason === "edge"
74
74
  ? "This video is already at that end of the waiting videos, so it can't move further."
75
75
  : "This video has already started or left the queue, so its place can't change. The queue has been read again.",
@@ -82,7 +82,6 @@ export function planningRoutes(deps) {
82
82
  if (fields.length)
83
83
  return problem(c, {
84
84
  status: 400,
85
- title: titleOf(400),
86
85
  detail: "Some settings need fixing before Slopify can estimate the cost. Fix the highlighted fields.",
87
86
  extensions: { fields },
88
87
  });
@@ -95,8 +94,7 @@ export function planningRoutes(deps) {
95
94
  if (input.draft.checkpoints?.length)
96
95
  return problem(c, {
97
96
  status: 409,
98
- title: titleOf(409),
99
- detail: "Videos with checkpoints turned on cannot be queued. Start them one at a time from Play with Review and start.",
97
+ detail: "Videos that pause for your review (Pauses and checks) can't be queued. Make them one at a time from Create.",
100
98
  });
101
99
  if (batchExists(deps.db, input.requestId))
102
100
  return c.json({ queue: queueEntries(deps.db, input.requestId) });
@@ -108,7 +106,6 @@ export function planningRoutes(deps) {
108
106
  catch {
109
107
  return problem(c, {
110
108
  status: 400,
111
- title: titleOf(400),
112
109
  detail: "The subtitle font you picked is no longer available. Choose another font before starting.",
113
110
  });
114
111
  }
@@ -118,7 +115,6 @@ export function planningRoutes(deps) {
118
115
  if (fields.length)
119
116
  return problem(c, {
120
117
  status: 400,
121
- title: titleOf(400),
122
118
  detail: "No videos were queued. Fix the highlighted fields, then try again.",
123
119
  extensions: { fields },
124
120
  });
@@ -1,6 +1,7 @@
1
1
  import { HTTPException } from "hono/http-exception";
2
2
  const titles = {
3
3
  400: "Bad Request",
4
+ 403: "Forbidden",
4
5
  404: "Not Found",
5
6
  409: "Conflict",
6
7
  415: "Unsupported Media Type",
@@ -12,7 +13,7 @@ export function problem(c, init) {
12
13
  // Extensions go first so a route cannot shadow a member RFC 9457 reserves.
13
14
  ...init.extensions,
14
15
  type: init.type ?? "about:blank",
15
- title: init.title,
16
+ title: init.title ?? titleOf(init.status),
16
17
  status: init.status,
17
18
  ...(init.detail === undefined ? {} : { detail: init.detail }),
18
19
  instance: c.req.path,
@@ -25,7 +26,6 @@ export function problemFromError(c, error, deps) {
25
26
  if (error instanceof HTTPException) {
26
27
  return problem(c, {
27
28
  status: error.status,
28
- title: titleOf(error.status),
29
29
  detail: error.message === "" ? undefined : error.message,
30
30
  });
31
31
  }
@@ -38,7 +38,6 @@ export function problemFromError(c, error, deps) {
38
38
  });
39
39
  return problem(c, {
40
40
  status: 500,
41
- title: titleOf(500),
42
41
  detail: `Slopify hit an internal error while handling this request. Try again; if it keeps happening, use Download diagnostics in Settings and report it (reference ${correlationId}).`,
43
42
  extensions: { correlationId },
44
43
  });
@@ -54,7 +53,6 @@ export function onInvalid(result, c) {
54
53
  }
55
54
  return problem(c, {
56
55
  status: 400,
57
- title: titleOf(400),
58
56
  detail: "Slopify could not read this request, which usually means the page is out of date. Reload the page and try again.",
59
57
  extensions: {
60
58
  errors: result.error.issues.map((issue) => ({
@@ -18,7 +18,7 @@ export async function createProject(deps, sent) {
18
18
  return {
19
19
  ok: false,
20
20
  status: 409,
21
- detail: "This project has checkpoints turned on, so it must be started from Play with Review and start.",
21
+ detail: "This project pauses for your review (Pauses and checks), so it starts from Create: press Make the video there.",
22
22
  fields: [],
23
23
  };
24
24
  const subtitles = draft.subtitles;
@@ -47,6 +47,7 @@ export async function createProject(deps, sent) {
47
47
  draft: picked.draft,
48
48
  staged: stagedFiles(deps.db),
49
49
  requiredSlots: picked.requiredSlots,
50
+ keywordUses: picked.keywordUses,
50
51
  });
51
52
  const modelErrors = modelFields(picked.draft, deps.catalogue);
52
53
  if (!admitted.ok || picked.missing.length > 0 || modelErrors.length > 0)