@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
@@ -58,7 +58,7 @@ export const starterPacks = [
58
58
  kind: "article",
59
59
  name: "Sleep lore · Story",
60
60
  body: [
61
- "Write a long, calm bedtime telling of {{topic}} for listeners who want to drift off to sleep.",
61
+ "Write a long, calm bedtime telling of {{Topic}} for listeners who want to drift off to sleep.",
62
62
  "",
63
63
  "Length: 2800-3200 words.",
64
64
  "",
@@ -83,7 +83,7 @@ export const starterPacks = [
83
83
  kind: "article",
84
84
  name: "Sleep lore · 60-second short",
85
85
  body: [
86
- `Subject: {{topic}}, as a quiet moment from myth or legend.`,
86
+ `Subject: {{Topic}}, as a quiet moment from myth or legend.`,
87
87
  "",
88
88
  scriptRules,
89
89
  "- Keep the calm, hushed tone of a bedtime story even in the hook.",
@@ -94,7 +94,7 @@ export const starterPacks = [
94
94
  kind: "image",
95
95
  name: "Sleep lore · Scene",
96
96
  body: [
97
- "A dreamlike painted scene from the legend of {{topic}}.",
97
+ "A dreamlike painted scene from the legend of {{Topic}}.",
98
98
  "Soft oil-painting style with visible brushwork, muted twilight palette of deep blues, dusky violets and warm lantern gold.",
99
99
  "Gentle haze, low contrast, wide calm composition with plenty of quiet space; distant figures rather than close faces.",
100
100
  "Peaceful and still, nothing threatening in the frame.",
@@ -106,7 +106,7 @@ export const starterPacks = [
106
106
  kind: "thumbnail",
107
107
  name: "Sleep lore · Thumbnail",
108
108
  body: [
109
- "A serene, luminous painting that sums up the legend of {{topic}} in one image.",
109
+ "A serene, luminous painting that sums up the legend of {{Topic}} in one image.",
110
110
  "One clear subject in the centre, soft moonlight or candlelight, deep blue and gold palette, gentle mist.",
111
111
  "Readable at a small size: simple shapes, strong silhouette, calm mood.",
112
112
  noText,
@@ -117,7 +117,7 @@ export const starterPacks = [
117
117
  kind: "description",
118
118
  name: "Sleep lore · Description",
119
119
  body: [
120
- "Write a YouTube description for a sleep story about {{topic}}.",
120
+ "Write a YouTube description for a sleep story about {{Topic}}.",
121
121
  "",
122
122
  "- Summary: 2-3 soothing sentences that invite the viewer to settle in. Mention that the story is calm and has no sudden sounds.",
123
123
  "- Chapters: one per part of the story, 3-6 gentle words each.",
@@ -164,7 +164,7 @@ export const starterPacks = [
164
164
  kind: "article",
165
165
  name: "True crime · Case",
166
166
  body: [
167
- "Write a documentary narration about the case of {{topic}}.",
167
+ "Write a documentary narration about the case of {{Topic}}.",
168
168
  "",
169
169
  "Length: 2200-2600 words.",
170
170
  "",
@@ -190,7 +190,7 @@ export const starterPacks = [
190
190
  kind: "article",
191
191
  name: "True crime · 60-second short",
192
192
  body: [
193
- "Subject: one striking, well-documented moment from the case of {{topic}}.",
193
+ "Subject: one striking, well-documented moment from the case of {{Topic}}.",
194
194
  "",
195
195
  scriptRules,
196
196
  "- Respectful and factual: no gore, no speculation about guilt, no invented detail.",
@@ -201,7 +201,7 @@ export const starterPacks = [
201
201
  kind: "image",
202
202
  name: "True crime · Scene",
203
203
  body: [
204
- "A moody documentary-style photograph evoking the setting of {{topic}}: the place, the era, the objects, the weather.",
204
+ "A moody documentary-style photograph evoking the setting of {{Topic}}: the place, the era, the objects, the weather.",
205
205
  "Cinematic 35mm look, overcast or night light, desaturated cool palette with deep shadows and a single practical light source.",
206
206
  "Empty streets, closed doors, rain on glass, paperwork on a desk; no recognisable real people, no bodies, no blood, no weapons pointed at anyone.",
207
207
  noText,
@@ -212,7 +212,7 @@ export const starterPacks = [
212
212
  kind: "thumbnail",
213
213
  name: "True crime · Thumbnail",
214
214
  body: [
215
- "A tense cinematic image that sums up the case of {{topic}}: one strong object or place in sharp focus against a dark, blurred background.",
215
+ "A tense cinematic image that sums up the case of {{Topic}}: one strong object or place in sharp focus against a dark, blurred background.",
216
216
  "High contrast, cold blue and amber light, heavy vignette, readable at phone size.",
217
217
  "No real people's faces, no gore.",
218
218
  noText,
@@ -223,7 +223,7 @@ export const starterPacks = [
223
223
  kind: "description",
224
224
  name: "True crime · Description",
225
225
  body: [
226
- "Write a YouTube description for a documentary about the case of {{topic}}.",
226
+ "Write a YouTube description for a documentary about the case of {{Topic}}.",
227
227
  "",
228
228
  "- Summary: 2-3 factual sentences on what happened and what the video covers. No sensational words.",
229
229
  "- Chapters: split where the story moves from events to investigation to outcome; 3-6 plain words each.",
@@ -273,7 +273,7 @@ export const starterPacks = [
273
273
  kind: "article",
274
274
  name: "History · Documentary",
275
275
  body: [
276
- "Write a documentary narration about {{topic}}.",
276
+ "Write a documentary narration about {{Topic}}.",
277
277
  "",
278
278
  "Length: 2000-2400 words.",
279
279
  "",
@@ -297,7 +297,7 @@ export const starterPacks = [
297
297
  kind: "article",
298
298
  name: "History · 60-second short",
299
299
  body: [
300
- "Subject: one surprising, true story or detail about {{topic}}.",
300
+ "Subject: one surprising, true story or detail about {{Topic}}.",
301
301
  "",
302
302
  scriptRules,
303
303
  "- Put the year and the place in the first two sentences.",
@@ -308,7 +308,7 @@ export const starterPacks = [
308
308
  kind: "image",
309
309
  name: "History · Scene",
310
310
  body: [
311
- "A historically grounded illustration of {{topic}}: period-accurate clothing, architecture, tools and landscape.",
311
+ "A historically grounded illustration of {{Topic}}: period-accurate clothing, architecture, tools and landscape.",
312
312
  "Rich painterly realism in the manner of a museum reconstruction, warm golden light, earthy ochre, umber and faded blue palette.",
313
313
  "Wide establishing views and mid shots of daily life; figures shown at a distance or from behind rather than as portraits of real people.",
314
314
  noText,
@@ -319,7 +319,7 @@ export const starterPacks = [
319
319
  kind: "thumbnail",
320
320
  name: "History · Thumbnail",
321
321
  body: [
322
- "A dramatic, detailed painting that sums up {{topic}} in one moment: one clear focal subject, strong light from one side, dust or smoke in the air.",
322
+ "A dramatic, detailed painting that sums up {{Topic}} in one moment: one clear focal subject, strong light from one side, dust or smoke in the air.",
323
323
  "Warm ochre and deep blue palette, high contrast, simple composition that reads at phone size.",
324
324
  noText,
325
325
  ].join(" "),
@@ -329,7 +329,7 @@ export const starterPacks = [
329
329
  kind: "description",
330
330
  name: "History · Description",
331
331
  body: [
332
- "Write a YouTube description for a history documentary about {{topic}}.",
332
+ "Write a YouTube description for a history documentary about {{Topic}}.",
333
333
  "",
334
334
  "- Summary: 2-3 sentences that name the period and place and say what the viewer will understand by the end.",
335
335
  "- Chapters: one per section of the narration, 2-6 words each, in title case.",
@@ -371,7 +371,7 @@ export const starterPacks = [
371
371
  kind: "article",
372
372
  name: "Science · Explainer",
373
373
  body: [
374
- "Write an explainer video narration about {{topic}} for curious viewers with no science background.",
374
+ "Write an explainer video narration about {{Topic}} for curious viewers with no science background.",
375
375
  "",
376
376
  "Length: 1400-1800 words.",
377
377
  "",
@@ -396,7 +396,7 @@ export const starterPacks = [
396
396
  kind: "article",
397
397
  name: "Science · 60-second short",
398
398
  body: [
399
- "Subject: one mind-bending but true fact about {{topic}}, and why it is so.",
399
+ "Subject: one mind-bending but true fact about {{Topic}}, and why it is so.",
400
400
  "",
401
401
  scriptRules,
402
402
  "- Give one real number with its unit and a comparison that makes it graspable.",
@@ -407,7 +407,7 @@ export const starterPacks = [
407
407
  kind: "image",
408
408
  name: "Science · Visual",
409
409
  body: [
410
- "A clean, striking visual that explains an aspect of {{topic}}.",
410
+ "A clean, striking visual that explains an aspect of {{Topic}}.",
411
411
  "Modern 3D-rendered or macro-photography look, crisp detail, dark background with vivid cyan, magenta and amber accents, soft rim light.",
412
412
  "One clear subject, scientifically plausible shapes and scales, generous negative space.",
413
413
  noText,
@@ -418,7 +418,7 @@ export const starterPacks = [
418
418
  kind: "thumbnail",
419
419
  name: "Science · Thumbnail",
420
420
  body: [
421
- "A bold, eye-catching image about {{topic}}: one surprising subject, glowing against a deep dark background.",
421
+ "A bold, eye-catching image about {{Topic}}: one surprising subject, glowing against a deep dark background.",
422
422
  "Saturated cyan and amber, strong contrast, simple composition that reads at phone size.",
423
423
  noText,
424
424
  ].join(" "),
@@ -428,7 +428,7 @@ export const starterPacks = [
428
428
  kind: "description",
429
429
  name: "Science · Description",
430
430
  body: [
431
- "Write a YouTube description for a science explainer about {{topic}}.",
431
+ "Write a YouTube description for a science explainer about {{Topic}}.",
432
432
  "",
433
433
  "- Summary: 2-3 sentences that pose the question and promise a clear answer, without exaggeration.",
434
434
  "- Chapters: one per step of the explanation, 2-6 words each.",
@@ -471,14 +471,14 @@ export const starterSet = {
471
471
  key: "shortScript",
472
472
  kind: "article",
473
473
  name: "Starter · 60-second short",
474
- body: ["Subject: {{topic}}.", "", scriptRules].join("\n"),
474
+ body: ["Subject: {{Topic}}.", "", scriptRules].join("\n"),
475
475
  },
476
476
  {
477
477
  key: "image",
478
478
  kind: "image",
479
479
  name: "Starter · Vertical scene",
480
480
  body: [
481
- "A cinematic vertical image about {{topic}}.",
481
+ "A cinematic vertical image about {{Topic}}.",
482
482
  "Rich colour, dramatic light, one clear subject large in the frame so it reads on a phone.",
483
483
  "Keep the lower half calm: captions are drawn over it.",
484
484
  noText,
@@ -121,7 +121,8 @@ export function shortDraft(input) {
121
121
  images: input.providers.images,
122
122
  articlePrompt: input.names.shortScript ?? "",
123
123
  imagePrompts: [{ name: input.names.image ?? "", number: shortImages }],
124
- values: { topic },
124
+ // {{Topic}} since 4.0; a pack installed before asks for {{topic}}, so both are filled.
125
+ values: { Topic: topic, topic },
125
126
  provided: {},
126
127
  silenceGapSeconds: 0.5,
127
128
  imageSeconds: shortImageSeconds,
@@ -19,7 +19,6 @@ export const sampleArchives = {
19
19
  audiobook: bundled("sample-audiobook.tar"),
20
20
  podcast: bundled("sample-podcast.tar"),
21
21
  };
22
- export const sampleArchive = sampleArchives.library;
23
22
  const archiveOf = (deps, id) => deps.archives?.[id] ?? sampleArchives[id];
24
23
  function recordedProject(db, id) {
25
24
  const record = readSampleRecord(db, id);
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { readSetting, writeSetting } from "../settings/repo.js";
2
+ import { readJsonSetting, readSetting, writeSetting } from "../settings/repo.js";
3
3
  // What the first five minutes remember, in the settings table: whether the first-run screen
4
4
  // was dismissed, which project is the bundled sample, and which library rows each installed
5
5
  // starter pack became. None of these keys is in a portable backup's settings, so another
@@ -25,16 +25,7 @@ const shortRequests = z.record(z.string(), z.string());
25
25
  // ceiling: only a retry of a recent click needs its answer.
26
26
  const shortRequestsKept = 20;
27
27
  function readJson(db, key, schema) {
28
- const raw = readSetting(db, key);
29
- if (raw === undefined)
30
- return undefined;
31
- try {
32
- const parsed = schema.safeParse(JSON.parse(raw));
33
- return parsed.success ? parsed.data : undefined;
34
- }
35
- catch {
36
- return undefined;
37
- }
28
+ return readJsonSetting(db, key, schema, undefined);
38
29
  }
39
30
  export function firstRunDismissed(db) {
40
31
  return readSetting(db, dismissedKey) !== undefined;
@@ -9,7 +9,8 @@ export function packTemplate(pack, names, voiceId) {
9
9
  return playDraftDocumentSchema.parse({
10
10
  schemaVersion: 1,
11
11
  form: {
12
- title: "",
12
+ // The topic typed in Play, or the one a schedule fills each run, names the video.
13
+ title: "{{Topic}}",
13
14
  format: "16:9",
14
15
  sources: {
15
16
  research: style.research ? "generate" : "off",
@@ -3,6 +3,7 @@ import { readFile } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { z } from "zod";
6
+ import { hasErrnoCode } from "../../kernel/errors.js";
6
7
  // The patch notes the app shows in Settings → Patch notes: Markdown files kept in the
7
8
  // repository's docs/patch-notes/ and copied into the build beside the compiled code
8
9
  // (scripts/copy-assets.mjs). index.json lists them with a title and a date; each note is
@@ -34,7 +35,7 @@ export async function listPatchNotes(dir) {
34
35
  raw = await readFile(join(dir, "index.json"), "utf8");
35
36
  }
36
37
  catch (error) {
37
- if (error.code === "ENOENT")
38
+ if (hasErrnoCode(error, "ENOENT"))
38
39
  throw new PatchNotesMissing("This copy of Slopify has no patch notes: its docs/patch-notes/index.json is missing. Reinstall Slopify (or run npm run build) and reload the page.");
39
40
  throw error;
40
41
  }
@@ -66,7 +67,7 @@ export async function readPatchNote(dir, id) {
66
67
  return await readFile(join(dir, `${id}.md`), "utf8");
67
68
  }
68
69
  catch (error) {
69
- if (error.code === "ENOENT")
70
+ if (hasErrnoCode(error, "ENOENT"))
70
71
  return undefined;
71
72
  throw error;
72
73
  }
@@ -9,6 +9,7 @@ import { pausesOfForm } from "../narration/pauses-model.js";
9
9
  import { reviewSettingsFromForm } from "../reviews/model.js";
10
10
  import { stageMakesItems } from "../reviews/rules.js";
11
11
  import { defaultShorts, shortsExtrasOf, shortsSettingsProblems, } from "../shorts/model.js";
12
+ import { socialOfForm } from "../social/settings.js";
12
13
  import { defaultSubtitles } from "../subtitles/model.js";
13
14
  import { ambientBedOfForm, ambientBedProblems } from "../video/ambient-bed.js";
14
15
  // Said where the control is, since the music sits in a closed disclosure on the Export rail.
@@ -206,6 +207,9 @@ export function toAdmissionDraft(input) {
206
207
  ...(form.descriptionPrompt?.trim() ? { descriptionPrompt: form.descriptionPrompt } : {}),
207
208
  }
208
209
  : {}),
210
+ // Posting is free unless a site's words come from a post prompt; none turned on is left out,
211
+ // which is what every draft saved before posting was.
212
+ ...((social) => (social === undefined ? {} : { social }))(socialOfForm(form.social)),
209
213
  // Cut from the narration too, so the same rule: a switch left on with narration Off asks
210
214
  // for nothing.
211
215
  ...(shortsOn && form.shorts !== undefined ? { shorts: shortsOf(form.shorts) } : {}),
@@ -25,8 +25,13 @@ export function reviewBinding(value) {
25
25
  attachmentIdentity: value.attachmentIdentity,
26
26
  });
27
27
  }
28
- export function resolveReviewInputs(deps, view, font) {
29
- const fresh = readDraft(deps, view.draft.id);
28
+ export function resolveReviewInputs(deps, view, font,
29
+ // A view no draft row holds (the template studio prices a schedule's run on one): it is its
30
+ // own latest version and has no uploads.
31
+ unsaved = false) {
32
+ const fresh = unsaved
33
+ ? { ok: true, value: view }
34
+ : readDraft(deps, view.draft.id);
30
35
  if (!fresh.ok)
31
36
  return fresh;
32
37
  if (fresh.value.draft.version !== view.draft.version ||
@@ -103,6 +108,7 @@ export function resolveReviewInputs(deps, view, font) {
103
108
  draft: { ...draft, values },
104
109
  staged,
105
110
  requiredSlots: basePicked.requiredSlots,
111
+ keywordUses: basePicked.keywordUses,
106
112
  });
107
113
  const accepted = admitted.ok ? admitted.draft : draft;
108
114
  const issues = [
@@ -8,11 +8,12 @@ import { resolveReviewInputs, reviewBinding, reviewRefusal } from "./review-inpu
8
8
  import { draftViewSchema, playReviewSchema } from "./schema.js";
9
9
  import { readDraft } from "./service.js";
10
10
  export { resolveReviewInputs } from "./review-inputs.js";
11
- export async function resolvePlayReview(deps, view) {
11
+ export async function resolvePlayReview(deps, view, options = {}) {
12
+ const unsaved = options.unsaved === true;
12
13
  const parsed = draftViewSchema.safeParse(view);
13
14
  if (!parsed.success)
14
15
  return { ok: false, reason: "invalid-edit", currentVersion: null, fields: [] };
15
- const before = resolveReviewInputs(deps, parsed.data, null);
16
+ const before = resolveReviewInputs(deps, parsed.data, null, unsaved);
16
17
  if (!before.ok)
17
18
  return before;
18
19
  let font = null;
@@ -32,7 +33,7 @@ export async function resolvePlayReview(deps, view) {
32
33
  ]);
33
34
  }
34
35
  }
35
- const after = resolveReviewInputs(deps, parsed.data, font);
36
+ const after = resolveReviewInputs(deps, parsed.data, font, unsaved);
36
37
  if (!after.ok)
37
38
  return after;
38
39
  const fields = [];
@@ -55,7 +56,7 @@ export async function resolvePlayReview(deps, view) {
55
56
  // without the font: `before` had none yet, and a Before Video checkpoint covers the render
56
57
  // that burns the captions in, so comparing it with `after` always differed and refused every
57
58
  // such review.
58
- const unchanged = resolveReviewInputs(deps, parsed.data, null);
59
+ const unchanged = resolveReviewInputs(deps, parsed.data, null, unsaved);
59
60
  if (!unchanged.ok)
60
61
  return unchanged;
61
62
  return reviewBinding(before.value) === reviewBinding(unchanged.value)
@@ -10,6 +10,7 @@ import { documentSettingsSchema } from "../document/theme-schema.js";
10
10
  import { librarySnapshotSchema } from "../library/snapshot.js";
11
11
  import { chunkModes } from "../narration/chunk.js";
12
12
  import { reviewers, reviewModes, reviewStages } from "../reviews/model.js";
13
+ import { socialSettingsSchema } from "../social/schema.js";
13
14
  import { subtitleModes, subtitlePositions } from "../subtitles/model.js";
14
15
  import { ambientBedSources } from "../video/ambient-bed.js";
15
16
  import { voicesSettingsSchema } from "../voices/model.js";
@@ -94,6 +95,9 @@ export const playDraftFormSchema = z
94
95
  levelSentences: z.boolean().optional(),
95
96
  // Absent on drafts and templates saved before the YouTube description: off, built-in prompt.
96
97
  youtubeDescription: z.boolean().optional(),
98
+ // Which other sites the project posts to and what each gets (`slices/social`), as the run
99
+ // stores it. Absent on drafts and templates saved before posting: nowhere.
100
+ social: socialSettingsSchema.optional(),
97
101
  showFigures: z.boolean().optional(),
98
102
  descriptionPrompt: text.optional(),
99
103
  // The project language (`kernel/ports/languages.ts`). Absent on drafts and templates saved
@@ -11,10 +11,13 @@ import { requestHash } from "../play-drafts/repo.js";
11
11
  import { reviewSettingsForm } from "../reviews/model.js";
12
12
  import { currentRevisionId, revisionById } from "../revisions/repo.js";
13
13
  import { shortsExtrasForm } from "../shorts/model.js";
14
+ import { socialPlatforms } from "../social/model.js";
15
+ import { socialSettingsSchema } from "../social/schema.js";
14
16
  import { ambientBedFormOf } from "../video/ambient-bed.js";
15
17
  import { usesScriptPrompt } from "../voices/model.js";
16
18
  import { templateNameMax } from "./schema.js";
17
19
  import { createTemplate, readTemplate } from "./service.js";
20
+ import { withoutSampleStandIns } from "./stand-ins.js";
18
21
  export const projectTemplateCreateSchema = z
19
22
  .object({
20
23
  id: z.uuid(),
@@ -88,6 +91,9 @@ export function documentFromProject(deps, revision) {
88
91
  addPrompt(usesScriptPrompt(config) ? "script" : "article", config.articlePrompt, "article");
89
92
  addPrompt("narration", config.narrationPrompt, "narration");
90
93
  addPrompt("description", config.descriptionPrompt, "description");
94
+ for (const platform of socialPlatforms)
95
+ if (config.social?.[platform]?.text === "prompt")
96
+ addPrompt("post", config.social[platform]?.prompt, `social.${platform}`);
91
97
  for (const [stage, picked] of Object.entries(config.reviews?.stages ?? {}))
92
98
  addPrompt("review", picked.prompt, `review.${stage}`);
93
99
  const definitions = revision.content.imageOrder.flatMap((key) => {
@@ -163,7 +169,7 @@ export function documentFromProject(deps, revision) {
163
169
  return {
164
170
  schemaVersion: 1,
165
171
  librarySnapshot: { prompts, entries },
166
- form: {
172
+ form: withoutSampleStandIns({
167
173
  title: config.title,
168
174
  format: config.format,
169
175
  sources: config.sources,
@@ -191,6 +197,7 @@ export function documentFromProject(deps, revision) {
191
197
  ...(config.thumbnailCount === 3 ? { thumbnailCount: 3 } : {}),
192
198
  ...(config.narrationPrompt === undefined ? {} : { narrationPrompt: config.narrationPrompt }),
193
199
  ...(config.youtubeDescription === true ? { youtubeDescription: true } : {}),
200
+ ...(config.social === undefined ? {} : { social: socialSettingsSchema.parse(config.social) }),
194
201
  ...(config.language === undefined ? {} : { language: config.language }),
195
202
  ...(config.descriptionPrompt === undefined
196
203
  ? {}
@@ -263,7 +270,7 @@ export function documentFromProject(deps, revision) {
263
270
  motionStyle: config.motionStyle,
264
271
  values: config.values,
265
272
  provided,
266
- },
273
+ }),
267
274
  section: "content",
268
275
  variants: [],
269
276
  // The length a project that scales its images planned for, so the template plans the same.
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { projectTemplateSchema } from "./schema.js";
3
+ import { withoutSampleStandIns } from "./stand-ins.js";
3
4
  // A template in the trash (`deleted_at` set, Settings → Trash) is invisible to every read here.
4
5
  const select = `SELECT t.id,r.version,r.name,t.created_at AS createdAt,r.created_at AS updatedAt,r.document_json AS document FROM project_templates t JOIN project_template_revisions r ON r.template_id=t.id AND t.deleted_at IS NULL`;
5
6
  const templateSummarySchema = z
@@ -20,7 +21,11 @@ export function templateById(db, id, version) {
20
21
  return undefined;
21
22
  if (typeof row.document !== "string")
22
23
  throw new Error("Template document is missing");
23
- return projectTemplateSchema.parse({ ...row, document: JSON.parse(row.document) });
24
+ const template = projectTemplateSchema.parse({ ...row, document: JSON.parse(row.document) });
25
+ // A template made from a sample before stand-ins were cleared reads as one that asks for the
26
+ // person's own providers.
27
+ const form = withoutSampleStandIns(template.document.form);
28
+ return { ...template, document: { ...template.document, form } };
24
29
  }
25
30
  export function templateSummaries(db) {
26
31
  return db
@@ -1,5 +1,6 @@
1
1
  import { templateChannelId } from "../channels/repo.js";
2
2
  import { snapshotEntry, snapshotPrompt } from "../library/snapshot.js";
3
+ import { socialPlatforms } from "../social/model.js";
3
4
  import { templateDocument } from "./one-off.js";
4
5
  export function templateSetup(deps, input) {
5
6
  const prompts = [];
@@ -25,6 +26,13 @@ export function templateSetup(deps, input) {
25
26
  kind: "image",
26
27
  name: input.form.reference?.source === "prompt" ? input.form.reference.prompt : "",
27
28
  },
29
+ ...socialPlatforms.map((platform) => {
30
+ const choice = input.form.social?.[platform];
31
+ return {
32
+ kind: "post",
33
+ name: choice?.text === "prompt" ? (choice.prompt ?? "") : "",
34
+ };
35
+ }),
28
36
  ];
29
37
  for (const choice of choices) {
30
38
  if (choice.name === "")
@@ -0,0 +1,22 @@
1
+ import { isSampleStandIn } from "../settings/model.js";
2
+ // A template made from a bundled sample asks for the person's own providers: the samples'
3
+ // stand-ins can't run anything new, so their choices are left blank, the same as a template
4
+ // nobody has picked a provider in (Play then offers the providers this computer has).
5
+ export function withoutSampleStandIns(form) {
6
+ const blankVoice = { provider: "", model: "", voice: "" };
7
+ const voices = form.voices;
8
+ return {
9
+ ...form,
10
+ llm: isSampleStandIn(form.llm.provider) ? { provider: "", model: "" } : form.llm,
11
+ audio: isSampleStandIn(form.audio.provider) ? { ...form.audio, ...blankVoice } : form.audio,
12
+ images: isSampleStandIn(form.images.provider) ? { provider: "", model: "" } : form.images,
13
+ ...(voices === undefined
14
+ ? {}
15
+ : {
16
+ voices: {
17
+ ...voices,
18
+ speakers: voices.speakers.map((speaker) => isSampleStandIn(speaker.voice.provider) ? { ...speaker, voice: blankVoice } : speaker),
19
+ },
20
+ }),
21
+ };
22
+ }
@@ -50,6 +50,8 @@ export function videoActivity(db, projectId) {
50
50
  return { label: "picking the shorts" };
51
51
  if (running("youtube:description"))
52
52
  return { label: "writing the YouTube description" };
53
+ if (rows.some((row) => row.key.startsWith("social:post:") && row.state === "running"))
54
+ return { label: "writing the posts for other sites" };
53
55
  if (running("subtitles:timing"))
54
56
  return percent("timing the captions", running("subtitles:timing"));
55
57
  if (running("subtitles:cues") || running("subtitles:files"))
@@ -1,4 +1,5 @@
1
1
  import { transact } from "../../kernel/db/tx.js";
2
+ import { internalError } from "../../kernel/errors.js";
2
3
  import { setProjectPaused } from "../admission/repo.js";
3
4
  import { requestHash as hash } from "../revisions/mutation-request.js";
4
5
  import { currentRevisionId } from "../revisions/repo.js";
@@ -92,14 +93,14 @@ export function admitPreview(deps, input) {
92
93
  continue;
93
94
  }
94
95
  if (existing?.state === "running")
95
- throw new Error("Slopify hit an internal error (a step is already running for a different version of the project). Try again; if it happens again, use Download diagnostics in Settings and report it.");
96
+ throw new Error(internalError("a step is already running for a different version of the project"));
96
97
  deps.db
97
98
  .prepare("DELETE FROM revision_work_reservations WHERE revision_id=? AND work_key=?")
98
99
  .run(view.revision.id, recipe.key);
99
100
  const key = reservationKey(recipe, view);
100
101
  const fingerprint = snapshot.anchors[key];
101
102
  if (fingerprint === undefined)
102
- throw new Error("Slopify hit an internal error (a step has no saved starting point). Try again; if it happens again, use Download diagnostics in Settings and report it.");
103
+ throw new Error(internalError("a step has no saved starting point"));
103
104
  const work = insertInvocation(deps, view, recipe, catalogue, { key, fingerprint }, false, view.revision.id, admissionId);
104
105
  workIds.push(work.workId);
105
106
  }
@@ -1,5 +1,6 @@
1
1
  import { statSync } from "node:fs";
2
2
  import { z } from "zod";
3
+ import { assetPathOrUndefined } from "../revisions/mutation-assets.js";
3
4
  import { stagePieceSchema } from "../revisions/schema.js";
4
5
  import { outputPath } from "../storage/layout.js";
5
6
  export function retainedNarrationPieces(deps, projectId) {
@@ -32,11 +33,9 @@ export function retainedNarrationPieces(deps, projectId) {
32
33
  }
33
34
  export function referencedAssetsAvailable(deps, projectId, ids) {
34
35
  return ids.filter((id) => {
35
- const row = deps.db
36
- .prepare("SELECT path FROM project_assets WHERE project_id=? AND id=?")
37
- .get(projectId, id);
38
- return (row !== undefined &&
39
- statSync(outputPath(deps.paths, projectId, z.string().parse(row.path)), {
36
+ const path = assetPathOrUndefined(deps, projectId, id);
37
+ return (path !== undefined &&
38
+ statSync(outputPath(deps.paths, projectId, path), {
40
39
  throwIfNoEntry: false,
41
40
  })?.isFile() === true);
42
41
  });
@@ -1,6 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { z } from "zod";
3
3
  import { transact } from "../../kernel/db/tx.js";
4
+ import { errorText } from "../../kernel/errors.js";
4
5
  import { currentRevisionId } from "../revisions/repo.js";
5
6
  import { recoverProject } from "./recovery.js";
6
7
  // How many times one narration chunk is recorded again by itself. A voice that garbles a
@@ -71,7 +72,7 @@ export function createNarrationRetries() {
71
72
  .catch((error) => {
72
73
  deps.log.write("error", "narration.retry", {
73
74
  projectId: retry.projectId,
74
- detail: error instanceof Error ? error.message : String(error),
75
+ detail: errorText(error),
75
76
  });
76
77
  settle(deps.db, retry, "failed", "internal error", deps.clock.now().toISOString());
77
78
  })
@@ -7,6 +7,7 @@ import { loudnessLabel } from "../loudness/model.js";
7
7
  import { reviewModeLabels, reviewModeOf, reviewStageLabels, reviewStages, } from "../reviews/model.js";
8
8
  import { getRevisionView } from "../revisions/view.js";
9
9
  import { musicVolumeOf, shortsSpeedOf } from "../shorts/model.js";
10
+ import { platformLabels, socialPlatforms } from "../social/model.js";
10
11
  import { ambientBedLabels } from "../video/ambient-bed.js";
11
12
  import { videoEditOf, videoEditRows } from "../video/edit-settings.js";
12
13
  export function previewDetails(deps, view, allRecipes, selected) {
@@ -76,15 +77,17 @@ export function previewDetails(deps, view, allRecipes, selected) {
76
77
  ? "Intro text"
77
78
  : row.key.startsWith("entry:outro")
78
79
  ? "Outro text"
79
- : row.stage === "article"
80
- ? "Article"
81
- : row.stage === "research"
82
- ? "Research"
83
- : row.key.startsWith("shorts:")
84
- ? "Short image prompts"
85
- : row.key === "images:scenes"
86
- ? "Image scenes"
87
- : "Thumbnail prompt";
80
+ : row.key === "article:digest"
81
+ ? "Keyword digest"
82
+ : row.stage === "article"
83
+ ? "Article"
84
+ : row.stage === "research"
85
+ ? "Research"
86
+ : row.key.startsWith("shorts:")
87
+ ? "Short image prompts"
88
+ : row.key === "images:scenes"
89
+ ? "Image scenes"
90
+ : "Thumbnail prompt";
88
91
  return [
89
92
  {
90
93
  key: row.key,
@@ -165,6 +168,7 @@ function inputChanges(parent, view) {
165
168
  add("Level the volume", before.loudness === undefined ? "Off" : loudnessSummary(before.loudness), after.loudness === undefined ? "Off" : loudnessSummary(after.loudness));
166
169
  add("YouTube description", before.youtubeDescription === true ? "On" : "Off", after.youtubeDescription === true ? "On" : "Off");
167
170
  add("Description prompt", before.descriptionPrompt, after.descriptionPrompt);
171
+ add("Posts", postsSummary(before.social), postsSummary(after.social));
168
172
  add("Shorts", before.shorts?.enabled === true ? "On" : "Off", after.shorts?.enabled === true ? "On" : "Off");
169
173
  add("Number of shorts", before.shorts?.count, after.shorts?.count);
170
174
  add("Short length (seconds)", before.shorts === undefined
@@ -261,3 +265,17 @@ function aliasLines(aliases) {
261
265
  .map((alias) => `${alias.written} → ${alias.spoken}${alias.wholeWord ? "" : " (inside words too)"}${alias.caseSensitive ? " (match case)" : ""}`)
262
266
  .join("\n");
263
267
  }
268
+ // The sites a version posts to, each with where its words come from: "X (post prompt), Bluesky
269
+ // (summary)"; "Off" for none.
270
+ function postsSummary(social) {
271
+ const sites = socialPlatforms.flatMap((platform) => {
272
+ const choice = social?.[platform];
273
+ if (choice === undefined)
274
+ return [];
275
+ const source = choice.text === "prompt"
276
+ ? `post prompt${choice.prompt?.trim() ? ` ${choice.prompt.trim()}` : ""}`
277
+ : choice.text;
278
+ return [`${platformLabels[platform]} (${source})`];
279
+ });
280
+ return sites.length === 0 ? "Off" : sites.join(", ");
281
+ }