@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
package/dist/main.js CHANGED
@@ -7,9 +7,12 @@ import ffmpegStatic from "ffmpeg-static";
7
7
  import { buildRegistry } from "./adapter-registry.js";
8
8
  import { alignSubtitlesWith } from "./adapters/alignment/index.js";
9
9
  import { prefetchModel } from "./adapters/alignment/prefetch.js";
10
- import { prepareFfmpeg } from "./adapters/ffmpeg.js";
10
+ import { ffmpegOutput, prepareFfmpeg } from "./adapters/ffmpeg.js";
11
11
  import { createHostCliClient } from "./adapters/host-cli/index.js";
12
+ import { createSearchInterest } from "./adapters/interest/search-interest.js";
12
13
  import { nodeRunCli } from "./adapters/llm/run-cli.js";
14
+ import { assistantSelfUrl, wireAssistant } from "./assistant-wiring.js";
15
+ import { startAutopilot } from "./autopilot-timers.js";
13
16
  import { curateRegistry } from "./catalog/registry.js";
14
17
  import { createCatalogueStore } from "./catalog/store.js";
15
18
  import { createAutostart } from "./edge/autostart/index.js";
@@ -20,6 +23,8 @@ import { createApp } from "./edge/http/app.js";
20
23
  import { createMutationLifecycle, drainMutationsWithDeadline } from "./edge/http/mutations.js";
21
24
  import { limitRequestTimes } from "./edge/http/timeouts.js";
22
25
  import { openFolder } from "./edge/open-folder.js";
26
+ import { nodeTailscaleRun } from "./edge/remote-access/cli.js";
27
+ import { createRemoteAccessService } from "./edge/remote-access/service.js";
23
28
  import { readHostLogin } from "./host-cli/status.js";
24
29
  import { createAudioPreviewStore } from "./kernel/audio-preview.js";
25
30
  import { systemClock } from "./kernel/clock.js";
@@ -30,7 +35,7 @@ import { causedBy } from "./kernel/errors.js";
30
35
  import { ulidIds } from "./kernel/ids.js";
31
36
  import { acquireInstanceLock } from "./kernel/lock.js";
32
37
  import { openLog } from "./kernel/log.js";
33
- import { attachPlaces, ensureDataDirs, ensureDirs, layout, repoint, subtitleModelDir, } from "./kernel/paths.js";
38
+ import { attachPlaces, attachSamples, ensureDataDirs, ensureDirs, layout, repoint, subtitleModelDir, } from "./kernel/paths.js";
34
39
  import { stageKinds } from "./kernel/pipeline.js";
35
40
  import { sqliteAttempts } from "./kernel/runner/attempt-repo.js";
36
41
  import { auditionVoice } from "./kernel/runner/audition.js";
@@ -41,14 +46,24 @@ import { createProviderQueue } from "./kernel/runner/queue.js";
41
46
  import { standaloneImage, standaloneLlm } from "./kernel/runner/standalone.js";
42
47
  import { readVersion } from "./kernel/version.js";
43
48
  import { modelSources } from "./model-catalog.js";
49
+ import { cliWatcher, lookAtModels, wireModelChecks } from "./model-checks.js";
44
50
  import { projectPaused, projectTrashed } from "./slices/admission/repo.js";
45
51
  import { createBackupService } from "./slices/backups/service.js";
46
52
  import { pumpQueue, queueWaiting } from "./slices/batch/index.js";
47
53
  import { settleInterruptedCastImages } from "./slices/channels/cast-images.js";
48
54
  import { approveCheckpoint } from "./slices/checkpoints/index.js";
49
55
  import { checkpointDecisionForWork, recoverCheckpointWork, settleReleasedCheckpoints, } from "./slices/checkpoints/recovery.js";
56
+ import { dailySampleBudget } from "./slices/designs/budget.js";
57
+ import { designCheckContext } from "./slices/designs/check-context.js";
58
+ import { contextChecks, sampleCheck } from "./slices/designs/gate.js";
59
+ import { runPdfWorker } from "./slices/designs/pdf-runner.js";
60
+ import { createDesignRenderer } from "./slices/designs/render.js";
61
+ import { createDesignRunner } from "./slices/designs/runner.js";
62
+ import { createDesignSamples } from "./slices/designs/sample.js";
50
63
  import { createEpisodeMemoryWatcher, } from "./slices/episodes/summarize.js";
51
64
  import { resolveFont } from "./slices/fonts/index.js";
