@gentbajko/slopify 3.25.8 → 4.0.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 (604) hide show
  1. package/dist/adapters/account-limits.js +30 -0
  2. package/dist/adapters/alignment/cache.js +3 -5
  3. package/dist/adapters/alignment/ctc.js +1 -2
  4. package/dist/adapters/alignment/lock.js +4 -3
  5. package/dist/adapters/alignment/multilingual.js +0 -3
  6. package/dist/adapters/alignment/prefetch.js +2 -1
  7. package/dist/adapters/alignment/worker.js +2 -1
  8. package/dist/adapters/explain.js +0 -3
  9. package/dist/adapters/ffmpeg.js +19 -1
  10. package/dist/adapters/host-cli/index.js +19 -3
  11. package/dist/adapters/http-failure.js +53 -0
  12. package/dist/adapters/image/codex.js +36 -4
  13. package/dist/adapters/image/fal.js +17 -50
  14. package/dist/adapters/image/google.js +31 -55
  15. package/dist/adapters/image/openai.js +20 -47
  16. package/dist/adapters/image/reference.js +36 -0
  17. package/dist/adapters/image/replicate.js +18 -47
  18. package/dist/adapters/interest/search-interest.js +113 -0
  19. package/dist/adapters/key-probes.js +53 -2
  20. package/dist/adapters/llm/antigravity.js +4 -0
  21. package/dist/adapters/llm/assistant-cli.js +388 -0
  22. package/dist/adapters/llm/child-session.js +83 -0
  23. package/dist/adapters/llm/claude-code-models.js +51 -98
  24. package/dist/adapters/llm/claude-code.js +13 -2
  25. package/dist/adapters/llm/codex-limits.js +27 -68
  26. package/dist/adapters/llm/codex-server-models.js +61 -109
  27. package/dist/adapters/llm/codex.js +12 -1
  28. package/dist/adapters/llm/openrouter.js +10 -47
  29. package/dist/adapters/llm/run-cli.js +6 -22
  30. package/dist/adapters/llm/sse-lines.js +5 -1
  31. package/dist/adapters/model-access.js +37 -0
  32. package/dist/adapters/tts/cartesia.js +15 -46
  33. package/dist/adapters/tts/elevenlabs.js +20 -52
  34. package/dist/adapters/tts/gemini.js +19 -40
  35. package/dist/adapters/tts/inworld-async.js +4 -1
  36. package/dist/adapters/tts/inworld.js +3 -0
  37. package/dist/adapters/tts/openai.js +20 -50
  38. package/dist/assets/models-lifecycle.yaml +6 -0
  39. package/dist/assistant-wiring.js +60 -0
  40. package/dist/autopilot-timers.js +59 -0
  41. package/dist/catalog/lifecycle.js +52 -0
  42. package/dist/catalog/propose.js +204 -0
  43. package/dist/catalog/registry.js +3 -1
  44. package/dist/catalog/schema.js +2 -0
  45. package/dist/catalog/store.js +39 -0
  46. package/dist/edge/autostart/native.js +3 -5
  47. package/dist/edge/autostart/prompt.js +2 -1
  48. package/dist/edge/autostart/service.js +3 -4
  49. package/dist/edge/cli-args.js +3 -4
  50. package/dist/edge/cli.js +2 -1
  51. package/dist/edge/docker-install/apply.js +11 -11
  52. package/dist/edge/docker-install/run.js +2 -1
  53. package/dist/edge/docker-install/state.js +4 -3
  54. package/dist/edge/docker-install/tree.js +2 -4
  55. package/dist/edge/docker-install/volume.js +3 -2
  56. package/dist/edge/docker.js +5 -4
  57. package/dist/edge/events/hub.js +5 -5
  58. package/dist/edge/http/actions.js +4 -25
  59. package/dist/edge/http/actor.js +5 -3
  60. package/dist/edge/http/app.js +85 -10
  61. package/dist/edge/http/assistant.js +127 -0
  62. package/dist/edge/http/audio-preview.js +4 -11
  63. package/dist/edge/http/auditions.js +1 -1
  64. package/dist/edge/http/autostart.js +5 -5
  65. package/dist/edge/http/backups.js +1 -3
  66. package/dist/edge/http/channel-memory.js +7 -20
  67. package/dist/edge/http/channels.js +13 -26
  68. package/dist/edge/http/checkpoints.js +33 -17
  69. package/dist/edge/http/design-templates.js +167 -0
  70. package/dist/edge/http/designs.js +178 -0
  71. package/dist/edge/http/diagnostics.js +5 -1
  72. package/dist/edge/http/document-themes.js +2 -11
  73. package/dist/edge/http/draft-files.js +1 -3
  74. package/dist/edge/http/draft-problem.js +4 -9
  75. package/dist/edge/http/drafts.js +3 -3
  76. package/dist/edge/http/entries.js +6 -9
  77. package/dist/edge/http/extension-auth.js +27 -0
  78. package/dist/edge/http/external-reviews.js +12 -11
  79. package/dist/edge/http/files.js +5 -11
  80. package/dist/edge/http/folder-location.js +1 -4
  81. package/dist/edge/http/fonts.js +0 -7
  82. package/dist/edge/http/home.js +38 -13
  83. package/dist/edge/http/host-cli.js +18 -8
  84. package/dist/edge/http/ids.js +8 -0
  85. package/dist/edge/http/keywords.js +35 -0
  86. package/dist/edge/http/model-checks.js +132 -0
  87. package/dist/edge/http/narration-peaks.js +5 -13
  88. package/dist/edge/http/onboarding.js +1 -14
  89. package/dist/edge/http/open-folder.js +5 -10
  90. package/dist/edge/http/outputs.js +4 -12
  91. package/dist/edge/http/patch-notes.js +4 -10
  92. package/dist/edge/http/planning.js +2 -6
  93. package/dist/edge/http/problem.js +2 -4
  94. package/dist/edge/http/project-create.js +1 -0
  95. package/dist/edge/http/project-templates.js +29 -17
  96. package/dist/edge/http/projects.js +2 -12
  97. package/dist/edge/http/prompts.js +7 -14
  98. package/dist/edge/http/pronunciations.js +1 -2
  99. package/dist/edge/http/providers.js +39 -24
  100. package/dist/edge/http/refusal.js +29 -0
  101. package/dist/edge/http/remote-access.js +40 -0
  102. package/dist/edge/http/remote-guard.js +71 -0
  103. package/dist/edge/http/request-guard.js +91 -0
  104. package/dist/edge/http/reviews.js +11 -24
  105. package/dist/edge/http/revision-files.js +5 -10
  106. package/dist/edge/http/revisions.js +10 -15
  107. package/dist/edge/http/run-cost.js +1 -2
  108. package/dist/edge/http/same-page.js +80 -0
  109. package/dist/edge/http/schedules.js +59 -32
  110. package/dist/edge/http/settings.js +22 -13
  111. package/dist/edge/http/social.js +282 -0
  112. package/dist/edge/http/staging.js +2 -4
  113. package/dist/edge/http/storage-files.js +5 -7
  114. package/dist/edge/http/storage.js +23 -23
  115. package/dist/edge/http/studio.js +23 -50
  116. package/dist/edge/http/style-preview.js +1 -4
  117. package/dist/edge/http/subtitles.js +3 -17
  118. package/dist/edge/http/template-studio.js +433 -0
  119. package/dist/edge/http/trash.js +10 -11
  120. package/dist/edge/http/tutorial.js +1 -2
  121. package/dist/edge/http/tutorials.js +5 -11
  122. package/dist/edge/http/update.js +7 -13
  123. package/dist/edge/http/waveform.js +3 -6
  124. package/dist/edge/http/youtube-edits.js +2 -3
  125. package/dist/edge/mcp/assistant.js +279 -0
  126. package/dist/edge/mcp/attribution.js +8 -2
  127. package/dist/edge/mcp/call-route.js +11 -2
  128. package/dist/edge/mcp/excluded-routes.js +25 -0
  129. package/dist/edge/mcp/http.js +11 -2
  130. package/dist/edge/mcp/instructions.js +5 -3
  131. package/dist/edge/mcp/library-tools.js +1 -0
  132. package/dist/edge/mcp/route-tool.js +35 -15
  133. package/dist/edge/mcp/server.js +13 -8
  134. package/dist/edge/mcp/tools-channels.js +2 -0
  135. package/dist/edge/mcp/tools-designs.js +165 -0
  136. package/dist/edge/mcp/tools-library.js +14 -2
  137. package/dist/edge/mcp/tools-planning.js +23 -4
  138. package/dist/edge/mcp/tools-projects.js +28 -1
  139. package/dist/edge/mcp/tools-runs.js +14 -1
  140. package/dist/edge/mcp/tools-schedules.js +28 -4
  141. package/dist/edge/mcp/tools-setup.js +61 -3
  142. package/dist/edge/mcp/tools-social.js +46 -0
  143. package/dist/edge/mcp/tools-storage.js +8 -0
  144. package/dist/edge/mcp/tools-template-studio.js +166 -0
  145. package/dist/edge/mcp/tools.js +6 -0
  146. package/dist/edge/remote-access/cli.js +71 -0
  147. package/dist/edge/remote-access/model.js +32 -0
  148. package/dist/edge/remote-access/rules.js +207 -0
  149. package/dist/edge/remote-access/service.js +203 -0
  150. package/dist/edge/remote-access/store.js +44 -0
  151. package/dist/edge/remote-access/views.js +43 -0
  152. package/dist/extension/slopify-studio-chrome.zip +0 -0
  153. package/dist/extension/slopify-studio-firefox.zip +0 -0
  154. package/dist/host-cli/install.js +2 -2
  155. package/dist/host-cli/open-folder.js +2 -2
  156. package/dist/host-cli/paths.js +2 -4
  157. package/dist/host-cli/server.js +4 -4
  158. package/dist/host-cli/service.js +3 -3
  159. package/dist/host-cli/status.js +7 -7
  160. package/dist/kernel/db/migrations/0063-model-checks.sql +20 -0
  161. package/dist/kernel/db/migrations/0064-template-studio.sql +46 -0
  162. package/dist/kernel/db/migrations/0065-promise-and-assistant-reviews.sql +58 -0
  163. package/dist/kernel/db/migrations/0066-assistant.sql +44 -0
  164. package/dist/kernel/db/migrations/0067-autopilot.sql +6 -0
  165. package/dist/kernel/db/migrations/0068-topic-scores.sql +17 -0
  166. package/dist/kernel/db/migrations/0070-designs.sql +53 -0
  167. package/dist/kernel/db/migrations/0071-design-usage.sql +33 -0
  168. package/dist/kernel/db/migrations/0072-design-templates.sql +33 -0
  169. package/dist/kernel/db/migrations/0073-schedule-design-kind.sql +5 -0
  170. package/dist/kernel/db/migrations/0074-template-bakeoffs.sql +44 -0
  171. package/dist/kernel/db/migrations/0075-social-posts.sql +25 -0
  172. package/dist/kernel/db/migrations/0076-channel-social.sql +5 -0
  173. package/dist/kernel/db/migrations/0077-post-prompts.sql +17 -0
  174. package/dist/kernel/db/tx.js +2 -4
  175. package/dist/kernel/errors.js +27 -1
  176. package/dist/kernel/json-answer.js +15 -0
  177. package/dist/kernel/lock.js +4 -9
  178. package/dist/kernel/paths.js +8 -0
  179. package/dist/kernel/ports/assistant-cli.js +4 -0
  180. package/dist/kernel/ports/host-cli.js +3 -0
  181. package/dist/kernel/ports/interest.js +4 -0
  182. package/dist/kernel/ports/languages.js +0 -3
  183. package/dist/kernel/ports/model.js +2 -0
  184. package/dist/kernel/runner/attempt.js +3 -1
  185. package/dist/kernel/runner/audition.js +3 -1
  186. package/dist/kernel/runner/checkpoint-authority.js +2 -1
  187. package/dist/kernel/runner/index.js +8 -10
  188. package/dist/kernel/runner/model-access.js +40 -0
  189. package/dist/kernel/runner/model-check.js +153 -0
  190. package/dist/kernel/runner/providers.js +15 -10
  191. package/dist/kernel/runner/standalone.js +9 -5
  192. package/dist/main.js +334 -19
  193. package/dist/model-checks.js +166 -0
  194. package/dist/patch-notes/3.25.9.md +5 -0
  195. package/dist/patch-notes/4.0.0.md +51 -0
  196. package/dist/patch-notes/index.json +12 -0
  197. package/dist/slices/admission/heads.js +2 -1
  198. package/dist/slices/admission/repo.js +2 -1
  199. package/dist/slices/admission/rules.js +43 -8
  200. package/dist/slices/admission/schema.js +8 -0
  201. package/dist/slices/admission/stage-writes.js +0 -3
  202. package/dist/slices/admission/start.js +48 -31
  203. package/dist/slices/admission/substitute.js +7 -4
  204. package/dist/slices/agents/attention-posts.js +31 -0
  205. package/dist/slices/agents/attention-templates.js +33 -0
  206. package/dist/slices/agents/attention.js +10 -1
  207. package/dist/slices/agents/connection.js +2 -6
  208. package/dist/slices/agents/model.js +6 -3
  209. package/dist/slices/agents/repo.js +15 -7
  210. package/dist/slices/article/continuation.js +0 -63
  211. package/dist/slices/article/plain.js +3 -2
  212. package/dist/slices/article/segments.js +2 -62
  213. package/dist/slices/assistant/access.js +1 -0
  214. package/dist/slices/assistant/asks.js +80 -0
  215. package/dist/slices/assistant/cost.js +54 -0
  216. package/dist/slices/assistant/gate.js +222 -0
  217. package/dist/slices/assistant/model.js +79 -0
  218. package/dist/slices/assistant/names.js +23 -0
  219. package/dist/slices/assistant/prompt.js +74 -0
  220. package/dist/slices/assistant/repo.js +74 -0
  221. package/dist/slices/assistant/tokens.js +18 -0
  222. package/dist/slices/assistant/turn.js +342 -0
  223. package/dist/slices/autopilot/buffer.js +76 -0
  224. package/dist/slices/autopilot/model.js +14 -0
  225. package/dist/slices/autopilot/notify.js +27 -0
  226. package/dist/slices/autopilot/repo.js +34 -0
  227. package/dist/slices/autopilot/signals.js +194 -0
  228. package/dist/slices/autopilot/warnings.js +85 -0
  229. package/dist/slices/autopilot/weekly.js +100 -0
  230. package/dist/slices/backups/files.js +2 -6
  231. package/dist/slices/backups/repo.js +3 -15
  232. package/dist/slices/backups/service.js +4 -3
  233. package/dist/slices/channels/cast-images.js +2 -1
  234. package/dist/slices/channels/model.js +0 -1
  235. package/dist/slices/channels/rebrand.js +0 -3
  236. package/dist/slices/channels/repo.js +4 -0
  237. package/dist/slices/channels/schema.js +6 -0
  238. package/dist/slices/channels/service.js +10 -0
  239. package/dist/slices/channels/videos.js +2 -14
  240. package/dist/slices/checkpoints/index.js +0 -1
  241. package/dist/slices/control/providers.js +0 -26
  242. package/dist/slices/designs/artwork.js +66 -0
  243. package/dist/slices/designs/budget.js +23 -0
  244. package/dist/slices/designs/calls.js +124 -0
  245. package/dist/slices/designs/check-context.js +38 -0
  246. package/dist/slices/designs/check-text.js +43 -0
  247. package/dist/slices/designs/fields.js +88 -0
  248. package/dist/slices/designs/frames.js +34 -0
  249. package/dist/slices/designs/gate.js +128 -0
  250. package/dist/slices/designs/layout.js +293 -0
  251. package/dist/slices/designs/model.js +35 -0
  252. package/dist/slices/designs/pdf-job.js +23 -0
  253. package/dist/slices/designs/pdf-pages.js +30 -0
  254. package/dist/slices/designs/pdf-runner.js +68 -0
  255. package/dist/slices/designs/pdf-worker.js +24 -0
  256. package/dist/slices/designs/picture-size.js +79 -0
  257. package/dist/slices/designs/pictures.js +55 -0
  258. package/dist/slices/designs/quote.js +24 -0
  259. package/dist/slices/designs/render-args.js +36 -0
  260. package/dist/slices/designs/render-input.js +59 -0
  261. package/dist/slices/designs/render.js +215 -0
  262. package/dist/slices/designs/repo.js +101 -0
  263. package/dist/slices/designs/requests.js +80 -0
  264. package/dist/slices/designs/runner.js +239 -0
  265. package/dist/slices/designs/sample-repo.js +91 -0
  266. package/dist/slices/designs/sample.js +222 -0
  267. package/dist/slices/designs/schema.js +87 -0
  268. package/dist/slices/designs/sections.js +44 -0
  269. package/dist/slices/designs/service.js +233 -0
  270. package/dist/slices/designs/steps-repo.js +102 -0
  271. package/dist/slices/designs/studio-kind.js +39 -0
  272. package/dist/slices/designs/template-checks.js +44 -0
  273. package/dist/slices/designs/template-make.js +118 -0
  274. package/dist/slices/designs/templates.js +218 -0
  275. package/dist/slices/document/fonts.js +2 -1
  276. package/dist/slices/episodes/summarize.js +5 -1
  277. package/dist/slices/estimate/index.js +45 -7
  278. package/dist/slices/fonts/catalog.js +3 -2
  279. package/dist/slices/fonts/discovery.js +3 -2
  280. package/dist/slices/fonts/files.js +2 -6
  281. package/dist/slices/fonts/index.js +0 -1
  282. package/dist/slices/fonts/sfnt.js +45 -10
  283. package/dist/slices/images/appearance.js +6 -15
  284. package/dist/slices/images/scenes.js +100 -27
  285. package/dist/slices/keywords/digest.js +84 -0
  286. package/dist/slices/keywords/facts.js +92 -0
  287. package/dist/slices/keywords/fill.js +80 -0
  288. package/dist/slices/keywords/model.js +75 -0
  289. package/dist/slices/keywords/rules.js +187 -0
  290. package/dist/slices/keywords/schema.js +28 -0
  291. package/dist/slices/keywords/specs.js +260 -0
  292. package/dist/slices/keywords/values.js +74 -0
  293. package/dist/slices/library/lint.js +29 -12
  294. package/dist/slices/library/model.js +2 -0
  295. package/dist/slices/library/photorealistic.js +4 -12
  296. package/dist/slices/library/rename.js +9 -7
  297. package/dist/slices/library/save.js +14 -10
  298. package/dist/slices/library/slots.js +37 -11
  299. package/dist/slices/library/transfer.js +2 -1
  300. package/dist/slices/library/used-by.js +25 -10
  301. package/dist/slices/loudness/loudnorm.js +51 -11
  302. package/dist/slices/model-checks/cost.js +61 -0
  303. package/dist/slices/model-checks/listing.js +124 -0
  304. package/dist/slices/model-checks/model.js +20 -0
  305. package/dist/slices/model-checks/record.js +32 -0
  306. package/dist/slices/model-checks/repo.js +120 -0
  307. package/dist/slices/model-checks/rules.js +112 -0
  308. package/dist/slices/model-checks/run.js +143 -0
  309. package/dist/slices/model-checks/service.js +198 -0
  310. package/dist/slices/model-upkeep/switch.js +70 -25
  311. package/dist/slices/model-upkeep/usage.js +26 -11
  312. package/dist/slices/narration/breaths.js +2 -1
  313. package/dist/slices/narration/clean-pieces.js +2 -1
  314. package/dist/slices/narration/concat.js +2 -1
  315. package/dist/slices/narration/peaks.js +3 -4
  316. package/dist/slices/narration/pronunciation-chunks.js +4 -3
  317. package/dist/slices/narration/pronunciation.js +3 -2
  318. package/dist/slices/narration/steering.js +4 -3
  319. package/dist/slices/notifications/notifier.js +4 -3
  320. package/dist/slices/notifications/rules.js +5 -2
  321. package/dist/slices/notifications/settings.js +4 -12
  322. package/dist/slices/notifications/subject.js +2 -1
  323. package/dist/slices/onboarding/copy.js +2 -1
  324. package/dist/slices/onboarding/first-run.js +3 -2
  325. package/dist/slices/onboarding/full-video.js +3 -2
  326. package/dist/slices/onboarding/install.js +4 -3
  327. package/dist/slices/onboarding/model.js +0 -16
  328. package/dist/slices/onboarding/packs.js +22 -22
  329. package/dist/slices/onboarding/quick-short.js +2 -1
  330. package/dist/slices/onboarding/sample.js +0 -1
  331. package/dist/slices/onboarding/state.js +2 -11
  332. package/dist/slices/onboarding/template.js +2 -1
  333. package/dist/slices/patch-notes/library.js +3 -2
  334. package/dist/slices/play-drafts/convert.js +4 -0
  335. package/dist/slices/play-drafts/review-inputs.js +8 -2
  336. package/dist/slices/play-drafts/review.js +5 -4
  337. package/dist/slices/play-drafts/schema.js +4 -0
  338. package/dist/slices/project-templates/from-project.js +9 -2
  339. package/dist/slices/project-templates/repo.js +6 -1
  340. package/dist/slices/project-templates/setup.js +8 -0
  341. package/dist/slices/project-templates/stand-ins.js +22 -0
  342. package/dist/slices/rebuild/activity.js +2 -0
  343. package/dist/slices/rebuild/admission-repo.js +3 -2
  344. package/dist/slices/rebuild/narration-history.js +4 -5
  345. package/dist/slices/rebuild/narration-retry.js +2 -1
  346. package/dist/slices/rebuild/preview-details.js +27 -9
  347. package/dist/slices/rebuild/preview-plan.js +3 -8
  348. package/dist/slices/rebuild/recipe-build.js +8 -3
  349. package/dist/slices/rebuild/recipe-describe.js +3 -3
  350. package/dist/slices/rebuild/recipe-digest.js +58 -0
  351. package/dist/slices/rebuild/recipe-input-schema.js +10 -0
  352. package/dist/slices/rebuild/recipe-keywords.js +71 -0
  353. package/dist/slices/rebuild/recipe-legacy.js +5 -1
  354. package/dist/slices/rebuild/recipe-model.js +4 -0
  355. package/dist/slices/rebuild/recipe-narration-text.js +2 -1
  356. package/dist/slices/rebuild/recipe-preparation.js +3 -3
  357. package/dist/slices/rebuild/recipe-reference.js +8 -4
  358. package/dist/slices/rebuild/recipe-reviews.js +27 -7
  359. package/dist/slices/rebuild/recipe-save.js +6 -3
  360. package/dist/slices/rebuild/recipe-scenes.js +40 -11
  361. package/dist/slices/rebuild/recipe-shorts.js +8 -8
  362. package/dist/slices/rebuild/recipe-social.js +46 -0
  363. package/dist/slices/rebuild/recipe-text.js +64 -20
  364. package/dist/slices/rebuild/recipe-validation.js +98 -28
  365. package/dist/slices/rebuild/recipe-visual.js +55 -16
  366. package/dist/slices/rebuild/recipe-work.js +15 -3
  367. package/dist/slices/rebuild/recipe-youtube.js +4 -3
  368. package/dist/slices/rebuild/recovery-selection.js +3 -1
  369. package/dist/slices/rebuild/recovery.js +3 -2
  370. package/dist/slices/rebuild/repo.js +4 -3
  371. package/dist/slices/rebuild/review-promise.js +25 -0
  372. package/dist/slices/rebuild/review-redo.js +2 -1
  373. package/dist/slices/rebuild/runtime-admission.js +4 -3
  374. package/dist/slices/rebuild/runtime-agent-review.js +11 -5
  375. package/dist/slices/rebuild/runtime-animate.js +9 -8
  376. package/dist/slices/rebuild/runtime-article.js +3 -2
  377. package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
  378. package/dist/slices/rebuild/runtime-document.js +8 -11
  379. package/dist/slices/rebuild/runtime-export-bed.js +6 -11
  380. package/dist/slices/rebuild/runtime-export-edit.js +6 -15
  381. package/dist/slices/rebuild/runtime-export-inputs.js +7 -7
  382. package/dist/slices/rebuild/runtime-export-short.js +8 -4
  383. package/dist/slices/rebuild/runtime-export.js +34 -12
  384. package/dist/slices/rebuild/runtime-figure-card.js +2 -1
  385. package/dist/slices/rebuild/runtime-image.js +4 -9
  386. package/dist/slices/rebuild/runtime-instructions.js +2 -0
  387. package/dist/slices/rebuild/runtime-keywords.js +59 -0
  388. package/dist/slices/rebuild/runtime-lines.js +2 -11
  389. package/dist/slices/rebuild/runtime-local.js +14 -20
  390. package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
  391. package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
  392. package/dist/slices/rebuild/runtime-narration-text.js +10 -15
  393. package/dist/slices/rebuild/runtime-pictures.js +2 -4
  394. package/dist/slices/rebuild/runtime-piece-label.js +10 -6
  395. package/dist/slices/rebuild/runtime-plan.js +31 -5
  396. package/dist/slices/rebuild/runtime-provider.js +60 -19
  397. package/dist/slices/rebuild/runtime-publication.js +10 -9
  398. package/dist/slices/rebuild/runtime-review.js +33 -28
  399. package/dist/slices/rebuild/runtime-run.js +4 -1
  400. package/dist/slices/rebuild/runtime-shorts.js +34 -50
  401. package/dist/slices/rebuild/runtime-store.js +3 -8
  402. package/dist/slices/rebuild/runtime-subtitles.js +16 -14
  403. package/dist/slices/rebuild/runtime-voices.js +8 -15
  404. package/dist/slices/rebuild/runtime-youtube.js +11 -29
  405. package/dist/slices/rebuild/transition-repo.js +6 -5
  406. package/dist/slices/rebuild/work-records.js +6 -0
  407. package/dist/slices/reruns/cascade.js +1 -2
  408. package/dist/slices/reruns/index.js +6 -9
  409. package/dist/slices/reviews/external-model.js +3 -0
  410. package/dist/slices/reviews/external-repo.js +2 -1
  411. package/dist/slices/reviews/external-rows.js +2 -3
  412. package/dist/slices/reviews/model.js +26 -8
  413. package/dist/slices/reviews/repo.js +2 -1
  414. package/dist/slices/reviews/rules.js +1 -0
  415. package/dist/slices/reviews/view.js +5 -2
  416. package/dist/slices/revisions/downloads.js +4 -5
  417. package/dist/slices/revisions/mutation-assets.js +7 -4
  418. package/dist/slices/revisions/mutation-cues.js +2 -5
  419. package/dist/slices/revisions/mutations.js +0 -1
  420. package/dist/slices/revisions/repo.js +3 -1
  421. package/dist/slices/revisions/schema.js +1 -0
  422. package/dist/slices/revisions/view.js +20 -0
  423. package/dist/slices/run-cost/limits.js +5 -2
  424. package/dist/slices/run-cost/meter.js +12 -5
  425. package/dist/slices/run-cost/panel.js +8 -74
  426. package/dist/slices/run-cost/plan-readings.js +127 -0
  427. package/dist/slices/run-cost/plan-use.js +169 -0
  428. package/dist/slices/run-cost/pricing.js +3 -3
  429. package/dist/slices/run-cost/week.js +32 -4
  430. package/dist/slices/schedules/agenda.js +11 -2
  431. package/dist/slices/schedules/by-date.js +42 -0
  432. package/dist/slices/schedules/calendar.js +5 -0
  433. package/dist/slices/schedules/design-agenda.js +36 -0
  434. package/dist/slices/schedules/design-check.js +41 -0
  435. package/dist/slices/schedules/design-run.js +126 -0
  436. package/dist/slices/schedules/next-run.js +62 -0
  437. package/dist/slices/schedules/prepare.js +18 -2
  438. package/dist/slices/schedules/repo.js +24 -16
  439. package/dist/slices/schedules/rescore.js +35 -0
  440. package/dist/slices/schedules/scheduler.js +13 -3
  441. package/dist/slices/schedules/schema.js +54 -3
  442. package/dist/slices/schedules/score.js +107 -0
  443. package/dist/slices/schedules/service.js +57 -24
  444. package/dist/slices/schedules/topic-list.js +15 -0
  445. package/dist/slices/schedules/topic-scores.js +104 -0
  446. package/dist/slices/schedules/topics.js +48 -36
  447. package/dist/slices/settings/cli-paths.js +4 -6
  448. package/dist/slices/settings/first-run.js +2 -11
  449. package/dist/slices/settings/model-reach.js +3 -17
  450. package/dist/slices/settings/model.js +10 -0
  451. package/dist/slices/settings/playback.js +33 -22
  452. package/dist/slices/settings/probe-read.js +16 -0
  453. package/dist/slices/settings/repo.js +33 -0
  454. package/dist/slices/settings/tutorial.js +2 -2
  455. package/dist/slices/settings/voices.js +4 -12
  456. package/dist/slices/shorts/pick.js +2 -15
  457. package/dist/slices/shorts/prompts.js +2 -13
  458. package/dist/slices/shorts/render.js +3 -0
  459. package/dist/slices/social/channel.js +44 -0
  460. package/dist/slices/social/defaults.js +17 -0
  461. package/dist/slices/social/due.js +36 -0
  462. package/dist/slices/social/extension.js +18 -0
  463. package/dist/slices/social/fit.js +115 -0
  464. package/dist/slices/social/limits.js +186 -0
  465. package/dist/slices/social/links.js +21 -0
  466. package/dist/slices/social/media.js +131 -0
  467. package/dist/slices/social/model.js +75 -0
  468. package/dist/slices/social/notice.js +19 -0
  469. package/dist/slices/social/pack.js +176 -0
  470. package/dist/slices/social/post-prompt.js +55 -0
  471. package/dist/slices/social/queue.js +31 -0
  472. package/dist/slices/social/repo.js +133 -0
  473. package/dist/slices/social/reshape.js +97 -0
  474. package/dist/slices/social/rules.js +5 -0
  475. package/dist/slices/social/schema.js +70 -0
  476. package/dist/slices/social/serve.js +51 -0
  477. package/dist/slices/social/service.js +128 -0
  478. package/dist/slices/social/settings.js +21 -0
  479. package/dist/slices/social/sources.js +114 -0
  480. package/dist/slices/social/state.js +110 -0
  481. package/dist/slices/social/text.js +149 -0
  482. package/dist/slices/storage/arrange.js +3 -1
  483. package/dist/slices/storage/assets.js +8 -10
  484. package/dist/slices/storage/backup-designs.js +74 -0
  485. package/dist/slices/storage/backup-export.js +8 -3
  486. package/dist/slices/storage/backup-format.js +10 -0
  487. package/dist/slices/storage/backup-import.js +20 -2
  488. package/dist/slices/storage/delete-project.js +6 -5
  489. package/dist/slices/storage/files-location.js +6 -8
  490. package/dist/slices/storage/layout.js +13 -2
  491. package/dist/slices/storage/model.js +3 -0
  492. package/dist/slices/storage/portable.js +16 -11
  493. package/dist/slices/storage/schema.js +2 -0
  494. package/dist/slices/storage/staging-refs.js +2 -1
  495. package/dist/slices/storage/staging.js +6 -9
  496. package/dist/slices/storage/trim.js +10 -3
  497. package/dist/slices/studio/calendar.js +4 -1
  498. package/dist/slices/studio/pick.js +2 -11
  499. package/dist/slices/studio/plan.js +6 -15
  500. package/dist/slices/studio/queue.js +3 -14
  501. package/dist/slices/studio/releases.js +26 -0
  502. package/dist/slices/studio/settings.js +14 -51
  503. package/dist/slices/studio/videos.js +12 -0
  504. package/dist/slices/style-preview/render.js +34 -13
  505. package/dist/slices/style-preview/schema.js +13 -0
  506. package/dist/slices/style-preview/service.js +2 -1
  507. package/dist/slices/style-preview/settings.js +33 -5
  508. package/dist/slices/telemetry/collector-client.js +2 -4
  509. package/dist/slices/telemetry/flush.js +2 -4
  510. package/dist/slices/telemetry/model.js +0 -7
  511. package/dist/slices/telemetry/record.js +10 -3
  512. package/dist/slices/template-studio/anatomy-view.js +118 -0
  513. package/dist/slices/template-studio/anatomy.js +73 -0
  514. package/dist/slices/template-studio/bakeoff-make.js +225 -0
  515. package/dist/slices/template-studio/bakeoff-repo.js +83 -0
  516. package/dist/slices/template-studio/bakeoff.js +333 -0
  517. package/dist/slices/template-studio/budget.js +103 -0
  518. package/dist/slices/template-studio/checks.js +273 -0
  519. package/dist/slices/template-studio/document-sample.js +56 -0
  520. package/dist/slices/template-studio/edit.js +15 -0
  521. package/dist/slices/template-studio/for-all.js +161 -0
  522. package/dist/slices/template-studio/free-video.js +31 -0
  523. package/dist/slices/template-studio/free.js +176 -0
  524. package/dist/slices/template-studio/gate.js +40 -0
  525. package/dist/slices/template-studio/hidden.js +20 -0
  526. package/dist/slices/template-studio/jobs.js +79 -0
  527. package/dist/slices/template-studio/loudness.js +111 -0
  528. package/dist/slices/template-studio/make.js +40 -0
  529. package/dist/slices/template-studio/model.js +54 -0
  530. package/dist/slices/template-studio/pack-import.js +253 -0
  531. package/dist/slices/template-studio/pack-samples.js +60 -0
  532. package/dist/slices/template-studio/pack.js +205 -0
  533. package/dist/slices/template-studio/paid-view.js +66 -0
  534. package/dist/slices/template-studio/paid.js +348 -0
  535. package/dist/slices/template-studio/quote.js +148 -0
  536. package/dist/slices/template-studio/ready.js +104 -0
  537. package/dist/slices/template-studio/repo.js +134 -0
  538. package/dist/slices/template-studio/reviews-path.js +58 -0
  539. package/dist/slices/template-studio/runner.js +84 -0
  540. package/dist/slices/template-studio/save.js +236 -0
  541. package/dist/slices/template-studio/say-it-as.js +248 -0
  542. package/dist/slices/template-studio/schedule-gate.js +34 -0
  543. package/dist/slices/template-studio/schedule-price.js +30 -0
  544. package/dist/slices/template-studio/schedule-sample.js +87 -0
  545. package/dist/slices/template-studio/schema.js +218 -0
  546. package/dist/slices/template-studio/scope.js +124 -0
  547. package/dist/slices/template-studio/sections.js +176 -0
  548. package/dist/slices/template-studio/service.js +173 -0
  549. package/dist/slices/template-studio/status.js +174 -0
  550. package/dist/slices/template-studio/topic.js +223 -0
  551. package/dist/slices/trash/designs.js +76 -0
  552. package/dist/slices/trash/model.js +13 -4
  553. package/dist/slices/trash/service.js +52 -2
  554. package/dist/slices/tutorials/library.js +3 -2
  555. package/dist/slices/video/ass-text.js +17 -0
  556. package/dist/slices/video/audio-export.js +2 -64
  557. package/dist/slices/video/encoding.js +160 -0
  558. package/dist/slices/video/ffmpeg.js +23 -21
  559. package/dist/slices/video/figure-card.js +1 -15
  560. package/dist/slices/video/slideshow.js +43 -18
  561. package/dist/slices/voices/palette.js +0 -3
  562. package/dist/slices/youtube/answer.js +2 -15
  563. package/dist/slices/youtube/edits-repo.js +2 -11
  564. package/dist/tutorials/Agents-MCP.md +2 -1
  565. package/dist/tutorials/Assistant.md +42 -0
  566. package/dist/tutorials/Channels.md +2 -0
  567. package/dist/tutorials/Home-and-Projects.md +19 -0
  568. package/dist/tutorials/Install.md +1 -0
  569. package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
  570. package/dist/tutorials/Models.md +33 -1
  571. package/dist/tutorials/Notifications.md +6 -0
  572. package/dist/tutorials/Play-Images.md +4 -0
  573. package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
  574. package/dist/tutorials/Prompts.md +10 -6
  575. package/dist/tutorials/Remote-Access.md +63 -0
  576. package/dist/tutorials/Reviews-and-Checkpoints.md +13 -2
  577. package/dist/tutorials/Schedules.md +21 -1
  578. package/dist/tutorials/Settings-Reference.md +50 -8
  579. package/dist/tutorials/Template-Studio.md +125 -0
  580. package/dist/tutorials/Templates.md +3 -0
  581. package/dist/tutorials/_Sidebar.md +5 -0
  582. package/dist/updater/work-in-progress.js +42 -12
  583. package/dist/web/assets/index-CkAI_2E7.css +1 -0
  584. package/dist/web/assets/index-DcD0cdfo.js +334 -0
  585. package/dist/web/assets/{pdf-T7MCwjIv.js → pdf-TODRwF31.js} +1 -1
  586. package/dist/web/index.html +2 -2
  587. package/package.json +5 -1
  588. package/dist/slices/article/provided-entries.js +0 -66
  589. package/dist/slices/article/run.js +0 -145
  590. package/dist/slices/images/run.js +0 -234
  591. package/dist/slices/narration/legacy-plan.js +0 -58
  592. package/dist/slices/narration/run.js +0 -270
  593. package/dist/slices/rebuild/runtime-actions.js +0 -90
  594. package/dist/slices/research/run.js +0 -224
  595. package/dist/slices/subtitles/prepare.js +0 -194
  596. package/dist/slices/subtitles/transcript.js +0 -34
  597. package/dist/slices/thumbnail/run.js +0 -219
  598. package/dist/slices/video/audio-inputs.js +0 -33
  599. package/dist/slices/video/reuse-audio.js +0 -62
  600. package/dist/slices/video/run.js +0 -78
  601. package/dist/slices/video/write-export.js +0 -158
  602. package/dist/slices/video/write-subtitles.js +0 -59
  603. package/dist/web/assets/index-BadsoORk.css +0 -1
  604. package/dist/web/assets/index-D8LqNsCl.js +0 -326
