@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
@@ -17,21 +17,12 @@ import { currentRevisionId } from "../../slices/revisions/repo.js";
17
17
  import { allowsCustomModel } from "../../slices/settings/models.js";
18
18
  import { providerStatuses } from "../../slices/settings/readiness.js";
19
19
  import { outputsOf } from "../../slices/storage/repo.js";
20
- import { onInvalid, problem, titleOf } from "./problem.js";
21
- const idParam = z.object({
22
- id: z
23
- .string()
24
- .min(1)
25
- .max(64)
26
- .regex(/^[0-9A-Za-z_-]+$/),
27
- });
20
+ import { idParam, idString } from "./ids.js";
21
+ import { onInvalid, problem } from "./problem.js";
22
+ import { revisionRequired } from "./refusal.js";
28
23
  const stageParam = idParam.extend({ kind: z.enum(stageKinds) });
29
24
  const imageParam = idParam.extend({
30
- outputId: z
31
- .string()
32
- .min(1)
33
- .max(64)
34
- .regex(/^[0-9A-Za-z_-]+$/),
25
+ outputId: idString,
35
26
  });
36
27
  // The return type is inferred so Hono keeps the route types the SPA's client is
37
28
  // generated from; see stagingRoutes.
@@ -105,11 +96,10 @@ export function actionRoutes(deps) {
105
96
  "revision-required": "This page is out of date. Reload the page, then try again.",
106
97
  conflict: "This project changed since the page loaded. Reload the page to see the latest, then try again.",
107
98
  "idempotency-conflict": "This action was already sent with different details. Reload the page, then try again.",
108
- "rebuild-required": "This change needs some outputs to be made again. In the Edit tab, use Choose what to remake (in the project's More menu) to see what will be regenerated and what it costs.",
99
+ "rebuild-required": "This change needs some outputs to be made again. Use Choose what to make again (in the project's More menu) to see what will be made again and what it costs.",
109
100
  };