65
+ import { accessRecorder } from "./slices/model-checks/record.js";
66
+ import { readChecks } from "./slices/model-checks/repo.js";
52
67
  import { decodePeaks } from "./slices/narration/peaks.js";
53
68
  import { projectLink } from "./slices/notifications/address.js";
54
69
  import { createNotificationSender } from "./slices/notifications/send.js";
@@ -68,13 +83,15 @@ import { releaseDueReviews } from "./slices/reviews/external-release.js";
68
83
  import { currentRevisionId } from "./slices/revisions/repo.js";
69
84
  import { createLimitGate, resumeAfterRestart } from "./slices/run-cost/limits.js";
70
85
  import { createStandaloneMeter, createUsageMeter } from "./slices/run-cost/meter.js";
86
+ import { refreshDesignSchedules } from "./slices/schedules/next-run.js";
71
87
  import { settleTerminalScheduleRuns } from "./slices/schedules/repo.js";
72
88
  import { createScheduleRunner } from "./slices/schedules/scheduler.js";
73
89
  import { nodeCliProbe } from "./slices/settings/cli-status.js";
74
- import { isLocalCliProvider, localCliConcurrency } from "./slices/settings/model.js";
90
+ import { isLocalCliProvider, localCliConcurrency, providerIds } from "./slices/settings/model.js";
75
91
  import { readSettings } from "./slices/settings/playback.js";
76
92
  import { providerStatuses } from "./slices/settings/readiness.js";
77
93
  import { readSetting } from "./slices/settings/repo.js";
94
+ import { createReshaper } from "./slices/social/reshape.js";
78
95
  import { arrangeChanged } from "./slices/storage/arrange.js";
79
96
  import { busyProjects } from "./slices/storage/backup-export.js";
80
97
  import { documentsDir, nodeDocumentsHost } from "./slices/storage/documents.js";
@@ -83,13 +100,27 @@ import { createPlaces, recoverPlaces } from "./slices/storage/places.js";
83
100
  import { reconcileStorage } from "./slices/storage/reconcile.js";
84
101
  import { installUnpackedExtension, unpackedExtensionDir, } from "./slices/studio/unpacked.js";
85
102
  import { previewPictures } from "./slices/style-preview/images.js";
103
+ import { bundledSampleAssets } from "./slices/style-preview/narration.js";
86
104
  import { ffmpegStylePreview } from "./slices/style-preview/render.js";
87
105
  import { createStylePreviews, stylePreviewDir } from "./slices/style-preview/service.js";
88
106
  import { collectorEndpoint, httpPostEvents } from "./slices/telemetry/collector-client.js";
89
107
  import { createFlusher } from "./slices/telemetry/flush.js";
90
- import { record } from "./slices/telemetry/record.js";
108
+ import { record, skippingProjects } from "./slices/telemetry/record.js";
109
+ import { makeBakeoff } from "./slices/template-studio/bakeoff-make.js";
110
+ import { readStudioSettings } from "./slices/template-studio/budget.js";
111
+ import { createDocumentSamples } from "./slices/template-studio/document-sample.js";
112
+ import { createFreeSamples } from "./slices/template-studio/free.js";
113
+ import { createLoudnessSamples } from "./slices/template-studio/loudness.js";
114
+ import { sampleMaker } from "./slices/template-studio/make.js";
115
+ import { makePaidSample } from "./slices/template-studio/paid.js";
116
+ import { sampleProjects, templateSampleCheck } from "./slices/template-studio/repo.js";
117
+ import { createSampleRunner } from "./slices/template-studio/runner.js";
118
+ import { storedUnknownAcks } from "./slices/template-studio/save.js";
119
+ import { notReadySentence, runnableTemplate, templateGate, } from "./slices/template-studio/schedule-gate.js";
120
+ import { createPriceCache } from "./slices/template-studio/service.js";
91
121
  import { createTrashPurge } from "./slices/trash/service.js";
92
- import { probeDurationMs } from "./slices/video/ffmpeg.js";
122
+ import { createNvencProbe, noNvenc, renderMachine, } from "./slices/video/encoding.js";
123
+ import { probeDurationMs, runFfmpegAt } from "./slices/video/ffmpeg.js";
93
124
  import { watchActivation } from "./updater/candidate.js";
94
125
  import { launchUpdate } from "./updater/install.js";
95
126
  import { isUpdateToken } from "./updater/model.js";
@@ -103,6 +134,21 @@ import { workInProgress } from "./updater/work-in-progress.js";
103
134
  const flushDelayMs = 1000;
