@gentbajko/slopify 3.25.9 → 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 (603) 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/4.0.0.md +51 -0
  195. package/dist/patch-notes/index.json +6 -0
  196. package/dist/slices/admission/heads.js +2 -1
  197. package/dist/slices/admission/repo.js +2 -1
  198. package/dist/slices/admission/rules.js +43 -8
  199. package/dist/slices/admission/schema.js +8 -0
  200. package/dist/slices/admission/stage-writes.js +0 -3
  201. package/dist/slices/admission/start.js +48 -31
  202. package/dist/slices/admission/substitute.js +7 -4
  203. package/dist/slices/agents/attention-posts.js +31 -0
  204. package/dist/slices/agents/attention-templates.js +33 -0
  205. package/dist/slices/agents/attention.js +10 -1
  206. package/dist/slices/agents/connection.js +2 -6
  207. package/dist/slices/agents/model.js +6 -3
  208. package/dist/slices/agents/repo.js +15 -7
  209. package/dist/slices/article/continuation.js +0 -63
  210. package/dist/slices/article/plain.js +3 -2
  211. package/dist/slices/article/segments.js +2 -62
  212. package/dist/slices/assistant/access.js +1 -0
  213. package/dist/slices/assistant/asks.js +80 -0
  214. package/dist/slices/assistant/cost.js +54 -0
  215. package/dist/slices/assistant/gate.js +222 -0
  216. package/dist/slices/assistant/model.js +79 -0
  217. package/dist/slices/assistant/names.js +23 -0
  218. package/dist/slices/assistant/prompt.js +74 -0
  219. package/dist/slices/assistant/repo.js +74 -0
  220. package/dist/slices/assistant/tokens.js +18 -0
  221. package/dist/slices/assistant/turn.js +342 -0
  222. package/dist/slices/autopilot/buffer.js +76 -0
  223. package/dist/slices/autopilot/model.js +14 -0
  224. package/dist/slices/autopilot/notify.js +27 -0
  225. package/dist/slices/autopilot/repo.js +34 -0
  226. package/dist/slices/autopilot/signals.js +194 -0
  227. package/dist/slices/autopilot/warnings.js +85 -0
  228. package/dist/slices/autopilot/weekly.js +100 -0
  229. package/dist/slices/backups/files.js +2 -6
  230. package/dist/slices/backups/repo.js +3 -15
  231. package/dist/slices/backups/service.js +4 -3
  232. package/dist/slices/channels/cast-images.js +2 -1
  233. package/dist/slices/channels/model.js +0 -1
  234. package/dist/slices/channels/rebrand.js +0 -3
  235. package/dist/slices/channels/repo.js +4 -0
  236. package/dist/slices/channels/schema.js +6 -0
  237. package/dist/slices/channels/service.js +10 -0
  238. package/dist/slices/channels/videos.js +2 -14
  239. package/dist/slices/checkpoints/index.js +0 -1
  240. package/dist/slices/control/providers.js +0 -26
  241. package/dist/slices/designs/artwork.js +66 -0
  242. package/dist/slices/designs/budget.js +23 -0
  243. package/dist/slices/designs/calls.js +124 -0
  244. package/dist/slices/designs/check-context.js +38 -0
  245. package/dist/slices/designs/check-text.js +43 -0
  246. package/dist/slices/designs/fields.js +88 -0
  247. package/dist/slices/designs/frames.js +34 -0
  248. package/dist/slices/designs/gate.js +128 -0
  249. package/dist/slices/designs/layout.js +293 -0
  250. package/dist/slices/designs/model.js +35 -0
  251. package/dist/slices/designs/pdf-job.js +23 -0
  252. package/dist/slices/designs/pdf-pages.js +30 -0
  253. package/dist/slices/designs/pdf-runner.js +68 -0
  254. package/dist/slices/designs/pdf-worker.js +24 -0
  255. package/dist/slices/designs/picture-size.js +79 -0
  256. package/dist/slices/designs/pictures.js +55 -0
  257. package/dist/slices/designs/quote.js +24 -0
  258. package/dist/slices/designs/render-args.js +36 -0
  259. package/dist/slices/designs/render-input.js +59 -0
  260. package/dist/slices/designs/render.js +215 -0
  261. package/dist/slices/designs/repo.js +101 -0
  262. package/dist/slices/designs/requests.js +80 -0
  263. package/dist/slices/designs/runner.js +239 -0
  264. package/dist/slices/designs/sample-repo.js +91 -0
  265. package/dist/slices/designs/sample.js +222 -0
  266. package/dist/slices/designs/schema.js +87 -0
  267. package/dist/slices/designs/sections.js +44 -0
  268. package/dist/slices/designs/service.js +233 -0
  269. package/dist/slices/designs/steps-repo.js +102 -0
  270. package/dist/slices/designs/studio-kind.js +39 -0
  271. package/dist/slices/designs/template-checks.js +44 -0
  272. package/dist/slices/designs/template-make.js +118 -0
  273. package/dist/slices/designs/templates.js +218 -0
  274. package/dist/slices/document/fonts.js +2 -1
  275. package/dist/slices/episodes/summarize.js +5 -1
  276. package/dist/slices/estimate/index.js +45 -7
  277. package/dist/slices/fonts/catalog.js +3 -2
  278. package/dist/slices/fonts/discovery.js +3 -2
  279. package/dist/slices/fonts/files.js +2 -6
  280. package/dist/slices/fonts/index.js +0 -1
  281. package/dist/slices/fonts/sfnt.js +45 -10
  282. package/dist/slices/images/appearance.js +6 -15
  283. package/dist/slices/images/scenes.js +100 -27
  284. package/dist/slices/keywords/digest.js +84 -0
  285. package/dist/slices/keywords/facts.js +92 -0
  286. package/dist/slices/keywords/fill.js +80 -0
  287. package/dist/slices/keywords/model.js +75 -0
  288. package/dist/slices/keywords/rules.js +187 -0
  289. package/dist/slices/keywords/schema.js +28 -0
  290. package/dist/slices/keywords/specs.js +260 -0
  291. package/dist/slices/keywords/values.js +74 -0
  292. package/dist/slices/library/lint.js +29 -12
  293. package/dist/slices/library/model.js +2 -0
  294. package/dist/slices/library/photorealistic.js +4 -12
  295. package/dist/slices/library/rename.js +9 -7
  296. package/dist/slices/library/save.js +14 -10
  297. package/dist/slices/library/slots.js +37 -11
  298. package/dist/slices/library/transfer.js +2 -1
  299. package/dist/slices/library/used-by.js +25 -10
  300. package/dist/slices/loudness/loudnorm.js +51 -11
  301. package/dist/slices/model-checks/cost.js +61 -0
  302. package/dist/slices/model-checks/listing.js +124 -0
  303. package/dist/slices/model-checks/model.js +20 -0
  304. package/dist/slices/model-checks/record.js +32 -0
  305. package/dist/slices/model-checks/repo.js +120 -0
  306. package/dist/slices/model-checks/rules.js +112 -0
  307. package/dist/slices/model-checks/run.js +143 -0
  308. package/dist/slices/model-checks/service.js +198 -0
  309. package/dist/slices/model-upkeep/switch.js +70 -25
  310. package/dist/slices/model-upkeep/usage.js +26 -11
  311. package/dist/slices/narration/breaths.js +2 -1
  312. package/dist/slices/narration/clean-pieces.js +2 -1
  313. package/dist/slices/narration/concat.js +2 -1
  314. package/dist/slices/narration/peaks.js +3 -4
  315. package/dist/slices/narration/pronunciation-chunks.js +4 -3
  316. package/dist/slices/narration/pronunciation.js +3 -2
  317. package/dist/slices/narration/steering.js +4 -3
  318. package/dist/slices/notifications/notifier.js +4 -3
  319. package/dist/slices/notifications/rules.js +5 -2
  320. package/dist/slices/notifications/settings.js +4 -12
  321. package/dist/slices/notifications/subject.js +2 -1
  322. package/dist/slices/onboarding/copy.js +2 -1
  323. package/dist/slices/onboarding/first-run.js +3 -2
  324. package/dist/slices/onboarding/full-video.js +3 -2
  325. package/dist/slices/onboarding/install.js +4 -3
  326. package/dist/slices/onboarding/model.js +0 -16
  327. package/dist/slices/onboarding/packs.js +22 -22
  328. package/dist/slices/onboarding/quick-short.js +2 -1
  329. package/dist/slices/onboarding/sample.js +0 -1
  330. package/dist/slices/onboarding/state.js +2 -11
  331. package/dist/slices/onboarding/template.js +2 -1
  332. package/dist/slices/patch-notes/library.js +3 -2
  333. package/dist/slices/play-drafts/convert.js +4 -0
  334. package/dist/slices/play-drafts/review-inputs.js +8 -2
  335. package/dist/slices/play-drafts/review.js +5 -4
  336. package/dist/slices/play-drafts/schema.js +4 -0
  337. package/dist/slices/project-templates/from-project.js +9 -2
  338. package/dist/slices/project-templates/repo.js +6 -1
  339. package/dist/slices/project-templates/setup.js +8 -0
  340. package/dist/slices/project-templates/stand-ins.js +22 -0
  341. package/dist/slices/rebuild/activity.js +2 -0
  342. package/dist/slices/rebuild/admission-repo.js +3 -2
  343. package/dist/slices/rebuild/narration-history.js +4 -5
  344. package/dist/slices/rebuild/narration-retry.js +2 -1
  345. package/dist/slices/rebuild/preview-details.js +27 -9
  346. package/dist/slices/rebuild/preview-plan.js +3 -8
  347. package/dist/slices/rebuild/recipe-build.js +8 -3
  348. package/dist/slices/rebuild/recipe-describe.js +3 -3
  349. package/dist/slices/rebuild/recipe-digest.js +58 -0
  350. package/dist/slices/rebuild/recipe-input-schema.js +10 -0
  351. package/dist/slices/rebuild/recipe-keywords.js +71 -0
  352. package/dist/slices/rebuild/recipe-legacy.js +5 -1
  353. package/dist/slices/rebuild/recipe-model.js +4 -0
  354. package/dist/slices/rebuild/recipe-narration-text.js +2 -1
  355. package/dist/slices/rebuild/recipe-preparation.js +3 -3
  356. package/dist/slices/rebuild/recipe-reference.js +8 -4
  357. package/dist/slices/rebuild/recipe-reviews.js +27 -7
  358. package/dist/slices/rebuild/recipe-save.js +6 -3
  359. package/dist/slices/rebuild/recipe-scenes.js +40 -11
  360. package/dist/slices/rebuild/recipe-shorts.js +8 -8
  361. package/dist/slices/rebuild/recipe-social.js +46 -0
  362. package/dist/slices/rebuild/recipe-text.js +64 -20
  363. package/dist/slices/rebuild/recipe-validation.js +98 -28
  364. package/dist/slices/rebuild/recipe-visual.js +55 -16
  365. package/dist/slices/rebuild/recipe-work.js +15 -3
  366. package/dist/slices/rebuild/recipe-youtube.js +4 -3
  367. package/dist/slices/rebuild/recovery-selection.js +3 -1
  368. package/dist/slices/rebuild/recovery.js +3 -2
  369. package/dist/slices/rebuild/repo.js +4 -3
  370. package/dist/slices/rebuild/review-promise.js +25 -0
  371. package/dist/slices/rebuild/review-redo.js +2 -1
  372. package/dist/slices/rebuild/runtime-admission.js +4 -3
  373. package/dist/slices/rebuild/runtime-agent-review.js +11 -5
  374. package/dist/slices/rebuild/runtime-animate.js +9 -8
  375. package/dist/slices/rebuild/runtime-article.js +3 -2
  376. package/dist/slices/rebuild/runtime-checkpoints.js +5 -4
  377. package/dist/slices/rebuild/runtime-document.js +8 -11
  378. package/dist/slices/rebuild/runtime-export-bed.js +6 -11
  379. package/dist/slices/rebuild/runtime-export-edit.js +6 -15
  380. package/dist/slices/rebuild/runtime-export-inputs.js +7 -7
  381. package/dist/slices/rebuild/runtime-export-short.js +8 -4
  382. package/dist/slices/rebuild/runtime-export.js +34 -12
  383. package/dist/slices/rebuild/runtime-figure-card.js +2 -1
  384. package/dist/slices/rebuild/runtime-image.js +4 -9
  385. package/dist/slices/rebuild/runtime-instructions.js +2 -0
  386. package/dist/slices/rebuild/runtime-keywords.js +59 -0
  387. package/dist/slices/rebuild/runtime-lines.js +2 -11
  388. package/dist/slices/rebuild/runtime-local.js +14 -20
  389. package/dist/slices/rebuild/runtime-narration-publication.js +2 -5
  390. package/dist/slices/rebuild/runtime-narration-reuse.js +9 -13
  391. package/dist/slices/rebuild/runtime-narration-text.js +10 -15
  392. package/dist/slices/rebuild/runtime-pictures.js +2 -4
  393. package/dist/slices/rebuild/runtime-piece-label.js +10 -6
  394. package/dist/slices/rebuild/runtime-plan.js +31 -5
  395. package/dist/slices/rebuild/runtime-provider.js +60 -19
  396. package/dist/slices/rebuild/runtime-publication.js +10 -9
  397. package/dist/slices/rebuild/runtime-review.js +33 -28
  398. package/dist/slices/rebuild/runtime-run.js +4 -1
  399. package/dist/slices/rebuild/runtime-shorts.js +25 -45
  400. package/dist/slices/rebuild/runtime-store.js +3 -8
  401. package/dist/slices/rebuild/runtime-subtitles.js +16 -14
  402. package/dist/slices/rebuild/runtime-voices.js +8 -15
  403. package/dist/slices/rebuild/runtime-youtube.js +11 -29
  404. package/dist/slices/rebuild/transition-repo.js +6 -5
  405. package/dist/slices/rebuild/work-records.js +6 -0
  406. package/dist/slices/reruns/cascade.js +1 -2
  407. package/dist/slices/reruns/index.js +6 -9
  408. package/dist/slices/reviews/external-model.js +3 -0
  409. package/dist/slices/reviews/external-repo.js +2 -1
  410. package/dist/slices/reviews/external-rows.js +2 -3
  411. package/dist/slices/reviews/model.js +26 -8
  412. package/dist/slices/reviews/repo.js +2 -1
  413. package/dist/slices/reviews/rules.js +1 -0
  414. package/dist/slices/reviews/view.js +5 -2
  415. package/dist/slices/revisions/downloads.js +4 -5
  416. package/dist/slices/revisions/mutation-assets.js +7 -4
  417. package/dist/slices/revisions/mutation-cues.js +2 -5
  418. package/dist/slices/revisions/mutations.js +0 -1
  419. package/dist/slices/revisions/repo.js +3 -1
  420. package/dist/slices/revisions/schema.js +1 -0
  421. package/dist/slices/revisions/view.js +20 -0
  422. package/dist/slices/run-cost/limits.js +5 -2
  423. package/dist/slices/run-cost/meter.js +12 -5
  424. package/dist/slices/run-cost/panel.js +8 -74
  425. package/dist/slices/run-cost/plan-readings.js +127 -0
  426. package/dist/slices/run-cost/plan-use.js +169 -0
  427. package/dist/slices/run-cost/pricing.js +3 -3
  428. package/dist/slices/run-cost/week.js +32 -4
  429. package/dist/slices/schedules/agenda.js +11 -2
  430. package/dist/slices/schedules/by-date.js +42 -0
  431. package/dist/slices/schedules/calendar.js +5 -0
  432. package/dist/slices/schedules/design-agenda.js +36 -0
  433. package/dist/slices/schedules/design-check.js +41 -0
  434. package/dist/slices/schedules/design-run.js +126 -0
  435. package/dist/slices/schedules/next-run.js +62 -0
  436. package/dist/slices/schedules/prepare.js +18 -2
  437. package/dist/slices/schedules/repo.js +24 -16
  438. package/dist/slices/schedules/rescore.js +35 -0
  439. package/dist/slices/schedules/scheduler.js +13 -3
  440. package/dist/slices/schedules/schema.js +54 -3
  441. package/dist/slices/schedules/score.js +107 -0
  442. package/dist/slices/schedules/service.js +57 -24
  443. package/dist/slices/schedules/topic-list.js +15 -0
  444. package/dist/slices/schedules/topic-scores.js +104 -0
  445. package/dist/slices/schedules/topics.js +48 -36
  446. package/dist/slices/settings/cli-paths.js +4 -6
  447. package/dist/slices/settings/first-run.js +2 -11
  448. package/dist/slices/settings/model-reach.js +3 -17
  449. package/dist/slices/settings/model.js +10 -0
  450. package/dist/slices/settings/playback.js +33 -22
  451. package/dist/slices/settings/probe-read.js +16 -0
  452. package/dist/slices/settings/repo.js +33 -0
  453. package/dist/slices/settings/tutorial.js +2 -2
  454. package/dist/slices/settings/voices.js +4 -12
  455. package/dist/slices/shorts/pick.js +2 -15
  456. package/dist/slices/shorts/prompts.js +2 -13
  457. package/dist/slices/shorts/render.js +3 -0
  458. package/dist/slices/social/channel.js +44 -0
  459. package/dist/slices/social/defaults.js +17 -0
  460. package/dist/slices/social/due.js +36 -0
  461. package/dist/slices/social/extension.js +18 -0
  462. package/dist/slices/social/fit.js +115 -0
  463. package/dist/slices/social/limits.js +186 -0
  464. package/dist/slices/social/links.js +21 -0
  465. package/dist/slices/social/media.js +131 -0
  466. package/dist/slices/social/model.js +75 -0
  467. package/dist/slices/social/notice.js +19 -0
  468. package/dist/slices/social/pack.js +176 -0
  469. package/dist/slices/social/post-prompt.js +55 -0
  470. package/dist/slices/social/queue.js +31 -0
  471. package/dist/slices/social/repo.js +133 -0
  472. package/dist/slices/social/reshape.js +97 -0
  473. package/dist/slices/social/rules.js +5 -0
  474. package/dist/slices/social/schema.js +70 -0
  475. package/dist/slices/social/serve.js +51 -0
  476. package/dist/slices/social/service.js +128 -0
  477. package/dist/slices/social/settings.js +21 -0
  478. package/dist/slices/social/sources.js +114 -0
  479. package/dist/slices/social/state.js +110 -0
  480. package/dist/slices/social/text.js +149 -0
  481. package/dist/slices/storage/arrange.js +3 -1
  482. package/dist/slices/storage/assets.js +8 -10
  483. package/dist/slices/storage/backup-designs.js +74 -0
  484. package/dist/slices/storage/backup-export.js +8 -3
  485. package/dist/slices/storage/backup-format.js +10 -0
  486. package/dist/slices/storage/backup-import.js +20 -2
  487. package/dist/slices/storage/delete-project.js +6 -5
  488. package/dist/slices/storage/files-location.js +6 -8
  489. package/dist/slices/storage/layout.js +13 -2
  490. package/dist/slices/storage/model.js +3 -0
  491. package/dist/slices/storage/portable.js +16 -11
  492. package/dist/slices/storage/schema.js +2 -0
  493. package/dist/slices/storage/staging-refs.js +2 -1
  494. package/dist/slices/storage/staging.js +6 -9
  495. package/dist/slices/storage/trim.js +10 -3
  496. package/dist/slices/studio/calendar.js +4 -1
  497. package/dist/slices/studio/pick.js +2 -11
  498. package/dist/slices/studio/plan.js +6 -15
  499. package/dist/slices/studio/queue.js +3 -14
  500. package/dist/slices/studio/releases.js +26 -0
  501. package/dist/slices/studio/settings.js +14 -51
  502. package/dist/slices/studio/videos.js +12 -0
  503. package/dist/slices/style-preview/render.js +34 -13
  504. package/dist/slices/style-preview/schema.js +13 -0
  505. package/dist/slices/style-preview/service.js +2 -1
  506. package/dist/slices/style-preview/settings.js +33 -5
  507. package/dist/slices/telemetry/collector-client.js +2 -4
  508. package/dist/slices/telemetry/flush.js +2 -4
  509. package/dist/slices/telemetry/model.js +0 -7
  510. package/dist/slices/telemetry/record.js +10 -3
  511. package/dist/slices/template-studio/anatomy-view.js +118 -0
  512. package/dist/slices/template-studio/anatomy.js +73 -0
  513. package/dist/slices/template-studio/bakeoff-make.js +225 -0
  514. package/dist/slices/template-studio/bakeoff-repo.js +83 -0
  515. package/dist/slices/template-studio/bakeoff.js +333 -0
  516. package/dist/slices/template-studio/budget.js +103 -0
  517. package/dist/slices/template-studio/checks.js +273 -0
  518. package/dist/slices/template-studio/document-sample.js +56 -0
  519. package/dist/slices/template-studio/edit.js +15 -0
  520. package/dist/slices/template-studio/for-all.js +161 -0
  521. package/dist/slices/template-studio/free-video.js +31 -0
  522. package/dist/slices/template-studio/free.js +176 -0
  523. package/dist/slices/template-studio/gate.js +40 -0
  524. package/dist/slices/template-studio/hidden.js +20 -0
  525. package/dist/slices/template-studio/jobs.js +79 -0
  526. package/dist/slices/template-studio/loudness.js +111 -0
  527. package/dist/slices/template-studio/make.js +40 -0
  528. package/dist/slices/template-studio/model.js +54 -0
  529. package/dist/slices/template-studio/pack-import.js +253 -0
  530. package/dist/slices/template-studio/pack-samples.js +60 -0
  531. package/dist/slices/template-studio/pack.js +205 -0
  532. package/dist/slices/template-studio/paid-view.js +66 -0
  533. package/dist/slices/template-studio/paid.js +348 -0
  534. package/dist/slices/template-studio/quote.js +148 -0
  535. package/dist/slices/template-studio/ready.js +104 -0
  536. package/dist/slices/template-studio/repo.js +134 -0
  537. package/dist/slices/template-studio/reviews-path.js +58 -0
  538. package/dist/slices/template-studio/runner.js +84 -0
  539. package/dist/slices/template-studio/save.js +236 -0
  540. package/dist/slices/template-studio/say-it-as.js +248 -0
  541. package/dist/slices/template-studio/schedule-gate.js +34 -0
  542. package/dist/slices/template-studio/schedule-price.js +30 -0
  543. package/dist/slices/template-studio/schedule-sample.js +87 -0
  544. package/dist/slices/template-studio/schema.js +218 -0
  545. package/dist/slices/template-studio/scope.js +124 -0
  546. package/dist/slices/template-studio/sections.js +176 -0
  547. package/dist/slices/template-studio/service.js +173 -0
  548. package/dist/slices/template-studio/status.js +174 -0
  549. package/dist/slices/template-studio/topic.js +223 -0
  550. package/dist/slices/trash/designs.js +76 -0
  551. package/dist/slices/trash/model.js +13 -4
  552. package/dist/slices/trash/service.js +52 -2
  553. package/dist/slices/tutorials/library.js +3 -2
  554. package/dist/slices/video/ass-text.js +17 -0
  555. package/dist/slices/video/audio-export.js +2 -64
  556. package/dist/slices/video/encoding.js +160 -0
  557. package/dist/slices/video/ffmpeg.js +23 -21
  558. package/dist/slices/video/figure-card.js +1 -15
  559. package/dist/slices/video/slideshow.js +43 -18
  560. package/dist/slices/voices/palette.js +0 -3
  561. package/dist/slices/youtube/answer.js +2 -15
  562. package/dist/slices/youtube/edits-repo.js +2 -11
  563. package/dist/tutorials/Agents-MCP.md +2 -1
  564. package/dist/tutorials/Assistant.md +42 -0
  565. package/dist/tutorials/Channels.md +2 -0
  566. package/dist/tutorials/Home-and-Projects.md +19 -0
  567. package/dist/tutorials/Install.md +1 -0
  568. package/dist/tutorials/Keywords-Slopify-Fills.md +87 -0
  569. package/dist/tutorials/Models.md +33 -1
  570. package/dist/tutorials/Notifications.md +6 -0
  571. package/dist/tutorials/Play-Images.md +4 -0
  572. package/dist/tutorials/Posting-to-Social-Sites.md +121 -0
  573. package/dist/tutorials/Prompts.md +10 -6
  574. package/dist/tutorials/Remote-Access.md +63 -0
  575. package/dist/tutorials/Reviews-and-Checkpoints.md +13 -2
  576. package/dist/tutorials/Schedules.md +21 -1
  577. package/dist/tutorials/Settings-Reference.md +50 -8
  578. package/dist/tutorials/Template-Studio.md +125 -0
  579. package/dist/tutorials/Templates.md +3 -0
  580. package/dist/tutorials/_Sidebar.md +5 -0
  581. package/dist/updater/work-in-progress.js +42 -12
  582. package/dist/web/assets/index-CkAI_2E7.css +1 -0
  583. package/dist/web/assets/index-DcD0cdfo.js +334 -0
  584. package/dist/web/assets/{pdf-T7MCwjIv.js → pdf-TODRwF31.js} +1 -1
  585. package/dist/web/index.html +2 -2
  586. package/package.json +5 -1
  587. package/dist/slices/article/provided-entries.js +0 -66
  588. package/dist/slices/article/run.js +0 -145
  589. package/dist/slices/images/run.js +0 -234
  590. package/dist/slices/narration/legacy-plan.js +0 -58
  591. package/dist/slices/narration/run.js +0 -270
  592. package/dist/slices/rebuild/runtime-actions.js +0 -90
  593. package/dist/slices/research/run.js +0 -224
  594. package/dist/slices/subtitles/prepare.js +0 -194
  595. package/dist/slices/subtitles/transcript.js +0 -34
  596. package/dist/slices/thumbnail/run.js +0 -219
  597. package/dist/slices/video/audio-inputs.js +0 -33
  598. package/dist/slices/video/reuse-audio.js +0 -62
  599. package/dist/slices/video/run.js +0 -78
  600. package/dist/slices/video/write-export.js +0 -158
  601. package/dist/slices/video/write-subtitles.js +0 -59
  602. package/dist/web/assets/index-BadsoORk.css +0 -1
  603. package/dist/web/assets/index-D8LqNsCl.js +0 -326