@@ -1,10 +1,8 @@
1
- import { spawn } from "node:child_process";
2
- import { mkdtemp, rm } from "node:fs/promises";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
1
  import { z } from "zod";
6
2
  import { cliCommand } from "../../kernel/cli-command.js";
7
3
  import { isoOfEpoch, windowKindOf, } from "../../kernel/ports/plan-limits.js";
4
+ import { withChildSession } from "./child-session.js";
5
+ import { lines } from "./sse-lines.js";
8
6
  // The Codex plan windows. `codex exec --json` reports none, so they are asked of the CLI's
9
7
  // app server with `account/rateLimits/read` - a metadata-only exchange that starts no thread
10
8
  // and spends nothing. Measured on 0.155.1: the reply carries `rateLimits.primary` and
@@ -40,49 +38,26 @@ export function codexWindows(result) {
40
38
  // method, a slow start: the windows are reported beside a run, never needed for it.
41
39
  export async function nodeCodexLimits(binary, env, timeoutMs = 10_000) {
42
40
  const command = cliCommand(binary);
43
- const directory = await mkdtemp(join(tmpdir(), "slopify-codex-limits-"));
44
- const child = spawn(command.file, [...command.args, "app-server", "--listen", "stdio://"], {
45
- cwd: directory,
46
- env: { ...env, PWD: directory },
47
- stdio: ["pipe", "pipe", "pipe"],
48
- windowsHide: true,
49
- detached: process.platform !== "win32",
50
- });
51
- child.on("error", () => { });
52
- child.stdin.on("error", () => { });
53
- child.stderr.resume();
54
- const closed = new Promise((resolve) => child.once("close", () => resolve()));
55
- const terminate = (signal) => {
56
- if (process.platform !== "win32" && child.pid !== undefined) {
57
- try {
58
- process.kill(-child.pid, signal);
59
- return;
60
- }
61
- catch {
62
- /* The process may already have exited. */
63
- }
64
- }
65
- child.kill(signal);
66
- };
67
- const timer = setTimeout(() => terminate("SIGKILL"), timeoutMs);
68
- const send = (message) => child.stdin.write(`${JSON.stringify(message)}\n`);
69
- let buffer = "";
70
- try {
71
- send({
72
- id: 1,
73
- method: "initialize",
74
- params: { clientInfo: { name: "slopify_limits", version: "1.0" } },
75
- });
76
- child.stdout.setEncoding("utf8");
77
- for await (const piece of child.stdout) {
78
- buffer += piece;
79
- if (buffer.length > 1024 * 1024)
80
- return null;
81
- let newline = buffer.indexOf("\n");
82
- while (newline >= 0) {
83
- const line = buffer.slice(0, newline).trim();
84
- buffer = buffer.slice(newline + 1);
85
- newline = buffer.indexOf("\n");
41
+ const oversize = () => new Error("Oversized reply");
42
+ return withChildSession({
43
+ file: command.file,
44
+ args: [...command.args, "app-server", "--listen", "stdio://"],
45
+ env: (directory) => ({ ...env, PWD: directory }),
46
+ directoryPrefix: "slopify-codex-limits-",
47
+ timeoutMs,
48
+ graceMs: 1000,
49
+ }, async ({ child, send }) => {
50
+ try {
51
+ send({
52
+ id: 1,
53
+ method: "initialize",
54
+ params: { clientInfo: { name: "slopify_limits", version: "1.0" } },
55
+ });
56
+ for await (const raw of lines(child.stdout, undefined, {
57
+ chars: 1024 * 1024,
58
+ error: oversize,
59
+ })) {
60
+ const line = raw.trim();
86
61
  if (line === "")
87
62
  continue;
88
63
  const reply = z
@@ -99,28 +74,12 @@ export async function nodeCodexLimits(binary, env, timeoutMs = 10_000) {
99
74
  return windows.length === 0 ? null : windows;
100
75
  }
101
76
  }
77
+ return null;
102
78
  }
103
- return null;
104
- }
105
- catch {
106
- return null;
107
- }
108
- finally {
109
- clearTimeout(timer);
110
- terminate("SIGTERM");
111
- let grace;
112
- await Promise.race([
113
- closed,
114
- new Promise((resolve) => {
115
- grace = setTimeout(() => {
116
- terminate("SIGKILL");
117
- resolve();
118
- }, 1000);
119
- }),
120
- ]);
121
- clearTimeout(grace);
122
- await rm(directory, { recursive: true, force: true });
123
- }
79
+ catch {
80
+ return null;
81
+ }
82
+ });
124
83
  }
125
84
  const months = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
126
85
  // Codex refuses a turn over the plan's allowance with "You've hit your usage limit. … Try
@@ -1,10 +1,8 @@
1
- import { spawn } from "node:child_process";
2
- import { mkdtemp, rm } from "node:fs/promises";
3
- import { tmpdir } from "node:os";
4
- import { join } from "node:path";
5
1
  import { z } from "zod";
6
2
  import { cliCommand } from "../../kernel/cli-command.js";
7
3
  import { thinkingModes as knownEfforts } from "../../kernel/ports/llm.js";
4
+ import { cappedOutput, withChildSession } from "./child-session.js";
5
+ import { lines } from "./sse-lines.js";
8
6
  const text = z
9
7
  .string()
10
8
  .trim()
@@ -28,39 +26,18 @@ const pageSchema = z.object({
28
26
  // model/list is a metadata-only app-server exchange: no thread, turn or tool is started.
29
27
  export async function nodeCodexServerModels(binary, env, timeoutMs = 15_000) {
30
28
  const command = cliCommand(binary);
31
- const directory = await mkdtemp(join(tmpdir(), "slopify-codex-models-"));
32
- const child = spawn(command.file, [...command.args, "app-server", "--listen", "stdio://"], {
33
- cwd: directory,
34
- env: { ...env, PWD: directory },
35
- stdio: ["pipe", "pipe", "pipe"],
36
- windowsHide: true,
37
- detached: process.platform !== "win32",
38
- });
39
- child.on("error", () => { });
40
- child.stdin.on("error", () => { });
41
- child.stderr.resume();
42
- const closed = new Promise((resolve) => child.once("close", () => resolve()));
43
- function terminate(signal) {
44
- if (process.platform !== "win32" && child.pid !== undefined) {
45
- try {
46
- process.kill(-child.pid, signal);
47
- return;
48
- }
49
- catch {
50
- /* The process may already have exited. */
51
- }
52
- }
53
- child.kill(signal);
54
- }
55
- const timer = setTimeout(() => terminate("SIGKILL"), timeoutMs);
56
- const send = (message) => child.stdin.write(`${JSON.stringify(message)}\n`);
57
- let expectedId = 1;
58
- let pages = 0;
59
- let bytes = 0;
60
- let buffer = "";
61
- const models = new Map();
62
- const cursors = new Set();
63
- try {
29
+ return withChildSession({
30
+ file: command.file,
31
+ args: [...command.args, "app-server", "--listen", "stdio://"],
32
+ env: (directory) => ({ ...env, PWD: directory }),
33
+ directoryPrefix: "slopify-codex-models-",
34
+ timeoutMs,
35
+ graceMs: 500,
36
+ }, async ({ child, send }) => {
37
+ let expectedId = 1;
38
+ let pages = 0;
39
+ const models = new Map();
40
+ const cursors = new Set();
64
41
  send({
65
42
  id: expectedId,
66
43
  method: "initialize",
@@ -68,83 +45,58 @@ export async function nodeCodexServerModels(binary, env, timeoutMs = 15_000) {
68
45
  clientInfo: { name: "slopify_model_discovery", version: "1.0" },
69
46
  },
70
47
  });
71
- child.stdout.setEncoding("utf8");
72
- for await (const piece of child.stdout) {
73
- bytes += Buffer.byteLength(piece);
74
- if (bytes > 4 * 1024 * 1024)
75
- throw new Error("Oversized metadata");
76
- buffer += piece;
77
- let newline = buffer.indexOf("\n");
78
- while (newline >= 0) {
79
- const line = buffer.slice(0, newline).trim();
80
- buffer = buffer.slice(newline + 1);
81
- newline = buffer.indexOf("\n");
82
- if (line === "")
83
- continue;
84
- const event = z
85
- .object({
86
- id: z.unknown().optional(),
87
- result: z.unknown().optional(),
88
- error: z.unknown().optional(),
89
- })
90
- .parse(JSON.parse(line));
91
- if (event.id !== expectedId)
92
- continue;
93
- if (event.error !== undefined)
94
- throw new Error("Discovery refused");
95
- let cursor;
96
- if (expectedId === 1) {
97
- send({ method: "initialized" });
48
+ const oversize = () => new Error("Oversized metadata");
49
+ for await (const raw of lines(cappedOutput(child.stdout, 4 * 1024 * 1024, oversize))) {
50
+ const line = raw.trim();
51
+ if (line === "")
52
+ continue;
53
+ const event = z
54
+ .object({
55
+ id: z.unknown().optional(),
56
+ result: z.unknown().optional(),
57
+ error: z.unknown().optional(),
58
+ })
59
+ .parse(JSON.parse(line));
60
+ if (event.id !== expectedId)
61
+ continue;
62
+ if (event.error !== undefined)
63
+ throw new Error("Discovery refused");
64
+ let cursor;
65
+ if (expectedId === 1) {
66
+ send({ method: "initialized" });
67
+ }
68
+ else {
69
+ const page = pageSchema.parse(event.result);
70
+ for (const row of page.data) {
71
+ if (row.hidden === true || models.has(row.model))
72
+ continue;
73
+ const thinkingModes = row.supportedReasoningEfforts
74
+ ?.map((item) => item.reasoningEffort)
75
+ .filter((effort) => knownEfforts.includes(effort));
76
+ models.set(row.model, {
77
+ id: row.model,
78
+ name: codexModelName(row.displayName),
79
+ ...(thinkingModes?.length ? { thinkingModes } : {}),
80
+ });
98
81
  }
99
- else {
100
- const page = pageSchema.parse(event.result);
101
- for (const row of page.data) {
102
- if (row.hidden === true || models.has(row.model))
103
- continue;
104
- const thinkingModes = row.supportedReasoningEfforts
105
- ?.map((item) => item.reasoningEffort)
106
- .filter((effort) => knownEfforts.includes(effort));
107
- models.set(row.model, {
108
- id: row.model,
109
- name: codexModelName(row.displayName),
110
- ...(thinkingModes?.length ? { thinkingModes } : {}),
111
- });
112
- }
113
- cursor = page.nextCursor;
114
- if (!cursor) {
115
- if (models.size === 0)
116
- throw new Error("No visible models");
117
- return [...models.values()];
118
- }
119
- if (cursors.has(cursor) || ++pages >= 20)
120
- throw new Error("Invalid pagination");
121
- cursors.add(cursor);
82
+ cursor = page.nextCursor;
83
+ if (!cursor) {
84
+ if (models.size === 0)
85
+ throw new Error("No visible models");
86
+ return [...models.values()];
122
87
  }
123
- send({
124
- id: ++expectedId,
125
- method: "model/list",
126
- params: { limit: 100, includeHidden: false, ...(cursor ? { cursor } : {}) },
127
- });
88
+ if (cursors.has(cursor) || ++pages >= 20)
89
+ throw new Error("Invalid pagination");
90
+ cursors.add(cursor);
128
91
  }
92
+ send({
93
+ id: ++expectedId,
94
+ method: "model/list",
95
+ params: { limit: 100, includeHidden: false, ...(cursor ? { cursor } : {}) },
96
+ });
129
97
  }
130
98
  throw new Error("Discovery ended before its reply");
131
- }
132
- finally {
133
- clearTimeout(timer);
134
- terminate("SIGTERM");
135
- let grace;
136
- await Promise.race([
137
- closed,
138
- new Promise((resolve) => {
139
- grace = setTimeout(() => {
140
- terminate("SIGKILL");
141
- resolve();
142
- }, 500);
143
- }),
144
- ]);
145
- clearTimeout(grace);
146
- await rm(directory, { recursive: true, force: true, maxRetries: 3, retryDelay: 50 });
147
- }
99
+ });
148
100
  }
149
101
  export function codexModelName(name) {
150
102
  return name.replace(/^(GPT-\d+(?:\.\d+)?)-/i, "$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
  }
@@ -2,8 +2,9 @@ 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 { droppedStream, httpFailure, providerSaid, refreshList, unreadable } from "../explain.js";
6
+ import { failureText, httpProviderError, kindOfStatus, requireKey, safeJson, } from "../http-failure.js";
7
+ import { accessField, modelAccessOf } from "../model-access.js";
7
8
  import { noImages } from "./image-workspace.js";
8
9
  import { sseData } from "./sse-lines.js";
9
10
  // The HTTP gateway adapter: the platform's own `fetch` plus the line reader beside this
@@ -86,7 +87,8 @@ export function openRouterLlm(deps) {
86
87
  // A stream that has already answered 200 reports a mid-flight failure in a data
87
88
  // frame; without this the stage would store half an article as a success.
88
89
  throw providerError({
89
- kind: kindOf(statusOf(chunk.error.code)),
90
+ kind: kindOfStatus(statusOf(chunk.error.code)),
91
+ ...accessField(statusOf(chunk.error.code), chunk.error.message),
90
92
  message: streamFailure(statusOf(chunk.error.code), redact(chunk.error.message)),
91
93
  });
92
94
  }
@@ -147,47 +149,16 @@ export function openRouterLlm(deps) {
147
149
  };
148
150
  }
149
151
  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";
152
+ // An attempt that finds no key fails rather than calling anonymously and being told off by
153
+ // the provider in words the user cannot act on.
154
+ return { Authorization: `Bearer ${requireKey(key, "OpenRouter")}`, ...appHeaders };
174
155
  }
175
156
  async function failure(response, next) {
176
- const text = await response.text().catch(() => "");
157
+ const text = await failureText(response);
177
158
  const parsed = errorBody.safeParse(safeJson(text));
178
159
  // The provider's own words, through the redactor - an error body may quote the key back.
179
160
  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
- });
161
+ return httpProviderError(response, kindOfStatus(response.status), httpFailure({ provider: "OpenRouter", status: response.status, detail: message, next }), undefined, modelAccessOf(response.status, message));
191
162
  }
192
163
  // A mid-stream error carries an HTTP-like code; with none, the provider's words are all there is.
193
164
  function streamFailure(status, detail) {
@@ -211,11 +182,3 @@ function parseChunk(data) {
211
182
  }
212
183
  return parsed.data;
213
184
  }
214
- function safeJson(text) {
215
- try {
216
- return JSON.parse(text);
217
- }
218
- catch {
219
- return undefined;
220
- }
221
- }
@@ -4,6 +4,7 @@ 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
6
  import { cliName, commandOf, quoted } from "../explain.js";
7
+ import { safeJson } from "../http-failure.js";
7
8
  // ceiling: the last 8 KiB of stderr is kept. A CLI that writes megabytes of progress there
8
9
  // would otherwise be held in memory for the length of a run, and the tail is the part that
9
10
  // says why it stopped. Streaming stderr to the log is the upgrade if a provider ever
@@ -108,7 +109,7 @@ export function nodeRunCli(binary, args, signal, options) {
108
109
  return {
109
110
  ...(inputWritten === undefined ? {} : { inputWritten }),
110
111
  pid: child.pid,
111
- stdout: child.stdout === null ? nothing : bytesOf(child.stdout),
112
+ stdout: bytesOf(child.stdout),
112
113
  stderr: () => stderr,
113
114
  ended,
114
115
  kill: terminate,
@@ -181,13 +182,6 @@ export function endedKind(ended) {
181
182
  export function stuckCli(binary) {
182
183
  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
184
  }
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
185
  const typed = z.object({ type: z.string() });
192
186
  // A JSONL line off a CLI's stdout. The raw value travels with its `type` because a schema
193
187
  // that names only `type` strips every other key, and each event's own shape is checked
@@ -215,22 +209,12 @@ export function cliShaped(binary, schema, value) {
215
209
  }
216
210
  return parsed.data;
217
211
  }
212
+ // fd 1 is always a pipe with no encoding, so its pieces are bytes; the null check is for the type.
218
213
  async function* bytesOf(source) {
214
+ if (source === null)
215
+ return;
219
216
  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) {
217
+ if (piece instanceof Uint8Array)
225
218
  yield piece;
226
- }
227
- }
228
- }
229
- function safeJson(text) {
230
- try {
231
- return JSON.parse(text);
232
- }
233
- catch {
234
- return undefined;
235
219
  }
236
220
  }
@@ -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
- }