110
101
  return problem(c, {
111
102
  status: codes[result.reason],
112
- title: titleOf(codes[result.reason]),
113
103
  detail: messages[result.reason],
114
104
  extensions: {
115
105
  reason: result.reason,
@@ -122,7 +112,6 @@ export function actionRoutes(deps) {
122
112
  if (deps.rebuild === undefined)
123
113
  return problem(c, {
124
114
  status: 503,
125
- title: titleOf(503),
126
115
  detail: "Resume and retry are not ready yet because Slopify is still starting. Wait a moment, reload the page and try again.",
127
116
  });
128
117
  const result = recoveryResultSchema.parse(await recoverProject(deps.rebuild, id, { ...input, action }));
@@ -138,13 +127,13 @@ export function actionRoutes(deps) {
138
127
  "no-revision": "The project's saved settings changed since the page loaded. Reload the page, then try again.",
139
128
  conflict: "This project changed since the page loaded. Reload the page to see the latest, then use Continue the run again.",
140
129
  "idempotency-conflict": "This action was already sent with different details. Reload the page, then try again.",
141
- "invalid-edit": "This section has settings that need fixing first. Open the Edit tab, choose Edit project and correct this section, then try again.",
130
+ "invalid-edit": "This section has settings that need fixing first. Correct this section in Edit settings, then try again.",
142
131
  "stale-preview": "What needs to be made changed since the page loaded. Reload the page, then use Continue the run again.",
143
- "invalid-selection": "This section has nothing generated to re-run because its content was supplied by you. To change it, open the Edit tab and choose Edit project.",
144
- "review-required": "Content you supplied or captions you edited by hand would be replaced. Change them in the Edit tab with Edit project, or use Choose what to remake (in the project's More menu) to confirm the replacement.",
145
- "cost-ack-required": "This re-run needs you to review its cost first. In the Edit tab, use Choose what to remake (in the project's More menu).",
132
+ "invalid-selection": "This section has nothing generated to make again because its content was supplied by you. To change it, use Edit settings.",
133
+ "review-required": "Content you supplied or captions you edited by hand would be replaced. Change them in Edit settings, or use Choose what to make again (in the project's More menu) to confirm the replacement.",
134
+ "cost-ack-required": "Making this again needs you to review its cost first. Use Choose what to make again (in the project's More menu).",
146
135
  readiness: "Slopify cannot run this yet. Check the provider, model, voice and any files you supplied, then use Continue the run.",
147
- running: "This section is still running. Wait for it to finish, or Pause the project, before re-running it.",
136
+ running: "This section is still running. Wait for it to finish, or Pause the project, before making it again.",
148
137
  "accepted-job": "This section has a finished provider job that Slopify has not collected yet.",
149
138
  "control-changed": "Another action on this project (such as Pause or Cancel) happened at the same time. Reload the page to see its current state, then try again.",
150
139
  };
@@ -154,12 +143,11 @@ export function actionRoutes(deps) {
154
143
  ...(result.intentRevisionId === undefined
155
144
  ? []
156
145
  : [
157
- "Your re-run request was saved. Use Continue the run to continue it instead of re-running again.",
146
+ "Your request to make it again was saved. Use Continue the run to go on with it instead of asking again.",
158
147
  ]),
159
148
  ].join(" ");
160
149
  return problem(c, {
161
150
  status,
162
- title: titleOf(status),
163
151
  detail,
164
152
  extensions: {
165
153
  reason: result.reason,
@@ -222,7 +210,6 @@ export function actionRoutes(deps) {
222
210
  if (keys.length === 0)
223
211
  return problem(c, {
224
212
  status: 409,
225
- title: titleOf(409),
226
213
  detail: "Nothing in this section was refused by a content filter, so there is no prompt to soften. Reload the page; if the section still shows an error, use Try again.",
227
214
  extensions: { reason: "nothing-refused" },
228
215
  });
@@ -243,11 +230,3 @@ export function actionRoutes(deps) {
243
230
  .delete("/:id/images/:outputId", zValidator("param", imageParam, onInvalid), revisionRequired)
244
231
  .post("/:id/images/:outputId/regenerate", zValidator("param", imageParam, onInvalid), revisionRequired));
245
232
  }
246
- function revisionRequired(c) {
247
- return problem(c, {
248
- status: 409,
249
- title: titleOf(409),
250
- detail: "This change is now made from the Edit tab. Choose Edit project, save your change, then use Choose what to remake (in the project's More menu).",
251
- extensions: { reason: "revision-required" },
252
- });
253
- }
@@ -2,9 +2,11 @@
2
2
  // No network request can set them (the Node server passes its own `{ incoming, outgoing }`),
3
3
  // which is how a route knows an agent asked, not the person.
4
4
  export const agentBindings = { actor: "agent" };
5
+ // The in-app assistant's calls, through its own MCP endpoint (`/mcp/assistant`).
6
+ export const assistantBindings = { actor: "assistant" };
5
7
  export function actorOf(c) {
6
8
  const env = c.env;
7
- return typeof env === "object" && env !== null && "actor" in env && env.actor === "agent"
8
- ? "agent"
9
- : "person";
9
+ if (typeof env !== "object" || env === null || !("actor" in env))
10
+ return "person";
11
+ return env.actor === "agent" || env.actor === "assistant" ? env.actor : "person";
10
12
  }
@@ -4,9 +4,12 @@ import { Hono } from "hono";
4
4
  import { streamSSE } from "hono/streaming";
5
5
  import { mcpPath } from "../../slices/agents/model.js";
6
6
  import { isSampleProject } from "../../slices/onboarding/sample.js";
7
+ import { sampleOwner } from "../../slices/template-studio/repo.js";
8
+ import { assistantMcpPath, assistantMcpRoutes, runAllowedCall } from "../mcp/assistant.js";
7
9
  import { mcpRoutes } from "../mcp/http.js";
8
10
  import { actionRoutes } from "./actions.js";
9
- import { agentBindings } from "./actor.js";
11
+ import { agentBindings, assistantBindings } from "./actor.js";
12
+ import { assistantRoutes } from "./assistant.js";
10
13
  import { audioPreviewRoutes } from "./audio-preview.js";
11
14
  import { auditionRoutes } from "./auditions.js";
12
15
  import { autostartRoutes } from "./autostart.js";
@@ -14,6 +17,8 @@ import { backupRoutes } from "./backups.js";
14
17
  import { channelMemoryRoutes } from "./channel-memory.js";
15
18
  import { channelRoutes } from "./channels.js";
16
19
  import { checkpointRoutes } from "./checkpoints.js";
20
+ import { designTemplateRoutes } from "./design-templates.js";
21
+ import { designRoutes } from "./designs.js";
17
22
  import { diagnosticsRoutes } from "./diagnostics.js";
18
23
  import { documentThemeRoutes } from "./document-themes.js";
19
24
  import { draftRoutes } from "./drafts.js";
@@ -22,24 +27,31 @@ import { externalReviewRoutes } from "./external-reviews.js";
22
27
  import { fileRoutes } from "./files.js";
23
28
  import { fontsRoutes } from "./fonts.js";
24
29
  import { homeRoutes, uploadedRoutes } from "./home.js";
30
+ import { keywordRoutes } from "./keywords.js";
31
+ import { modelCheckRoutes, providerCheckRoutes } from "./model-checks.js";
25
32
  import { narrationPeakRoutes } from "./narration-peaks.js";
26
33
  import { onboardingRoutes } from "./onboarding.js";
27
34
  import { openFolderRoutes } from "./open-folder.js";
28
35
  import { outputRoutes } from "./outputs.js";
29
36
  import { patchNotesRoutes } from "./patch-notes.js";
30
37
  import { planningRoutes } from "./planning.js";
31
- import { problem, problemFromError, titleOf } from "./problem.js";
38
+ import { problem, problemFromError } from "./problem.js";
32
39
  import { projectTemplateRoutes } from "./project-templates.js";
33
40
  import { projectRoutes } from "./projects.js";
34
41
  import { promptRoutes } from "./prompts.js";
35
42
  import { pronunciationRoutes } from "./pronunciations.js";
36
43
  import { providerRoutes } from "./providers.js";
44
+ import { remoteAccessRoutes } from "./remote-access.js";
45
+ import { remoteGuard } from "./remote-guard.js";
46
+ import { requestGuard } from "./request-guard.js";
37
47
  import { reviewRoutes } from "./reviews.js";
38
48
  import { revisionFileRoutes, revisionFolderRoutes } from "./revision-files.js";
39
49
  import { revisionRoutes } from "./revisions.js";
40
50
  import { runCostRoutes } from "./run-cost.js";
51
+ import { viaFunnel } from "./same-page.js";
41
52
  import { calendarRoutes, scheduleRoutes } from "./schedules.js";
42
53
  import { settingsRoutes } from "./settings.js";
54
+ import { socialRoutes } from "./social.js";
43
55
  import { stagingRoutes } from "./staging.js";
44
56
  import { startRecorder } from "./starts.js";
45
57
  import { storageRoutes } from "./storage.js";
@@ -48,6 +60,7 @@ import { studioRoutes } from "./studio.js";
48
60
  import { stylePreviewRoutes } from "./style-preview.js";
49
61
  import { subtitleRoutes } from "./subtitles.js";
50
62
  import { telemetryRoutes } from "./telemetry.js";
63
+ import { templateStudioRoutes } from "./template-studio.js";
51
64
  import { trashRoutes } from "./trash.js";
52
65
  import { tutorialRoutes } from "./tutorial.js";
53
66
  import { tutorialPagesRoutes } from "./tutorials.js";
@@ -57,7 +70,7 @@ import { whatsNewRoutes } from "./whats-new.js";
57
70
  import { youtubeEditRoutes } from "./youtube-edits.js";
58
71
  const notBuilt = "The Slopify UI is not built yet. The API is running: try /api/health.\n" +
59
72
  "Build the SPA with `npm run build` at the repository root.\n";
60
- function apiRoutes(deps, startedAt) {
73
+ function apiRoutes(deps, startedAt, runAllowed) {
61
74
  return (new Hono()
62
75
  .get("/health", (c) => c.json({
63
76
  status: "ok",
@@ -72,9 +85,12 @@ function apiRoutes(deps, startedAt) {
72
85
  .route("/drafts", draftRoutes(deps.drafts))
73
86
  .route("/diagnostics", diagnosticsRoutes(deps))
74
87
  .route("/project-templates", projectTemplateRoutes(deps.drafts))
88
+ .route("/template-studio", templateStudioRoutes(deps))
75
89
  .route("/schedules", scheduleRoutes(deps.schedules))
76
90
  .route("/channels", channelRoutes(deps))
77
91
  .route("/channels", channelMemoryRoutes(deps))
92
+ .route("/designs", designRoutes(deps.designs))
93
+ .route("/design-templates", designTemplateRoutes(deps.designTemplates))
78
94
  .route("/calendar", calendarRoutes(deps.schedules))
79
95
  .route("/projects", planningRoutes(deps))
80
96
  .route("/projects", projectRoutes(deps))
@@ -98,6 +114,7 @@ function apiRoutes(deps, startedAt) {
98
114
  .route("/projects", youtubeEditRoutes(deps))
99
115
  .route("/fonts", fontsRoutes(deps))
100
116
  .route("/prompts", promptRoutes(deps))
117
+ .route("/keywords", keywordRoutes(deps))
101
118
  .route("/entries", entryRoutes(deps))
102
119
  .route("/document-themes", documentThemeRoutes(deps))
103
120
  .route("/pronunciations", pronunciationRoutes(deps))
@@ -105,19 +122,51 @@ function apiRoutes(deps, startedAt) {
105
122
  .route("/telemetry", telemetryRoutes(deps))
106
123
  .route("/usage", usageRoutes(deps))
107
124
  .route("/settings/autostart", autostartRoutes(deps.autostart))
125
+ .route("/settings/remote-access", remoteAccessRoutes(deps.remoteAccess))
108
126
  .route("/settings", settingsRoutes(deps))
109
127
  .route("/studio", studioRoutes(deps))
128
+ .route("/social", socialRoutes(deps))
110
129
  .route("/style-preview", stylePreviewRoutes(deps))
111
130
  .route("/tutorial", tutorialRoutes(deps))
112
131
  .route("/whats-new", whatsNewRoutes(deps))
113
132
  .route("/patch-notes", patchNotesRoutes(deps))
114
133
  .route("/tutorials", tutorialPagesRoutes(deps))
134
+ .route("/providers", providerCheckRoutes(deps))
115
135
  .route("/providers", providerRoutes(deps))
116
- .route("/onboarding", onboardingRoutes(deps)));
136
+ .route("/model-checks", modelCheckRoutes(deps))
137
+ .route("/onboarding", onboardingRoutes(deps))
138
+ .route("/assistant", assistantRoutes(deps, runAllowed)));
117
139
  }
118
140
  export function createApp(deps) {
119
141
  const startedAt = deps.clock.now().getTime();
142
+ // An Allow's call goes through the API in-process as the assistant, like its MCP calls.
143
+ const runAllowed = (call) => runAllowedCall({
144
+ db: deps.db,
145
+ ids: deps.ids,
146
+ clock: deps.clock,
147
+ log: deps.log,
148
+ api: async (request) => app.request(request, undefined, assistantBindings),
149
+ }, call);
120
150
  const app = new Hono()
151
+ // Slopify has no login, so it never answers the public internet. Tailscale marks every
152
+ // request that came through Funnel; Slopify never turns Funnel on, and this holds even if
153
+ // someone else does.
154
+ .use("*", async (c, next) => {
155
+ if (!viaFunnel(c.req.raw.headers))
156
+ return next();
157
+ return problem(c, {
158
+ status: 403,
159
+ detail: "Slopify doesn't answer the public internet: this request came through Tailscale Funnel. On the computer Slopify runs on, run tailscale funnel status to see which port has Funnel, turn it off with tailscale funnel --https=<that port> off, and open Slopify on your other devices through Settings → Remote access instead.",
160
+ });
161
+ })
162
+ // Only Slopify's own names, and changes only from its own page (`request-guard.ts`).
163
+ .use("*", requestGuard({
164
+ listenHost: deps.host,
165
+ remoteHost: deps.remoteAccess?.remoteHost,
166
+ extraHosts: deps.allowedHosts ?? [],
167
+ }))
168
+ // Over remote access: only the account that turned it on, and no host setup.
169
+ .use("*", remoteGuard(deps.remoteAccess))
121
170
  .use("*", async (c, next) => {
122
171
  // A provisional candidate must not trigger the stale-tab Reload dialog.
123
172
  if (!deps.updater?.locked())
@@ -130,14 +179,12 @@ export function createApp(deps) {
130
179
  if (deps.installationPending?.() && new URL(c.req.url).pathname !== "/api/update/activate")
131
180
  return problem(c, {
132
181
  status: 503,
133
- title: titleOf(503),
134
182
  detail: "Slopify is still finishing its Docker setup. Wait for the launcher to finish, then try again.",
135
183
  });
136
184
  const releaseRequest = deps.mutations?.begin();
137
185
  if (deps.mutations !== undefined && releaseRequest === undefined)
138
186
  return problem(c, {
139
187
  status: 503,
140
- title: titleOf(503),
141
188
  detail: "Slopify is shutting down, so changes cannot be saved right now. Start it again, reload the page and try again.",
142
189
  });
143
190
  const updateRoute = [
@@ -151,7 +198,6 @@ export function createApp(deps) {
151
198
  releaseRequest?.();
152
199
  return problem(c, {
153
200
  status: 409,
154
- title: titleOf(409),
155
201
  detail: "Slopify is updating. Wait for it to restart, reload the page and try again.",
156
202
  });
157
203
  }
@@ -176,15 +222,28 @@ export function createApp(deps) {
176
222
  return next();
177
223
  return problem(c, {
178
224
  status: 409,
179
- title: titleOf(409),
180
- detail: "This is the sample project, which is read-only so trying things on it never spends anything. Press Make my own copy at the top of the sample's page, then edit and rebuild the copy.",
225
+ detail: "This is a sample project, which is read-only so trying things on it never spends anything. Press Make my own copy at the top right of its page, then change and make the copy again.",
181
226
  extensions: { reason: "sample-read-only" },
182
227
  });
228
+ })
229
+ // A template's studio sample is changed only through its studio (`slices/template-studio`),
230
+ // whose runner reaches the project's slices directly: no project route may change it.
231
+ .use("/api/projects/:id/*", async (c, next) => {
232
+ if (["GET", "HEAD", "OPTIONS"].includes(c.req.method))
233
+ return next();
234
+ const owner = sampleOwner(deps.db, c.req.param("id"));
235
+ if (owner === undefined)
236
+ return next();
237
+ return problem(c, {
238
+ status: 409,
239
+ detail: `This is the sample project of the template ${owner.name}. Change the template in Edit template instead: Templates → ${owner.name} → Edit template.`,
240
+ extensions: { reason: "template-sample" },
241
+ });
183
242
  })
184
243
  .use("/api/*", startRecorder(deps))
185
244
  .onError((error, c) => problemFromError(c, error, deps))
186
245
  .notFound(missing)
187
- .route("/api", apiRoutes(deps, startedAt))
246
+ .route("/api", apiRoutes(deps, startedAt, runAllowed))
188
247
  .get("/api/events/global", (c) => streamSSE(c, (stream) => deps.hub.subscribeGlobal(stream, c.req.raw.signal)))
189
248
  .get("/api/events/projects/:id", (c) => streamSSE(c, (stream) => deps.hub.subscribe(c.req.param("id"), stream, c.req.raw.signal)))
190
249
  // Files are served by URL, not through the API.
@@ -193,6 +252,23 @@ export function createApp(deps) {
193
252
  // The API answers for its whole prefix, so an unknown endpoint is a problem+json 404
194
253
  // rather than the SPA's index.html with a 200.
195
254
  .all("/api/*", missing);
255
+ const mcpDeps = {
256
+ db: deps.db,
257
+ paths: deps.paths,
258
+ ids: deps.ids,
259
+ clock: deps.clock,
260
+ log: deps.log,
261
+ version: deps.version,
262
+ host: deps.host,
263
+ ...(deps.measureAudio === undefined ? {} : { measureAudio: deps.measureAudio }),
264
+ };
265
+ // The in-app assistant reaches it the same way, as the assistant, with its turn's token.
266
+ // Mounted first: `/mcp` must never answer for it.
267
+ app.route(assistantMcpPath, assistantMcpRoutes({
268
+ ...mcpDeps,
269
+ turns: deps.assistant?.tokens ?? deps.assistantTurns,
270
+ api: async (request) => app.request(request, undefined, assistantBindings),
271
+ }));
196
272
  // Agents reach the same API in-process, as the agent (`actor.ts`): every tool validates,
197
273
  // refuses and answers exactly like the page's own request.
198
274
  app.route(mcpPath, mcpRoutes({
@@ -225,7 +301,6 @@ const sampleReadOnlyExempt = /\/(revisions\/prepare|rebuild\/preview|open-folder
225
301
  function missing(c) {
226
302
  return problem(c, {
227
303
  status: 404,
228
- title: titleOf(404),
229
304
  detail: `${c.req.method} ${c.req.path} is not a route of this API.`,
230
305
  });
231
306
  }
@@ -0,0 +1,129 @@
1
+ import { zValidator } from "@hono/zod-validator";
2
+ import { Hono } from "hono";
3
+ import { z } from "zod";
4
+ import { assistantCliPreferences, assistantScreenSchema, assistantTextMax, } from "../../slices/assistant/model.js";
5
+ import { setCliPreference } from "../../slices/assistant/repo.js";
6
+ import { actorOf } from "./actor.js";
7
+ import { idParam } from "./ids.js";
8
+ import { onInvalid, problem } from "./problem.js";
9
+ import { hostOnlySentence } from "./remote-guard.js";
10
+ import { viaProxy } from "./same-page.js";
11
+ // The assistant panel's chat. The person's own: an agent or the assistant itself is refused
12
+ // here, so nothing but a press in the page answers an ask.
13
+ const messageBody = z
14
+ .object({
15
+ text: z
16
+ .string()
17
+ .trim()
18
+ .min(1, "Write a message first.")
19
+ .max(assistantTextMax, `Keep a message to ${String(assistantTextMax)} characters.`),
20
+ screen: assistantScreenSchema.optional(),
21
+ })
22
+ .strict();
23
+ const answerBody = z.object({ answer: z.enum(["allow", "deny"]) }).strict();
24
+ const cliBody = z.object({ preference: z.enum(assistantCliPreferences) }).strict();
25
+ const notWired = "This copy of Slopify was started without the assistant. Restart Slopify, then open the assistant again.";
26
+ function personOnly(c) {
27
+ return actorOf(c) === "person"
28
+ ? undefined
29
+ : problem(c, {
30
+ status: 403,
31
+ detail: "The assistant's chat is the person's: only a press in Slopify's page sends a message or answers an ask.",
32
+ });
33
+ }
34
+ export function assistantRoutes(deps,
35
+ // On Allow, the asked call is made by Slopify itself (`edge/mcp/assistant.ts`).
36
+ runAllowed) {
37
+ const assistant = deps.assistant;
38
+ const wired = (c) => personOnly(c) ?? assistant ?? problem(c, { status: 503, detail: notWired });
39
+ return new Hono()
40
+ .get("/", async (c) => {
41
+ const refused = personOnly(c);
42
+ if (refused !== undefined)
43
+ return refused;
44
+ if (assistant === undefined)
45
+ return c.json({
46
+ available: false,
47
+ cli: null,
48
+ reason: notWired,
49
+ fix: null,
50
+ preference: "auto",
51
+ ready: [],
52
+ session: null,
53
+ });
54
+ const { choice, preference, ready } = await assistant.status();
55
+ return c.json({
56
+ available: choice.ok,
57
+ cli: choice.ok ? choice.cli : null,
58
+ reason: choice.ok ? null : choice.reason,
59
+ fix: choice.ok ? null : choice.fix,
60
+ preference,
61
+ ready,
62
+ session: assistant.session() ?? null,
63
+ });
64
+ })
65
+ .post("/sessions", (c) => {
66
+ const service = wired(c);
67
+ if (service instanceof Response)
68
+ return service;
69
+ const id = service.newSession();
70
+ return c.json({ session: service.session(id) }, 201);
71
+ })
72
+ .post("/sessions/:id/messages", zValidator("param", idParam, onInvalid), zValidator("json", messageBody, onInvalid), (c) => {
73
+ const service = wired(c);
74
+ if (service instanceof Response)
75
+ return service;
76
+ const { text, screen } = c.req.valid("json");
77
+ const sent = service.send(c.req.valid("param").id, text, screen);
78
+ if (sent.ok)
79
+ return c.json({ turnId: sent.turnId }, 202);
80
+ return problem(c, {
81
+ status: sent.reason === "unknown-session" ? 404 : 409,
82
+ detail: sent.reason === "unknown-session"
83
+ ? "This chat no longer exists. Press New chat and send your message again."
84
+ : sent.reason === "busy"
85
+ ? "The assistant is still answering in this chat. Wait for it, or press Stop, then send your message."
86
+ : "Two assistant chats are answering already. Wait for one to finish, or press Stop in it, then send your message.",
87
+ extensions: { reason: sent.reason },
88
+ });
89
+ })
90
+ .post("/sessions/:id/stop", zValidator("param", idParam, onInvalid), (c) => {
91
+ const service = wired(c);
92
+ if (service instanceof Response)
93
+ return service;
94
+ return c.json({ stopped: service.stop(c.req.valid("param").id) });
95
+ })
96
+ .post("/asks/:id", zValidator("param", idParam, onInvalid), zValidator("json", answerBody, onInvalid), (c) => {
97
+ // An Allow starts paid or removing work: it is pressed on this computer, or on the
98
+ // person's own device through remote access, never by another account (`remote-guard.ts`).
99
+ if (c.req.valid("json").answer === "allow" && viaProxy(c.req.raw.headers))
100
+ return problem(c, {
101
+ status: 403,
102
+ detail: hostOnlySentence("The assistant's Allow is pressed"),
103
+ extensions: { reason: "host-only" },
104
+ });
105
+ const service = wired(c);
106
+ if (service instanceof Response)
107
+ return service;
108
+ const answered = service.answer(c.req.valid("param").id, c.req.valid("json").answer, runAllowed);
109
+ if (answered.ok)
110
+ return c.json({ ask: answered.ask });
111
+ return problem(c, {
112
+ status: answered.reason === "unknown" ? 404 : 409,
113
+ detail: answered.reason === "unknown"
114
+ ? "This ask no longer exists. Ask the assistant again."
115
+ : answered.reason === "expired"
116
+ ? "This ask waited more than 15 minutes, so it expired before your answer. Ask the assistant again, so it can check the cost again."
117
+ : "This ask was already answered.",
118
+ extensions: { reason: answered.reason },
119
+ });
120
+ })
121
+ .put("/cli", zValidator("json", cliBody, onInvalid), (c) => {
122
+ const refused = personOnly(c);
123
+ if (refused !== undefined)
124
+ return refused;
125
+ const { preference } = c.req.valid("json");
126
+ setCliPreference(deps.db, preference);
127
+ return c.json({ preference });
128
+ });
129
+ }
@@ -4,18 +4,12 @@ import { z } from "zod";
4
4
  import { currentRevisionId } from "../../slices/revisions/repo.js";
5
5
  import { projectTitle } from "../../slices/storage/repo.js";
6
6
  import { currentWorkOrigin } from "../events/visibility.js";
7
- import { onInvalid, problem, titleOf } from "./problem.js";
8
- const projectParam = z.object({
9
- projectId: z
10
- .string()
11
- .min(1)
12
- .max(64)
13
- .regex(/^[0-9A-Za-z_-]+$/),
14
- });
15
- const previewParam = projectParam.extend({ previewId: z.uuid() });
7
+ import { projectIdParam } from "./ids.js";
8
+ import { onInvalid, problem } from "./problem.js";
9
+ const previewParam = projectIdParam.extend({ previewId: z.uuid() });
16
10
  export function audioPreviewRoutes(deps) {
17
11
  return new Hono()
18
- .get("/:projectId/audio-preview", zValidator("param", projectParam, onInvalid), (c) => {
12
+ .get("/:projectId/audio-preview", zValidator("param", projectIdParam, onInvalid), (c) => {
19
13
  const { projectId } = c.req.valid("param");
20
14
  if (projectTitle(deps.db, projectId) === undefined)
21
15
  return missing(c);
@@ -48,7 +42,6 @@ export function audioPreviewRoutes(deps) {
48
42
  function missing(c) {
49
43
  return problem(c, {
50
44
  status: 404,
51
- title: titleOf(404),
52
45
  detail: "This live audio preview has ended. Play the finished narration from the project's audio outputs instead.",
53
46
  });
54
47
  }
@@ -10,7 +10,7 @@ const line = z.object({
10
10
  model: z.string().min(1).max(200),
11
11
  text: z.string().trim().min(1).max(auditionLineMax),
12
12
  });
13
- const quoteBody = z.object({
13
+ export const quoteBody = z.object({
14
14
  lines: z
15
15
  .array(line.extend({ speaker: z.string().max(100) }))
16
16
  .min(1)
@@ -2,7 +2,7 @@ import { zValidator } from "@hono/zod-validator";
2
2
  import { Hono } from "hono";
3
3
  import { z } from "zod";
4
4
  import { AutostartRefusal } from "../autostart/service.js";
5
- import { onInvalid, problem, titleOf } from "./problem.js";
5
+ import { onInvalid, problem } from "./problem.js";
6
6
  const body = z.object({ enabled: z.boolean() });
7
7
  // Settings → General's "Start Slopify when I log in", and the first-run screen's offer of it.
8
8
  // In Docker the view says whether Docker starts at login, and turning it on or off is refused
@@ -12,26 +12,26 @@ export function autostartRoutes(service) {
12
12
  return (new Hono()
13
13
  .get("/", async (c) => {
14
14
  if (service === undefined)
15
- return problem(c, { status: 404, title: titleOf(404), detail: unavailable });
15
+ return problem(c, { status: 404, detail: unavailable });
16
16
  c.header("Cache-Control", "no-store");
17
17
  return c.json(await service.view());
18
18
  })
19
19
  .put("/", zValidator("json", body, onInvalid), async (c) => {
20
20
  if (service === undefined)
21
- return problem(c, { status: 404, title: titleOf(404), detail: unavailable });
21
+ return problem(c, { status: 404, detail: unavailable });
22
22
  try {
23
23
  return c.json(await service.set(c.req.valid("json").enabled));
24
24
  }
25
25
  catch (error) {
26
26
  if (!(error instanceof AutostartRefusal))
27
27
  throw error;
28
- return problem(c, { status: 409, title: titleOf(409), detail: error.message });
28
+ return problem(c, { status: 409, detail: error.message });
29
29
  }
30
30
  })
31
31
  // The first-run screen's No thanks: never offer it there again, change nothing.
32
32
  .post("/answer", async (c) => {
33
33
  if (service === undefined)
34
- return problem(c, { status: 404, title: titleOf(404), detail: unavailable });
34
+ return problem(c, { status: 404, detail: unavailable });
35
35
  return c.json(await service.answer());
36
36
  }));
37
37
  }
@@ -2,8 +2,8 @@ import { zValidator } from "@hono/zod-validator";
2
2
  import { Hono } from "hono";
3
3
  import { HTTPException } from "hono/http-exception";
4
4
  import { backupConfigInputSchema } from "../../slices/backups/model.js";
5
- import { onInvalid, problem, titleOf } from "./problem.js";
6
- // Settings → Backups: the schedule, the folder, the last result and Back up now. Writing an
5
+ import { onInvalid, problem } from "./problem.js";
6
+ // Settings → Backup & storage: the schedule, the folder, the last result and Back up now. Writing an
7
7
  // archive takes minutes, so Back up now answers at once and the screen polls this view.
8
8
  export function backupRoutes(service) {
9
9
  const backups = () => {
@@ -21,7 +21,6 @@ export function backupRoutes(service) {
21
21
  if (!saved.ok)
22
22
  return problem(c, {
23
23
  status: 400,
24
- title: titleOf(400),
25
24
  detail: saved.detail,
26
25
  extensions: { field: "folder" },
27
26
  });
@@ -32,7 +31,6 @@ export function backupRoutes(service) {
32
31
  if (!started.ok)
33
32
  return problem(c, {
34
33
  status: started.status,
35
- title: titleOf(started.status),
36
34
  detail: started.detail,
37
35
  });
38
36
  return c.json(await backups().view(), 202);