@@ -0,0 +1,204 @@
1
+ // ceiling: a new OpenRouter model is proposed only from a vendor the list already carries,
2
+ // only when it was published in the last 60 days, and at most 10 a day, so the PR stays
3
+ // reviewable and the list stays curated.
4
+ export const newWithinDays = 60;
5
+ export const newPerRun = 10;
6
+ const source = "https://openrouter.ai/api/v1/models";
7
+ const perMillion = (perToken) => perToken === undefined ? undefined : Math.round(perToken * 1e6 * 1e6) / 1e6;
8
+ function rateNote(today) {
9
+ return `Public OpenRouter rates read ${today}; routing, long context, reasoning and web search may add charges.`;
10
+ }
11
+ const reasoningThinking = {
12
+ low: { effort: "low" },
13
+ medium: { effort: "medium" },
14
+ high: { effort: "high" },
15
+ };
16
+ function refreshed(row, live, today) {
17
+ const input = perMillion(live.promptPerToken);
18
+ const output = perMillion(live.completionPerToken);
19
+ const cached = perMillion(live.cachedPerToken);
20
+ const priced = (input !== undefined && input !== row.pricing.inputPerMillionTokens) ||
21
+ (output !== undefined && output !== row.pricing.outputPerMillionTokens);
22
+ const pricing = priced
23
+ ? {
24
+ ...row.pricing,
25
+ ...(input === undefined ? {} : { inputPerMillionTokens: input }),
26
+ ...(output === undefined ? {} : { outputPerMillionTokens: output }),
27
+ ...(cached === undefined ? {} : { cachedInputPerMillionTokens: cached }),
28
+ note: rateNote(today),
29
+ }
30
+ : row.pricing;
31
+ const llm = {
32
+ ...row.llm,
33
+ ...(live.contextLength === undefined ? {} : { contextTokens: live.contextLength }),
34
+ ...(live.maxOutputTokens === undefined ? {} : { maxOutputTokens: live.maxOutputTokens }),
35
+ ...(row.llm.thinking === undefined && live.reasoning === true
36
+ ? { thinking: reasoningThinking }
37
+ : {}),
38
+ };
39
+ return { row: { ...row, pricing, llm }, priced };
40
+ }
41
+ function proposedRow(live, today) {
42
+ const input = perMillion(live.promptPerToken);
43
+ const output = perMillion(live.completionPerToken);
44
+ return {
45
+ provider: "openrouter",
46
+ id: live.id,
47
+ name: (live.name ?? live.id).slice(0, 120),
48
+ enabled: true,
49
+ deprecated: false,
50
+ source,
51
+ keywords: ["llm"],
52
+ pricing: {
53
+ ...(input === undefined ? {} : { inputPerMillionTokens: input }),
54
+ ...(output === undefined ? {} : { outputPerMillionTokens: output }),
55
+ note: rateNote(today),
56
+ },
57
+ llm: {
58
+ webSearch: false,
59
+ ...(live.contextLength === undefined ? {} : { contextTokens: live.contextLength }),
60
+ ...(live.maxOutputTokens === undefined ? {} : { maxOutputTokens: live.maxOutputTokens }),
61
+ ...(live.reasoning === true ? { thinking: reasoningThinking } : {}),
62
+ },
63
+ };
64
+ }
65
+ function isNew(live, vendors, today) {
66
+ if (live.id.includes(":"))
67
+ return false;
68
+ const vendor = live.id.split("/")[0] ?? "";
69
+ if (!vendors.has(vendor))
70
+ return false;
71
+ if (!(live.inputs ?? []).includes("text") || !(live.outputs ?? []).includes("text"))
72
+ return false;
73
+ if (live.outputs !== undefined && live.outputs.length !== 1)
74
+ return false;
75
+ if (live.promptPerToken === undefined || live.completionPerToken === undefined)
76
+ return false;
77
+ if (live.created === undefined)
78
+ return false;
79
+ const age = (Date.parse(`${today}T00:00:00Z`) - live.created * 1000) / 86_400_000;
80
+ return age >= 0 && age <= newWithinDays;
81
+ }
82
+ export function proposeCatalogue(current, sources) {
83
+ const live = new Map(sources.openRouter.map((row) => [row.id, row]));
84
+ const added = [];
85
+ const retired = [];
86
+ const priced = [];
87
+ // A model past its lifecycle date retires, and its entry has done its job.
88
+ const expired = current.lifecycle.models.filter((row) => row.retiresOn <= sources.today);
89
+ const expiredKey = new Set(expired.map((row) => `${row.family}:${row.provider}:${row.id}`));
90
+ const retire = (family, row, vanished) => {
91
+ if (row.deprecated)
92
+ return row;
93
+ if (!vanished && !expiredKey.has(`${family}:${row.provider}:${row.id}`))
94
+ return row;
95
+ retired.push(row.id);
96
+ return { ...row, deprecated: true };
97
+ };
98
+ const llm = current.catalogue.llm.map((row) => {
99
+ if (row.provider !== "openrouter")
100
+ return retire("llm", row, false);
101
+ const found = live.get(row.id);
102
+ // An empty listing is a failed read, never "everything retired".
103
+ const vanished = live.size > 0 && found === undefined;
104
+ const next = retire("llm", row, vanished);
105
+ if (found === undefined || next.deprecated)
106
+ return next;
107
+ const fresh = refreshed(next, found, sources.today);
108
+ if (fresh.priced)
109
+ priced.push(row.id);
110
+ return fresh.row;
111
+ });
112
+ const vendors = new Set(current.catalogue.llm
113
+ .filter((row) => row.provider === "openrouter")
114
+ .map((row) => row.id.split("/")[0] ?? ""));
115
+ const known = new Set(current.catalogue.llm.map((row) => `${row.provider}:${row.id}`));
116
+ const room = Math.max(0, 300 - llm.length);
117
+ const fresh = sources.openRouter
118
+ .filter((row) => !known.has(`openrouter:${row.id}`) && isNew(row, vendors, sources.today))
119
+ .sort((a, b) => (b.created ?? 0) - (a.created ?? 0))
120
+ .slice(0, Math.min(newPerRun, room))
121
+ .map((row) => proposedRow(row, sources.today));
122
+ for (const row of fresh)
123
+ added.push(row.id);
124
+ const image = current.catalogue.image.map((row) => retire("image", row, false));
125
+ const tts = current.catalogue.tts.map((row) => retire("tts", row, false));
126
+ const changed = added.length + retired.length + priced.length > 0;
127
+ const catalogue = {
128
+ ...current.catalogue,
129
+ updatedAt: changed ? sources.today : current.catalogue.updatedAt,
130
+ llm: [...llm, ...fresh],
131
+ image,
132
+ tts,
133
+ };
134
+ // Metadata (context, output limit, thinking) can change without a price change.
135
+ const metadataChanged = JSON.stringify(catalogue.llm) !== JSON.stringify(current.catalogue.llm);
136
+ const lifecycle = {
137
+ ...current.lifecycle,
138
+ models: current.lifecycle.models.filter((row) => row.retiresOn > sources.today),
139
+ };
140
+ return {
141
+ catalogue: metadataChanged && !changed ? { ...catalogue, updatedAt: sources.today } : catalogue,
142
+ lifecycle,
143
+ added,
144
+ retired,
145
+ priced,
146
+ changed: changed || metadataChanged || expired.length > 0,
147
+ };
148
+ }
149
+ // The PR's title and the script's last line: "Models: 3 new, 1 retired, 2 price changes".
150
+ export function proposalSummary(proposal) {
151
+ const count = (n, one, many) => `${String(n)} ${n === 1 ? one : many}`;
152
+ return `Models: ${count(proposal.added.length, "new", "new")}, ${count(proposal.retired.length, "retired", "retired")}, ${count(proposal.priced.length, "price change", "price changes")}`;
153
+ }
154
+ // OpenRouter's full listing, read loosely: a row that does not read cleanly is skipped.
155
+ export function readOpenRouterModels(value) {
156
+ const data = typeof value === "object" && value !== null ? value.data : undefined;
157
+ if (!Array.isArray(data))
158
+ return [];
159
+ const num = (raw) => {
160
+ const n = typeof raw === "string" || typeof raw === "number" ? Number(raw) : Number.NaN;
161
+ return Number.isFinite(n) && n >= 0 ? n : undefined;
162
+ };
163
+ const int = (raw) => {
164
+ const n = num(raw);
165
+ return n !== undefined && Number.isInteger(n) && n > 0 ? n : undefined;
166
+ };
167
+ const strings = (raw) => Array.isArray(raw) ? raw.filter((one) => typeof one === "string") : undefined;
168
+ const rows = [];
169
+ for (const raw of data) {
170
+ if (typeof raw !== "object" || raw === null)
171
+ continue;
172
+ const row = raw;
173
+ if (typeof row.id !== "string" || row.id === "" || row.id.length > 200)
174
+ continue;
175
+ const pricing = (typeof row.pricing === "object" && row.pricing !== null ? row.pricing : {});
176
+ const architecture = (typeof row.architecture === "object" && row.architecture !== null ? row.architecture : {});
177
+ const top = (typeof row.top_provider === "object" && row.top_provider !== null ? row.top_provider : {});
178
+ const params = strings(row.supported_parameters) ?? [];
179
+ rows.push({
180
+ id: row.id,
181
+ ...(typeof row.name === "string" && row.name !== "" ? { name: row.name } : {}),
182
+ ...(int(row.created) === undefined ? {} : { created: int(row.created) }),
183
+ ...(int(row.context_length) === undefined ? {} : { contextLength: int(row.context_length) }),
184
+ ...(int(top.max_completion_tokens) === undefined
185
+ ? {}
186
+ : { maxOutputTokens: int(top.max_completion_tokens) }),
187
+ ...(num(pricing.prompt) === undefined ? {} : { promptPerToken: num(pricing.prompt) }),
188
+ ...(num(pricing.completion) === undefined
189
+ ? {}
190
+ : { completionPerToken: num(pricing.completion) }),
191
+ ...(num(pricing.input_cache_read) === undefined
192
+ ? {}
193
+ : { cachedPerToken: num(pricing.input_cache_read) }),
194
+ ...(strings(architecture.input_modalities) === undefined
195
+ ? {}
196
+ : { inputs: strings(architecture.input_modalities) }),
197
+ ...(strings(architecture.output_modalities) === undefined
198
+ ? {}
199
+ : { outputs: strings(architecture.output_modalities) }),
200
+ reasoning: params.includes("reasoning"),
201
+ });
202
+ }
203
+ return rows;
204
+ }
@@ -1,7 +1,7 @@
1
1
  import { thinkingModes } from "../kernel/ports/llm.js";
