@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
@@ -0,0 +1,124 @@
1
+ import { detectSlots } from "../admission/substitute.js";
2
+ // What a template's paid sample makes: a short taste of one video about the sample topic, so a
3
+ // Save costs cents, not a whole video. The limits are the document's (fewer pictures, one
4
+ // thumbnail, one short, no checkpoints) and the steps' (`config.sample`: the article's outline
5
+ // and first chapter, the narration's opening).
6
+ // The most pictures a sample draws.
7
+ export const samplePictures = 4;
8
+ // The narration a sample says: about 30 seconds, the length of the video sample.
9
+ export const sampleSpokenWords = 80;
10
+ // The shortest short a sample cuts: its narration is only about 30-45 seconds, so a template's
11
+ // own minimum (45 s or more for the starter packs) would leave nothing to cut.
12
+ export const sampleShortMinSeconds = 15;
13
+ // Put under the article prompt of a sample, unless the person asked for the full script. The
14
+ // prompt anatomy shows it as Slopify's.
15
+ export const sampleArticleInstruction = "This is a short sample of the script: write the outline and only chapter 1, then stop.";
16
+ // The template's setup as its sample runs it. Every keyword the title names and the template
17
+ // leaves empty is the topic; a title without one is the topic itself. A section the user
18
+ // provides at run time has no sample, so it is off here, with no file to attach; text the
19
+ // template holds is kept.
20
+ export function sampleDocument(template, scope) {
21
+ const { form } = template;
22
+ const topic = scope.topic.trim();
23
+ const names = detectSlots(form.title).names;
24
+ const values = Object.create(null);
25
+ for (const [name, value] of Object.entries(form.values))
26
+ values[name] = value;
27
+ for (const name of names)
28
+ if ((values[name] ?? "").trim() === "")
29
+ values[name] = topic;
30
+ const off = (source) => (source === "provide" ? "off" : source);
31
+ // Text the template itself holds (pasted research or article) is the same in every run, so
32
+ // the sample uses it; a file is added to each video in Play, so there is none here.
33
+ const kept = (source, text) => source === "provide" && text.trim() !== "" ? source : off(source);
34
+ const research = kept(form.sources.research, form.provided.research);
35
+ const article = kept(form.sources.article, form.provided.article);
36
+ const sources = {
37
+ research,
38
+ article,
39
+ audio: off(form.sources.audio),
40
+ images: off(form.sources.images),
41
+ thumbnail: off(form.sources.thumbnail),
42
+ video: off(form.sources.video),
43
+ ...(form.sources.document === undefined ? {} : { document: off(form.sources.document) }),
44
+ };
45
+ const reviews = form.reviews === undefined
46
+ ? undefined
47
+ : form.reviews.reviewer === "agent"
48
+ ? // An agent's reviews are answered outside Slopify: the sample never asks it.
49
+ { ...form.reviews, stages: {} }
50
+ : form.reviews;
51
+ const { imageScale: _scaled, ...unscaled } = form;
52
+ return {
53
+ ...template,
54
+ variants: [],
55
+ form: {
56
+ ...unscaled,
57
+ title: names.length === 0 ? topic : form.title,
58
+ values,
59
+ sources,
60
+ checkpoints: [],
61
+ thumbnailCount: 1,
62
+ imagePrompts: cappedPrompts(form.imagePrompts, samplePictures),
63
+ ...(form.shorts === undefined
64
+ ? {}
65
+ : {
66
+ shorts: {
67
+ ...form.shorts,
68
+ count: form.shorts.enabled ? "1" : form.shorts.count,
69
+ minSeconds: sampleShortMinimum(form.shorts.minSeconds),
70
+ },
71
+ }),
72
+ ...(reviews === undefined ? {} : { reviews }),
73
+ ...(form.reference === undefined || form.reference.source !== "provide"
74
+ ? {}
75
+ : { reference: { ...form.reference, source: "off" } }),
76
+ ...(form.ambientBed === undefined || form.ambientBed.source !== "upload"
77
+ ? {}
78
+ : { ambientBed: { ...form.ambientBed, source: "none" } }),
79
+ provided: {
80
+ research: research === "provide" ? form.provided.research : "",
81
+ article: article === "provide" ? form.provided.article : "",
82
+ audio: null,
83
+ thumbnail: null,
84
+ images: [],
85
+ ...(form.provided.reference === undefined ? {} : { reference: null }),
86
+ ...(form.provided.shortsMusic === undefined ? {} : { shortsMusic: null }),
87
+ ...(form.provided.ambientBed === undefined ? {} : { ambientBed: null }),
88
+ },
89
+ },
90
+ };
91
+ }
92
+ // The image prompts with at most `most` pictures between them, in order: each keeps its own
93
+ // number while they fit, and a prompt past the limit draws none.
94
+ function cappedPrompts(prompts, most) {
95
+ let left = most;
96
+ return prompts.flatMap((prompt) => {
97
+ const wanted = Number.parseInt(prompt.number, 10);
98
+ const count = Math.min(Number.isFinite(wanted) && wanted > 0 ? wanted : 1, left);
99
+ left -= count;
100
+ return count > 0 ? [{ ...prompt, number: String(count) }] : [];
101
+ });
102
+ }
103
+ // The opening of the narration a sample says: whole sentences up to about `words` words, at
104
+ // least the first sentence.
105
+ export function sampleNarrationText(text, words = sampleSpokenWords) {
106
+ const sentences = text.match(/[^.!?\n]+(?:[.!?]+["')\]]*|\n+|$)/gu) ?? [text];
107
+ let kept = "";
108
+ let count = 0;
109
+ for (const sentence of sentences) {
110
+ const size = sentence.split(/\s+/u).filter((word) => word !== "").length;
111
+ if (kept !== "" && count + size > words)
112
+ break;
113
+ kept += sentence;
114
+ count += size;
115
+ }
116
+ return kept.trim();
117
+ }
118
+ // The template's minimum, or the sample's when the template's is longer (or not a number).
119
+ function sampleShortMinimum(minSeconds) {
120
+ const wanted = Number.parseInt(minSeconds, 10);
121
+ return Number.isFinite(wanted) && wanted <= sampleShortMinSeconds
122
+ ? minSeconds
123
+ : String(sampleShortMinSeconds);
124
+ }
@@ -0,0 +1,176 @@
1
+ import { templateSections } from "./model.js";
2
+ export const sourceSections = {
3
+ research: "subject",
4
+ article: "script",
5
+ audio: "voice",
6
+ images: "pictures",
7
+ thumbnail: "thumbnail",
8
+ video: "video",
9
+ document: "document",
10
+ };
11
+ const providedSections = {
12
+ research: "subject",
13
+ article: "script",
14
+ audio: "voice",
15
+ thumbnail: "thumbnail",
16
+ images: "pictures",
17
+ reference: "pictures",
18
+ shortsMusic: "shorts",
19
+ ambientBed: "video",
20
+ };
21
+ export const formSections = {
22
+ title: "subject",
23
+ language: "subject",
24
+ values: "subject",
25
+ checkpoints: "reviews",
26
+ reviews: "reviews",
27
+ format: "video",
28
+ sources: null,
29
+ provided: null,
30
+ llm: "script",
31
+ articlePrompt: "script",
32
+ intro: "script",
33
+ outro: "script",
34
+ audio: "voice",
35
+ narrationPrompt: "voice",
36
+ loudness: "voice",
37
+ sentencePause: "voice",
38
+ paragraphPause: "voice",
39
+ removeBreaths: "voice",
40
+ deEss: "voice",
41
+ levelSentences: "voice",
42
+ chunking: "voice",
43
+ voices: "voice",
44
+ images: "pictures",
45
+ reference: "pictures",
46
+ imagePrompts: "pictures",
47
+ imageScale: "pictures",
48
+ imageScenes: "pictures",
49
+ subtitles: "video",
50
+ imageSeconds: "video",
51
+ edgeSilenceSeconds: "video",
52
+ zoomPercent: "video",
53
+ motionStyle: "video",
54
+ silenceGapSeconds: "video",
55
+ videoEdit: "video",
56
+ ambientBed: "video",
57
+ showFigures: "video",
58
+ useBrandKit: "video",
59
+ thumbnailPrompt: "thumbnail",
60
+ thumbnailCount: "thumbnail",
61
+ shorts: "shorts",
62
+ document: "document",
63
+ youtubeDescription: "upload",
64
+ descriptionPrompt: "upload",
65
+ social: "upload",
66
+ };
67
+ export const documentSections = {
68
+ schemaVersion: null,
69
+ librarySnapshot: null,
70
+ templateSource: null,
71
+ section: null,
72
+ channelId: "subject",
73
+ variants: "subject",
74
+ queue: "schedule",
75
+ expectedWords: "script",
76
+ previewText: "voice",
77
+ fontUpload: "video",
78
+ };
79
+ // The section a setting belongs to, by its path in the template document (`form.audio.voice`).
80
+ // Null for what no section shows (the schema version, Play's open tab).
81
+ export function sectionOfField(path) {
82
+ const [top, field, key] = path;
83
+ if (top !== "form")
84
+ return top === undefined ? null : (lookup(documentSections, top) ?? null);
85
+ if (field === "sources")
86
+ return key === undefined ? null : (lookup(sourceSections, key) ?? null);
87
+ if (field === "provided")
88
+ return key === undefined ? null : (lookup(providedSections, key) ?? null);
89
+ return field === undefined ? null : (lookup(formSections, field) ?? null);
90
+ }
91
+ function lookup(table, key) {
92
+ return Object.hasOwn(table, key) ? table[key] : undefined;
93
+ }
94
+ // The section a piece of rebuild work shows its sample in, by its work key (`article:body`,
95
+ // `image:harbor`, `review:article:body`). Undefined for a key no section shows.
96
+ export function sectionOfWork(key) {
97
+ if (key.startsWith("review:"))
98
+ return "reviews";
99
+ const prefix = key.split(":")[0] ?? "";
100
+ return workPrefixes[prefix];
101
+ }
102
+ const workPrefixes = {
103
+ research: "subject",
104
+ article: "script",
105
+ entry: "script",
106
+ script: "script",
107
+ audio: "voice",
108
+ narration: "voice",
109
+ level: "voice",
110
+ voices: "voice",
111
+ image: "pictures",
112
+ images: "pictures",
113
+ reference: "pictures",
114
+ figure: "pictures",
115
+ thumbnail: "thumbnail",
116
+ export: "video",
117
+ subtitles: "video",
118
+ video: "video",
119
+ animate: "video",
120
+ shorts: "shorts",
121
+ youtube: "upload",
122
+ social: "upload",
123
+ document: "document",
124
+ };
125
+ // What a section's sample is made from: a change in a section outdates the samples after it.
126
+ // Reviews judge the script, voice, pictures and thumbnail, so a change there outdates reviews;
127
+ // the schedule depends on nothing but itself and the subject (titles come from the topics).
128
+ const dependents = {
129
+ subject: ["script", "schedule"],
130
+ script: ["voice", "pictures", "thumbnail", "document", "upload", "reviews"],
131
+ voice: ["video", "reviews"],
132
+ pictures: ["video", "thumbnail", "reviews"],
133
+ video: ["shorts", "upload"],
134
+ thumbnail: ["reviews"],
135
+ shorts: [],
136
+ document: [],
137
+ reviews: [],
138
+ upload: [],
139
+ schedule: [],
140
+ };
141
+ // Every section whose sample a change from `before` to `after` outdates, in pipeline order.
142
+ export function affectedSections(before, after) {
143
+ const changed = new Set();
144
+ for (const path of changedPaths(before, after, [])) {
145
+ const section = sectionOfField(path);
146
+ if (section !== null)
147
+ changed.add(section);
148
+ }
149
+ return withDependents([...changed]);
150
+ }
151
+ // The sections given and every section whose sample is made from them, in pipeline order.
152
+ export function withDependents(sections) {
153
+ const affected = new Set();
154
+ const visit = (section) => {
155
+ if (affected.has(section))
156
+ return;
157
+ affected.add(section);
158
+ for (const next of dependents[section])
159
+ visit(next);
160
+ };
161
+ for (const section of sections)
162
+ visit(section);
163
+ return templateSections.filter((section) => affected.has(section));
164
+ }
165
+ // Paths go down to the third level (`form.sources.audio`), where every section boundary lies.
166
+ function changedPaths(before, after, path) {
167
+ if (JSON.stringify(before) === JSON.stringify(after))
168
+ return [];
169
+ if (path.length >= 3 || !isRecord(before) || !isRecord(after))
170
+ return [path];
171
+ const keys = new Set([...Object.keys(before), ...Object.keys(after)]);
172
+ return [...keys].flatMap((key) => changedPaths(before[key], after[key], [...path, key]));
173
+ }
174
+ function isRecord(value) {
175
+ return typeof value === "object" && value !== null && !Array.isArray(value);
176
+ }
@@ -0,0 +1,173 @@
1
+ import { z } from "zod";
2
+ import { readinessIsUsable } from "../../kernel/ports/model.js";
3
+ import { lastAgentConnection } from "../agents/connection.js";
4
+ import { snapshotEntry, snapshotPrompt } from "../library/snapshot.js";
5
+ import { readNotificationUrl } from "../notifications/settings.js";
6
+ import { templateById } from "../project-templates/repo.js";
7
+ import { scheduleRows } from "../schedules/repo.js";
8
+ import { listVoices, readJsonSetting } from "../settings/repo.js";
9
+ import { freeChecks } from "./checks.js";
10
+ import { checkedVersion, gateOf, isGated, runnableVersion } from "./gate.js";
11
+ import { queuedJob, runningJob } from "./jobs.js";
12
+ import { fallbackSampleTopic } from "./model.js";
13
+ import { paidView } from "./paid-view.js";
14
+ import { gatesOf, sampleOf } from "./repo.js";
15
+ import { reviewsPath } from "./reviews-path.js";
16
+ import { monthlyCost, upcomingRuns } from "./schedule-sample.js";
17
+ import { baseStatuses, madeStatuses } from "./status.js";
18
+ export function createPriceCache() {
19
+ // ceiling: one entry per schedule and template version seen since boot, a few bytes each.
20
+ const prices = new Map();
21
+ return { get: (key) => prices.get(key), set: (key, price) => void prices.set(key, price) };
22
+ }
23
+ export function priceKey(schedule, template) {
24
+ return `${schedule.id}@${String(schedule.version)}:${template.id}@${String(template.version)}`;
25
+ }
26
+ export const sampleTopicKey = "templateStudio.sampleTopic.default";
27
+ export function defaultSampleTopic(db) {
28
+ const topic = readJsonSetting(db, sampleTopicKey, z.string(), fallbackSampleTopic).trim();
29
+ return topic === "" ? fallbackSampleTopic : topic;
30
+ }
31
+ // The schedules that run a template now: not deleted, not finished.
32
+ export function templateSchedules(db, templateId) {
33
+ return scheduleRows(db).filter((schedule) =>
34
+ // A design schedule names a design template, never a project template.
35
+ schedule.templateKind === "project" &&
36
+ schedule.templateId === templateId &&
37
+ schedule.deletedAt === null &&
38
+ (schedule.status === "active" || schedule.status === "paused"));
39
+ }
40
+ function fitOf(schedule) {
41
+ const { cadence } = schedule;
42
+ return {
43
+ id: schedule.id,
44
+ name: schedule.name,
45
+ topicKeyword: schedule.topicKeyword,
46
+ runDays: cadence.kind === "weekly"
47
+ ? cadence.days
48
+ : cadence.kind === "daily"
49
+ ? [0, 1, 2, 3, 4, 5, 6]
50
+ : [],
51
+ releases: schedule.releases.map((release) => ({
52
+ day: release.day,
53
+ shorts: release.shorts.length,
54
+ })),
55
+ paused: schedule.status === "paused",
56
+ };
57
+ }
58
+ function bodiesOf(db, document) {
59
+ const snapshot = document.librarySnapshot;
60
+ if (snapshot === undefined)
61
+ return [];
62
+ return [
63
+ ...snapshot.prompts.map((prompt) => snapshotPrompt(db, snapshot, prompt.kind, prompt.name)?.body ?? prompt.body),
64
+ ...snapshot.entries.map((entry) => snapshotEntry(db, snapshot, entry.category, entry.name)?.body ?? entry.body),
65
+ ];
66
+ }
67
+ // The providers' readiness probes CLIs, which takes seconds: every caller in the window
68
+ // shares one lookup, and a failed one is never kept.
69
+ export function createReadinessCache(load, now = Date.now, ttlMs = 30_000) {
70
+ let held;
71
+ return () => {
72
+ const at = now();
73
+ if (held !== undefined && at - held.at < ttlMs)
74
+ return held.value;
75
+ const value = load();
76
+ const entry = { at, value };
77
+ held = entry;
78
+ value.catch(() => {
79
+ if (held === entry)
80
+ held = undefined;
81
+ });
82
+ return value;
83
+ };
84
+ }
85
+ const missingTemplate = "This template no longer exists; it may have been deleted. Go to Library → Templates to see your templates.";
86
+ // The studio page's content, answered without waiting for the providers' readiness: the
87
+ // checks that need it are read on their own (`getStudioChecks`).
88
+ export async function getStudio(deps, id) {
89
+ const template = templateById(deps.db, id);
90
+ if (template === undefined)
91
+ return { ok: false, reason: "not-found", message: missingTemplate };
92
+ const gates = gatesOf(deps.db, id);
93
+ const sample = sampleOf(deps.db, id);
94
+ const schedules = templateSchedules(deps.db, id);
95
+ const now = deps.clock.now();
96
+ const cost = monthlyCost(schedules, pricesOf(deps, schedules, template), now);
97
+ const running = runningJob(deps.db);
98
+ const queued = queuedJob(deps.db, id);
99
+ const free = deps.free.view(id, template.document, {
100
+ running: running?.templateId === id && running.templateVersion === template.version,
101
+ queued: queued !== undefined,
102
+ });
103
+ const paid = paidView(deps, id, template);
104
+ return {
105
+ ok: true,
106
+ value: {
107
+ template,
108
+ gate: gateOf(gates, template.version),
109
+ runnableVersion: runnableVersion(gates, template.version) ?? null,
110
+ gated: isGated(gates),
111
+ checkedVersion: checkedVersion(gates, template.version) ?? null,
112
+ sample: {
113
+ topic: sample?.topic ?? defaultSampleTopic(deps.db),
114
+ topicSource: sample?.topicSource ?? "fixed",
115
+ fullScript: sample?.fullScript ?? false,
116
+ },
117
+ sections: carriedSentences(baseStatuses(template.document, {
118
+ ...madeStatuses(free, schedules.length, cost),
119
+ ...paid.statuses,
120
+ }), gates.find((gate) => gate.version === template.version)),
121
+ paid: paid.view,
122
+ free,
123
+ schedule: { runs: upcomingRuns(schedules, template.document, now), cost },
124
+ reviews: reviewsPath(template.document),
125
+ },
126
+ };
127
+ }
128
+ // A version Slopify wrote itself keeps its gate, but what it changed has no sample yet: each
129
+ // stale section says who made the change.
130
+ function carriedSentences(sections, gate) {
131
+ if (gate?.state !== "carried" || gate.carriedFrom === null)
132
+ return sections;
133
+ const why = `Slopify made version ${String(gate.version)} from version ${String(gate.carriedFrom)} itself (a retired model switched, or a new name on restore).`;
134
+ return sections.map((section) => section.state === "stale" ? { ...section, sentence: `${why} ${section.sentence}` } : section);
135
+ }
136
+ function pricesOf(deps, schedules, template) {
137
+ return new Map(schedules.flatMap((schedule) => {
138
+ const price = deps.prices.get(priceKey(schedule, template));
139
+ return price === undefined ? [] : [[schedule.id, price]];
140
+ }));
141
+ }
142
+ // The free checks a template passes before Mark ready. The providers' readiness is the slow
143
+ // part, so the page asks for these on their own.
144
+ export async function getStudioChecks(deps, id) {
145
+ const template = templateById(deps.db, id);
146
+ if (template === undefined)
147
+ return { ok: false, reason: "not-found", message: missingTemplate };
148
+ const statuses = await deps.providerStatuses();
149
+ const schedules = templateSchedules(deps.db, id);
150
+ const now = deps.clock.now();
151
+ const cost = monthlyCost(schedules, pricesOf(deps, schedules, template), now);
152
+ return {
153
+ ok: true,
154
+ value: {
155
+ version: template.version,
156
+ checks: freeChecks({
157
+ templateId: id,
158
+ document: template.document,
159
+ bodies: bodiesOf(deps.db, template.document),
160
+ providers: new Map(statuses.map((status) => [
161
+ status.id,
162
+ { name: status.displayName, ready: readinessIsUsable(status.readiness) },
163
+ ])),
164
+ schedules: schedules.map(fitOf),
165
+ voices: listVoices(deps.db),
166
+ monthlyCost: cost,
167
+ notificationUrl: readNotificationUrl(deps.db) !== null,
168
+ agentSeenAt: lastAgentConnection(deps.db),
169
+ now,
170
+ }),
171
+ },
172
+ };
173
+ }
@@ -0,0 +1,174 @@
1
+ import { sectionLabel, templateSections, } from "./model.js";
2
+ import { affectedSections } from "./sections.js";
3
+ // What a section's sample is made from, by the step that makes it; null for a section whose
4
+ // sample never depends on a source (the schedule).
5
+ function sourceOf(document, section) {
6
+ const { form } = document;
7
+ switch (section) {
8
+ // Text the template itself holds is in every run, and in its sample (`scope.ts`).
9
+ case "subject":
10
+ return heldText(form.sources.research, form.provided.research);
11
+ case "script":
12
+ return heldText(form.sources.article, form.provided.article);
13
+ case "voice":
14
+ return form.sources.audio;
15
+ case "pictures":
16
+ return form.sources.images;
17
+ case "thumbnail":
18
+ return form.sources.thumbnail;
19
+ case "video":
20
+ return form.sources.video;
21
+ case "document":
22
+ return form.sources.document ?? "off";
23
+ case "shorts":
24
+ return form.shorts?.enabled === true && form.sources.video !== "off" ? "generate" : "off";
25
+ case "upload":
26
+ return form.sources.video;
27
+ case "reviews": {
28
+ const on = (form.checkpoints?.length ?? 0) > 0 ||
29
+ Object.values(form.reviews?.stages ?? {}).some((stage) => stage.mode !== "off");
30
+ return on ? "generate" : "off";
31
+ }
32
+ case "schedule":
33
+ return null;
34
+ }
35
+ }
36
+ function heldText(source, text) {
37
+ return source === "provide" && text.trim() !== "" ? "held" : source;
38
+ }
39
+ const offSentence = {
40
+ subject: "Research is off: the script is written from the topic alone.",
41
+ script: "The script is off.",
42
+ voice: "The narration is off.",
43
+ pictures: "Pictures are off.",
44
+ thumbnail: "The thumbnail is off.",
45
+ video: "The video is off.",
46
+ shorts: "Shorts are off.",
47
+ document: "The PDF document is off.",
48
+ reviews: "No review or checkpoint is on.",
49
+ upload: "No video, so there is no upload pack.",
50
+ schedule: "",
51
+ };
52
+ // Each section's state before any sample: off, provided at run time (no sample, never blocks
53
+ // Mark ready), or waiting for its first sample. Samples made since replace these (`free` and,
54
+ // later, the paid samples' versions).
55
+ export function baseStatuses(document, made = {}) {
56
+ return templateSections.map((id) => {
57
+ const label = sectionLabel[id];
58
+ const source = sourceOf(document, id);
59
+ if (source === "off")
60
+ return { id, label, state: "off", sentence: offSentence[id] };
61
+ if (source === "provide")
62
+ return {
63
+ id,
64
+ label,
65
+ state: "provided",
66
+ sentence: "Provided at run time: you add the file to each video, so there is no sample.",
67
+ };
68
+ return (made[id] ?? {
69
+ id,
70
+ label,
71
+ state: "stale",
72
+ sentence: "No sample yet. Press Save to make one, or Make sample.",
73
+ });
74
+ });
75
+ }
76
+ // What the free samples say of their sections. The voice's own sample is a paid one; until it
77
+ // is made, Voice shows the loudness before and after.
78
+ export function madeStatuses(free, schedules, cost) {
79
+ const of = (id, sample) => sample.state === "off"
80
+ ? undefined
81
+ : { id, label: sectionLabel[id], state: sample.state, sentence: sample.sentence };
82
+ const made = {};
83
+ const video = of("video", free.video);
84
+ if (video !== undefined)
85
+ made.video = video;
86
+ const voice = of("voice", free.loudness);
87
+ if (voice !== undefined)
88
+ made.voice = voice;
89
+ const document = of("document", free.document);
90
+ if (document !== undefined)
91
+ made.document = document;
92
+ made.reviews = {
93
+ id: "reviews",
94
+ label: sectionLabel.reviews,
95
+ state: "current",
96
+ sentence: "Where a run stops, and who answers each stop.",
97
+ };
98
+ made.schedule =
99
+ schedules === 0
100
+ ? {
101
+ id: "schedule",
102
+ label: sectionLabel.schedule,
103
+ state: "off",
104
+ sentence: "No schedule runs this template yet. Make one in Calendar → Schedules.",
105
+ }
106
+ : {
107
+ id: "schedule",
108
+ label: sectionLabel.schedule,
109
+ state: cost?.problem === null || cost === null ? "current" : "stale",
110
+ sentence: cost?.problem ??
111
+ (cost !== null && cost.paused.schedules === schedules
112
+ ? `${schedules === 1 ? "1 paused schedule uses" : `${String(schedules)} paused schedules use`} this template: its next runs once resumed, and what they would cost a month.`
113
+ : "The next runs with the titles their topics fill, and the cost a month."),
114
+ };
115
+ return made;
116
+ }
117
+ // The sections a paid sample shows: what the providers make. The video, the PDF and the
118
+ // schedule keep their free samples; the voice shows the loudness until a paid one is made.
119
+ export const paidSections = [
120
+ "subject",
121
+ "script",
122
+ "voice",
123
+ "pictures",
124
+ "thumbnail",
125
+ "shorts",
126
+ "upload",
127
+ ];
128
+ // What each paid section's sample is for the current version: made for it, being made,
129
+ // waiting (with why and what to press), failed (with the step's own sentence), or made for an
130
+ // older version and outdated by a change since. A section the change since the last made
131
+ // sample never touched keeps that sample, current.
132
+ export function paidStatuses(input) {
133
+ const row = input.versions.find((one) => one.templateVersion === input.headVersion);
134
+ const done = input.versions.find((one) => one.state === "done" && one.templateVersion <= input.headVersion);
135
+ const madeFrom = done === undefined ? undefined : input.documentOf(done.templateVersion);
136
+ const changed = new Set(madeFrom === undefined || done === undefined
137
+ ? paidSections
138
+ : affectedSections(madeFrom, input.headDocument));
139
+ const status = (id, state, sentence) => ({
140
+ id,
141
+ label: sectionLabel[id],
142
+ state,
143
+ sentence,
144
+ });
145
+ const made = {};
146
+ if (row === undefined && done === undefined)
147
+ return made;
148
+ for (const id of paidSections) {
149
+ if (row?.state === "done") {
150
+ made[id] = status(id, "current", `Made for version ${String(input.headVersion)}.`);
151
+ continue;
152
+ }
153
+ if (!changed.has(id) && done !== undefined) {
154
+ made[id] = status(id, "current", `Made for version ${String(done.templateVersion)}; nothing it shows changed since.`);
155
+ continue;
156
+ }
157
+ const pending = row?.state === "queued" || row?.state === "making";
158
+ if (pending && (input.running || row?.state === "making"))
159
+ made[id] = status(id, "making", `Making the sample of version ${String(input.headVersion)}.`);
160
+ else if (pending)
161
+ made[id] = status(id, "waiting", input.busyElsewhere
162
+ ? "Waits for another template's sample to finish."
163
+ : "Queued: it starts in a moment.");
164
+ else if (row?.state === "held")
165
+ made[id] = status(id, "waiting", row.heldReason ?? "Waiting. Press Make sample to make it.");
166
+ else if (row?.state === "failed")
167
+ made[id] = status(id, "needs-fix", row.heldReason ?? "The sample failed. Press Make sample to try again.");
168
+ else
169
+ made[id] = status(id, "stale", done === undefined
170
+ ? "No sample yet. Press Make sample to make one."
171
+ : `Changed since the sample of version ${String(done.templateVersion)}. Press Make sample to see it again.`);
172
+ }
173
+ return made;
174
+ }