104
135
  const collectorTimeoutMs = 10_000;
105
136
  const mutationDrainTimeoutMs = 5_000;
137
+ // ceiling: removing the serve handler is two quick tailscale calls; a hung Tailscale must not
138
+ // hold the shutdown, and the next start removes or replaces what is left.
139
+ const remoteAccessStopMs = 5_000;
140
+ // ceiling: an image call usually answers within a minute; shutdown waits no longer than this
141
+ // for one already sent, and the next start marks a step still making as stopped.
142
+ const designIdleMs = 60_000;
143
+ function withDeadline(work, ms) {
144
+ return new Promise((resolve) => {
145
+ const timer = setTimeout(resolve, ms);
146
+ void work.finally(() => {
147
+ clearTimeout(timer);
148
+ resolve();
149
+ });
150
+ });
151
+ }
106
152
  export function createScheduleTickLifecycle(deps) {
107
153
  let stopping = false;
108
154
  let inflight;
@@ -195,6 +241,9 @@ export async function boot(config, options = {}) {
195
241
  recoverPlaces(db, paths);
196
242
  const places = createPlaces(db);
197
243
  attachPlaces(paths, places);
244
+ // A template's studio sample keeps its folder in the data dir, never in Projects
245
+ // (`slices/template-studio`): set before anything reads or reconciles a project's files.
246
+ attachSamples(paths, sampleProjects(db, paths.dataDir));
198
247
  const runtimeDb = db;
199
248
  const interrupted = markInterruptedStages(db, clock);
200
249
  recoverCheckpointWork(db);
@@ -205,6 +254,17 @@ export async function boot(config, options = {}) {
205
254
  // candidate's committed activation pointer has been verified.
206
255
  const reconciled = pendingActivation ? undefined : reconcileStorage(db, paths);
207
256
  const log = openLog(paths.logs, clock);
257
+ // Settings → Production defaults → Video encoder: the bundled ffmpeg first, then the
258
+ // computer's own. Asked once, when the settings page or a render first needs it.
259
+ const nvenc = createNvencProbe({
260
+ candidates: [ffmpeg, "ffmpeg", "/usr/bin/ffmpeg"],
261
+ exec: ffmpegOutput,
262
+ log,
263
+ });
264
+ // Settings → Production defaults → Render priority for the ffmpeg work outside a project's
265
+ // render (Template Studio's samples, designs' drawing, posts' pictures), read as each starts.
266
+ const renderPriority = () => readSettings({ db: runtimeDb, log }).renderPriority;
267
+ const runFfmpeg = runFfmpegAt(renderPriority);
208
268
  log.write("info", "boot", {
209
269
  detail: reconciled === undefined
210
270
  ? `interrupted stages ${interrupted}, settled schedules ${settledSchedules}, storage reconciliation deferred during update activation`
@@ -225,6 +285,8 @@ export async function boot(config, options = {}) {
225
285
  ids,
226
286
  log,
227
287
  presentEvent: eventPresenter(eventDb),
288
+ // A template's hidden sample is told to its studio, never to the shell or Home.
289
+ quiet: templateSampleCheck(eventDb),
228
290
  }), (event) => {
229
291
  notifier.observe(event);
230
292
  episodes?.observe(event);
@@ -252,11 +314,15 @@ export async function boot(config, options = {}) {
252
314
  }), catalogue);
253
315
  // Calls that belong to no project (topic generation, episode summaries, cast pictures)
254
316
  // still go through the attempt wrapper, and are metered against their schedule or channel.
317
+ // What real calls teach about each model for the person's keys and logins (Settings →
318
+ // Models, the pickers); no run reads it back.
319
+ const access = accessRecorder({ db, clock });
255
320
  const standalone = {
256
321
  registry,
257
322
  clock,
258
323
  log,
259
324
  meter: createStandaloneMeter({ db, ids, clock, catalogue: () => catalogue.read() }),
325
+ access,
260
326
  };
261
327
  episodes = createEpisodeMemoryWatcher({
262
328
  db,
@@ -285,6 +351,7 @@ export async function boot(config, options = {}) {
285
351
  registry,
286
352
  catalogue,
287
353
  ffmpeg,
354
+ nvenc,
288
355
  audioPreviews,
289
356
  });
290
357
  const updateDb = db;
@@ -306,6 +373,8 @@ export async function boot(config, options = {}) {
306
373
  // Folders are renamed only by a version that is committed: an update on trial can still be
307
374
  // rolled back to a version that knows only id-named folders.
308
375
  let arrangeAllowed = !pendingActivation;
376
+ // What an update waits for that only lives in memory; set once those parts are wired.
377
+ let liveWork = () => undefined;
309
378
  const updater = createUpdater({
310
379
  ...(isUpdateToken(candidateToken)
311
380
  ? {
@@ -348,9 +417,8 @@ export async function boot(config, options = {}) {
348
417
  ? "npm was not found, so in-app updates are off. Install Node.js with npm (https://nodejs.org), or update from the terminal: npx @gentbajko/slopify@latest"
349
418
  : undefined,
350
419
  // An update never installs while a job is going (`updater/work-in-progress.ts`).
351
- busy: () => workInProgress(updateDb, (id) => runner.hasInflight?.(id) === true, Date.now()) !==
352
- undefined,
353
- busyWith: () => workInProgress(updateDb, (id) => runner.hasInflight?.(id) === true, Date.now()),
420
+ busy: () => workInProgress(updateDb, (id) => runner.hasInflight?.(id) === true, Date.now(), liveWork) !== undefined,
421
+ busyWith: () => workInProgress(updateDb, (id) => runner.hasInflight?.(id) === true, Date.now(), liveWork),
354
422
  report: (message) => log.write("warn", "update", { detail: message }),
355
423
  install: async (next, restarting) => {
356
424
  if (npm === undefined)
@@ -384,6 +452,18 @@ export async function boot(config, options = {}) {
384
452
  modelsFor: modelSources(registry).modelsFor,
385
453
  emit: (projectId, event) => hub.emit(projectId, event),
386
454
  };
455
+ // Which models work for the person's keys and logins (Settings → Models, the pickers).
456
+ const { checks: modelChecks, listing: modelListing } = wireModelChecks({
457
+ db,
458
+ clock,
459
+ log,
460
+ registry,
461
+ catalogue: () => catalogue.read(),
462
+ lifecycle: catalogue.lifecycle,
463
+ fetch: globalThis.fetch,
464
+ statuses: rebuild.providers,
465
+ });
466
+ const autoModelChecks = options.refreshModels === true;
387
467
  // Redos a review asked for before the last shutdown start now.
388
468
  reviewRedos.bind(rebuild);
389
469
  reviewRedos.kick();
@@ -421,10 +501,20 @@ export async function boot(config, options = {}) {
421
501
  flusher.soon();
422
502
  },
423
503
  };
504
+ // Built with the designs further down; design schedules make their pieces with it.
505
+ let designMake;
424
506
  const scheduleRunnerDeps = {
425
507
  ...draftDeps,
426
- template: (id) => templateById(runtimeDb, id),
508
+ designs: () => designMake,
509
+ // The newest version that may run: legacy, marked ready, or carried by Slopify. Only a
510
+ // project template's: a design schedule asks the designs (runnableDesignVersion).
511
+ template: (id) => runnableTemplate(runtimeDb, id),
512
+ notReady: (id) => notReadySentence(runtimeDb, id),
513
+ templateHead: (id) => templateById(runtimeDb, id),
514
+ templateGate: (id) => templateGate(runtimeDb, id),
427
515
  topicLlm: (call) => standaloneLlm(standalone, call),
516
+ // Asked only for schedules set to rank topics by public search interest.
517
+ interest: createSearchInterest({ fetch: globalThis.fetch, version, now: () => clock.now() }),
428
518
  topicsWaiting: (event) => {
429
519
  hub.emitGlobal(event);
430
520
  notifier.observeTopics(event);
@@ -443,6 +533,59 @@ export async function boot(config, options = {}) {
443
533
  detail: "Scheduled jobs could not be advanced.",
444
534
  }),
445
535
  });
536
+ // Library → Templates → Open studio: its free samples, made one job at a time in the
537
+ // background (`slices/template-studio/runner.ts`).
538
+ const stylePreviews = createStylePreviews({
539
+ dir: stylePreviewDir(paths.dataDir),
540
+ render: ffmpegStylePreview({
541
+ ffmpeg,
542
+ paths,
543
+ log,
544
+ dir: stylePreviewDir(paths.dataDir),
545
+ // Encoded and prioritised as this computer's videos are (`slices/video/encoding.ts`).
546
+ machine: async () => (await renderMachine({ settings: readSettings({ db: runtimeDb, log }), nvenc, log }))
547
+ .machine,
548
+ }),
549
+ pictures: previewPictures({ db, paths }),
550
+ log,
551
+ });
552
+ const studioCache = join(paths.dataDir, "cache", "template-studio");
553
+ const loudnessSamples = createLoudnessSamples({
554
+ ffmpeg,
555
+ dir: join(studioCache, "loudness"),
556
+ source: bundledSampleAssets().narration,
557
+ log,
558
+ priority: renderPriority,
559
+ });
560
+ const documentSamples = createDocumentSamples({ dir: join(studioCache, "document") });
561
+ const freeSamples = createFreeSamples({
562
+ stylePreviews,
563
+ loudness: loudnessSamples,
564
+ documents: documentSamples,
565
+ loudnessDefault: () => readSettings({ db: runtimeDb, log }).loudness,
566
+ });
567
+ const studioPrices = createPriceCache();
568
+ // The unknown prices accepted on Save, shared by the studio's routes and its sample loop,
569
+ // and kept across restarts.
570
+ const studioAcks = storedUnknownAcks(db);
571
+ const sampleChanged = (templateId) => hub.emitGlobal({ type: "template.sample", templateId });
572
+ const sampleRunner = createSampleRunner({
573
+ db,
574
+ log,
575
+ changed: sampleChanged,
576
+ make: sampleMaker({
577
+ db,
578
+ free: freeSamples,
579
+ prices: studioPrices,
580
+ review: draftDeps,
581
+ changed: sampleChanged,
582
+ // Paid samples run on their hidden project through the same engine as every project.
583
+ paid: (job, signal) => makePaidSample({ start: draftDeps, rebuild, acks: studioAcks }, job, signal),
584
+ // Compare models: copies of the sample, made one bake-off at a time on the same loop.
585
+ bakeoff: (job, signal) => makeBakeoff({ start: draftDeps, rebuild }, job, signal),
586
+ }),
587
+ });
588
+ sampleRunner.start();
446
589
  const mutations = createMutationLifecycle();
447
590
  const folderConfiguration = await dockerFolderConfiguration(process.env, paths.projects);
448
591
  const filesService = createFilesService({
@@ -489,6 +632,18 @@ export async function boot(config, options = {}) {
489
632
  version,
490
633
  env: process.env,
491
634
  });
635
+ // Settings → General → Remote access. It proxies to the port the server really got, read
636
+ // when it applies; nothing applies before the server listens.
637
+ const remoteAccess = createRemoteAccessService({
638
+ db,
639
+ run: nodeTailscaleRun(process.platform),
640
+ platform: process.platform,
641
+ container: process.env.SLOPIFY_CONTAINER === "1",
642
+ listenHost: config.host,
643
+ port: () => listeningPort,
644
+ log,
645
+ now: () => Date.now(),
646
+ });
492
647
  if (options.refreshAutostart === true)
493
648
  void autostart.refresh().catch((error) => {
494
649
  log.write("warn", "autostart.refresh", { detail: causedBy(error) });
@@ -505,8 +660,109 @@ export async function boot(config, options = {}) {
505
660
  catch (error) {
506
661
  log.write("warn", "studio.extension", { detail: causedBy(error) });
507
662
  }
663
+ const autopilot = startAutopilot({
664
+ db: updateDb,
665
+ clock,
666
+ log,
667
+ dataDir: paths.dataDir,
668
+ template: (id) => templateById(updateDb, id),
669
+ catalogue: () => catalogue.read(),
670
+ fetch: globalThis.fetch,
671
+ send: sendNotification,
672
+ hostCli,
673
+ readLogin: readHostLogin,
674
+ });
675
+ // The assistant panel's chat: turns on this computer's Claude Code or Codex, reaching this
676
+ // server's own `/mcp/assistant`. In the Docker copy it says why it isn't there.
677
+ const assistant = wireAssistant({
678
+ db: updateDb,
679
+ ids,
680
+ clock,
681
+ log,
682
+ emit: hub.emitGlobal,
683
+ spawn: nodeRunCli,
684
+ probe: nodeCliProbe,
685
+ readLogin: readHostLogin,
686
+ selfUrl: () => assistantSelfUrl(config.host, listeningPort),
687
+ container: hostCli !== undefined,
688
+ });
689
+ // Library → Designs: paid pictures through the attempt wrapper, metered on the design;
690
+ // drawing in a child ffmpeg and PDFs in a forked worker, never on this thread.
691
+ // The template editor's samples hear when a sample's picture lands, to start the next.
692
+ let designSamples;
693
+ const designService = {
694
+ db,
695
+ clock,
696
+ ids,
697
+ paths,
698
+ log,
699
+ emit: (event) => {
700
+ hub.emitGlobal(event);
701
+ if (event.type === "design.changed")
702
+ designSamples?.designChanged(event.designId);
703
+ },
704
+ };
705
+ const designRenderer = createDesignRenderer({
706
+ db,
707
+ paths,
708
+ log,
709
+ clock,
710
+ ffmpeg,
711
+ runFfmpeg,
712
+ font: (fontId) => resolveFont(paths, fontId),
713
+ pdf: (job, signal) => runPdfWorker(job, signal),
714
+ });
715
+ const designRunner = createDesignRunner({
716
+ ...designService,
717
+ catalogue: () => catalogue.read(),
718
+ generate: ({ designId, ...call }) => standaloneImage(standalone, { ...call, owner: { kind: "design", id: designId } }),
719
+ shrink: (bytes) => designRenderer.shrink(bytes, AbortSignal.timeout(120_000)),
720
+ });
721
+ designRunner.recover();
722
+ liveWork = () => modelChecks.running().length > 0
723
+ ? "the model checks"
724
+ : assistant.turnsRunning() > 0
725
+ ? "the assistant's answer"
726
+ : undefined;
727
+ designMake = {
728
+ service: designService,
729
+ runner: designRunner,
730
+ catalogue: () => catalogue.read(),
731
+ };
732
+ designSamples = createDesignSamples({
733
+ service: designService,
734
+ runner: designRunner,
735
+ catalogue: () => catalogue.read(),
736
+ budget: () => dailySampleBudget(runtimeDb, log),
737
+ plans: () => readStudioSettings(runtimeDb).samplesUsePlans,
738
+ timeZone: () => Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC",
739
+ });
740
+ designSamples.recover();
741
+ const designChecks = designCheckContext({
742
+ resolveFont: (fontId) => resolveFont(paths, fontId),
743
+ providers: rebuild.providers,
744
+ });
508
745
  const app = createApp({
746
+ assistant,
747
+ autopilot,
748
+ designs: { service: designService, runner: designRunner, renderer: designRenderer },
749
+ // Pictures cut to a post's shape, in a child ffmpeg like the designs' drawing.
750
+ social: { reshaper: createReshaper({ paths, ffmpeg, runFfmpeg, log }) },
751
+ designTemplates: {
752
+ service: designService,
753
+ runner: designRunner,
754
+ catalogue: () => catalogue.read(),
755
+ checks: async (templateId, doc, version) => [
756
+ ...(await contextChecks(doc, templateId, designChecks)),
757
+ sampleCheck(runtimeDb, templateId, version),
758
+ ],
759
+ samples: designSamples,
760
+ templateChanged: (templateId) => {
761
+ refreshDesignSchedules(runtimeDb, templateId, clock.now());
762
+ },
763
+ },
509
764
  autostart,
765
+ remoteAccess,
510
766
  rebuild,
511
767
  drafts: draftDeps,
512
768
  schedules: scheduleDeps,
@@ -523,20 +779,29 @@ export async function boot(config, options = {}) {
523
779
  db,
524
780
  paths,
525
781
  host: config.host,
782
+ allowedHosts: (process.env.SLOPIFY_ALLOWED_HOSTS ?? "")
783
+ .split(",")
784
+ .map((name) => name.trim())
785
+ .filter((name) => name !== ""),
526
786
  hub,
527
787
  runner,
528
788
  updater,
529
789
  mutations,
530
790
  sendNotification,
791
+ nvenc,
531
792
  audioPreviews,
532
- stylePreviews: createStylePreviews({
533
- dir: stylePreviewDir(paths.dataDir),
534
- render: ffmpegStylePreview({ ffmpeg, paths, log, dir: stylePreviewDir(paths.dataDir) }),
535
- pictures: previewPictures({ db, paths }),
536
- log,
537
- }),
793
+ stylePreviews,
794
+ templateStudio: {
795
+ free: freeSamples,
796
+ prices: studioPrices,
797
+ wake: sampleRunner.wake,
798
+ acks: studioAcks,
799
+ loudnessSource: loudnessSamples.source,
800
+ loudnessFile: loudnessSamples.file,
801
+ documentFile: documentSamples.file,
802
+ },
538
803
  ...modelSources(registry),
539
- audition: (call, signal) => auditionVoice({ registry, clock, log }, call, signal),
804
+ audition: (call, signal) => auditionVoice({ registry, clock, log, access }, call, signal),
540
805
  voiceLanguages: async (provider, voiceId, signal) => {
541
806
  try {
542
807
  return await registry.tts(provider).voiceLanguages?.(voiceId, signal);
@@ -546,6 +811,9 @@ export async function boot(config, options = {}) {
546
811
  }
547
812
  },
548
813
  catalogue,
814
+ modelChecks,
815
+ modelListing,
816
+ autoModelChecks,
549
817
  clock,
550
818
  ids,
551
819
  log,
@@ -627,12 +895,28 @@ export async function boot(config, options = {}) {
627
895
  catalogue.sync().then((status) => {
628
896
  if (status.warning !== null)
629
897
  log.write("warn", "model-catalog.sync", { detail: status.warning });
898
+ // A model new to the list may already be on the person's key's own list.
899
+ for (const provider of new Set(status.changes.added.map((added) => added.provider)))
900
+ if (isProviderId(provider))
901
+ void modelListing.refresh(provider, true).catch((error) => {
902
+ log.write("warn", "model-checks.listing", { detail: causedBy(error) });
903
+ });
630
904
  }, (error) => log.write("warn", "model-catalog.sync", { detail: causedBy(error) }));
631
905
  };
632
906
  syncModels();
907
+ // Model checks look hourly too: the weekly look, and a CLI that became usable. Both run in
908
+ // the background and never hold a request or a run.
909
+ const lookForClis = cliWatcher(modelChecks, rebuild.providers, (provider) => readChecks(updateDb, provider).length > 0);
910
+ const lookForModels = () => {
911
+ if (!autoModelChecks)
912
+ return;
913
+ lookAtModels(modelChecks, lookForClis).catch((error) => log.write("warn", "model-checks", { detail: causedBy(error) }));
914
+ };
915
+ lookForModels();
633
916
  const modelTimer = setInterval(() => {
634
917
  if (catalogue.syncDue?.(Date.now()) === true)
635
918
  syncModels();
919
+ lookForModels();
636
920
  }, 60 * 60_000);
637
921
  const backupTimer = setInterval(() => {
638
922
  backups.tick().catch((error) => {
@@ -685,6 +969,11 @@ export async function boot(config, options = {}) {
685
969
  };
686
970
  const arrangeTimer = setInterval(arrange, 5_000);
687
971
  listeningPort = portOf(server) ?? config.port;
972
+ // Never awaited: Tailscale's answer must not hold the start-up. A problem is logged with
973
+ // its fix and shown in Settings.
974
+ void remoteAccess.start().catch((error) => {
975
+ log.write("warn", "remote-access.start", { detail: causedBy(error) });
976
+ });
688
977
  // Whatever last run left queued goes out at start. Nothing waits for
689
978
  // it, and an unreachable collector costs one refused socket.
690
979
  flusher.soon();
@@ -715,13 +1004,22 @@ export async function boot(config, options = {}) {
715
1004
  clearInterval(trashTimer);
716
1005
  clearInterval(arrangeTimer);
717
1006
  clearInterval(modelTimer);
1007
+ modelChecks.stop();
1008
+ autopilot.stop();
718
1009
  const mutationDrain = mutations.stop();
719
1010
  const scheduleDrain = scheduleTicks.stop();
720
1011
  const topicDrain = scheduleRunner.stop();
1012
+ // A local sample render is stopped and its job queued again at the next start.
1013
+ const sampleDrain = sampleRunner.stop();
721
1014
  // A backup being written is stopped and its partial file removed, not waited for.
722
1015
  const backupDrain = backups.stop();
723
1016
  const serverClose = beginServerClose(server);
724
1017
  stopActivation();
1018
+ // Slopify's serve handler goes with it, so no proxy points at a port another program
1019
+ // could take while Slopify is stopped; the next start puts it back.
1020
+ const remoteDrain = withDeadline(remoteAccess.stop().catch((error) => {
1021
+ log.write("warn", "remote-access.stop", { detail: causedBy(error) });
1022
+ }), remoteAccessStopMs);
725
1023
  audioPreviews.close();
726
1024
  modelPrefetch.abort();
727
1025
  try {
@@ -730,7 +1028,13 @@ export async function boot(config, options = {}) {
730
1028
  await drainMutationsWithDeadline(mutationDrain, serverClose.terminate, mutationDrainTimeoutMs);
731
1029
  await scheduleDrain;
732
1030
  await topicDrain;
1031
+ await sampleDrain;
733
1032
  await backupDrain;
1033
+ await remoteDrain;
1034
+ // An assistant turn left running would keep spending the person's plan.
1035
+ await assistant.stopAll();
1036
+ // A picture call already sent is paid for: let it land rather than lose it.
1037
+ await withDeadline(designRunner.idle(), designIdleMs);
734
1038
  await runner.abortAll();
735
1039
  await episodes?.settled();
736
1040
  }
@@ -764,16 +1068,16 @@ export async function boot(config, options = {}) {
764
1068
  throw error;
765
1069
  }
766
1070
  }
767
- export function wireRunner({ onFinished, audioPreviews, db, paths, clock, ids, log, hub, telemetry, flusher, registry, catalogue, ffmpeg,
1071
+ export function wireRunner({ onFinished, audioPreviews, db, paths, clock, ids, log, hub, telemetry, flusher, registry, catalogue, ffmpeg, nvenc = async () => ({ available: false, reason: noNvenc }),
768
1072
  // Settings → Production defaults → Subtitle timing model, read as each alignment starts.
769
1073
  alignSubtitles: aligner = alignSubtitlesWith(() => readSettings({ db, log }).subtitleModel), }) {
770
1074
  // A stage counts what it did and the queue is flushed after each new event. `record`
771
1075
  // swallows its own failures, so this can neither fail a stage nor widen what leaves the
772
1076
  // machine - the payload allow-list is checked inside it.
773
- const count = (type, counters) => {
1077
+ const count = skippingProjects((type, counters) => {
774
1078
  record(telemetry, type, counters);
775
1079
  flusher.soon();
776
- };
1080
+ }, templateSampleCheck(db));
777
1081
  const execution = {
778
1082
  db,
779
1083
  paths,
@@ -782,6 +1086,8 @@ alignSubtitles: aligner = alignSubtitlesWith(() => readSettings({ db, log }).sub
782
1086
  log,
783
1087
  ffmpeg,
784
1088
  alignSubtitles: aligner,
1089
+ // Settings → Production defaults → Rendering, read as each render starts.
1090
+ renderMachine: (projectId) => renderMachine({ settings: readSettings({ db, log }), nvenc, log, projectId }),
785
1091
  audioPreviews,
786
1092
  count,
787
1093
  };
@@ -793,6 +1099,7 @@ alignSubtitles: aligner = alignSubtitlesWith(() => readSettings({ db, log }).sub
793
1099
  clock,
794
1100
  log,
795
1101
  meter: createUsageMeter({ db, ids, clock, catalogue: () => catalogue.read() }),
1102
+ access: accessRecorder({ db, clock }),
796
1103
  limits: createLimitGate({
797
1104
  db,
798
1105
  clock,
@@ -873,6 +1180,11 @@ alignSubtitles: aligner = alignSubtitlesWith(() => readSettings({ db, log }).sub
873
1180
  emitRunningCount: (running) => {
874
1181
  hub.emitGlobal({ type: "running.count", count: running });
875
1182
  },
1183
+ // The shell's "N running" leaves out the template studio's hidden samples.
1184
+ counted: (() => {
1185
+ const sample = templateSampleCheck(db);
1186
+ return (projectId) => !sample(projectId);
1187
+ })(),
876
1188
  log,
877
1189
  });
878
1190
  return { ...runner, checkpoints };
@@ -921,6 +1233,9 @@ export function urlOf(host, port) {
921
1233
  }
922
1234
  // A stage can only be `running` at boot if the previous process died mid-run;
923
1235
  // nothing auto-resumes, the user retries by hand.
1236
+ function isProviderId(id) {
1237
+ return providerIds.includes(id);
1238
+ }
924
1239
  export function markInterruptedStages(db, clock) {
925
1240
  const result = db
926
1241
  .prepare("UPDATE stages SET state = CASE WHEN EXISTS (SELECT 1 FROM project_controls WHERE project_id = stages.project_id AND paused = 1) THEN 'pending' ELSE 'failed' END, failure_reason = CASE WHEN EXISTS (SELECT 1 FROM project_controls WHERE project_id = stages.project_id AND paused = 1) THEN NULL ELSE 'interrupted' END, finished_at = CASE WHEN EXISTS (SELECT 1 FROM project_controls WHERE project_id = stages.project_id AND paused = 1) THEN NULL ELSE ? END WHERE state = 'running'")