@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
@@ -4,7 +4,10 @@ import { liveProject } from "../admission/repo.js";
4
4
  import { externalReviewOf } from "../reviews/external-rows.js";
5
5
  import { waitingExternalReviewRows } from "../reviews/external-waiting.js";
6
6
  import { projectHolds } from "../reviews/holds.js";
7
+ import { templateSampleProjects } from "../template-studio/repo.js";
7
8
  import { setAsideProjects } from "../uploads/repo.js";
9
+ import { postsWaiting } from "./attention-posts.js";
10
+ import { templatesNotReady } from "./attention-templates.js";
8
11
  import { extensionFailures, failedSteps, heldTopics, lateUploads, pausedRuns, rowsOf, stoppedRuns, } from "./attention-work.js";
9
12
  export const attentionKinds = [
10
13
  "external-review",
@@ -16,6 +19,9 @@ export const attentionKinds = [
16
19
  "held-topics",
17
20
  "late-upload",
18
21
  "extension-failure",
22
+ "template-not-ready",
23
+ // A post filled in another site's form, waiting for the person to press Post (`slices/social`).
24
+ "post-due",
19
25
  ];
20
26
  const projectOf = z.object({ project_id: z.string() });
21
27
  // Oldest first. A project Kept as is waits for nobody, so none of its entries is listed. Each
@@ -47,8 +53,11 @@ export function needsAttention(deps, now) {
47
53
  ["held topics", () => heldTopics(db, skip)],
48
54
  ["late uploads", () => lateUploads(deps, now)],
49
55
  ["extension failures", () => extensionFailures(db, skip)],
56
+ ["templates not ready", () => templatesNotReady(db, now, skip, deps.notReady)],
57
+ ["posts", () => postsWaiting(deps)],
50
58
  ];
51
59
  const aside = setAsideProjects(db);
60
+ const samples = templateSampleProjects(db);
52
61
  return sources
53
62
  .flatMap(([source, entries]) => {
54
63
  try {
@@ -61,7 +70,7 @@ export function needsAttention(deps, now) {
61
70
  return [];
62
71
  }
63
72
  })
64
- .filter((entry) => entry.projectId === null || !aside.has(entry.projectId))
73
+ .filter((entry) => entry.projectId === null || (!aside.has(entry.projectId) && !samples.has(entry.projectId)))
65
74
  .toSorted((a, b) => a.since.localeCompare(b.since));
66
75
  }
67
76
  function titles(db) {
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { readSetting, writeSetting } from "../settings/repo.js";
2
+ import { readJsonSetting, writeSetting } from "../settings/repo.js";
3
3
  // When an agent last opened an MCP session. This install's own fact, so backups leave it out
4
4
  // (`storage/portable.ts`).
5
5
  export const agentConnectionKey = "agents.lastConnectedAt";
@@ -7,9 +7,5 @@ export function recordAgentConnection(db, at) {
7
7
  writeSetting(db, agentConnectionKey, JSON.stringify(at));
8
8
  }
9
9
  export function lastAgentConnection(db) {
10
- const raw = readSetting(db, agentConnectionKey);
11
- if (raw === undefined)
12
- return null;
13
- const parsed = z.iso.datetime().safeParse(JSON.parse(raw));
14
- return parsed.success ? parsed.data : null;
10
+ return readJsonSetting(db, agentConnectionKey, z.iso.datetime(), null);
15
11
  }
@@ -1,7 +1,10 @@
1
1
  import { z } from "zod";
2
- // Agents: an AI agent (Claude Code, Codex, ...) driving Slopify through its MCP endpoint.
3
- // Browser-safe: Settings → Connections → Agents (MCP) builds its setup lines from these.
4
- export const actors = ["person", "agent"];
2
+ // Agents: an AI agent (Claude Code, Codex, ...) driving Slopify through its MCP endpoint, and
3
+ // the in-app assistant, which drives it the same way from Slopify's own chat. Browser-safe:
4
+ // Settings → Connections → Agents (MCP) builds its setup lines from these.
5
+ export const actors = ["person", "agent", "assistant"];
6
+ // Who an MCP call recorded in `agent_actions` came from.
7
+ export const agentActors = ["agent", "assistant"];
5
8
  export const mcpPath = "/mcp";
6
9
  export function mcpUrl(origin) {
7
10
  return `${origin.replace(/\/+$/, "")}${mcpPath}`;
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { actors } from "./model.js";
2
+ import { actors, agentActors } from "./model.js";
3
3
  // ceiling: Settings shows the latest twenty; a project's own are in its history.
4
4
  export const recentAgentActionsMax = 20;
5
5
  const actionRow = z.object({
@@ -10,6 +10,7 @@ const actionRow = z.object({
10
10
  title: z.string(),
11
11
  revision_id: z.string().nullable(),
12
12
  created_at: z.string(),
13
+ actor: z.enum(agentActors),
13
14
  });
14
15
  function actionOf(value) {
15
16
  const row = actionRow.parse(value);
@@ -21,16 +22,17 @@ function actionOf(value) {
21
22
  title: row.title,
22
23
  revisionId: row.revision_id,
23
24
  createdAt: row.created_at,
25
+ actor: row.actor,
24
26
  };
25
27
  }
26
28
  // A project the call itself deleted for good is gone: the action is kept without it. A call
27
29
  // sent again with its idempotencyKey was answered with its first answer, so it adds no second
28
30
  // row (`agent_actions_once`); any other failure to record it is thrown.
29
31
  export function recordAgentAction(db, action, idempotencyKey) {
30
- db.prepare(`INSERT INTO agent_actions(id,project_id,schedule_id,tool,title,revision_id,created_at,idempotency_key)
31
- VALUES (?,(SELECT id FROM projects WHERE id=?),?,?,?,?,?,?)
32
+ db.prepare(`INSERT INTO agent_actions(id,project_id,schedule_id,tool,title,revision_id,created_at,idempotency_key,actor)
33
+ VALUES (?,(SELECT id FROM projects WHERE id=?),?,?,?,?,?,?,?)
32
34
  ON CONFLICT(tool,COALESCE(project_id,''),idempotency_key) WHERE idempotency_key IS NOT NULL
33
- DO NOTHING`).run(action.id, action.projectId, action.scheduleId, action.tool, action.title, action.revisionId, action.createdAt, idempotencyKey ?? null);
35
+ DO NOTHING`).run(action.id, action.projectId, action.scheduleId, action.tool, action.title, action.revisionId, action.createdAt, idempotencyKey ?? null, action.actor);
34
36
  }
35
37
  export function agentActionsOf(db, projectId) {
36
38
  return db
@@ -38,12 +40,18 @@ export function agentActionsOf(db, projectId) {
38
40
  .all(projectId)
39
41
  .map(actionOf);
40
42
  }
41
- export function agentRevisionIds(db, projectId) {
43
+ function revisionIdsBy(db, projectId, actor) {
42
44
  return new Set(db
43
- .prepare("SELECT DISTINCT revision_id FROM agent_actions WHERE project_id=? AND revision_id IS NOT NULL")
44
- .all(projectId)
45
+ .prepare("SELECT DISTINCT revision_id FROM agent_actions WHERE project_id=? AND actor=? AND revision_id IS NOT NULL")
46
+ .all(projectId, actor)
45
47
  .map((row) => String(row.revision_id)));
46
48
  }
49
+ export function agentRevisionIds(db, projectId) {
50
+ return revisionIdsBy(db, projectId, "agent");
51
+ }
52
+ export function assistantRevisionIds(db, projectId) {
53
+ return revisionIdsBy(db, projectId, "assistant");
54
+ }
47
55
  export function recentAgentActions(db) {
48
56
  return db
49
57
  .prepare(`SELECT a.*, COALESCE(p.title, s.name) AS subject FROM agent_actions a
@@ -1,9 +1,5 @@
1
- import { noTokens, plusUsage } from "../telemetry/model.js";
2
1
  // At most 3 continuations; still unfinished after the third is a failed attempt.
3
2
  export const continuationLimit = 3;
4
- // The provider's own word for "I stopped because I ran out of room", which is what every
5
- // adapter maps its finish reason to (`kernel/ports/llm.ts`).
6
- const truncatedReason = "length";
7
3
  // A fixed 'Research notes' header followed by the notes, then the rendered article prompt;
8
4
  // without research, the rendered prompt alone. One user message, and no parameters of the app's
9
5
  // own: the provider's defaults are used.
@@ -35,62 +31,3 @@ export function continuationMessages(base, soFar) {
35
31
  },
36
32
  ];
37
33
  }
38
- export async function writeArticle(providers, choice, brief, onDelta) {
39
- const base = articleMessages(brief);
40
- const sent = [{ label: "Article", messages: base }];
41
- const stream = (event) => {
42
- if (event.type === "delta") {
43
- onDelta(event.text);
44
- }
45
- };
46
- let result = await providers.llm({
47
- provider: choice.provider,
48
- model: choice.model,
49
- ...(choice.thinking === undefined ? {} : { thinking: choice.thinking }),
50
- messages: base,
51
- check: written,
52
- }, stream);
53
- if (!result.ok)
54
- return result;
55
- let answer = result.value;
56
- const pieces = [answer.text];
57
- let tokens = plusUsage(noTokens, answer.usage);
58
- for (let n = 1; truncated(answer) && n <= continuationLimit; n += 1) {
59
- const messages = continuationMessages(base, pieces.join(""));
60
- sent.push({ label: `Continuation ${String(n)}`, messages });
61
- result = await providers.llm({
62
- provider: choice.provider,
63
- model: choice.model,
64
- ...(choice.thinking === undefined ? {} : { thinking: choice.thinking }),
65
- messages,
66
- // The last continuation allowed is the one that has to end the article: a fourth
67
- // truncation is a failed attempt, which is the wrapper's to retry. The
68
- // loop therefore never sees a truncated answer with its budget spent.
69
- check: n === continuationLimit ? finished : written,
70
- }, stream);
71
- if (!result.ok)
72
- return result;
73
- answer = result.value;
74
- pieces.push(answer.text);
75
- tokens = plusUsage(tokens, answer.usage);
76
- }
77
- return { ok: true, value: { markdown: pieces.join(""), sent, tokens } };
78
- }
79
- function truncated(answer) {
80
- return answer.finishReason === truncatedReason;
81
- }
82
- // Empty response → failed attempt.
83
- function written(answer) {
84
- return answer.text.trim() === ""
85
- ? "The AI model returned an empty article. Try again; if it keeps happening, choose a different model in Edit project → Providers."
86
- : undefined;
87
- }
88
- function finished(answer) {
89
- const empty = written(answer);
90
- if (empty !== undefined) {
91
- return empty;
92
- }
93
- return truncated(answer)
94
- ? `The article was still unfinished after ${String(continuationLimit)} continuations because the AI model kept stopping at its length limit. Ask for a shorter article in Edit project → Prompts, or choose a model with a larger output limit in Edit project → Providers, then Try again.`
95
- : undefined;
96
- }
@@ -1,6 +1,7 @@
1
1
  import { remark } from "remark";
2
2
  import remarkGfm from "remark-gfm";
3
3
  import stripMarkdown from "strip-markdown";
4
+ import { internalError } from "../../kernel/errors.js";
4
5
  // ceiling: conversions remembered. The same article is converted again every time a run plans
5
6
  // its work, which is several times a step; a long article took seconds each time, on the
6
7
  // thread that answers the page. The oldest goes first.
@@ -26,11 +27,11 @@ function convert(markdown) {
26
27
  const paragraphs = tree.children
27
28
  .map((node) => {
28
29
  if (node.type !== "paragraph")
29
- throw new Error("Slopify hit an internal error (the article couldn't be turned into plain text). Try again; if it happens again, use Download diagnostics in Settings and report it.");
30
+ throw new Error(internalError("the article couldn't be turned into plain text"));
30
31
  return node.children
31
32
  .map((child) => {
32
33
  if (child.type !== "text")
33
- throw new Error("Slopify hit an internal error (the article couldn't be turned into plain text). Try again; if it happens again, use Download diagnostics in Settings and report it.");
34
+ throw new Error(internalError("the article couldn't be turned into plain text"));
34
35
  return child.value;
35
36
  })
36
37
  .join("");
@@ -1,41 +1,6 @@
1
- import { insertPiece, piecesOf, setPiece } from "../../kernel/runner/piece-repo.js";
2
1
  import { subjectOf } from "../admission/model.js";
3
- import { noTokens, plusUsage } from "../telemetry/model.js";
4
- export const categories = ["intro", "outro"];
5
- export async function writeSegment(providers, choice, config, category, article, sent) {
6
- const picked = config[category];
7
- if (picked === undefined)
8
- return { ok: true, value: undefined };
9
- const body = config.rendered[category];
10
- if (body === undefined)
11
- throw new Error(`Slopify hit an internal error (the ${category} text was never filled in). Try again; if it happens again, use Download diagnostics in Settings and report it.`);
12
- const common = { category, name: picked.name, mode: picked.mode };
13
- if (picked.mode === "text")
14
- return { ok: true, value: { ...common, text: body, tokens: noTokens } };
15
- if (choice === undefined)
16
- throw new Error(`No AI model is set for writing the ${category}. Choose one in Edit project → Providers, then Try again.`);
17
- const messages = segmentMessages(body, config, article);
18
- sent.push({ label: category === "intro" ? "Intro" : "Outro", messages });
19
- const answer = await providers.llm({
20
- provider: choice.provider,
21
- model: choice.model,
22
- ...(choice.thinking === undefined ? {} : { thinking: choice.thinking }),
23
- messages,
24
- check: (given) => given.text.trim() === ""
25
- ? `The AI model returned an empty ${category}. Try again; if it keeps happening, choose a different model in Edit project → Providers.`
26
- : undefined,
27
- });
28
- if (!answer.ok)
29
- return answer;
30
- return {
31
- ok: true,
32
- value: {
33
- ...common,
34
- text: answer.value.text.trim(),
35
- tokens: plusUsage(noTokens, answer.value.usage),
36
- },
37
- };
38
- }
2
+ // The message an intro or outro is written from by the text model: its prompt, the title, the
3
+ // run's keywords and the article's plain text (`rebuild/recipe-text.ts`).
39
4
  export function segmentMessages(body, config, article) {
40
5
  const values = Object.entries(config.values);
41
6
  return [
@@ -59,28 +24,3 @@ export function segmentMessages(body, config, article) {
59
24
  },
60
25
  ];
61
26
  }
62
- export function keepSegment(deps, context, segment, idx) {
63
- const payload = JSON.stringify({
64
- category: segment.category,
65
- name: segment.name,
66
- mode: segment.mode,
67
- text: segment.text,
68
- });
69
- const existing = piecesOf(deps.db, context.stage.id, "segment").find((piece) => piece.idx === idx);
70
- if (existing === undefined) {
71
- insertPiece(deps.db, {
72
- id: deps.ids.next(),
73
- stageId: context.stage.id,
74
- kind: "segment",
75
- idx,
76
- state: "done",
77
- payload,
78
- });
79
- }
80
- else
81
- setPiece(deps.db, existing.id, "done", payload);
82
- }
83
- export function instructionsText(sent) {
84
- const parts = sent.map((one) => `=== ${one.label} ===\n\n${one.messages.map((message) => message.content).join("\n\n")}`);
85
- return `${parts.join("\n\n")}\n`;
86
- }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,80 @@
1
+ import { z } from "zod";
2
+ import { askWindowMs } from "./gate.js";
3
+ import { askStates } from "./model.js";
4
+ // What the assistant asked the person first, and their answer. An Allow is a grant for that
5
+ // one call: used once, within 15 minutes, in the session it was asked in.
6
+ const askRow = z.object({
7
+ id: z.string(),
8
+ session_id: z.string(),
9
+ tool: z.string(),
10
+ text: z.string(),
11
+ state: z.enum(askStates),
12
+ created_at: z.string(),
13
+ decided_at: z.string().nullable(),
14
+ });
15
+ function askOf(value) {
16
+ const row = askRow.parse(value);
17
+ return {
18
+ id: row.id,
19
+ sessionId: row.session_id,
20
+ tool: row.tool,
21
+ text: row.text,
22
+ state: row.state,
23
+ createdAt: row.created_at,
24
+ decidedAt: row.decided_at,
25
+ };
26
+ }
27
+ const columns = "id, session_id, tool, text, state, created_at, decided_at";
28
+ function windowStart(now) {
29
+ return new Date(now.valueOf() - askWindowMs).toISOString();
30
+ }
31
+ // Asks nobody answered and Allows nobody used in time.
32
+ function expire(db, now) {
33
+ const since = windowStart(now);
34
+ db.prepare("UPDATE assistant_asks SET state='expired' WHERE (state='asked' AND created_at<?) OR (state='allowed' AND decided_at<?)").run(since, since);
35
+ }
36
+ // The same call asked again while the first ask still waits is the same card.
37
+ export function openAsk(db, ask, now) {
38
+ expire(db, now);
39
+ const waiting = db
40
+ .prepare(`SELECT ${columns} FROM assistant_asks WHERE session_id=? AND tool=? AND args_hash=? AND state='asked'`)
41
+ .get(ask.sessionId, ask.tool, ask.argsHash);
42
+ if (waiting !== undefined)
43
+ return askOf(waiting);
44
+ db.prepare("INSERT INTO assistant_asks(id, session_id, tool, args_hash, text, state, created_at) VALUES (?,?,?,?,?,'asked',?)").run(ask.id, ask.sessionId, ask.tool, ask.argsHash, ask.text, now.toISOString());
45
+ return askOf(db.prepare(`SELECT ${columns} FROM assistant_asks WHERE id=?`).get(ask.id));
46
+ }
47
+ export function decideAsk(db, id, answer, now) {
48
+ expire(db, now);
49
+ const found = db.prepare(`SELECT ${columns} FROM assistant_asks WHERE id=?`).get(id);
50
+ if (found === undefined)
51
+ return { ok: false, reason: "unknown" };
52
+ const ask = askOf(found);
53
+ if (ask.state === "expired")
54
+ return { ok: false, reason: "expired" };
55
+ if (ask.state !== "asked")
56
+ return { ok: false, reason: "decided" };
57
+ db.prepare("UPDATE assistant_asks SET state=?, decided_at=? WHERE id=? AND state='asked'").run(answer === "allow" ? "allowed" : "denied", now.toISOString(), id);
58
+ return {
59
+ ok: true,
60
+ ask: askOf(db.prepare(`SELECT ${columns} FROM assistant_asks WHERE id=?`).get(id)),
61
+ };
62
+ }
63
+ // Uses the person's Allow for this exact call, once. False when there is none to use.
64
+ export function consumeGrant(db, grant, now) {
65
+ expire(db, now);
66
+ const used = db
67
+ .prepare(`UPDATE assistant_asks SET state='used' WHERE id=(
68
+ SELECT id FROM assistant_asks WHERE session_id=? AND tool=? AND args_hash=? AND state='allowed'
69
+ ORDER BY decided_at DESC LIMIT 1)
70
+ RETURNING id`)
71
+ .all(grant.sessionId, grant.tool, grant.argsHash);
72
+ return used.length > 0;
73
+ }
74
+ export function asksOf(db, sessionId, now) {
75
+ expire(db, now);
76
+ return db
77
+ .prepare(`SELECT ${columns} FROM assistant_asks WHERE session_id=? ORDER BY created_at, rowid`)
78
+ .all(sessionId)
79
+ .map(askOf);
80
+ }
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ // The cost sentence on an ask card, from the estimate the preview (Choose what to remake) or
3
+ // Play's review already showed for this exact work.
4
+ const money = (value) => `$${value.toFixed(2)}`;
5
+ function range(low, high) {
6
+ return Math.abs(high - low) < 0.005 ? money(low) : `${money(low)}–${money(high)}`;
7
+ }
8
+ export function costSentence(estimates) {
9
+ const low = estimates.reduce((sum, one) => sum + one.low, 0);
10
+ const high = estimates.reduce((sum, one) => sum + one.high, 0);
11
+ const unknown = estimates.reduce((sum, one) => sum + one.unknown, 0);
12
+ const onPlan = estimates.some((one) => one.apiLow !== undefined);
13
+ const priced = high > 0 ? `estimated at ${range(low, high)}` : onPlan ? "" : "estimated at $0.00";
14
+ const plan = onPlan ? "part of it runs on your CLI plan's allowance" : "";
15
+ const unpriced = unknown === 0
16
+ ? ""
17
+ : `${String(unknown)} ${unknown === 1 ? "step has" : "steps have"} no price in the catalogue`;
18
+ const parts = [priced, plan, unpriced].filter((part) => part !== "");
19
+ return `This starts paid work${parts.length === 0 ? "" : `: ${parts.join("; ")}`}.`;
20
+ }
21
+ export const unpricedSentence = "This starts paid work; Slopify can't price it here.";
22
+ // A schedule call starts nothing now: runs begin at the schedule's times, and are paid then.
23
+ export function scheduleSentence(tool) {
24
+ switch (tool) {
25
+ case "create_schedule":
26
+ return "It starts active: runs start at the schedule's times and are paid then.";
27
+ case "update_schedule":
28
+ return "Runs start at the schedule's times and are paid then; a paused schedule stays paused, so nothing runs until you resume it.";
29
+ case "resume_schedule":
30
+ return "Runs start again at the schedule's times and are paid then.";
31
+ default:
32
+ return undefined;
33
+ }
34
+ }
35
+ const costsSchema = z
36
+ .object({
37
+ currency: z.literal("USD"),
38
+ low: z.number(),
39
+ high: z.number(),
40
+ unknown: z.number(),
41
+ apiLow: z.number().optional(),
42
+ })
43
+ .loose();
44
+ // The estimate a preview_rebuild or review_draft answer carries, keyed by the id the start
45
+ // call names (previewId, reviewId).
46
+ export function estimateOfAnswer(value) {
47
+ const preview = z.object({ id: z.string(), costs: costsSchema }).safeParse(value);
48
+ if (preview.success)
49
+ return { id: preview.data.id, estimates: [preview.data.costs] };
50
+ const review = z.object({ id: z.string(), estimates: z.array(costsSchema) }).safeParse(value);
51
+ if (review.success)
52
+ return { id: review.data.id, estimates: review.data.estimates };
53
+ return undefined;
54
+ }
@@ -0,0 +1,222 @@
1
+ import { createHash } from "node:crypto";
2
+ // "Ask first": which of Slopify's tools the assistant may only call once the person pressed
3
+ // Allow, and how a later call is matched to that Allow. The model can't approve itself: a
4
+ // call with confirmed: true counts only against a grant the person made (`repo.ts`).
5
+ // Never offered to the assistant: an external review is the reviewing agent's or the
6
+ // person's, the library's export and import move every prompt at once, uploads take files
7
+ // from disk, and emptying the trash or deleting old versions can't be undone.
8
+ export const assistantExcludedTools = new Set([
9
+ "submit_review_verdict",
10
+ "get_external_review",
11
+ "import_library",
12
+ "export_library",
13
+ "delete_from_trash",
14
+ "delete_from_trash_many",
15
+ "delete_old_versions",
16
+ ]);
17
+ // The tools that start work a provider bills for (or that the plan's allowance pays for).
18
+ export const assistantCostlyTools = [
19
+ "start_draft",
20
+ "start_rebuild",
21
+ "make_quick_short",
22
+ "make_full_video_draft",
23
+ "retry_stage",
24
+ "soften_stage",
25
+ "rerun_stage",
26
+ "resume_project",
27
+ "approve_checkpoint",
28
+ "generate_topics",
29
+ "generate_cast_picture",
30
+ "quote_voice_sample",
31
+ "prepare_topic",
32
+ "instantiate_template",
33
+ "approve_topic",
34
+ "approve_topics",
35
+ "approve_all_topics",
36
+ "switch_retired_model",
37
+ "switch_all_retired_models",
38
+ // Settings → Models' Check models sends each model one small paid request.
39
+ "check_models",
40
+ // Library → Designs: each draws a picture a provider bills for. A template's Save draws the
41
+ // editor's sample when it asks for one, so it asks whatever it sends.
42
+ "edit_design_picture",
43
+ "make_design_artwork",
44
+ "make_design_from_template",
45
+ "make_design_template_sample",
46
+ "retry_design_step",
47
+ "save_design_template",
48
+ // Library → Templates → Open studio: each makes (or remakes) a template's paid sample. A
49
+ // studio Save makes the paid sample of what changed when it asks for one, so it asks
50
+ // whatever it sends. The daily budget is the most the samples may spend, so raising it is
51
+ // the person's call too.
52
+ "save_template_studio",
53
+ "make_template_sample",
54
+ "set_sample_topic",
55
+ "set_sample_full_script",
56
+ "say_it_as",
57
+ "update_template_studio_settings",
58
+ // Redo makes a flagged item again with the provider.
59
+ "redo_review",
60
+ // Taking a checkpoint off lets the paid steps behind it start (one the run waits at must be
61
+ // approved instead, `edge/http/checkpoints.ts`).
62
+ "change_checkpoints",
63
+ // A schedule starts paid runs at its times: making, changing or resuming one decides them.
64
+ "create_schedule",
65
+ "update_schedule",
66
+ "resume_schedule",
67
+ // A restored project picks up where it was, paid steps included.
68
+ "restore_from_trash",
69
+ "restore_from_trash_many",
70
+ ];
71
+ const costly = new Set(assistantCostlyTools);
72
+ // The tools that send something out of Slopify, or choose where it is sent: words a page or a
73
+ // file planted in the chat must not be able to point Slopify's notifications elsewhere.
74
+ export const assistantOutwardTools = [
75
+ "set_notification_url",
76
+ "send_test_notification",
77
+ // Rescore sends each topic's title to search engines; Check providers asks every provider
78
+ // with the person's keys.
79
+ "score_topics",
80
+ "check_providers",
81
+ ];
82
+ const outward = new Set(assistantOutwardTools);
83
+ // Every other tool that changes something, named here so that a new one has to be put in one
84
+ // list or the other (`edge/mcp/assistant.test.ts`): free to call, nothing billed or sent.
85
+ export const assistantFreeTools = [
86
+ "move_projects_to_channel",
87
+ "move_in_run_queue",
88
+ "estimate_run",
89
+ "hide_autopilot_warning",
90
+ "set_weekly_report",
91
+ "mark_uploaded",
92
+ "keep_as_is",
93
+ "preview_added_output",
94
+ "add_output",
95
+ "overrule_review",
96
+ "edit_description_field",
97
+ "set_description_links",
98
+ "set_pack_slot",
99
+ "set_pack_real_footage",
100
+ "set_pack_pick",
101
+ "set_pack_playlists",
102
+ // A post's settings, text, Reddit fields and link: Fill in <site> stays the person's.
103
+ "set_post_choice",
104
+ "edit_post_text",
105
+ "set_reddit_post",
106
+ "set_post_link",
107
+ "remove_from_fill_queue",
108
+ "swap_releases",
109
+ "set_release",
110
+ "set_posting_plan",
111
+ "set_lead_time",
112
+ "set_youtube_link",
113
+ "pause_project",
114
+ "prepare_revision",
115
+ "save_revision",
116
+ "restore_revision",
117
+ "preview_rebuild",
118
+ "create_draft",
119
+ "save_draft",
120
+ "fork_draft",
121
+ "review_draft",
122
+ "create_template",
123
+ "template_from_project",
124
+ "next_chapter_template",
125
+ "update_template",
126
+ "pause_schedule",
127
+ "reject_topics",
128
+ "restore_topics",
129
+ "reject_topic",
130
+ "edit_held_topic",
131
+ "set_topic_queue",
132
+ "move_topic",
133
+ "transfer_topic",
134
+ "create_channel",
135
+ "update_channel",
136
+ "set_ai_disclosure",
137
+ "add_cast_member",
138
+ "move_cast_member",
139
+ "update_cast_member",
140
+ "set_channel_template",
141
+ "set_episode_memory",
142
+ "update_episode_memory",
143
+ "preview_channel_videos",
144
+ "import_channel_videos",
145
+ "create_design",
146
+ "update_design",
147
+ "quote_design_edit",
148
+ "quote_design_artwork",
149
+ "set_design_version",
150
+ "create_design_template",
151
+ "quote_design_template",
152
+ "create_prompt",
153
+ "update_prompt",
154
+ "set_prompt_photorealistic",
155
+ "restore_prompt_version",
156
+ "create_entry",
157
+ "update_entry",
158
+ "restore_entry_version",
159
+ "create_document_theme",
160
+ "update_document_theme",
161
+ "set_narration_aliases",
162
+ "update_settings",
163
+ "set_default_channel_links",
164
+ "add_voice",
165
+ "set_voice_languages",
166
+ "set_voice_real_person",
167
+ "set_studio_playlists",
168
+ "dismiss_model_notices",
169
+ // The published catalogue: read from Slopify's site, nothing of the person's goes with it.
170
+ "check_catalogue",
171
+ "refresh_catalogue",
172
+ "install_starter_pack",
173
+ "restore_samples",
174
+ "copy_sample",
175
+ "quote_template_save",
176
+ "quote_say_it_as",
177
+ "quote_samples_for_all",
178
+ "make_template_free_samples",
179
+ "quote_bakeoff",
180
+ // Prices remakes for several projects; starting each is start_rebuild's.
181
+ "preview_remake_outdated",
182
+ ];
183
+ // Removing something (DELETE), anything the page confirms, paid work, and sending out.
184
+ export function isGated(tool) {
185
+ return (tool.method === "DELETE" ||
186
+ tool.confirm !== undefined ||
187
+ costly.has(tool.name) ||
188
+ tool.sends === true ||
189
+ outward.has(tool.name));
190
+ }
191
+ export function isOutward(tool) {
192
+ return tool.sends === true || outward.has(tool.name);
193
+ }
194
+ // ceiling: an ask can be answered, and an Allow used, for 15 minutes. Past that the costs
195
+ // may have moved, so the assistant has to ask again.
196
+ export const askWindowMs = 15 * 60_000;
197
+ // The same call is the same arguments, whatever key retries it and whether it says it is
198
+ // confirmed: those two are what a call after Allow changes.
199
+ export function argsHash(args) {
200
+ const { confirmed: _confirmed, body, ...rest } = args;
201
+ const kept = typeof body === "object" && body !== null && !Array.isArray(body)
202
+ ? { ...rest, body: withoutKey(body) }
203
+ : body === undefined
204
+ ? rest
205
+ : { ...rest, body };
206
+ return createHash("sha256").update(canonical(kept)).digest("hex");
207
+ }
208
+ function withoutKey(body) {
209
+ const { idempotencyKey: _key, ...rest } = body;
210
+ return rest;
211
+ }
212
+ function canonical(value) {
213
+ if (Array.isArray(value))
214
+ return `[${value.map(canonical).join(",")}]`;
215
+ if (typeof value === "object" && value !== null)
216
+ return `{${Object.entries(value)
217
+ .filter(([, one]) => one !== undefined)
218
+ .toSorted(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
219
+ .map(([key, one]) => `${JSON.stringify(key)}:${canonical(one)}`)
220
+ .join(",")}}`;
221
+ return JSON.stringify(value) ?? "null";
222
+ }