2
2
  import { providerError } from "../kernel/ports/model.js";
3
3
  import { isLocalCliProvider, systemVoiceProvider } from "../slices/settings/model.js";
4
- import { referenceRefusal, takesReferenceImage } from "./schema.js";
4
+ import { editRefusal, referenceRefusal, takesReferenceImage } from "./schema.js";
5
5
  export function curateRegistry(registry, catalogue) {
6
6
  const requireModel = (provider, family, id) => {
7
7
  const models = catalogue.models(provider, family);
@@ -135,6 +135,8 @@ export function curateRegistry(registry, catalogue) {
135
135
  kind: "unsupported",
136
136
  message: "The chosen image model has no effort setting. In the Edit tab, choose Edit project and set the images' Effort back to Model default under Providers, then use Continue the run.",
137
137
  });
138
+ if (request.edit !== undefined && !takesReferenceImage(model))
139
+ throw providerError({ kind: "unsupported", message: editRefusal });
138
140
  if (request.reference !== undefined && !takesReferenceImage(model))
139
141
  throw providerError({
140
142
  kind: "unsupported",
@@ -106,6 +106,8 @@ export function takesReferenceImage(model) {
106
106
  }
107
107
  // What the run says when the chosen image model cannot take the establishing image.
108
108
  export const referenceRefusal = "The chosen image model can't use an establishing image as a reference, so the images can't be drawn to match it. Choose an image model that can (Codex CLI, OpenAI, Google, or a fal.ai model listed with reference) under Images → Model on Play or in Edit project → Providers, or set Establishing image to Off in the Images section.";
109
+ // What a design's edit says when the chosen image model takes no input picture.
110
+ export const editRefusal = "This image model can't edit a picture. Choose Codex CLI, OpenAI, Google, or FLUX.2 or Nano Banana 2 on fal.ai under Made with … · change.";
109
111
  // The image-to-video models a provider offers, as Animate images lists them.
110
112
  export function videoModelsOf(catalogue, provider) {
111
113
  return catalogue.image.filter((m) => m.provider === provider && m.enabled && !m.deprecated && isVideoModel(m));
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSyn
2
2
  import { join } from "node:path";
3
3
  import { parse, stringify } from "yaml";
4
4
  import { isLocalCliProvider } from "../slices/settings/model.js";
5
+ import { emptyLifecycle, lifecycleSource, parseLifecycle } from "./lifecycle.js";
5
6
  import { applyOpenRouterListing, catalogueFamilies, combineChanges, mergeCatalogue, modelKey, noChanges, } from "./merge.js";
6
7
  import { catalogueSchema, isVideoModel } from "./schema.js";
7
8
  export const catalogueSource = "https://raw.githubusercontent.com/GentBajko/slopify/main/packages/app/src/assets/models.yaml";
@@ -33,6 +34,42 @@ export function createCatalogueStore(deps) {
33
34
  let refreshing;
34
35
  let syncing;
35
36
  const syncPath = join(deps.dataDir, "models-sync.json");
37
+ const lifecyclePath = join(deps.dataDir, "models-lifecycle.yaml");
38
+ const shippedLifecycle = () => {
39
+ try {
40
+ return parseLifecycle(deps.bundledLifecycle ??
41
+ readFileSync(new URL("../assets/models-lifecycle.yaml", import.meta.url), "utf8"));
42
+ }
43
+ catch {
44
+ return emptyLifecycle;
45
+ }
46
+ };
47
+ let lifecycle;
48
+ const readLifecycle = () => {
49
+ if (lifecycle !== undefined)
50
+ return lifecycle;
51
+ try {
52
+ lifecycle = parseLifecycle(readFileSync(lifecyclePath, "utf8"));
53
+ }
54
+ catch {
55
+ // No downloaded copy yet, or a damaged one: the shipped list stands in.
56
+ lifecycle = shippedLifecycle();
57
+ }
58
+ return lifecycle;
59
+ };
60
+ // Optional: a failed download keeps the last copy, and nothing else of the check depends on it.
61
+ async function syncLifecycle() {
62
+ try {
63
+ const text = await download(lifecycleSource, 256 * 1024);
64
+ const next = parseLifecycle(text);
65
+ writeFileSync(`${lifecyclePath}.next`, text, { mode: 0o600 });
66
+ renameSync(`${lifecyclePath}.next`, lifecyclePath);
67
+ lifecycle = next;
68
+ }
69
+ catch {
70
+ // Kept as it was.
71
+ }
72
+ }
36
73
  const now = deps.now ?? (() => new Date());
37
74
  function read() {
38
75
  try {
@@ -141,6 +178,7 @@ export function createCatalogueStore(deps) {
141
178
  const known = new Set(saved.known ?? keysOf(parseCatalogue(bundled)));
142
179
  const merged = mergeCatalogue(local, published, known);
143
180
  const live = applyOpenRouterListing(merged.catalogue, await openRouterListing());
181
+ await syncLifecycle();
144
182
  const changes = combineChanges(merged.changes, live.changes);
145
183
  const text = `${syncedHeader}${stringify(live.catalogue, { aliasDuplicateObjects: false })}`;
146
184
  const next = parseCatalogue(text);
@@ -169,6 +207,7 @@ export function createCatalogueStore(deps) {
169
207
  return last === null || at - Date.parse(last) >= catalogueCheckIntervalMs;
170
208
  },
171
209
  read,
210
+ lifecycle: readLifecycle,
172
211
  models: (provider, family) => read()[family].filter((m) => m.provider === provider && m.enabled && !m.deprecated && !isVideoModel(m)),
173
212
  status: () => {
174
213
  const saved = readSync();
@@ -1,6 +1,7 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { mkdir, readFile, rename, rmdir, unlink, writeFile } from "node:fs/promises";
3
3
  import { posix, win32 } from "node:path";
4
+ import { hasErrnoCode } from "../../kernel/errors.js";
4
5
  import { agentLabel, cmdLauncher, desktopEntry, desktopExecArg, desktopMarker, launchAgent, launcherMarker, runKey, runValue, shellLauncher, windowsPathProblem, windowsRunCommand, xmlText, } from "./launcher.js";
5
6
  const launcherDir = "autostart";
6
7
  // How each entry spells the launcher's path.
@@ -173,7 +174,7 @@ export const nodeAutostartFs = {
173
174
  return await readFile(path, "utf8");
174
175
  }
175
176
  catch (error) {
176
- if (isMissing(error))
177
+ if (hasErrnoCode(error, "ENOENT"))
177
178
  return undefined;
178
179
  throw error;
179
180
  }
@@ -190,7 +191,7 @@ export const nodeAutostartFs = {
190
191
  await unlink(path);
191
192
  }
192
193
  catch (error) {
193
- if (!isMissing(error))
194
+ if (!hasErrnoCode(error, "ENOENT"))
194
195
  throw error;
195
196
  }
196
197
  },
@@ -214,6 +215,3 @@ export const nodeAutostartExec = (file, args) => new Promise((resolve) => {
214
215
  resolve({ code, stdout, stderr: stderr || (error?.message ?? "") });
215
216
  });
216
217
  });
217
- function isMissing(error) {
218
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
219
- }
@@ -1,4 +1,5 @@
1
1
  import { createInterface } from "node:readline/promises";
2
+ import { errorText } from "../../kernel/errors.js";
2
3
  export const autostartQuestion = "Start Slopify when you log in? (Y/n) ";
3
4
  // The two flags as one answer: undefined when neither was given.
4
5
  export function autostartFlag(values) {
@@ -67,6 +68,6 @@ export async function settleAutostart(options) {
67
68
  : `${view.summary} Turn it on any time in Settings → General.`);
68
69
  }
69
70
  catch (error) {
70
- options.warn(error instanceof Error ? error.message : String(error));
71
+ options.warn(errorText(error));
71
72
  }
72
73
  }
@@ -1,3 +1,4 @@
1
+ import { errnoCode, errorText } from "../../kernel/errors.js";
1
2
  import { readSetting, writeSetting } from "../../slices/settings/repo.js";
2
3
  import { desktopHowTo, howToFor } from "./docker.js";
3
4
  import { autostartAnsweredKey } from "./model.js";
@@ -77,10 +78,8 @@ function desktopSummary(docker) {
77
78
  }
78
79
  // The native steps already speak in sentences; a file error from the disk doesn't.
79
80
  function plain(error, enabled) {
80
- const message = error instanceof Error ? error.message : String(error);
81
- const code = error instanceof Error && "code" in error && typeof error.code === "string"
82
- ? error.code
83
- : undefined;
81
+ const message = errorText(error);
82
+ const code = errnoCode(error);
84
83
  if (code === undefined)
85
84
  return message;
86
85
  const path = error instanceof Error && "path" in error && typeof error.path === "string"
@@ -1,4 +1,5 @@
1
1
  import { parseArgs } from "node:util";
2
+ import { errnoCode, errorText } from "../kernel/errors.js";
2
3
  const options = {
3
4
  port: { type: "string" },
4
5
  host: { type: "string" },
@@ -24,15 +25,13 @@ export function parseCli(args) {
24
25
  parsed = parse(args);
25
26
  }
26
27
  catch (error) {
27
- const code = error instanceof Error && "code" in error && typeof error.code === "string"
28
- ? error.code
29
- : undefined;
28
+ const code = errnoCode(error);
30
29
  if (code === "ERR_PARSE_ARGS_UNKNOWN_OPTION") {
31
30
  const flag = /'([^']+)'/.exec(error instanceof Error ? error.message : "")?.[1];
32
31
  throw new Error(`Slopify doesn't know the option ${flag ?? "you gave"}. Run npx @gentbajko/slopify --help to see every option.`);
33
32
  }
34
33
  if (code === "ERR_PARSE_ARGS_INVALID_OPTION_VALUE")
35
- throw new Error(`${error instanceof Error ? error.message : String(error)}. Run npx @gentbajko/slopify --help to see how each option is written.`);
34
+ throw new Error(`${errorText(error)}. Run npx @gentbajko/slopify --help to see how each option is written.`);
36
35
  throw error;
37
36
  }
38
37
  if (parsed.values.help === true || parsed.positionals[0] === "help")
package/dist/edge/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { configFrom } from "../kernel/config/index.js";
3
+ import { errnoCode } from "../kernel/errors.js";
3
4
  import { readVersion } from "../kernel/version.js";
4
5
  import { boot } from "../main.js";
5
6
  import { forwardManagedUpdate } from "../updater/forward.js";
@@ -113,7 +114,7 @@ catch (error) {
113
114
  function explainStartupError(error, config) {
114
115
  if (!(error instanceof Error))
115
116
  return String(error);
116
- const code = "code" in error && typeof error.code === "string" ? error.code : undefined;
117
+ const code = errnoCode(error);
117
118
  const syscall = "syscall" in error && typeof error.syscall === "string" ? error.syscall : "";
118
119
  if (config !== undefined && syscall === "listen") {
119
120
  const other = config.port === 7070 ? 7071 : 7070;
@@ -3,11 +3,11 @@ import { constants } from "node:fs";
3
3
  import { cp, lstat, mkdir, open, readdir, readFile, rename, rm, rmdir, unlink, } from "node:fs/promises";
4
4
  import { dirname, join } from "node:path";
5
5
  import { setTimeout as delay } from "node:timers/promises";
6
- import { hasCode } from "../../host-cli/paths.js";
7
6
  import { privateRead } from "../../host-cli/service.js";
7
+ import { errorText, hasErrnoCode } from "../../kernel/errors.js";
8
8
  import { recoveryId } from "./engine.js";
9
9
  import { installSchema, legacyJournalSchema, legacyReceiptSchema, privateDirectory, readState, settledLegacyPhases, updateSchema, writeState, writeText, } from "./state.js";
10
- import { contains, identity, isMissing, privateTree, safePath, treeDigest } from "./tree.js";
10
+ import { contains, identity, privateTree, safePath, treeDigest } from "./tree.js";
11
11
  const upArgs = ["up", "--detach", "--force-recreate", "--no-build", "--pull", "never"];
12
12
  /**
13
13
  * Installs or updates the Docker installation `<name>`: one transaction that waits for running
@@ -247,13 +247,13 @@ async function locked(o, e, directory) {
247
247
  };
248
248
  }
249
249
  catch (cause) {
250
- const reason = cause instanceof Error ? cause.message : String(cause);
250
+ const reason = errorText(cause);
251
251
  try {
252
252
  await rollback(o, e, directory, u);
253
253
  await unlink(paths.update);
254
254
  }
255
255
  catch (failure) {
256
- throw new Error(`Slopify could not finish, and could not fully put the previous version back either. Don't delete anything: ${u.backup ? `your data's recovery copy is the Docker volume ${u.backup}, ` : ""}progress is recorded in ${paths.update}. Fix the problem below and run the same command again; it finishes the undo first. What failed: ${reason} Undo problem: ${failure instanceof Error ? failure.message : String(failure)}`, { cause });
256
+ throw new Error(`Slopify could not finish, and could not fully put the previous version back either. Don't delete anything: ${u.backup ? `your data's recovery copy is the Docker volume ${u.backup}, ` : ""}progress is recorded in ${paths.update}. Fix the problem below and run the same command again; it finishes the undo first. What failed: ${reason} Undo problem: ${errorText(failure)}`, { cause });
257
257
  }
258
258
  throw new Error(`${o.mode === "update" ? "The update" : "The install"} failed, so Slopify put the previous version back${u.previous.kind === "none" ? "" : " and nothing was lost"}. What failed: ${reason}${u.backup ? ` The recovery copy of your data is kept in the Docker volume ${u.backup}.` : ""}`, { cause });
259
259
  }
@@ -312,7 +312,7 @@ async function tidyUp(o, e, u) {
312
312
  removed.push(what);
313
313
  }
314
314
  catch (error) {
315
- problems.push(`Couldn't remove ${what}, so it is kept. ${fix} Why: ${error instanceof Error ? error.message : String(error)}`);
315
+ problems.push(`Couldn't remove ${what}, so it is kept. ${fix} Why: ${errorText(error)}`);
316
316
  }
317
317
  };
318
318
  try {
@@ -332,7 +332,7 @@ async function tidyUp(o, e, u) {
332
332
  }
333
333
  }
334
334
  catch (error) {
335
- problems.push(`Couldn't list older recovery volumes and containers to tidy up, so all of them are kept. See them with docker volume ls --filter label=io.slopify.transaction. Why: ${error instanceof Error ? error.message : String(error)}`);
335
+ problems.push(`Couldn't list older recovery volumes and containers to tidy up, so all of them are kept. See them with docker volume ls --filter label=io.slopify.transaction. Why: ${errorText(error)}`);
336
336
  }
337
337
  return { removed, problems };
338
338
  }
@@ -395,14 +395,14 @@ async function publishProjects(o, e, source, projects, id, current) {
395
395
  }
396
396
  // assertEmpty checked it before anything changed; rmdir still refuses if files appeared since.
397
397
  await rmdir(projects).catch((error) => {
398
- if (!isMissing(error))
398
+ if (!hasErrnoCode(error, "ENOENT"))
399
399
  throw error;
400
400
  });
401
401
  await rename(staging, projects);
402
402
  }
403
403
  async function assertFolder(path) {
404
404
  const s = await lstat(path).catch((error) => {
405
- if (isMissing(error))
405
+ if (hasErrnoCode(error, "ENOENT"))
406
406
  return null;
407
407
  throw error;
408
408
  });
@@ -411,7 +411,7 @@ async function assertFolder(path) {
411
411
  }
412
412
  async function assertEmpty(path) {
413
413
  const entries = await readdir(path).catch((error) => {
414
- if (isMissing(error))
414
+ if (hasErrnoCode(error, "ENOENT"))
415
415
  return [];
416
416
  throw error;
417
417
  });
@@ -437,7 +437,7 @@ async function lock(path) {
437
437
  return () => unlink(path);
438
438
  }
439
439
  catch (error) {
440
- if (!hasCode(error, "EEXIST"))
440
+ if (!hasErrnoCode(error, "EEXIST"))
441
441
  throw error;
442
442
  const pid = Number((await readFile(path, "utf8").catch(() => "")).trim());
443
443
  if (Number.isInteger(pid) && pid > 0 && alive(pid))
@@ -453,6 +453,6 @@ function alive(pid) {
453
453
  return true;
454
454
  }
455
455
  catch (error) {
456
- return hasCode(error, "EPERM");
456
+ return hasErrnoCode(error, "EPERM");
457
457
  }
458
458
  }
@@ -4,6 +4,7 @@ import { join, resolve } from "node:path";
4
4
  import { createInterface } from "node:readline/promises";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { nodeHostSetupRunner } from "../../host-cli/install.js";
7
+ import { errorText } from "../../kernel/errors.js";
7
8
  import { readVersion } from "../../kernel/version.js";
8
9
  import { documentsDir, nodeDocumentsHost } from "../../slices/storage/documents.js";
9
10
  import { recordLoginStart } from "../autostart/docker-record.js";
@@ -116,7 +117,7 @@ export async function runDockerCommand(command) {
116
117
  now: () => new Date(),
117
118
  report: (line) => console.log(line),
118
119
  }).catch((error) => {
119
- console.warn(`Slopify couldn't check whether Docker starts when you log in (${error instanceof Error ? error.message : String(error)}). Settings → General will say it doesn't know; run the command again to check again.`);
120
+ console.warn(`Slopify couldn't check whether Docker starts when you log in (${errorText(error)}). Settings → General will say it doesn't know; run the command again to check again.`);
120
121
  });
121
122
  }
122
123
  finally {
@@ -2,7 +2,8 @@ import { lstat, mkdir } from "node:fs/promises";
2
2
  import { dirname, isAbsolute, join, resolve, sep } from "node:path";
3
3
  import { z } from "zod";
4
4
  import { privateRead, privateWrite } from "../../host-cli/service.js";
5
- import { isMissing, syncDirectory } from "./tree.js";
5
+ import { hasErrnoCode } from "../../kernel/errors.js";
6
+ import { syncDirectory } from "./tree.js";
6
7
  export const identifier = z
7
8
  .string()
8
9
  .min(1)
@@ -102,7 +103,7 @@ export async function privateDirectory(path, uid) {
102
103
  for (const name of path.split(sep).filter(Boolean)) {
103
104
  current = join(current, name);
104
105
  await mkdir(current, { mode: 0o700 }).catch((error) => {
105
- if (!(typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST"))
106
+ if (!hasErrnoCode(error, "EEXIST"))
106
107
  throw error;
107
108
  });
108
109
  const s = await lstat(current);
@@ -117,7 +118,7 @@ export async function privateDirectory(path, uid) {
117
118
  }
118
119
  export async function readState(path, schema, uid) {
119
120
  const s = await lstat(path).catch((error) => {
120
- if (isMissing(error))
121
+ if (hasErrnoCode(error, "ENOENT"))
121
122
  return undefined;
122
123
  throw error;
123
124
  });
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
2
2
  import { constants } from "node:fs";
3
3
  import { chmod, lchown, lstat, mkdir, open, readdir, readlink } from "node:fs/promises";
4
4
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
5
+ import { hasErrnoCode } from "../../kernel/errors.js";
5
6
  export async function identity(path) {
6
7
  const s = await lstat(path, { bigint: true });
7
8
  if (!s.isDirectory() || s.isSymbolicLink())
@@ -42,7 +43,7 @@ export async function safePath(path, home, stateRoot, createParents) {
42
43
  for (const [i, part] of parts.entries()) {
43
44
  current = join(current, part);
44
45
  let s = await lstat(current).catch((error) => {
45
- if (isMissing(error))
46
+ if (hasErrnoCode(error, "ENOENT"))
46
47
  return undefined;
47
48
  throw error;
48
49
  });
@@ -60,9 +61,6 @@ export async function safePath(path, home, stateRoot, createParents) {
60
61
  throw new Error(`Other users can write to ${current}, which contains the project folder. Choose a project folder inside your home folder with --projects-dir <folder>, or fix it with chmod go-w ${current}.`);
61
62
  }
62
63
  }
63
- export function isMissing(error) {
64
- return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
65
- }
66
64
  export async function syncDirectory(path) {
67
65
  const fd = await open(path, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
68
66
  try {
@@ -2,12 +2,13 @@ import { execFileSync } from "node:child_process";
2
2
  import { chmod, lchown, lstat, mkdir, readdir, rm } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { isMissing, syncDirectory, treeDigest } from "./tree.js";
5
+ import { hasErrnoCode } from "../../kernel/errors.js";
6
+ import { syncDirectory, treeDigest } from "./tree.js";
6
7
  export async function volumeOperation(args) {
7
8
  const [operation, user = "0:0"] = args;
8
9
  if (operation === "projects") {
9
10
  const present = await lstat("/source/projects").catch((e) => {
10
- if (isMissing(e))
11
+ if (hasErrnoCode(e, "ENOENT"))
11
12
  return null;
12
13
  throw e;
13
14
  });
@@ -3,9 +3,10 @@ import { join } from "node:path";
3
3
  import { setTimeout as delay } from "node:timers/promises";
4
4
  import { z } from "zod";
5
5
  import { installHostPackage } from "../host-cli/install.js";
6
- import { ensureBridgeToken, hasCode, prepareHostPaths } from "../host-cli/paths.js";
6
+ import { ensureBridgeToken, prepareHostPaths } from "../host-cli/paths.js";
7
7
  import { ensureHostService, privateRead, privateWrite } from "../host-cli/service.js";
8
8
  import { hostCommandName, resolveHostCommand } from "../host-cli/status.js";
9
+ import { errorText, hasErrnoCode } from "../kernel/errors.js";
9
10
  import { hostLlmIds } from "../kernel/ports/host-cli.js";
10
11
  export function assertManagedDockerHost(platform, uid, gid) {
11
12
  if (platform !== "linux")
@@ -28,8 +29,8 @@ export async function planDockerHostCli(options) {
28
29
  installed = true;
29
30
  }
30
31
  catch (error) {
31
- if (!hasCode(error, "ENOENT"))
32
- throw new Error(`Could not check whether ${hostCommandName(id)} is installed on this machine (${error instanceof Error ? error.message : String(error)}). Nothing was changed. Fix the problem, or start with --host-cli=off to use API keys only.`);
32
+ if (!hasErrnoCode(error, "ENOENT"))
33
+ throw new Error(`Could not check whether ${hostCommandName(id)} is installed on this machine (${errorText(error)}). Nothing was changed. Fix the problem, or start with --host-cli=off to use API keys only.`);
33
34
  }
34
35
  }
35
36
  if (!installed)
@@ -73,7 +74,7 @@ async function ensureDockerHostCli(options, uid, receiptPath) {
73
74
  break;
74
75
  }
75
76
  catch (error) {
76
- if (!hasCode(error, "EEXIST"))
77
+ if (!hasErrnoCode(error, "EEXIST"))
77
78
  throw error;
78
79
  if (Date.now() >= deadline)
79
80
  throw new Error(`Another Slopify launcher is setting up the host CLI helper right now. Wait for it to finish and try again. If no other launcher is running, delete the folder ${lock} and retry.`);