@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
@@ -5,6 +5,7 @@ import { z } from "zod";
5
5
  import { redact } from "../../kernel/log.js";
6
6
  import { providerError } from "../../kernel/ports/model.js";
7
7
  import { cliCheck, cliReported } from "../explain.js";
8
+ import { accessField } from "../model-access.js";
8
9
  import { cliLoginError } from "./cli-login-error.js";
9
10
  import { codexPlanLimit } from "./codex-limits.js";
10
11
  import { nodeCodexModels } from "./codex-models.js";
@@ -52,7 +53,10 @@ const disabledFeatures = [
52
53
  // "-i, --image <FILE>... Optional image(s) to attach to the initial prompt"), which needs no
53
54
  // tool: `view_image` stays disabled. Each is given as its own flag so a path is never read as
54
55
  // the prompt.
55
- export function codexArgs(req, directory, documents, images) {
56
+ // One ephemeral, read-only turn in `directory` with every local tool, hook, plugin, skill and
57
+ // project document left out. The content adapter and the in-app assistant (`assistant-cli.ts`)
58
+ // both start from it and add their own instructions, search setting and MCP servers.
59
+ export function hardenedCodexBase(directory) {
56
60
  return [
57
61
  "exec",
58
62
  "--json",
@@ -86,6 +90,11 @@ export function codexArgs(req, directory, documents, images) {
86
90
  "include_environment_context=false",
87
91
  "-c",
88
92
  'shell_environment_policy.inherit="none"',
93
+ ];
94
+ }
95
+ export function codexArgs(req, directory, documents, images) {
96
+ return [
97
+ ...hardenedCodexBase(directory),
89
98
  "-c",
90
99
  `instructions=${JSON.stringify(writingRole + (documents ? " Use the explicitly supplied research MCP tool to read request documents; it is the only permitted local reference source." : ""))}`,
91
100
  "-c",
@@ -221,6 +230,7 @@ export function codexLlm(deps) {
221
230
  throw codexLimitError(failed, planLimit);
222
231
  throw providerError({
223
232
  kind: "other",
233
+ ...accessField(null, failed),
224
234
  message: cliReported(binary, redact(cliShaped(binary, turnFailed, event.value).error.message), cliCheck(binary)),
225
235
  });
226
236
  }
@@ -234,6 +244,7 @@ export function codexLlm(deps) {
234
244
  throw codexLimitError(failed, planLimit);
235
245
  throw providerError({
236
246
  kind: "other",
247
+ ...accessField(null, failed),
237
248
  message: cliReported(binary, redact(cliShaped(binary, errorEvent, event.value).message), cliCheck(binary)),
238
249
  });
239
250
  }
@@ -6,6 +6,7 @@ import { fileURLToPath } from "node:url";
6
6
  import { z } from "zod";
7
7
  import { documentIndex, llmDocumentsSchema, } from "../../kernel/ports/llm-documents.js";
8
8
  import { providerError } from "../../kernel/ports/model.js";
9
+ import { editSettings } from "../../kernel/ports/settings-places.js";
9
10
  export const documentServerName = "slopify_research";
10
11
  export const documentTool = "read_document";
11
12
  export const documentToolName = `mcp__${documentServerName}__${documentTool}`;
@@ -16,7 +17,7 @@ export function documentWorkspace(input) {
16
17
  if (!parsed.success)
17
18
  throw providerError({
18
19
  kind: "unsupported",
19
- message: "The research notes are too large, or not in a form the AI model can be given, so nothing was sent. Make the inputs shorter in Edit project, then use Try again; if it keeps happening, use Download diagnostics in Settings and report it.",
20
+ message: `The research notes are too large, or not in a form the AI model can be given, so nothing was sent. Make the research notes shorter in ${editSettings.article}, then use Try again; if it keeps happening, use Download diagnostics in Settings and report it.`,
20
21
  });
21
22
  const documents = parsed.data;
22
23
  const directory = mkdtempSync(join(tmpdir(), "slopify-documents-"));
@@ -82,6 +83,6 @@ export function documentWorkspace(input) {
82
83
  function unread() {
83
84
  return providerError({
84
85
  kind: "unavailable",
85
- message: "The AI model did not read all of the research notes, so its answer was not used (the attempt may still have used your quota). Use Try again; if it keeps happening, choose another model in the Providers section of Edit project.",
86
+ message: `The AI model did not read all of the research notes, so its answer was not used (the attempt may still have used your quota). Use Try again; if it keeps happening, choose another model in ${editSettings.writer}.`,
86
87
  });
87
88
  }
@@ -2,6 +2,7 @@ import { copyFileSync, mkdtempSync, rmSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { basename, extname, join } from "node:path";
4
4
  import { providerError } from "../../kernel/ports/model.js";
5
+ import { editSettings } from "../../kernel/ports/settings-places.js";
5
6
  const extensions = new Set([".png", ".jpg", ".jpeg", ".webp"]);
6
7
  // ceiling: a review shows one image, or a short's handful plus the establishing image.
7
8
  export const imagesMax = 12;
@@ -47,12 +48,12 @@ export function readFileName(path) {
47
48
  export function unseenImages() {
48
49
  return providerError({
49
50
  kind: "unavailable",
50
- message: "The reviewer answered without opening every picture it was given, so its verdict was not used (the attempt may still have used your quota). Use Try again; if it keeps happening, choose Codex as the reviewer in Edit project → Reviews.",
51
+ message: `The reviewer answered without opening every picture it was given, so its verdict was not used (the attempt may still have used your quota). Use Try again; if it keeps happening, choose Codex as the reviewer in ${editSettings.checks}.`,
51
52
  });
52
53
  }
53
54
  export function noImages(provider) {
54
55
  return providerError({
55
56
  kind: "unsupported",
56
- message: `Slopify can't show pictures to ${provider}, so a review that needs them was not sent. In Edit project → Reviews, choose Claude Code or Codex as the reviewer, or set the picture reviews to Off, then use Try again.`,
57
+ message: `Slopify can't show pictures to ${provider}, so a review that needs them was not sent. In ${editSettings.checks}, choose Claude Code or Codex as the reviewer, or set the picture reviews to Off, then use Try again.`,
57
58
  });
58
59
  }
@@ -2,8 +2,10 @@ import { z } from "zod";
2
2
  import { redact } from "../../kernel/log.js";
3
3
  import { documentMessages } from "../../kernel/ports/llm-documents.js";
4
4
  import { providerError } from "../../kernel/ports/model.js";
5
- import { droppedStream, httpFailure, missingKey, providerSaid, refreshList, unreadable, } from "../explain.js";
6
- import { retryAfter } from "../retry-after.js";
5
+ import { editSettings } from "../../kernel/ports/settings-places.js";
6
+ import { droppedStream, httpFailure, providerSaid, refreshList, unreadable } from "../explain.js";
7
+ import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
8
+ import { accessField, modelAccessOf } from "../model-access.js";
7
9
  import { noImages } from "./image-workspace.js";
8
10
  import { sseData } from "./sse-lines.js";
9
11
  // The HTTP gateway adapter: the platform's own `fetch` plus the line reader beside this
@@ -86,7 +88,8 @@ export function openRouterLlm(deps) {
86
88
  // A stream that has already answered 200 reports a mid-flight failure in a data
87
89
  // frame; without this the stage would store half an article as a success.
88
90
  throw providerError({
89
- kind: kindOf(statusOf(chunk.error.code)),
91
+ kind: kindOfStatus(statusOf(chunk.error.code)),
92
+ ...accessField(statusOf(chunk.error.code), chunk.error.message),
90
93
  message: streamFailure(statusOf(chunk.error.code), redact(chunk.error.message)),
91
94
  });
92
95
  }
@@ -147,53 +150,22 @@ export function openRouterLlm(deps) {
147
150
  };
148
151
  }
149
152
  function headers(key) {
150
- // An attempt that finds no key fails rather than calling anonymously
151
- // and being told off by the provider in words the user cannot act on. `missing_key`
152
- // rather than `auth` because the same rule makes it terminal: there is nothing to
153
- // retry until the user saves a key, and the wrapper is where that is decided.
154
- if (key === undefined || key === "") {
155
- throw providerError({ kind: "missing_key", message: missingKey("OpenRouter") });
156
- }
157
- return { Authorization: `Bearer ${key}`, ...appHeaders };
158
- }
159
- // Only the adapter sees the vendor's status code, so only the adapter names the kind.
160
- function kindOf(status) {
161
- if (status === 401 || status === 403) {
162
- return "auth";
163
- }
164
- if (status === 429) {
165
- return "rate_limit";
166
- }
167
- // ceiling: everything else is `other` and is retried, so a 400 or a 402 fails the same
168
- // way four times over. A terminal "this will never work" kind has to reach the port's
169
- // error contract first, which is not this adapter's to widen.
170
- // The provider's own server failed; the same request may well succeed later.
171
- if (status >= 500)
172
- return "dropped";
173
- return "other";
153
+ // An attempt that finds no key fails rather than calling anonymously and being told off by
154
+ // the provider in words the user cannot act on.
155
+ return { Authorization: `Bearer ${requireKey(key, "OpenRouter")}`, ...appHeaders };
174
156
  }
175
157
  async function failure(response, next) {
176
- const text = await response.text().catch(() => "");
158
+ const text = await failureText(response);
177
159
  const parsed = errorBody.safeParse(safeJson(text));
178
160
  // The provider's own words, through the redactor - an error body may quote the key back.
179
161
  const message = redact(parsed.success ? parsed.data.error.message : text.trim() || response.statusText);
180
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
181
- return providerError({
182
- kind: kindOf(response.status),
183
- message: httpFailure({
184
- provider: "OpenRouter",
185
- status: response.status,
186
- detail: message,
187
- next,
188
- }),
189
- ...(retryAfterMs === undefined ? {} : { retryAfterMs }),
190
- });
162
+ return httpProviderError(response, kindOfStatus(response.status), httpFailure({ provider: "OpenRouter", status: response.status, detail: message, next }), undefined, modelAccessOf(response.status, message));
191
163
  }
192
164
  // A mid-stream error carries an HTTP-like code; with none, the provider's words are all there is.
193
165
  function streamFailure(status, detail) {
194
166
  return status >= 400
195
167
  ? httpFailure({ provider: "OpenRouter", status, detail })
196
- : providerSaid("OpenRouter", "stopped part-way through the answer", detail, "Use Try again; if it keeps happening, choose another model in the Providers section of Edit project.");
168
+ : providerSaid("OpenRouter", "stopped part-way through the answer", detail, `Use Try again; if it keeps happening, choose another model in ${editSettings.writer}.`);
197
169
  }
198
170
  function statusOf(code) {
199
171
  return typeof code === "number" ? code : Number(code ?? 0);
@@ -211,11 +183,3 @@ function parseChunk(data) {
211
183
  }
212
184
  return parsed.data;
213
185
  }
214
- function safeJson(text) {
215
- try {
216
- return JSON.parse(text);
217
- }
218
- catch {
219
- return undefined;
220
- }
221
- }
@@ -3,7 +3,9 @@ import { z } from "zod";
3
3
  import { cliCommand } from "../../kernel/cli-command.js";
4
4
  import { redact } from "../../kernel/log.js";
5
5
  import { providerError } from "../../kernel/ports/model.js";
6
+ import { editSettings } from "../../kernel/ports/settings-places.js";
6
7
  import { cliName, commandOf, quoted } from "../explain.js";
8
+ import { safeJson } from "../http-failure.js";
7
9
  // ceiling: the last 8 KiB of stderr is kept. A CLI that writes megabytes of progress there
8
10
  // would otherwise be held in memory for the length of a run, and the tail is the part that
9
11
  // says why it stopped. Streaming stderr to the log is the upgrade if a provider ever
@@ -108,7 +110,7 @@ export function nodeRunCli(binary, args, signal, options) {
108
110
  return {
109
111
  ...(inputWritten === undefined ? {} : { inputWritten }),
110
112
  pid: child.pid,
111
- stdout: child.stdout === null ? nothing : bytesOf(child.stdout),
113
+ stdout: bytesOf(child.stdout),
112
114
  stderr: () => stderr,
113
115
  ended,
114
116
  kill: terminate,
@@ -139,7 +141,7 @@ export function cliInput(text) {
139
141
  if (Buffer.byteLength(text) >= 8 * 1024 * 1024)
140
142
  throw providerError({
141
143
  kind: "unsupported",
142
- message: "This prompt is larger than the CLI accepts (8 MB), so nothing was sent. Make the inputs shorter in Edit project, or choose an API provider such as OpenRouter in its Providers section, then use Try again.",
144
+ message: `This prompt is larger than the CLI accepts (8 MB), so nothing was sent. Make the article or its research notes shorter in ${editSettings.article}, or choose an API service such as OpenRouter under Written by there, then use Try again.`,
143
145
  });
144
146
  return text;
145
147
  }
@@ -168,7 +170,7 @@ export function promptOf(messages) {
168
170
  export function endedWithout(binary, ended, stderr) {
169
171
  const said = redact(stderr.trim());
170
172
  if (ended.error !== null)
171
- return `The ${cliName(binary)} could not be started${quoted("", redact(ended.error.message))}. Check it is installed and set up in Settings → Providers, then use Try again.`;
173
+ return `The ${cliName(binary)} could not be started${quoted("", redact(ended.error.message))}. Check it is installed and set up in Settings → Keys & services, then use Try again.`;
172
174
  const how = ended.code === null ? "killed by the system" : `exit code ${String(ended.code)}`;
173
175
  return `The ${cliName(binary)} stopped without answering${quoted(how, said)}. Run ${commandOf(binary)} in a terminal to check it works and is signed in, then use Try again.`;
174
176
  }
@@ -181,13 +183,6 @@ export function endedKind(ended) {
181
183
  export function stuckCli(binary) {
182
184
  return `The ${cliName(binary)} stopped responding and could not be shut down. Close any leftover ${commandOf(binary)} processes or restart your computer, then use Try again.`;
183
185
  }
184
- // Unreachable while stdio names `pipe` for fd 1; it is here so the type carries no null
185
- // and no non-null assertion is needed to read the stream.
186
- const nothing = {
187
- [Symbol.asyncIterator]: () => ({
188
- next: () => Promise.resolve({ done: true, value: undefined }),
189
- }),
190
- };
191
186
  const typed = z.object({ type: z.string() });
192
187
  // A JSONL line off a CLI's stdout. The raw value travels with its `type` because a schema
193
188
  // that names only `type` strips every other key, and each event's own shape is checked
@@ -215,22 +210,12 @@ export function cliShaped(binary, schema, value) {
215
210
  }
216
211
  return parsed.data;
217
212
  }
213
+ // fd 1 is always a pipe with no encoding, so its pieces are bytes; the null check is for the type.
218
214
  async function* bytesOf(source) {
215
+ if (source === null)
216
+ return;
219
217
  for await (const piece of source) {
220
- if (typeof piece === "string") {
221
- yield new TextEncoder().encode(piece);
222
- continue;
223
- }
224
- if (piece instanceof Uint8Array) {
218
+ if (piece instanceof Uint8Array)
225
219
  yield piece;
226
- }
227
- }
228
- }
229
- function safeJson(text) {
230
- try {
231
- return JSON.parse(text);
232
- }
233
- catch {
234
- return undefined;
235
220
  }
236
221
  }
@@ -5,7 +5,9 @@
5
5
  // the middle of one, or inside a multi-byte character. TextDecoder's streaming mode holds
6
6
  // back the tail of a split UTF-8 sequence instead of emitting a replacement character,
7
7
  // and the leftover buffer holds back a split line.
8
- export async function* lines(chunks, signal) {
8
+ export async function* lines(chunks, signal,
9
+ // A producer that never ends a line would otherwise grow the buffer without bound.
10
+ pending) {
9
11
  const decoder = new TextDecoder("utf-8");
10
12
  let buffer = "";
11
13
  for await (const chunk of chunks) {
@@ -15,6 +17,8 @@ export async function* lines(chunks, signal) {
15
17
  yield withoutCr(buffer.slice(0, at));
16
18
  buffer = buffer.slice(at + 1);
17
19
  }
20
+ if (pending !== undefined && buffer.length > pending.chars)
21
+ throw pending.error();
18
22
  }
19
23
  buffer += decoder.decode();
20
24
  // A producer that ends without a trailing newline still wrote a whole line, and one cut
@@ -0,0 +1,37 @@
1
+ // Whether a provider's failure says the account can't use the chosen model. Read from the
2
+ // status and the provider's own words, since only the adapter sees them; it never changes the
3
+ // error's kind, so a run fails exactly as before. Undefined: the failure says nothing about
4
+ // the model.
5
+ // Not-found comes first: OpenAI's "does not exist or you do not have access to it" is about a
6
+ // model id, not a plan. The loose phrases count only when the text is about a model, so a
7
+ // voice or a file that does not exist is not mistaken for one.
8
+ const notFound = /model_not_found|not a valid model|model not found|no endpoints found|invalid model|unknown model|is not found for api version|models\/[^ ]+ is not found/i;
9
+ const looseNotFound = /does not exist|may not exist|not[_ ]found/i;
10
+ const noAccess = /not supported when using codex with a chatgpt account|not (?:available|included|supported) (?:on|in|for|with) your (?:current )?(?:plan|account|subscription|tier|region|country)|upgrade your (?:plan|subscription)|must be verified to use the model|does not have access to (?:the )?model|do not have access to (?:this|the) model|not allowed to (?:use|access) (?:this|the) model|requires a paid plan/i;
11
+ const mentionsModel = /\bmodel/i;
12
+ // `atModel`: the request went to the model's own address (fal.ai's and Replicate's endpoints,
13
+ // Google's models/<id>), so a 404 or 403 there is about the model whatever the words say.
14
+ export function modelAccessOf(status, text, atModel = false) {
15
+ if (notFound.test(text))
16
+ return "not-found";
17
+ // "Upgrade your plan" or "not found" alone is as often about credits, a voice or a feature
18
+ // as about a model.
19
+ if (mentionsModel.test(text)) {
20
+ if (looseNotFound.test(text))
21
+ return "not-found";
22
+ if (noAccess.test(text))
23
+ return "no-access";
24
+ }
25
+ else if (!atModel)
26
+ return undefined;
27
+ if (status === 404)
28
+ return "not-found";
29
+ if (status === 403)
30
+ return "no-access";
31
+ return undefined;
32
+ }
33
+ // Spread into a providerError init.
34
+ export function accessField(status, text, atModel = false) {
35
+ const access = modelAccessOf(status, text, atModel);
36
+ return access === undefined ? {} : { access };
37
+ }
@@ -1,8 +1,9 @@
1
1
  import { z } from "zod";
2
2
  import { redact } from "../../kernel/log.js";
3
3
  import { providerError } from "../../kernel/ports/model.js";
4
- import { httpFailure, missingKey, noAudio, voiceFix } from "../explain.js";
5
- import { retryAfter } from "../retry-after.js";
4
+ import { httpFailure, noAudio, voiceFix } from "../explain.js";
5
+ import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
6
+ import { modelAccessOf } from "../model-access.js";
6
7
  import { cartesiaLanguages, lookUp } from "./voice-languages.js";
7
8
  // The HTTP gateway adapter for Cartesia. `fetch` and
8
9
  // nothing else; `/tts/bytes` streams the audio it renders, so the response body is
@@ -69,45 +70,21 @@ export function cartesiaTts(deps) {
69
70
  };
70
71
  }
71
72
  function keyOf(deps) {
72
- const key = deps.key();
73
- // An absent key is terminal, so it never becomes a request.
74
- if (key === undefined || key === "") {
75
- throw providerError({ kind: "missing_key", message: missingKey("Cartesia") });
76
- }
77
- return key;
78
- }
79
- function kindOf(status) {
80
- if (status === 401 || status === 403) {
81
- return "auth";
82
- }
83
- // `concurrency_limited` is the plan's own limit and arrives as a 429 like any other, so
84
- // the status is enough and the code below only reaches the message.
85
- if (status === 429) {
86
- return "rate_limit";
87
- }
88
- // ceiling: as in the other two adapters, everything else is `other` and is retried.
89
- // The provider's own server failed; the same request may well succeed later.
90
- if (status >= 500)
91
- return "dropped";
92
- return "other";
73
+ return requireKey(deps.key(), "Cartesia");
93
74
  }
94
75
  async function failure(response, voiceId) {
95
- const text = await response.text().catch(() => "");
76
+ const text = await failureText(response);
96
77
  const message = redact(detailOf(text) || response.statusText);
97
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
98
- return providerError({
99
- kind: kindOf(response.status),
100
- // `voice_not_found` has to say which voice was asked for; Cartesia's
101
- // own message does not repeat the id.
102
- message: httpFailure({
103
- provider: "Cartesia",
104
- status: response.status,
105
- detail: message,
106
- subject: `narration request for voice "${voiceId}"`,
107
- fix: voiceFix(voiceId),
108
- }),
109
- ...(retryAfterMs === undefined ? {} : { retryAfterMs }),
110
- });
78
+ return httpProviderError(response, kindOfStatus(response.status),
79
+ // `voice_not_found` has to say which voice was asked for; Cartesia's
80
+ // own message does not repeat the id.
81
+ httpFailure({
82
+ provider: "Cartesia",
83
+ status: response.status,
84
+ detail: message,
85
+ subject: `narration request for voice "${voiceId}"`,
86
+ fix: voiceFix(voiceId),
87
+ }), undefined, modelAccessOf(response.status, text));
111
88
  }
112
89
  function detailOf(text) {
113
90
  const parsed = errorBody.safeParse(safeJson(text));
@@ -120,11 +97,3 @@ function detailOf(text) {
120
97
  const parts = [code, message].filter((part) => part !== undefined && part !== "");
121
98
  return parts.length === 0 ? text.trim() : parts.join(": ");
122
99
  }
123
- function safeJson(text) {
124
- try {
125
- return JSON.parse(text);
126
- }
127
- catch {
128
- return undefined;
129
- }
130
- }
@@ -1,8 +1,9 @@
1
1
  import { z } from "zod";
2
2
  import { redact } from "../../kernel/log.js";
3
3
  import { providerError } from "../../kernel/ports/model.js";
4
- import { httpFailure, missingKey, noAudio, refreshList, unreadable, voiceFix } from "../explain.js";
5
- import { retryAfter } from "../retry-after.js";
4
+ import { httpFailure, noAudio, refreshList, unreadable, voiceFix } from "../explain.js";
5
+ import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
6
+ import { modelAccessOf } from "../model-access.js";
6
7
  import { elevenLabsLanguages, lookUp } from "./voice-languages.js";
7
8
  // The HTTP gateway adapter for ElevenLabs: the platform's own `fetch` and nothing else. The
8
9
  // response body already is the `ReadableStream<Uint8Array>` the port asks for, so an SDK
@@ -99,52 +100,27 @@ export function elevenLabsTts(deps) {
99
100
  };
100
101
  }
101
102
  function keyOf(deps) {
102
- const key = deps.key();
103
- // `missing_key`, not `auth`, because that rule makes it terminal.
104
- if (key === undefined || key === "") {
105
- throw providerError({ kind: "missing_key", message: missingKey("ElevenLabs") });
106
- }
107
- return key;
108
- }
109
- // Only the adapter sees the vendor's status code, so only the adapter names the kind.
110
- function kindOf(status) {
111
- if (status === 401 || status === 403) {
112
- return "auth";
113
- }
114
- if (status === 429) {
115
- return "rate_limit";
116
- }
117
- // ceiling: everything else is `other` and is retried, so a text past the character limit
118
- // fails the same way four times over. A terminal "this will never work" kind has to reach the
119
- // port's error contract first, which is not this adapter's to widen.
120
- // The provider's own server failed; the same request may well succeed later.
121
- if (status >= 500)
122
- return "dropped";
123
- return "other";
103
+ return requireKey(deps.key(), "ElevenLabs");
124
104
  }
125
105
  async function failure(response, voiceId, next) {
126
- const text = await response.text().catch(() => "");
106
+ const text = await failureText(response);
127
107
  // The provider's own words, through the redactor - an error body may quote the key back.
128
108
  const message = redact(detailOf(text) || response.statusText);
129
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
130
- return providerError({
131
- kind: kindOf(response.status),
132
- // A rejected voice ID has to be named, and it is the one part of the
133
- // request the user chose. It is not secret, unlike everything else on the wire.
134
- message: httpFailure({
135
- provider: "ElevenLabs",
136
- status: response.status,
137
- detail: message,
138
- next,
139
- ...(voiceId === undefined
140
- ? {}
141
- : {
142
- subject: `narration request for voice "${voiceId}"`,
143
- fix: voiceFix(voiceId),
144
- }),
145
- }),
146
- ...(retryAfterMs === undefined ? {} : { retryAfterMs }),
147
- });
109
+ return httpProviderError(response, kindOfStatus(response.status),
110
+ // A rejected voice ID has to be named, and it is the one part of the
111
+ // request the user chose. It is not secret, unlike everything else on the wire.
112
+ httpFailure({
113
+ provider: "ElevenLabs",
114
+ status: response.status,
115
+ detail: message,
116
+ next,
117
+ ...(voiceId === undefined
118
+ ? {}
119
+ : {
120
+ subject: `narration request for voice "${voiceId}"`,
121
+ fix: voiceFix(voiceId),
122
+ }),
123
+ }), undefined, modelAccessOf(response.status, text));
148
124
  }
149
125
  function detailOf(text) {
150
126
  const parsed = errorBody.safeParse(safeJson(text));
@@ -159,11 +135,3 @@ function detailOf(text) {
159
135
  // (`max_character_limit_exceeded`, `voice_not_found`) and the message is the sentence.
160
136
  return [detail.status, detail.message].filter((part) => part !== undefined).join(": ");
161
137
  }
162
- function safeJson(text) {
163
- try {
164
- return JSON.parse(text);
165
- }
166
- catch {
167
- return undefined;
168
- }
169
- }
@@ -1,8 +1,11 @@
1
1
  import { z } from "zod";
2
+ import { internalError } from "../../kernel/errors.js";
2
3
  import { redact } from "../../kernel/log.js";
3
4
  import { providerError } from "../../kernel/ports/model.js";
4
- import { httpFailure, internalError, missingKey, noAudio, providerSaid, refreshList, unreadable, voiceFix, } from "../explain.js";
5
- import { retryAfter } from "../retry-after.js";
5
+ import { editSettings } from "../../kernel/ports/settings-places.js";
6
+ import { httpFailure, noAudio, providerSaid, refreshList, unreadable, voiceFix, } from "../explain.js";
7
+ import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
8
+ import { modelAccessOf } from "../model-access.js";
6
9
  // The HTTP gateway adapter for Gemini's speech generation (generateContent with an AUDIO
7
10
  // response, https://ai.google.dev/gemini-api/docs/speech-generation), billed to a Gemini API
8
11
  // key. One voice is `speechConfig.voiceConfig`; a conversation of exactly two voices is
@@ -132,7 +135,7 @@ function audioOf(text) {
132
135
  if (blocked)
133
136
  throw providerError({
134
137
  kind: "refusal",
135
- message: providerSaid("Google", "refused to speak this narration under its content rules", blocked, "Reword that part of the script or article, or choose another voice provider under Speakers (Edit project → Providers)."),
138
+ message: providerSaid("Google", "refused to speak this narration under its content rules", blocked, `Reword that part of the script or article, or choose another voice service under Speakers (${editSettings.narration}).`),
136
139
  });
137
140
  for (const candidate of parsed.data.candidates ?? [])
138
141
  for (const part of candidate.content?.parts ?? []) {
@@ -156,24 +159,10 @@ function streamOf(bytes) {
156
159
  });
157
160
  }
158
161
  function keyOf(deps) {
159
- // `missing_key`, not `auth`, because that rule makes it terminal.
160
- const key = deps.key();
161
- if (key === undefined || key === "") {
162
- throw providerError({ kind: "missing_key", message: missingKey("Google") });
163
- }
164
- return key;
165
- }
166
- function kindOf(status) {
167
- if (status === 401 || status === 403)
168
- return "auth";
169
- if (status === 429)
170
- return "rate_limit";
171
- if (status >= 500)
172
- return "dropped";
173
- return "other";
162
+ return requireKey(deps.key(), "Google");
174
163
  }
175
164
  async function failure(response, voiceId, next) {
176
- const text = await response.text().catch(() => "");
165
+ const text = await failureText(response);
177
166
  const parsed = errorBody.safeParse(safeJson(text));
178
167
  // Through the redactor: an error body may quote the key back.
179
168
  const detail = redact((parsed.success ? parsed.data.error.message : undefined) ??
@@ -181,26 +170,17 @@ async function failure(response, voiceId, next) {
181
170
  // Google answers an unknown key with 400 API_KEY_INVALID rather than 401.
182
171
  const badKey = response.status === 400 && text.includes("API_KEY_INVALID");
183
172
  const status = badKey ? 401 : response.status;
184
- const retryAfterMs = retryAfter(response.headers.get("retry-after"));
185
- return providerError({
186
- kind: badKey ? "auth" : kindOf(response.status),
187
- message: httpFailure({
188
- provider: "Google",
189
- status,
190
- detail,
191
- next,
192
- ...(voiceId === undefined
193
- ? {}
194
- : { subject: `narration request for voice "${voiceId}"`, fix: voiceFix(voiceId) }),
195
- }),
196
- ...(retryAfterMs === undefined ? {} : { retryAfterMs }),
197
- });
198
- }
199
- function safeJson(text) {
200
- try {
201
- return JSON.parse(text);
202
- }
203
- catch {
204
- return undefined;
205
- }
173
+ return httpProviderError(response, badKey ? "auth" : kindOfStatus(response.status), httpFailure({
174
+ provider: "Google",
175
+ status,
176
+ detail,
177
+ next,
178
+ ...(voiceId === undefined
179
+ ? {}
180
+ : { subject: `narration request for voice "${voiceId}"`, fix: voiceFix(voiceId) }),
181
+ }), undefined,
182
+ // A narration request goes to the model's own address (models/<id>:generateContent).
183
+ badKey || voiceId === undefined
184
+ ? undefined
185
+ : modelAccessOf(response.status, `${parsed.success ? (parsed.data.error.status ?? "") : ""} ${detail}`, true));
206
186
  }
@@ -1,7 +1,10 @@
1
1
  import { z } from "zod";
2
+ import { internalError } from "../../kernel/errors.js";
2
3
  import { redact } from "../../kernel/log.js";
3
4
  import { providerError } from "../../kernel/ports/model.js";
4
- import { httpFailure, internalError, noAudio, providerSaid, unreadable, voiceFix, } from "../explain.js";
5
+ import { editSettings } from "../../kernel/ports/settings-places.js";
6
+ import { httpFailure, noAudio, providerSaid, unreadable, voiceFix } from "../explain.js";
7
+ import { accessField } from "../model-access.js";
5
8
  import { retryAfter } from "../retry-after.js";
6
9
  const operationName = /^workspaces\/[A-Za-z0-9_-]+\/ttsAsyncJobs\/[A-Za-z0-9_-]+\/operations\/[A-Za-z0-9_-]+$/;
7
10
  const operationSchema = z.object({
@@ -23,7 +26,7 @@ export async function* inworldAsync(deps, request, key) {
23
26
  if (saved === undefined && request.text.length > 100_000) {
24
27
  throw providerError({
25
28
  kind: "unsupported",
26
- message: "This narration part is longer than the 100,000 characters Inworld takes at once (10,000 on On-Demand accounts). Set Chunking to Paragraph in the Providers section of Edit project, then use Try again.",
29
+ message: `This narration part is longer than the 100,000 characters Inworld takes at once (10,000 on On-Demand accounts). Set Chunking to Paragraph in ${editSettings.narration}, then use Try again.`,
27
30
  });
28
31
  }
29
32
  const headers = { Authorization: `Basic ${key}`, "Content-Type": "application/json" };
@@ -137,6 +140,7 @@ async function check(response, key, voiceId) {
137
140
  const detail = clean(await response.text().catch(() => ""), key);
138
141
  const retryAfterMs = retryAfter(response.headers.get("retry-after"));
139
142
  throw providerError({
143
+ ...accessField(response.status, detail),
140
144
  kind: response.status === 401 || response.status === 403
141
145
  ? "auth"
142
146
  : response.status === 429