@crievo/omni 0.0.0-stage → 0.1.1

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 (708) hide show
  1. package/.env.example +41 -0
  2. package/README.md +2 -2
  3. package/bin/omni.mjs +18 -0
  4. package/docs/onboarding/clone-voice.png +0 -0
  5. package/docs/onboarding/getting-started.png +0 -0
  6. package/docs/onboarding/new-video.png +0 -0
  7. package/docs/onboarding/providers.png +0 -0
  8. package/docs/onboarding/publish.png +0 -0
  9. package/docs/onboarding/references.png +0 -0
  10. package/docs/onboarding.md +212 -0
  11. package/omnivideo.config.example.json +437 -0
  12. package/package.json +40 -4
  13. package/reference/captions.md +156 -0
  14. package/reference/carousel-contract.md +91 -0
  15. package/reference/cloud.md +96 -0
  16. package/reference/learnings.md +792 -0
  17. package/reference/omnichat.md +305 -0
  18. package/reference/premiere-mcp.md +91 -0
  19. package/reference/publish.md +305 -0
  20. package/reference/scenes-contract.md +109 -0
  21. package/reference/studio.md +666 -0
  22. package/reference/voicestudio.md +81 -0
  23. package/reference/writing-for-voice.md +67 -0
  24. package/requirements.txt +3 -0
  25. package/studio/api/app.ts +87 -0
  26. package/studio/api/lib/errors.ts +33 -0
  27. package/studio/api/lib/files.ts +41 -0
  28. package/studio/api/lib/hono.ts +9 -0
  29. package/studio/api/lib/result.ts +14 -0
  30. package/studio/api/lib/validate.ts +31 -0
  31. package/studio/api/lib/video.ts +10 -0
  32. package/studio/api/middleware/json-charset.ts +11 -0
  33. package/studio/api/middleware/local-only.ts +32 -0
  34. package/studio/api/middleware/no-timeout.ts +10 -0
  35. package/studio/api/routes/admin.ts +18 -0
  36. package/studio/api/routes/agent-cascade.ts +100 -0
  37. package/studio/api/routes/agent-history.ts +23 -0
  38. package/studio/api/routes/agent.ts +162 -0
  39. package/studio/api/routes/analytics.ts +31 -0
  40. package/studio/api/routes/approval.ts +60 -0
  41. package/studio/api/routes/archive.ts +12 -0
  42. package/studio/api/routes/captions.ts +28 -0
  43. package/studio/api/routes/carousel.ts +38 -0
  44. package/studio/api/routes/clone.ts +27 -0
  45. package/studio/api/routes/create.ts +19 -0
  46. package/studio/api/routes/events.ts +11 -0
  47. package/studio/api/routes/export.ts +14 -0
  48. package/studio/api/routes/media.ts +30 -0
  49. package/studio/api/routes/omnichat.ts +113 -0
  50. package/studio/api/routes/onboarding.ts +14 -0
  51. package/studio/api/routes/publish.ts +40 -0
  52. package/studio/api/routes/queue.ts +14 -0
  53. package/studio/api/routes/references.ts +40 -0
  54. package/studio/api/routes/runner.ts +17 -0
  55. package/studio/api/routes/schedule.ts +47 -0
  56. package/studio/api/routes/services.ts +11 -0
  57. package/studio/api/routes/sessions.ts +27 -0
  58. package/studio/api/routes/settings.ts +102 -0
  59. package/studio/api/routes/sound.ts +45 -0
  60. package/studio/api/routes/thumbnail.ts +18 -0
  61. package/studio/api/routes/usage.ts +13 -0
  62. package/studio/api/routes/videos.ts +41 -0
  63. package/studio/api/routes/voices.ts +71 -0
  64. package/studio/api/services/admin.ts +113 -0
  65. package/studio/api/services/agent-cascade.ts +975 -0
  66. package/studio/api/services/agent-claude.ts +47 -0
  67. package/studio/api/services/agent-history.ts +103 -0
  68. package/studio/api/services/agent-persona.ts +77 -0
  69. package/studio/api/services/agent-tools.ts +2237 -0
  70. package/studio/api/services/agent-ui-tools.ts +259 -0
  71. package/studio/api/services/agent-wait.ts +32 -0
  72. package/studio/api/services/agent.ts +553 -0
  73. package/studio/api/services/analytics.ts +92 -0
  74. package/studio/api/services/approval.ts +134 -0
  75. package/studio/api/services/archive.ts +38 -0
  76. package/studio/api/services/captions.ts +268 -0
  77. package/studio/api/services/carousel.ts +206 -0
  78. package/studio/api/services/classify.ts +196 -0
  79. package/studio/api/services/clone-phrases.ts +75 -0
  80. package/studio/api/services/clone.ts +722 -0
  81. package/studio/api/services/create.ts +421 -0
  82. package/studio/api/services/events.ts +215 -0
  83. package/studio/api/services/media.ts +32 -0
  84. package/studio/api/services/omnichat.ts +624 -0
  85. package/studio/api/services/onboarding.ts +77 -0
  86. package/studio/api/services/publish.ts +287 -0
  87. package/studio/api/services/queue.ts +150 -0
  88. package/studio/api/services/references.ts +269 -0
  89. package/studio/api/services/root.ts +60 -0
  90. package/studio/api/services/services.ts +114 -0
  91. package/studio/api/services/sessions.ts +1007 -0
  92. package/studio/api/services/settings.ts +983 -0
  93. package/studio/api/services/sound.ts +311 -0
  94. package/studio/api/services/thumbnail.ts +133 -0
  95. package/studio/api/services/usage.ts +27 -0
  96. package/studio/api/services/videos.ts +418 -0
  97. package/studio/api/services/voice-pause.ts +98 -0
  98. package/studio/api/services/voices.ts +324 -0
  99. package/studio/runner/runner.ts +244 -0
  100. package/studio/shared/omni-actions.ts +68 -0
  101. package/studio/shared/omni-admin.ts +52 -0
  102. package/studio/shared/omni-farewell.ts +48 -0
  103. package/studio/shared/omni-hotword.ts +20 -0
  104. package/studio/shared/omni-screens.ts +228 -0
  105. package/studio/shared/schemas/admin.ts +15 -0
  106. package/studio/shared/schemas/agent-cascade.ts +58 -0
  107. package/studio/shared/schemas/agent-history.ts +73 -0
  108. package/studio/shared/schemas/agent.ts +50 -0
  109. package/studio/shared/schemas/analytics.ts +6 -0
  110. package/studio/shared/schemas/approval.ts +22 -0
  111. package/studio/shared/schemas/captions.ts +19 -0
  112. package/studio/shared/schemas/carousel.ts +26 -0
  113. package/studio/shared/schemas/clone.ts +40 -0
  114. package/studio/shared/schemas/common.ts +16 -0
  115. package/studio/shared/schemas/omnichat.ts +54 -0
  116. package/studio/shared/schemas/onboarding.ts +5 -0
  117. package/studio/shared/schemas/publish.ts +45 -0
  118. package/studio/shared/schemas/references.ts +20 -0
  119. package/studio/shared/schemas/settings.ts +82 -0
  120. package/studio/shared/schemas/sound.ts +22 -0
  121. package/studio/shared/schemas/videos.ts +38 -0
  122. package/studio/shared/schemas/voices.ts +23 -0
  123. package/studio/shared/types/api.ts +1290 -0
  124. package/studio/studio.ts +148 -0
  125. package/studio/tsconfig.json +15 -0
  126. package/studio/web/assets/logos/cartesia.svg +4 -0
  127. package/studio/web/assets/logos/elevenlabs.svg +12 -0
  128. package/studio/web/assets/logos/fish.svg +24 -0
  129. package/studio/web/assets/logos/omni-black.png +0 -0
  130. package/studio/web/assets/logos/omni-white.png +0 -0
  131. package/studio/web/assets/logos/voicestudio.svg +21 -0
  132. package/studio/web/components/AgentMark.tsx +7 -0
  133. package/studio/web/components/AgentWalking.tsx +11 -0
  134. package/studio/web/components/ApiKeyField.tsx +104 -0
  135. package/studio/web/components/AppShell.tsx +64 -0
  136. package/studio/web/components/ApprovalNotice.tsx +65 -0
  137. package/studio/web/components/AvatarGroupIcon.tsx +22 -0
  138. package/studio/web/components/AvatarNameField.tsx +86 -0
  139. package/studio/web/components/AvatarPicker.tsx +84 -0
  140. package/studio/web/components/BrandLogo.tsx +16 -0
  141. package/studio/web/components/CartesiaPlanSetting.tsx +90 -0
  142. package/studio/web/components/ClaudeWalking.tsx +32 -0
  143. package/studio/web/components/CloneVoiceDialog/GuidedScript.tsx +39 -0
  144. package/studio/web/components/CloneVoiceDialog/LanguageBar.tsx +37 -0
  145. package/studio/web/components/CloneVoiceDialog/LevelMeter.tsx +31 -0
  146. package/studio/web/components/CloneVoiceDialog/ProviderChoice.tsx +81 -0
  147. package/studio/web/components/CloneVoiceDialog/QualityPanel.tsx +62 -0
  148. package/studio/web/components/CloneVoiceDialog/RecordStep.tsx +50 -0
  149. package/studio/web/components/CloneVoiceDialog/RecorderBar.tsx +79 -0
  150. package/studio/web/components/CloneVoiceDialog/RedoSummary.tsx +54 -0
  151. package/studio/web/components/CloneVoiceDialog/SaveStep.tsx +91 -0
  152. package/studio/web/components/CloneVoiceDialog/SourceBar.tsx +30 -0
  153. package/studio/web/components/CloneVoiceDialog/index.tsx +141 -0
  154. package/studio/web/components/CloneVoiceDialog/types.ts +28 -0
  155. package/studio/web/components/CloneVoiceDialog/useCloneVoice.ts +528 -0
  156. package/studio/web/components/ConnectionSignals.tsx +51 -0
  157. package/studio/web/components/EditVoiceDialog/EditVoiceFooter.tsx +72 -0
  158. package/studio/web/components/EditVoiceDialog/ProviderCards.tsx +81 -0
  159. package/studio/web/components/EditVoiceDialog/index.tsx +256 -0
  160. package/studio/web/components/ErrorBanner.tsx +115 -0
  161. package/studio/web/components/FinishedTask.tsx +41 -0
  162. package/studio/web/components/FishModelSetting.tsx +69 -0
  163. package/studio/web/components/FishPriceSetting.tsx +44 -0
  164. package/studio/web/components/HumanBanner.tsx +64 -0
  165. package/studio/web/components/Lightbox.tsx +41 -0
  166. package/studio/web/components/LogStream.tsx +42 -0
  167. package/studio/web/components/Markdown.tsx +21 -0
  168. package/studio/web/components/MissingDmsPanel/BatchSend.tsx +137 -0
  169. package/studio/web/components/MissingDmsPanel/CommentCard.tsx +168 -0
  170. package/studio/web/components/MissingDmsPanel/CommentFeed.tsx +45 -0
  171. package/studio/web/components/MissingDmsPanel/DmBubble.tsx +38 -0
  172. package/studio/web/components/MissingDmsPanel/ReplyComposer.tsx +63 -0
  173. package/studio/web/components/MissingDmsPanel/index.tsx +98 -0
  174. package/studio/web/components/NotFound.tsx +48 -0
  175. package/studio/web/components/Omni/OmniAvatarPicker.tsx +92 -0
  176. package/studio/web/components/Omni/OmniCards.tsx +202 -0
  177. package/studio/web/components/Omni/OmniGlow.tsx +183 -0
  178. package/studio/web/components/Omni/OmniHistory.tsx +119 -0
  179. package/studio/web/components/Omni/OmniHotword.tsx +40 -0
  180. package/studio/web/components/Omni/OmniMicSelect.tsx +92 -0
  181. package/studio/web/components/Omni/OmniVoiceSample.tsx +81 -0
  182. package/studio/web/components/Omni/OmniWidget.tsx +743 -0
  183. package/studio/web/components/Omni/PendingActions.tsx +200 -0
  184. package/studio/web/components/Omni/Transcript.tsx +127 -0
  185. package/studio/web/components/OmnichatAccountStatus.tsx +87 -0
  186. package/studio/web/components/OmnichatRulePanel/RuleConfig.tsx +150 -0
  187. package/studio/web/components/OmnichatRulePanel/RuleDryRun.tsx +15 -0
  188. package/studio/web/components/OmnichatRulePanel/RuleEnableConfirm.tsx +42 -0
  189. package/studio/web/components/OmnichatRulePanel/RuleSkeleton.tsx +18 -0
  190. package/studio/web/components/OmnichatRulePanel/RuleStatus.tsx +55 -0
  191. package/studio/web/components/OmnichatRulePanel/index.tsx +115 -0
  192. package/studio/web/components/OmnichatRulePanel/rule-steps.ts +67 -0
  193. package/studio/web/components/OmnichatRulePanel/steps/MessageStep.tsx +91 -0
  194. package/studio/web/components/OmnichatRulePanel/steps/RepliesStep.tsx +201 -0
  195. package/studio/web/components/OmnichatRulePanel/steps/TriggerStep.tsx +76 -0
  196. package/studio/web/components/OmnichatRulePanel/steps/types.ts +11 -0
  197. package/studio/web/components/Palette.tsx +17 -0
  198. package/studio/web/components/PlatformCard.tsx +109 -0
  199. package/studio/web/components/PlatformIcon.tsx +19 -0
  200. package/studio/web/components/ProviderCard.tsx +80 -0
  201. package/studio/web/components/ProviderDetail.tsx +367 -0
  202. package/studio/web/components/ProviderLogo.tsx +20 -0
  203. package/studio/web/components/QueuePanel.tsx +77 -0
  204. package/studio/web/components/ReferenceActions.tsx +89 -0
  205. package/studio/web/components/ReferencePicker.tsx +136 -0
  206. package/studio/web/components/ResultMessage.tsx +7 -0
  207. package/studio/web/components/RuleForm.tsx +138 -0
  208. package/studio/web/components/RuleLog.tsx +151 -0
  209. package/studio/web/components/RunningTask.tsx +23 -0
  210. package/studio/web/components/SampleList.tsx +55 -0
  211. package/studio/web/components/SessionPanel.tsx +352 -0
  212. package/studio/web/components/SettingRow.tsx +14 -0
  213. package/studio/web/components/SettingsCategorySkeleton.tsx +25 -0
  214. package/studio/web/components/SidePanel.tsx +77 -0
  215. package/studio/web/components/Sidebar.tsx +289 -0
  216. package/studio/web/components/StageStepper.tsx +87 -0
  217. package/studio/web/components/StudioOffline.tsx +80 -0
  218. package/studio/web/components/TaskName.tsx +17 -0
  219. package/studio/web/components/TopBanners.tsx +30 -0
  220. package/studio/web/components/VideoOmnichatPanel.tsx +287 -0
  221. package/studio/web/components/VoiceAvatar.tsx +33 -0
  222. package/studio/web/components/VoiceCarousel.tsx +196 -0
  223. package/studio/web/components/VoiceCategory.tsx +9 -0
  224. package/studio/web/components/VoiceModal.tsx +39 -0
  225. package/studio/web/components/VoiceProfileCard.tsx +75 -0
  226. package/studio/web/components/VoiceProfilePicker.tsx +107 -0
  227. package/studio/web/components/VoiceProfilesSettings.tsx +150 -0
  228. package/studio/web/components/VoiceProviderCard.tsx +118 -0
  229. package/studio/web/components/VoiceProvidersCard.tsx +26 -0
  230. package/studio/web/components/WaitList.tsx +21 -0
  231. package/studio/web/components/icons.tsx +247 -0
  232. package/studio/web/components/ui/accordion.tsx +47 -0
  233. package/studio/web/components/ui/badge.tsx +18 -0
  234. package/studio/web/components/ui/calendar.tsx +43 -0
  235. package/studio/web/components/ui/chart.tsx +229 -0
  236. package/studio/web/components/ui/checkbox.tsx +26 -0
  237. package/studio/web/components/ui/cx.ts +2 -0
  238. package/studio/web/components/ui/date-time-picker.tsx +84 -0
  239. package/studio/web/components/ui/panel.tsx +23 -0
  240. package/studio/web/components/ui/picker.tsx +58 -0
  241. package/studio/web/components/ui/popover.tsx +24 -0
  242. package/studio/web/components/ui/select.tsx +89 -0
  243. package/studio/web/components/ui/skeleton.tsx +10 -0
  244. package/studio/web/components/ui/slider.tsx +68 -0
  245. package/studio/web/components/ui/switch.tsx +13 -0
  246. package/studio/web/components/ui/tooltip.tsx +59 -0
  247. package/studio/web/hooks/useAccounts.ts +27 -0
  248. package/studio/web/hooks/useAdmin.ts +12 -0
  249. package/studio/web/hooks/useAnalytics.ts +21 -0
  250. package/studio/web/hooks/useAvatarAudioReactive.ts +87 -0
  251. package/studio/web/hooks/useBrowserConnect.ts +48 -0
  252. package/studio/web/hooks/useClonePlan.ts +14 -0
  253. package/studio/web/hooks/useConnected.ts +7 -0
  254. package/studio/web/hooks/useLiveQuery.ts +29 -0
  255. package/studio/web/hooks/useMenuCollapsed.ts +32 -0
  256. package/studio/web/hooks/useMicDevices.ts +53 -0
  257. package/studio/web/hooks/useMissingDms.ts +211 -0
  258. package/studio/web/hooks/useMissingSetupSteps.ts +26 -0
  259. package/studio/web/hooks/useNow.ts +11 -0
  260. package/studio/web/hooks/useOmniAgent.ts +278 -0
  261. package/studio/web/hooks/useOmniClaude.ts +124 -0
  262. package/studio/web/hooks/useOmniDock.ts +142 -0
  263. package/studio/web/hooks/useOmniGreeting.ts +60 -0
  264. package/studio/web/hooks/useOmniHotword.ts +128 -0
  265. package/studio/web/hooks/useOmnichat.ts +26 -0
  266. package/studio/web/hooks/useOnboarding.ts +27 -0
  267. package/studio/web/hooks/usePost.ts +23 -0
  268. package/studio/web/hooks/useQueue.ts +10 -0
  269. package/studio/web/hooks/useReferences.ts +20 -0
  270. package/studio/web/hooks/useRuleEditor.ts +101 -0
  271. package/studio/web/hooks/useRunner.ts +24 -0
  272. package/studio/web/hooks/useSaveAction.ts +23 -0
  273. package/studio/web/hooks/useSchedule.ts +11 -0
  274. package/studio/web/hooks/useServices.ts +10 -0
  275. package/studio/web/hooks/useSessions.ts +15 -0
  276. package/studio/web/hooks/useSettings.ts +11 -0
  277. package/studio/web/hooks/useSettingsSection.ts +30 -0
  278. package/studio/web/hooks/useSidePanel.ts +23 -0
  279. package/studio/web/hooks/useSound.ts +30 -0
  280. package/studio/web/hooks/useUsage.ts +11 -0
  281. package/studio/web/hooks/useVideoVoice.ts +36 -0
  282. package/studio/web/hooks/useVideos.ts +21 -0
  283. package/studio/web/hooks/useVoiceProfilePreview.ts +52 -0
  284. package/studio/web/hooks/useVoiceProfiles.ts +7 -0
  285. package/studio/web/hooks/useVoiceRunning.ts +10 -0
  286. package/studio/web/hooks/useVoiceStudioClosed.ts +8 -0
  287. package/studio/web/index.html +19 -0
  288. package/studio/web/lib/agent.ts +7 -0
  289. package/studio/web/lib/alerts.ts +210 -0
  290. package/studio/web/lib/analytics-metrics.ts +351 -0
  291. package/studio/web/lib/api.ts +70 -0
  292. package/studio/web/lib/audio.ts +39 -0
  293. package/studio/web/lib/avatars.ts +41 -0
  294. package/studio/web/lib/calendar.ts +218 -0
  295. package/studio/web/lib/caption-position.ts +249 -0
  296. package/studio/web/lib/carousel.ts +24 -0
  297. package/studio/web/lib/chime.ts +42 -0
  298. package/studio/web/lib/clone-voice.ts +55 -0
  299. package/studio/web/lib/export.ts +11 -0
  300. package/studio/web/lib/files.ts +8 -0
  301. package/studio/web/lib/format.ts +93 -0
  302. package/studio/web/lib/media.ts +29 -0
  303. package/studio/web/lib/mic-device.ts +72 -0
  304. package/studio/web/lib/missing-dms.ts +70 -0
  305. package/studio/web/lib/omni-cards.ts +42 -0
  306. package/studio/web/lib/omni-cascade.ts +1067 -0
  307. package/studio/web/lib/omni-greeting-audio.ts +24 -0
  308. package/studio/web/lib/omni-hotword.ts +231 -0
  309. package/studio/web/lib/omni-panel.ts +67 -0
  310. package/studio/web/lib/omni-realtime.ts +811 -0
  311. package/studio/web/lib/omni-ui.ts +402 -0
  312. package/studio/web/lib/omni-wait.ts +174 -0
  313. package/studio/web/lib/omnichat-api.ts +44 -0
  314. package/studio/web/lib/orb.ts +270 -0
  315. package/studio/web/lib/pcm-recorder.ts +115 -0
  316. package/studio/web/lib/platforms.ts +17 -0
  317. package/studio/web/lib/providers.ts +27 -0
  318. package/studio/web/lib/publish-draft.ts +52 -0
  319. package/studio/web/lib/publish-settings.ts +81 -0
  320. package/studio/web/lib/query-client.ts +122 -0
  321. package/studio/web/lib/references.ts +13 -0
  322. package/studio/web/lib/services.ts +40 -0
  323. package/studio/web/lib/sessions.ts +103 -0
  324. package/studio/web/lib/settings-categories.ts +58 -0
  325. package/studio/web/lib/sound-audio.ts +33 -0
  326. package/studio/web/lib/sound-timeline.ts +291 -0
  327. package/studio/web/lib/sse.ts +86 -0
  328. package/studio/web/lib/stage-history.ts +141 -0
  329. package/studio/web/lib/stages.ts +344 -0
  330. package/studio/web/lib/studio-offline.ts +60 -0
  331. package/studio/web/lib/upload.ts +24 -0
  332. package/studio/web/lib/video-tabs.ts +118 -0
  333. package/studio/web/lib/voice-profile-draft.ts +34 -0
  334. package/studio/web/lib/voice-profiles.ts +3 -0
  335. package/studio/web/main.tsx +14 -0
  336. package/studio/web/pages/AdminPage/index.tsx +123 -0
  337. package/studio/web/pages/AgentPage/components/Measurements.tsx +102 -0
  338. package/studio/web/pages/AgentPage/index.tsx +28 -0
  339. package/studio/web/pages/AnalyticsPage/components/About.tsx +52 -0
  340. package/studio/web/pages/AnalyticsPage/components/ChannelCards.tsx +106 -0
  341. package/studio/web/pages/AnalyticsPage/components/ChannelView.tsx +137 -0
  342. package/studio/web/pages/AnalyticsPage/components/CollectionStatus.tsx +46 -0
  343. package/studio/web/pages/AnalyticsPage/components/Comparison.tsx +68 -0
  344. package/studio/web/pages/AnalyticsPage/components/Diagnosis.tsx +50 -0
  345. package/studio/web/pages/AnalyticsPage/components/Highlights.tsx +49 -0
  346. package/studio/web/pages/AnalyticsPage/components/Hint.tsx +11 -0
  347. package/studio/web/pages/AnalyticsPage/components/HookVsBody.tsx +100 -0
  348. package/studio/web/pages/AnalyticsPage/components/HourlyWave.tsx +133 -0
  349. package/studio/web/pages/AnalyticsPage/components/Insights.tsx +70 -0
  350. package/studio/web/pages/AnalyticsPage/components/MetricCard.tsx +46 -0
  351. package/studio/web/pages/AnalyticsPage/components/PlanSection.tsx +40 -0
  352. package/studio/web/pages/AnalyticsPage/components/ProgressionChart.tsx +155 -0
  353. package/studio/web/pages/AnalyticsPage/components/ReelBarsChart.tsx +154 -0
  354. package/studio/web/pages/AnalyticsPage/components/ReelThumb.tsx +19 -0
  355. package/studio/web/pages/AnalyticsPage/components/ReelView.tsx +290 -0
  356. package/studio/web/pages/AnalyticsPage/components/ReelsTable.tsx +269 -0
  357. package/studio/web/pages/AnalyticsPage/components/RequestWithFocus.tsx +38 -0
  358. package/studio/web/pages/AnalyticsPage/components/SegmentedControl.tsx +35 -0
  359. package/studio/web/pages/AnalyticsPage/components/VsMedian.tsx +31 -0
  360. package/studio/web/pages/AnalyticsPage/index.tsx +17 -0
  361. package/studio/web/pages/GettingStartedPage/index.tsx +174 -0
  362. package/studio/web/pages/NewVideoPage/components/DeliverablesPicker.tsx +62 -0
  363. package/studio/web/pages/NewVideoPage/components/FormatPicker.tsx +33 -0
  364. package/studio/web/pages/NewVideoPage/index.tsx +133 -0
  365. package/studio/web/pages/NotFoundPage/index.tsx +9 -0
  366. package/studio/web/pages/OmnichatPage/components/NewFromLink.tsx +59 -0
  367. package/studio/web/pages/OmnichatPage/components/RuleListItem.tsx +64 -0
  368. package/studio/web/pages/OmnichatPage/components/RulePreview.tsx +14 -0
  369. package/studio/web/pages/OmnichatPage/components/RuleView.tsx +88 -0
  370. package/studio/web/pages/OmnichatPage/index.tsx +153 -0
  371. package/studio/web/pages/QueuePage/index.tsx +22 -0
  372. package/studio/web/pages/ReferencePage/components/ReferenceTexts.tsx +131 -0
  373. package/studio/web/pages/ReferencePage/index.tsx +216 -0
  374. package/studio/web/pages/ReferencesPage/components/NewReferenceForm.tsx +150 -0
  375. package/studio/web/pages/ReferencesPage/components/ReferenceCard.tsx +42 -0
  376. package/studio/web/pages/ReferencesPage/components/ReferenceGridSkeleton.tsx +31 -0
  377. package/studio/web/pages/ReferencesPage/index.tsx +67 -0
  378. package/studio/web/pages/SchedulePage/components/CalendarSkeleton.tsx +18 -0
  379. package/studio/web/pages/SchedulePage/components/DayView.tsx +177 -0
  380. package/studio/web/pages/SchedulePage/components/HourPicker.tsx +103 -0
  381. package/studio/web/pages/SchedulePage/components/MonthDayCell.tsx +111 -0
  382. package/studio/web/pages/SchedulePage/components/MonthView.tsx +47 -0
  383. package/studio/web/pages/SchedulePage/components/PlatformIcons.tsx +12 -0
  384. package/studio/web/pages/SchedulePage/components/PostThumb.tsx +15 -0
  385. package/studio/web/pages/SchedulePage/components/WeekColumn.tsx +75 -0
  386. package/studio/web/pages/SchedulePage/components/WeekView.tsx +35 -0
  387. package/studio/web/pages/SchedulePage/index.tsx +285 -0
  388. package/studio/web/pages/SettingsPage/components/AgentAccounts.tsx +263 -0
  389. package/studio/web/pages/SettingsPage/components/AgentCategory.tsx +20 -0
  390. package/studio/web/pages/SettingsPage/components/ModelPicker.tsx +49 -0
  391. package/studio/web/pages/SettingsPage/components/ModelsSettings.tsx +138 -0
  392. package/studio/web/pages/SettingsPage/components/PlatformsCategory.tsx +23 -0
  393. package/studio/web/pages/SettingsPage/components/PublishingCategory/AccountStatus.tsx +29 -0
  394. package/studio/web/pages/SettingsPage/components/PublishingCategory/AutoPublishPanel.tsx +90 -0
  395. package/studio/web/pages/SettingsPage/components/PublishingCategory/BrowserConnect.tsx +62 -0
  396. package/studio/web/pages/SettingsPage/components/PublishingCategory/CheckField.tsx +19 -0
  397. package/studio/web/pages/SettingsPage/components/PublishingCategory/InstagramPanel.tsx +113 -0
  398. package/studio/web/pages/SettingsPage/components/PublishingCategory/OmnichatSettingsPanel.tsx +146 -0
  399. package/studio/web/pages/SettingsPage/components/PublishingCategory/SaveBar.tsx +33 -0
  400. package/studio/web/pages/SettingsPage/components/PublishingCategory/SchedulePanel.tsx +132 -0
  401. package/studio/web/pages/SettingsPage/components/PublishingCategory/SettingsCard.tsx +47 -0
  402. package/studio/web/pages/SettingsPage/components/PublishingCategory/SettingsCardGroup.tsx +19 -0
  403. package/studio/web/pages/SettingsPage/components/PublishingCategory/TextPanel.tsx +55 -0
  404. package/studio/web/pages/SettingsPage/components/PublishingCategory/TiktokPanel.tsx +123 -0
  405. package/studio/web/pages/SettingsPage/components/PublishingCategory/YoutubePanel.tsx +100 -0
  406. package/studio/web/pages/SettingsPage/components/PublishingCategory/badges.tsx +15 -0
  407. package/studio/web/pages/SettingsPage/components/PublishingCategory/index.tsx +40 -0
  408. package/studio/web/pages/SettingsPage/components/PublishingCategory/types.ts +10 -0
  409. package/studio/web/pages/SettingsPage/components/UsageCategory.tsx +389 -0
  410. package/studio/web/pages/SettingsPage/components/VoiceProvidersCategory.tsx +97 -0
  411. package/studio/web/pages/SettingsPage/index.tsx +85 -0
  412. package/studio/web/pages/VideoPage/components/AudioPlayer.tsx +113 -0
  413. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/AxisField.tsx +50 -0
  414. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionList.tsx +56 -0
  415. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionListItem.tsx +92 -0
  416. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionMargins.tsx +57 -0
  417. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionStyleFields.tsx +70 -0
  418. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/CaptionTextForm.tsx +87 -0
  419. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/ColorField.tsx +37 -0
  420. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/MarginField.tsx +59 -0
  421. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/NumberField.tsx +57 -0
  422. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/PositionControls.tsx +140 -0
  423. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/captionEditor.ts +215 -0
  424. package/studio/web/pages/VideoPage/components/CaptionPositionEditor/useCaptionPosition.ts +154 -0
  425. package/studio/web/pages/VideoPage/components/CarouselChangeRequest.tsx +72 -0
  426. package/studio/web/pages/VideoPage/components/CarouselCompositionStage.tsx +80 -0
  427. package/studio/web/pages/VideoPage/components/CarouselCreate.tsx +63 -0
  428. package/studio/web/pages/VideoPage/components/CarouselMissing.tsx +19 -0
  429. package/studio/web/pages/VideoPage/components/CarouselPublishStage.tsx +173 -0
  430. package/studio/web/pages/VideoPage/components/CarouselScriptStage.tsx +82 -0
  431. package/studio/web/pages/VideoPage/components/CarouselSlideCard.tsx +49 -0
  432. package/studio/web/pages/VideoPage/components/CarouselViewer.tsx +55 -0
  433. package/studio/web/pages/VideoPage/components/ChangedVoices.tsx +53 -0
  434. package/studio/web/pages/VideoPage/components/CompositionStage.tsx +78 -0
  435. package/studio/web/pages/VideoPage/components/CoverPicker.tsx +32 -0
  436. package/studio/web/pages/VideoPage/components/EditorStage.tsx +53 -0
  437. package/studio/web/pages/VideoPage/components/LineTakes.tsx +160 -0
  438. package/studio/web/pages/VideoPage/components/LineTextEditor.tsx +124 -0
  439. package/studio/web/pages/VideoPage/components/LineVoicePicker.tsx +37 -0
  440. package/studio/web/pages/VideoPage/components/MediaImage.tsx +25 -0
  441. package/studio/web/pages/VideoPage/components/MotionScriptStage.tsx +39 -0
  442. package/studio/web/pages/VideoPage/components/NarrationStage.tsx +70 -0
  443. package/studio/web/pages/VideoPage/components/PublishForm.tsx +387 -0
  444. package/studio/web/pages/VideoPage/components/PublishStage.tsx +76 -0
  445. package/studio/web/pages/VideoPage/components/PublishText.tsx +149 -0
  446. package/studio/web/pages/VideoPage/components/ScenesApprovalPanel.tsx +278 -0
  447. package/studio/web/pages/VideoPage/components/ScheduledInfo.tsx +72 -0
  448. package/studio/web/pages/VideoPage/components/ScriptApprovalPanel.tsx +189 -0
  449. package/studio/web/pages/VideoPage/components/ScriptStage.tsx +17 -0
  450. package/studio/web/pages/VideoPage/components/SequencePlayer.tsx +146 -0
  451. package/studio/web/pages/VideoPage/components/SoundTimeline/AddSound.tsx +117 -0
  452. package/studio/web/pages/VideoPage/components/SoundTimeline/AreaSelection.tsx +74 -0
  453. package/studio/web/pages/VideoPage/components/SoundTimeline/BedPanel.tsx +94 -0
  454. package/studio/web/pages/VideoPage/components/SoundTimeline/BedRow.tsx +45 -0
  455. package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionOverlay.tsx +44 -0
  456. package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionSaveBar.tsx +32 -0
  457. package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionsPanel.tsx +22 -0
  458. package/studio/web/pages/VideoPage/components/SoundTimeline/ClipBlock.tsx +111 -0
  459. package/studio/web/pages/VideoPage/components/SoundTimeline/ClipPanel.tsx +76 -0
  460. package/studio/web/pages/VideoPage/components/SoundTimeline/CutsPanel.tsx +44 -0
  461. package/studio/web/pages/VideoPage/components/SoundTimeline/EditorTabBar.tsx +73 -0
  462. package/studio/web/pages/VideoPage/components/SoundTimeline/EffectChoice.tsx +46 -0
  463. package/studio/web/pages/VideoPage/components/SoundTimeline/EffectItem.tsx +89 -0
  464. package/studio/web/pages/VideoPage/components/SoundTimeline/EffectPanel.tsx +232 -0
  465. package/studio/web/pages/VideoPage/components/SoundTimeline/EffectsRow.tsx +21 -0
  466. package/studio/web/pages/VideoPage/components/SoundTimeline/Lane.tsx +39 -0
  467. package/studio/web/pages/VideoPage/components/SoundTimeline/MarkerRow.tsx +40 -0
  468. package/studio/web/pages/VideoPage/components/SoundTimeline/MuteButton.tsx +36 -0
  469. package/studio/web/pages/VideoPage/components/SoundTimeline/NumberInput.tsx +37 -0
  470. package/studio/web/pages/VideoPage/components/SoundTimeline/PlanWarnings.tsx +19 -0
  471. package/studio/web/pages/VideoPage/components/SoundTimeline/PlayerResizeHandle.tsx +50 -0
  472. package/studio/web/pages/VideoPage/components/SoundTimeline/PreviewControls.tsx +51 -0
  473. package/studio/web/pages/VideoPage/components/SoundTimeline/SceneRow.tsx +54 -0
  474. package/studio/web/pages/VideoPage/components/SoundTimeline/SettingsPanel.tsx +65 -0
  475. package/studio/web/pages/VideoPage/components/SoundTimeline/SoundLibrary.tsx +99 -0
  476. package/studio/web/pages/VideoPage/components/SoundTimeline/SoundPreview.tsx +82 -0
  477. package/studio/web/pages/VideoPage/components/SoundTimeline/SpeedPanel.tsx +128 -0
  478. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineDock.tsx +56 -0
  479. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineFooter.tsx +26 -0
  480. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineSkeleton.tsx +21 -0
  481. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineToolbar.tsx +160 -0
  482. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineTracks.tsx +121 -0
  483. package/studio/web/pages/VideoPage/components/SoundTimeline/TrackSidebar.tsx +30 -0
  484. package/studio/web/pages/VideoPage/components/SoundTimeline/VoiceRow.tsx +53 -0
  485. package/studio/web/pages/VideoPage/components/SoundTimeline/Waveform.tsx +97 -0
  486. package/studio/web/pages/VideoPage/components/SoundTimeline/clipActions.ts +50 -0
  487. package/studio/web/pages/VideoPage/components/SoundTimeline/effectActions.ts +161 -0
  488. package/studio/web/pages/VideoPage/components/SoundTimeline/index.tsx +161 -0
  489. package/studio/web/pages/VideoPage/components/SoundTimeline/timelineGeometry.ts +45 -0
  490. package/studio/web/pages/VideoPage/components/SoundTimeline/types.ts +43 -0
  491. package/studio/web/pages/VideoPage/components/SoundTimeline/useAutosave.ts +107 -0
  492. package/studio/web/pages/VideoPage/components/SoundTimeline/useEditorShortcuts.ts +168 -0
  493. package/studio/web/pages/VideoPage/components/SoundTimeline/useFitHeight.ts +40 -0
  494. package/studio/web/pages/VideoPage/components/SoundTimeline/useFollowPlayhead.ts +21 -0
  495. package/studio/web/pages/VideoPage/components/SoundTimeline/useListenMix.ts +43 -0
  496. package/studio/web/pages/VideoPage/components/SoundTimeline/usePlayback.ts +231 -0
  497. package/studio/web/pages/VideoPage/components/SoundTimeline/usePlayerWidth.ts +27 -0
  498. package/studio/web/pages/VideoPage/components/SoundTimeline/useSoundData.ts +124 -0
  499. package/studio/web/pages/VideoPage/components/SoundTimeline/useSoundTimeline.ts +511 -0
  500. package/studio/web/pages/VideoPage/components/StageDrawer/CompareVersions.tsx +111 -0
  501. package/studio/web/pages/VideoPage/components/StageDrawer/VersionCard.tsx +81 -0
  502. package/studio/web/pages/VideoPage/components/StageDrawer/VersionMedia.tsx +24 -0
  503. package/studio/web/pages/VideoPage/components/StageDrawer/VersionText.tsx +15 -0
  504. package/studio/web/pages/VideoPage/components/StageDrawer/index.tsx +109 -0
  505. package/studio/web/pages/VideoPage/components/StageProcess.tsx +126 -0
  506. package/studio/web/pages/VideoPage/components/StageResult.tsx +69 -0
  507. package/studio/web/pages/VideoPage/components/SwapReference.tsx +92 -0
  508. package/studio/web/pages/VideoPage/components/ThumbnailPanel.tsx +252 -0
  509. package/studio/web/pages/VideoPage/components/TimingPanel.tsx +89 -0
  510. package/studio/web/pages/VideoPage/components/VideoPlayer.tsx +18 -0
  511. package/studio/web/pages/VideoPage/components/VideoSkeleton.tsx +50 -0
  512. package/studio/web/pages/VideoPage/components/VideoVoiceInfo.tsx +33 -0
  513. package/studio/web/pages/VideoPage/components/VideoVoicePicker.tsx +165 -0
  514. package/studio/web/pages/VideoPage/components/VoicePauseBanner.tsx +56 -0
  515. package/studio/web/pages/VideoPage/components/WithLogo.tsx +10 -0
  516. package/studio/web/pages/VideoPage/index.tsx +295 -0
  517. package/studio/web/pages/VideosPage/components/PublishedOn.tsx +85 -0
  518. package/studio/web/pages/VideosPage/components/ServicesPanel.tsx +81 -0
  519. package/studio/web/pages/VideosPage/components/SessionsPanel.tsx +62 -0
  520. package/studio/web/pages/VideosPage/components/VideoListSkeleton.tsx +25 -0
  521. package/studio/web/pages/VideosPage/components/VideoRow.tsx +122 -0
  522. package/studio/web/pages/VideosPage/index.tsx +134 -0
  523. package/studio/web/pages/VoicePage/index.tsx +28 -0
  524. package/studio/web/router.tsx +201 -0
  525. package/studio/web/styles/base/elements.css +55 -0
  526. package/studio/web/styles/base/utilities.css +25 -0
  527. package/studio/web/styles/components/badge.css +33 -0
  528. package/studio/web/styles/components/claude-running.css +27 -0
  529. package/studio/web/styles/components/claude-session.css +212 -0
  530. package/studio/web/styles/components/claude-walking.css +92 -0
  531. package/studio/web/styles/components/clone-voice-save.css +136 -0
  532. package/studio/web/styles/components/clone-voice.css +379 -0
  533. package/studio/web/styles/components/controls.css +70 -0
  534. package/studio/web/styles/components/data-and-image.css +54 -0
  535. package/studio/web/styles/components/forms.css +132 -0
  536. package/studio/web/styles/components/human-banner.css +99 -0
  537. package/studio/web/styles/components/lightbox.css +50 -0
  538. package/studio/web/styles/components/markdown.css +68 -0
  539. package/studio/web/styles/components/modal.css +70 -0
  540. package/studio/web/styles/components/omni-cards.css +105 -0
  541. package/studio/web/styles/components/omni.css +859 -0
  542. package/studio/web/styles/components/omnichat.css +538 -0
  543. package/studio/web/styles/components/panel.css +115 -0
  544. package/studio/web/styles/components/platform-card.css +140 -0
  545. package/studio/web/styles/components/provider-card.css +132 -0
  546. package/studio/web/styles/components/queue.css +185 -0
  547. package/studio/web/styles/components/reference-actions.css +133 -0
  548. package/studio/web/styles/components/reference-picker.css +146 -0
  549. package/studio/web/styles/components/results-drawer.css +224 -0
  550. package/studio/web/styles/components/segmented.css +115 -0
  551. package/studio/web/styles/components/side-panel-tab.css +23 -0
  552. package/studio/web/styles/components/status-signals.css +66 -0
  553. package/studio/web/styles/components/stepper.css +208 -0
  554. package/studio/web/styles/components/table.css +19 -0
  555. package/studio/web/styles/components/tabs.css +24 -0
  556. package/studio/web/styles/components/ui/accordion.css +71 -0
  557. package/studio/web/styles/components/ui/chart.css +162 -0
  558. package/studio/web/styles/components/ui/checkbox.css +37 -0
  559. package/studio/web/styles/components/ui/date-picker.css +153 -0
  560. package/studio/web/styles/components/ui/select.css +110 -0
  561. package/studio/web/styles/components/ui/skeleton.css +25 -0
  562. package/studio/web/styles/components/ui/slider.css +81 -0
  563. package/studio/web/styles/components/ui/switch.css +41 -0
  564. package/studio/web/styles/components/ui/tooltip.css +24 -0
  565. package/studio/web/styles/components/voice-carousel.css +255 -0
  566. package/studio/web/styles/components/voice-editor.css +179 -0
  567. package/studio/web/styles/components/voice-grid.css +56 -0
  568. package/studio/web/styles/components/voice-profiles.css +192 -0
  569. package/studio/web/styles/design-system.md +136 -0
  570. package/studio/web/styles/index.css +116 -0
  571. package/studio/web/styles/layout/page.css +41 -0
  572. package/studio/web/styles/layout/sidebar-groups.css +39 -0
  573. package/studio/web/styles/layout/sidebar.css +111 -0
  574. package/studio/web/styles/pages/agent.css +26 -0
  575. package/studio/web/styles/pages/analytics/dashboard.css +614 -0
  576. package/studio/web/styles/pages/analytics/insights.css +48 -0
  577. package/studio/web/styles/pages/getting-started.css +166 -0
  578. package/studio/web/styles/pages/new-video/form.css +32 -0
  579. package/studio/web/styles/pages/not-found.css +59 -0
  580. package/studio/web/styles/pages/references.css +204 -0
  581. package/studio/web/styles/pages/schedule/calendar.css +541 -0
  582. package/studio/web/styles/pages/schedule/chip-states.css +60 -0
  583. package/studio/web/styles/pages/settings/models.css +72 -0
  584. package/studio/web/styles/pages/settings/shell.css +361 -0
  585. package/studio/web/styles/pages/settings/usage.css +63 -0
  586. package/studio/web/styles/pages/studio-offline.css +105 -0
  587. package/studio/web/styles/pages/video/caption-controls.css +194 -0
  588. package/studio/web/styles/pages/video/captions-grid.css +70 -0
  589. package/studio/web/styles/pages/video/captions.css +79 -0
  590. package/studio/web/styles/pages/video/editor-chat.css +103 -0
  591. package/studio/web/styles/pages/video/export.css +50 -0
  592. package/studio/web/styles/pages/video/frames.css +29 -0
  593. package/studio/web/styles/pages/video/fullscreen-stage.css +400 -0
  594. package/studio/web/styles/pages/video/instagram-carousel.css +309 -0
  595. package/studio/web/styles/pages/video/layout.css +285 -0
  596. package/studio/web/styles/pages/video/narration.css +138 -0
  597. package/studio/web/styles/pages/video/preview-overview.css +11 -0
  598. package/studio/web/styles/pages/video/processing-notice.css +34 -0
  599. package/studio/web/styles/pages/video/publish-when.css +76 -0
  600. package/studio/web/styles/pages/video/publish.css +97 -0
  601. package/studio/web/styles/pages/video/result.css +96 -0
  602. package/studio/web/styles/pages/video/scenes.css +167 -0
  603. package/studio/web/styles/pages/video/sound-timeline.css +672 -0
  604. package/studio/web/styles/pages/video/sound-toolbar.css +149 -0
  605. package/studio/web/styles/pages/video/take-player.css +100 -0
  606. package/studio/web/styles/pages/video/thumbnail.css +157 -0
  607. package/studio/web/styles/pages/video/timeline.css +117 -0
  608. package/studio/web/styles/pages/video/voice-picker.css +14 -0
  609. package/studio/web/styles/pages/video-list/active-row.css +27 -0
  610. package/studio/web/styles/pages/video-list/card-link.css +49 -0
  611. package/studio/web/styles/pages/video-list/list.css +86 -0
  612. package/studio/web/styles/theme/identity/details.css +204 -0
  613. package/studio/web/styles/theme/identity/shell.css +249 -0
  614. package/studio/web/styles/theme/identity/surfaces.css +183 -0
  615. package/studio/web/styles/theme/identity/titles-and-buttons.css +120 -0
  616. package/studio/web/styles/theme/no-borders/blocks.css +208 -0
  617. package/studio/web/styles/theme/no-borders/controls.css +256 -0
  618. package/studio/web/styles/tokens.css +245 -0
  619. package/studio/web/types/api.ts +2 -0
  620. package/studio/web/types/assets.d.ts +9 -0
  621. package/templates/brief.md +27 -0
  622. package/templates/captions.html +204 -0
  623. package/templates/carousel-composition.md +47 -0
  624. package/templates/carousel-script.md +60 -0
  625. package/templates/components/voiceavatar/README.md +87 -0
  626. package/templates/components/voiceavatar/demo.html +50 -0
  627. package/templates/components/voiceavatar/voiceavatar.js +415 -0
  628. package/templates/motion.md +80 -0
  629. package/templates/playbook.md +43 -0
  630. package/templates/reference.md +123 -0
  631. package/templates/scene.html +112 -0
  632. package/templates/scenes.example.json +96 -0
  633. package/templates/script.md +63 -0
  634. package/templates/slide.html +71 -0
  635. package/templates/wireframe.html +91 -0
  636. package/tools/analysis.mjs +300 -0
  637. package/tools/approval.mjs +442 -0
  638. package/tools/assemble.mjs +942 -0
  639. package/tools/build-motion.mjs +437 -0
  640. package/tools/captions.mjs +246 -0
  641. package/tools/carousel.mjs +558 -0
  642. package/tools/compose.mjs +307 -0
  643. package/tools/cuts.mjs +74 -0
  644. package/tools/editor.mjs +419 -0
  645. package/tools/epidemic-capture.js +54 -0
  646. package/tools/fanout.mjs +69 -0
  647. package/tools/history.mjs +70 -0
  648. package/tools/history.py +61 -0
  649. package/tools/job-queue.mjs +180 -0
  650. package/tools/job_queue.py +430 -0
  651. package/tools/lib/agents.mjs +412 -0
  652. package/tools/lib/channel.mjs +399 -0
  653. package/tools/lib/claude-settings.mjs +67 -0
  654. package/tools/lib/cli.mjs +9 -0
  655. package/tools/lib/fanout.mjs +234 -0
  656. package/tools/lib/http.mjs +94 -0
  657. package/tools/lib/index.js +14 -0
  658. package/tools/lib/mcp-server.mjs +69 -0
  659. package/tools/lib/metrics/metrics.mjs +204 -0
  660. package/tools/lib/narration.mjs +15 -0
  661. package/tools/lib/oauth-client.mjs +295 -0
  662. package/tools/lib/omnichat/config.mjs +139 -0
  663. package/tools/lib/omnichat/errors.mjs +42 -0
  664. package/tools/lib/omnichat/extract.mjs +82 -0
  665. package/tools/lib/omnichat/gate.mjs +151 -0
  666. package/tools/lib/omnichat/manual.mjs +166 -0
  667. package/tools/lib/omnichat/match.mjs +78 -0
  668. package/tools/lib/omnichat/pass.mjs +393 -0
  669. package/tools/lib/omnichat/record.mjs +208 -0
  670. package/tools/lib/omnichat/text.mjs +315 -0
  671. package/tools/lib/omnichat/webhook.mjs +166 -0
  672. package/tools/lib/pairing.mjs +99 -0
  673. package/tools/lib/paths.mjs +41 -0
  674. package/tools/lib/platforms/instagram.mjs +469 -0
  675. package/tools/lib/platforms/tiktok.mjs +343 -0
  676. package/tools/lib/platforms/youtube.mjs +228 -0
  677. package/tools/lib/publish/publish.mjs +244 -0
  678. package/tools/lib/schedule/schedule.mjs +191 -0
  679. package/tools/lib/service.mjs +134 -0
  680. package/tools/lib/skill-client.mjs +126 -0
  681. package/tools/lib/skills-release.mjs +196 -0
  682. package/tools/lib/testing.mjs +52 -0
  683. package/tools/lib/up.mjs +187 -0
  684. package/tools/metrics.mjs +415 -0
  685. package/tools/models.mjs +134 -0
  686. package/tools/narrate.mjs +257 -0
  687. package/tools/omni.mjs +298 -0
  688. package/tools/omni_paths.py +12 -0
  689. package/tools/omnichat.mjs +1577 -0
  690. package/tools/omnivideo.py +1122 -0
  691. package/tools/package.mjs +130 -0
  692. package/tools/platforms.mjs +236 -0
  693. package/tools/premiere.mjs +533 -0
  694. package/tools/publish.mjs +1496 -0
  695. package/tools/reference.mjs +1408 -0
  696. package/tools/render.mjs +426 -0
  697. package/tools/runner.mjs +156 -0
  698. package/tools/setup.mjs +466 -0
  699. package/tools/skills-release.mjs +93 -0
  700. package/tools/sound.mjs +1323 -0
  701. package/tools/soundtrack.mjs +217 -0
  702. package/tools/thumbnail.mjs +271 -0
  703. package/tools/timing.mjs +108 -0
  704. package/tools/usage.py +628 -0
  705. package/tools/voice-envelope.mjs +185 -0
  706. package/tools/voice.py +448 -0
  707. package/tools/voice_sample.py +75 -0
  708. package/tools/wireframe.mjs +230 -0
@@ -0,0 +1,311 @@
1
+ /* Sound timeline: the effects of beats and transitions and the bed, edited from the
2
+ UI. Each change is planned by tools/sound.mjs itself (volume relative to the
3
+ voice, ducking, trim, stretch, pitch) in a draft outside the video dir, and the
4
+ UI plays the ready WAVs over the voice: what you hear is what assemble
5
+ mixes. Saving writes to scenes.json; the export only changes on reassembly. */
6
+
7
+ import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
8
+ import { join, resolve, sep, basename } from "node:path";
9
+ import { ROOT, NODE, TOOLS_DIR, readJson } from "./root";
10
+ import { loadVideo, beatTime } from "../../../tools/timing.mjs";
11
+ import {
12
+ planSound,
13
+ applyDraft,
14
+ applyClips,
15
+ soundCatalog,
16
+ sanitizeSound,
17
+ sanitizeBed,
18
+ sanitizeSpeed,
19
+ finalClock,
20
+ kitDir,
21
+ } from "../../../tools/sound.mjs";
22
+ import { videoClips, lineClips, lineDuration } from "../../../tools/soundtrack.mjs";
23
+ import { normalizeCuts } from "../../../tools/cuts.mjs";
24
+ import { chatWith } from "./create";
25
+ import type { ApiResult } from "./sessions";
26
+
27
+ type Result = { ok: true; output: string } | { ok: false; error: string };
28
+ const DRAFT_DIR = join(ROOT, ".sound-draft");
29
+
30
+ const normalizeSound = (s: any) => (typeof s === "string" ? { name: s } : { ...s });
31
+ const asList = (sound: any) => (sound == null ? [] : (Array.isArray(sound) ? sound : [sound]).map(normalizeSound));
32
+
33
+ /* the export's base MP4 (without the speed), for the timeline picture, and the cuts it already has */
34
+ function baseExport(
35
+ dir: string,
36
+ ): { rel: string; cuts: { from: number; to: number }[]; scene_clips: Record<string, unknown> } | null {
37
+ const m = readJson<any>(join(dir, "export", "assembly.json"));
38
+ const rel = m?.base_mp4 ?? m?.mp4;
39
+ return rel && existsSync(join(dir, rel)) ? { rel, cuts: m.cuts ?? [], scene_clips: m.scene_clips ?? {} } : null;
40
+ }
41
+
42
+ /* the export at the chosen speed (assembly.json `mp4` when it isn't the base): once it matches the
43
+ edit, the editor plays it instead of the base, so what plays there is what goes out */
44
+ function spedExport(dir: string): { path: string; mtime: number; speed: number } | null {
45
+ const m = readJson<any>(join(dir, "export", "assembly.json"));
46
+ const speed = Number(m?.speed);
47
+ if (!m?.base_mp4 || !m.mp4 || m.mp4 === m.base_mp4 || !(speed > 1) || !existsSync(join(dir, m.mp4))) return null;
48
+ return { path: m.mp4, mtime: Math.round(statSync(join(dir, m.mp4)).mtimeMs), speed };
49
+ }
50
+
51
+ export function getSoundData(dir: string) {
52
+ const video = loadVideo(dir);
53
+ /* each place's instant is in voice time (without the scene clips): the UI maps it onto the animation piece */
54
+ const places: any[] = [];
55
+ video.scenes.forEach((c: any, i: number) => {
56
+ if (i > 0)
57
+ places.push({
58
+ type: "transition",
59
+ scene: c.id,
60
+ element: "transition",
61
+ instant: +c.start.toFixed(3),
62
+ sounds: asList(typeof c.transition === "object" ? c.transition?.sound : null),
63
+ });
64
+ for (const b of c.beats ?? []) {
65
+ let instant: number | null = null,
66
+ error: string | null = null;
67
+ try {
68
+ instant = +(c.start + beatTime(c, b)).toFixed(3);
69
+ } catch (e: any) {
70
+ error = e.message;
71
+ }
72
+ places.push({ type: "beat", scene: c.id, element: b.element, instant, error, sounds: asList(b.sound) });
73
+ }
74
+ });
75
+ const exp = baseExport(dir);
76
+ return {
77
+ total: video.total_duration,
78
+ provisional: video.provisional,
79
+ format: video.format,
80
+ scenes: video.scenes.map((c: any) => {
81
+ const mp4 = c.mp4 ?? `motion/${c.id}.mp4`;
82
+ return {
83
+ id: c.id,
84
+ title: c.title ?? null,
85
+ start: c.start,
86
+ duration: c.duration,
87
+ clips: videoClips(c),
88
+ mp4: existsSync(join(dir, mp4)) ? { path: mp4, mtime: Math.round(statSync(join(dir, mp4)).mtimeMs) } : null,
89
+ };
90
+ }),
91
+ lines: video.scenes.flatMap((c: any) =>
92
+ (c.lines ?? []).map((l: any) => ({
93
+ id: l.id,
94
+ scene: c.id,
95
+ start: +(c.start + l.start).toFixed(3),
96
+ end: +(c.start + l.end).toFixed(3),
97
+ dur: lineDuration(l),
98
+ clips: lineClips(l),
99
+ wav: l.wav && existsSync(join(dir, l.wav)) ? l.wav : null,
100
+ text: l.text,
101
+ })),
102
+ ),
103
+ places,
104
+ bed: video.bed ? normalizeSound(video.bed) : null,
105
+ /* editor area cuts, in scenes.json time (tools/cuts.mjs) */
106
+ cuts: normalizeCuts(video.cuts, video.total_duration, video.format.fps),
107
+ /* the export speed (1 to 1.5); a video that never chose one in the editor keeps the one the old
108
+ export panel left in assembly.json */
109
+ speed: sanitizeSpeed(video.speed ?? readJson<any>(join(dir, "export", "assembly.json"))?.speed),
110
+ catalog: soundCatalog(dir),
111
+ export: exp
112
+ ? {
113
+ path: exp.rel,
114
+ mtime: Math.round(statSync(join(dir, exp.rel)).mtimeMs),
115
+ cuts: exp.cuts,
116
+ scene_clips: exp.scene_clips,
117
+ }
118
+ : null,
119
+ speed_export: spedExport(dir),
120
+ /* scenes.json changed after the export (the timeline save, or another stage): needs reassembly */
121
+ export_outdated: !exp || statSync(join(dir, "scenes.json")).mtimeMs > statSync(join(dir, exp.rel)).mtimeMs,
122
+ };
123
+ }
124
+
125
+ /* one draft per request, in a new dir; those before the previous one are removed (the UI
126
+ may still be downloading the previous one's WAVs) */
127
+ let counter = 0;
128
+ function draftDir(slug: string) {
129
+ const base = join(DRAFT_DIR, slug);
130
+ mkdirSync(base, { recursive: true });
131
+ const n = `${Date.now()}-${++counter}`;
132
+ const old = readdirSync(base).sort();
133
+ for (const v of old.slice(0, Math.max(0, old.length - 1))) rmSync(join(base, v), { recursive: true, force: true });
134
+ return { dir: join(base, n), rel: n };
135
+ }
136
+
137
+ export function planDraft(slug: string, dir: string, draft: any) {
138
+ try {
139
+ const video = applyDraft(dir, loadVideo(dir), draft);
140
+ const { dir: outDir, rel } = draftDir(slug);
141
+ /* the editor plays at 100%: the bed is made for the draft's cuts, not its speed */
142
+ const r = planSound(dir, video, { outDir, clock: finalClock(video, 1) });
143
+ const url = (file: string) =>
144
+ `/sound-draft/${encodeURIComponent(slug)}/${rel}/${encodeURIComponent(basename(file))}`;
145
+ const withUrl = ({ file, ...x }: any) => ({ ...x, url: url(file) });
146
+ return {
147
+ ok: true as const,
148
+ items: r.items.map(withUrl),
149
+ bed: r.bed ? withUrl(r.bed) : null,
150
+ warnings: r.warnings,
151
+ voice: r.voice,
152
+ ducking: r.ducking,
153
+ };
154
+ } catch (e: any) {
155
+ return { ok: false as const, error: e.message };
156
+ }
157
+ }
158
+
159
+ /* draft WAV: only inside .sound-draft/<slug>/ */
160
+ export function draftFile(slug: string, rest: string): string | null {
161
+ const base = resolve(DRAFT_DIR, slug);
162
+ const abs = resolve(base, rest);
163
+ return abs.startsWith(base + sep) && abs.endsWith(".wav") && existsSync(abs) ? abs : null;
164
+ }
165
+
166
+ /* a file from the global kit, for the waveform */
167
+ export function kitFile(name: string): string | null {
168
+ const abs = resolve(kitDir, name);
169
+ return abs.startsWith(resolve(kitDir) + sep) && abs.endsWith(".mp3") && existsSync(abs) ? abs : null;
170
+ }
171
+
172
+ /* writes the draft to scenes.json: the sound of each beat, each transition, the bed and the cuts */
173
+ export function saveSound(dir: string, draft: any): Result {
174
+ const file = join(dir, "scenes.json");
175
+ const raw = readJson<any>(file);
176
+ if (!raw) return { ok: false, error: "scenes.json não existe" };
177
+ const video = loadVideo(dir);
178
+ const total = video.total_duration;
179
+ let changed = 0;
180
+ try {
181
+ for (const l of draft?.places ?? []) {
182
+ const i = raw.scenes.findIndex((c: any) => c.id === l.scene);
183
+ if (i < 0) throw new Error(`cena ${l.scene} não existe`);
184
+ const scene = raw.scenes[i];
185
+ const sounds = (l.sounds ?? []).map((s: any) => sanitizeSound(dir, s));
186
+ const sound = sounds.length === 0 ? null : sounds.length === 1 ? sounds[0] : sounds;
187
+ if (l.type === "transition") {
188
+ if (i === 0) throw new Error("a primeira cena não tem passagem");
189
+ const p = scene.transition && typeof scene.transition === "object" ? { ...scene.transition } : {};
190
+ if (sound) p.sound = sound;
191
+ else delete p.sound;
192
+ if (Object.keys(p).length) scene.transition = p;
193
+ else delete scene.transition;
194
+ } else {
195
+ const beat = (scene.beats ?? []).find((b: any) => b.element === l.element);
196
+ if (!beat) throw new Error(`${l.scene}: beat ${l.element} não existe`);
197
+ if (sound) beat.sound = sound;
198
+ else delete beat.sound;
199
+ }
200
+ changed++;
201
+ }
202
+ /* `bed` and `cuts` right before `scenes`, like the rest of the contract; empty is dropped */
203
+ let next = raw;
204
+ const beforeScenes = (field: string, value: any) => {
205
+ const r: any = {};
206
+ for (const [k, v] of Object.entries(next)) {
207
+ if (k === field) continue;
208
+ if (k === "scenes" && value) r[field] = value;
209
+ r[k] = v;
210
+ }
211
+ if (value && !(field in r)) r[field] = value;
212
+ next = r;
213
+ };
214
+ /* razor and drag clips (animation and voice), validated against the loaded durations; the default one is dropped */
215
+ const ref = structuredClone(video);
216
+ applyClips(ref, draft);
217
+ const match = (target: any, from: any) => {
218
+ delete target.video_em;
219
+ for (const k of ["clips", "video_offset"]) {
220
+ if (from && k in from) target[k] = from[k];
221
+ else delete target[k];
222
+ }
223
+ };
224
+ for (const c of raw.scenes) {
225
+ const rc = ref.scenes.find((x: any) => x.id === c.id);
226
+ if (draft?.scene_clips && c.id in draft.scene_clips) match(c, rc);
227
+ for (const l of c.lines ?? []) {
228
+ if (draft?.line_clips && l.id in draft.line_clips) {
229
+ const rl = rc?.lines?.find((x: any) => x.id === l.id);
230
+ if (rl && "clips" in rl) l.clips = rl.clips;
231
+ else delete l.clips;
232
+ }
233
+ }
234
+ }
235
+ if (draft && "bed" in draft) beforeScenes("bed", sanitizeBed(dir, draft.bed, total));
236
+ if (draft && "cuts" in draft) {
237
+ const c = normalizeCuts(draft.cuts, total, video.format.fps);
238
+ beforeScenes("cuts", c.length ? c : null);
239
+ }
240
+ if (draft && "speed" in draft) beforeScenes("speed", sanitizeSpeed(draft.speed));
241
+ const tmp = `${file}.${process.pid}.tmp`;
242
+ writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n");
243
+ renameSync(tmp, file);
244
+ } catch (e: any) {
245
+ return { ok: false, error: e.message };
246
+ }
247
+ return {
248
+ ok: true,
249
+ output: `som salvo no scenes.json (${changed} lugar(es)${draft && "bed" in draft ? " e a cama" : ""}${draft?.cuts?.length ? `, ${draft.cuts.length} corte(s)` : ""}${draft && "speed" in draft ? `, velocidade ${Math.round(sanitizeSpeed(draft.speed) * 100)}%` : ""})`,
250
+ };
251
+ }
252
+
253
+ /* adds an Epidemic effect to the video's list: sound.mjs download itself (only the URL
254
+ captured in the player gets in), which writes the MP3 to sfx/ and the origin to sfx/sources.json */
255
+ export async function downloadEffect(dir: string, body: any): Promise<Result> {
256
+ const url = String(body?.url ?? "").trim();
257
+ const name = String(body?.name ?? "").trim();
258
+ if (!url) return { ok: false, error: "cole a URL da Epidemic (audiocdn.epidemicsound.com/lqmp3/<id>.mp3)" };
259
+ const p = Bun.spawn([NODE, join(TOOLS_DIR, "sound.mjs"), "download", dir, url, ...(name ? [name] : [])], {
260
+ cwd: ROOT,
261
+ stdout: "pipe",
262
+ stderr: "pipe",
263
+ env: { ...process.env, OMNIVIDEO_ORIGIN: "studio" },
264
+ });
265
+ const [o, e, exit] = await Promise.all([new Response(p.stdout).text(), new Response(p.stderr).text(), p.exited]);
266
+ if (exit !== 0) return { ok: false, error: (e || o).trim().replace(/^erro:\s*/, "") || `sound.mjs saiu com ${exit}` };
267
+ return { ok: true, output: o.trim() };
268
+ }
269
+
270
+ /* adds a sound from an Epidemic page (playlist, theme, search): the editor's agent session opens it in
271
+ Chrome, plays the tracks, takes the lqmp3 URL from the player and runs sound.mjs download. The
272
+ timeline reloads when the agent stops. */
273
+ export function captureFromPage(slug: string, body: any): ApiResult {
274
+ let page: URL;
275
+ try {
276
+ page = new URL(String(body?.url ?? "").trim());
277
+ } catch {
278
+ return { ok: false, error: "cole o link de uma página da Epidemic (https://www.epidemicsound.com/music/…)" };
279
+ }
280
+ if (page.protocol !== "https:" || !/^(www\.)?epidemicsound\.com$/.test(page.hostname))
281
+ return { ok: false, error: "o link precisa ser de epidemicsound.com" };
282
+ const name = String(body?.name ?? "").trim();
283
+ const search = page.pathname.split("/").filter(Boolean).pop() ?? "";
284
+ const message = [
285
+ `Adicione ao vídeo uma faixa desta página da Epidemic: ${page.href}`,
286
+ "Só isto: não mexa na timeline, no scenes.json nem na montagem, e não baixe de outra fonte.",
287
+ "1. Carregue as ferramentas do Claude in Chrome (ToolSearch) e abra a página numa aba nova; tire um screenshot, porque a lista só monta com a aba pintada.",
288
+ "2. Rode no javascript_tool o código de `node tools/sound.mjs capture 8`. Ele dá play nas faixas e devolve [{ title, duration, url }], com a URL https://audiocdn.epidemicsound.com/lqmp3/<id>.mp3 lida do `src` do player (a música usa a mesma URL dos efeitos; o blob: da página é outro recurso, ignore). Lista vazia: espere e tente de novo uma vez.",
289
+ `3. Escolha a primeira faixa cuja URL ainda não esteja em videos/${slug}/sfx/sources.json e baixe: \`node tools/sound.mjs download videos/${slug} <url> ${name || "<nome-curto-da-faixa>"} --search "${search}"\`. Música tem mais de 30 s; se a faixa for um efeito curto, diga isso.`,
290
+ "4. Feche a aba que você abriu e responda em uma linha: arquivo, título e duração.",
291
+ "Chrome fora do ar ou Epidemic sem responder: pare e diga o que abrir.",
292
+ ].join("\n");
293
+ return chatWith("edit", slug, message);
294
+ }
295
+
296
+ /* reassembles the export with the new sound: assemble.mjs waits in the queue and the stage follows it */
297
+ export async function reassemble(dir: string): Promise<Result> {
298
+ const p = Bun.spawn([NODE, join(TOOLS_DIR, "assemble.mjs"), dir], {
299
+ cwd: ROOT,
300
+ stdout: "pipe",
301
+ stderr: "pipe",
302
+ env: { ...process.env, OMNIVIDEO_ORIGIN: "studio" },
303
+ });
304
+ const output = Promise.all([new Response(p.stdout).text(), new Response(p.stderr).text()]);
305
+ const early = await Promise.race([p.exited, Bun.sleep(2500).then(() => null)]);
306
+ if (early !== null && early !== 0) {
307
+ const [o, e] = await output;
308
+ return { ok: false, error: (e || o).trim() || `assemble.mjs saiu com ${early}` };
309
+ }
310
+ return { ok: true, output: early === 0 ? (await output)[0].trim() : "remontando (acompanhe na fila)" };
311
+ }
@@ -0,0 +1,133 @@
1
+ /* Thumbnail from the UI: the Publish stage asks the video's Claude (skill
2
+ av-thumbnail) for three random versions (v1–v3) or one with the user's
3
+ instruction (v4), and then only picks one. The two requests are separate: one
4
+ doesn't erase the other. A finished version can also be changed: Claude starts
5
+ from its HTML, keeps everything and changes only what was asked. Nothing is generated on its own: without the user's request, the
6
+ thumbnail/ dir doesn't even exist. tools/thumbnail.mjs, which the skill calls,
7
+ renders the PNGs and records thumbnail.json. */
8
+
9
+ import { existsSync, mkdirSync, writeFileSync, renameSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { NODE, TOOLS_DIR, run, readJson } from "./root";
12
+ import { chatWith } from "./create";
13
+ import { keepPrevious } from "../../../tools/history.mjs";
14
+
15
+ type Result = { ok: true; output: string } | { ok: false; error: string };
16
+ type ThumbnailRequests = {
17
+ random: { at: string } | null;
18
+ manual: { at: string; instruction: string } | null;
19
+ /* the change requested for each version (v1–v4); gone when the version is redone from scratch */
20
+ changes: Record<string, { at: string; instruction: string }>;
21
+ };
22
+
23
+ const VERSION = /^v[1-4]$/;
24
+
25
+ function readRequests(file: string): ThumbnailRequests {
26
+ const p = readJson<any>(file);
27
+ /* old shape: a single request, the one for the three ({ at, request }; before the migration { em, pedido }) */
28
+ if (p && ("at" in p || "em" in p)) return { random: { at: p.at ?? p.em }, manual: null, changes: {} };
29
+ return { random: p?.random ?? null, manual: p?.manual ?? null, changes: p?.changes ?? {} };
30
+ }
31
+
32
+ function writeRequests(file: string, p: ThumbnailRequests) {
33
+ const tmp = `${file}.${process.pid}.tmp`;
34
+ writeFileSync(tmp, JSON.stringify(p, null, 2) + "\n");
35
+ renameSync(tmp, file);
36
+ }
37
+
38
+ export function requestThumbnail(
39
+ slug: string,
40
+ dir: string,
41
+ mode: unknown,
42
+ instruction: unknown,
43
+ version?: unknown,
44
+ ): Result {
45
+ const scenes = readJson<any>(join(dir, "scenes.json"));
46
+ if (!scenes?.format)
47
+ return { ok: false, error: "o vídeo ainda não tem scenes.json com formato: a thumbnail usa a proporção dele" };
48
+ const change = mode === "change";
49
+ const manual = mode === "manual";
50
+ const text = typeof instruction === "string" ? instruction.replace(/\s+/g, " ").trim().slice(0, 600) : "";
51
+ if (manual && !text) return { ok: false, error: "escreva a instrução da sua versão" };
52
+ const target = String(version ?? "");
53
+ if (change) {
54
+ if (!VERSION.test(target)) return { ok: false, error: `versão inválida: ${target || "(vazia)"}` };
55
+ if (!text) return { ok: false, error: "diga o que mudar nesta thumbnail" };
56
+ if (!existsSync(join(dir, "thumbnail", `${target}.html`)) || !existsSync(join(dir, "thumbnail", `${target}.png`)))
57
+ return { ok: false, error: `a versão ${target} ainda não foi criada` };
58
+ }
59
+
60
+ /* the request is recorded first: the UI shows "creating" right away and knows if
61
+ Claude stopped without delivering (request newer than the version) */
62
+ const thumbDir = join(dir, "thumbnail");
63
+ mkdirSync(thumbDir, { recursive: true });
64
+ const file = join(thumbDir, "request.json");
65
+ const before = readRequests(file);
66
+ const at = new Date().toISOString();
67
+ /* redoing from scratch drops the change recorded on the redone versions; a change only records that version's */
68
+ const withoutChange = (ids: string[]) =>
69
+ Object.fromEntries(Object.entries(before.changes).filter(([id]) => !ids.includes(id)));
70
+ writeRequests(
71
+ file,
72
+ change
73
+ ? { ...before, changes: { ...before.changes, [target]: { at, instruction: text } } }
74
+ : manual
75
+ ? { ...before, manual: { at, instruction: text }, changes: withoutChange(["v4"]) }
76
+ : { ...before, random: { at }, changes: withoutChange(["v1", "v2", "v3"]) },
77
+ );
78
+ /* the change's starting point (current HTML and PNG) goes to history/ before Claude touches it */
79
+ if (change)
80
+ keepPrevious(dir, "thumbnail", target, [`thumbnail/${target}.html`, `thumbnail/${target}.png`]).close({
81
+ keep: true,
82
+ });
83
+
84
+ const size = "`node tools/thumbnail.mjs videos/" + slug + " size`";
85
+ const message = (
86
+ change
87
+ ? [
88
+ `Pedido pela tela (etapa Publicar): ALTERE a thumbnail ${target} deste vídeo, que já existe, com a skill av-thumbnail, em videos/${slug}.`,
89
+ `Alteração pedida pelo usuário: ${text}`,
90
+ `Parta de thumbnail/${target}.html (a versão de agora já está em history/thumbnail/${target}/) e preserve LITERALMENTE tudo o que a alteração não cita: layout, textos, cores, fontes, tamanhos, posições, SVG, CSS. Use Edit com trocas pontuais; não reescreva o arquivo nem redesenhe do zero, e não "melhore" nada que não foi pedido. Mantenha o <title> e o <meta name="description">, e só mude a descrição se a alteração mudar o que a thumbnail mostra.`,
91
+ `Edite só thumbnail/${target}.html e renderize com \`node tools/thumbnail.mjs videos/${slug} render ${target}\`. Não mexa nas outras versões. Compare o PNG novo com o anterior (history/thumbnail/${target}/) e confirme que só mudou o pedido.`,
92
+ ]
93
+ : manual
94
+ ? [
95
+ `Pedido pela tela (etapa Publicar): gere a versão manual da thumbnail deste vídeo (v4) com a skill av-thumbnail, em videos/${slug}.`,
96
+ `Uma versão só, em HTML, SVG e CSS, no estilo do vídeo e na proporção dele (${size}), seguindo esta instrução do usuário: ${text}`,
97
+ "Escreva só thumbnail/v4.html e renderize com `node tools/thumbnail.mjs videos/" +
98
+ slug +
99
+ " render v4`. Não mexa em v1, v2 e v3.",
100
+ ]
101
+ : [
102
+ `Pedido pela tela (etapa Publicar): gere as três thumbnails aleatórias deste vídeo (v1, v2 e v3) com a skill av-thumbnail, em videos/${slug}.`,
103
+ `Três ideias diferentes, sorteadas com \`node tools/thumbnail.mjs videos/${slug} draw\`, em HTML, SVG e CSS, no estilo do vídeo e na proporção dele (${size}).`,
104
+ "Renderize com `node tools/thumbnail.mjs videos/" + slug + " render v1,v2,v3`. Não mexa na v4.",
105
+ ]
106
+ )
107
+ .concat("Leia os PNG e pare aí: a escolha é do usuário, na tela. Não publique nem refaça outra etapa.")
108
+ .join("\n");
109
+ const r = chatWith("video", slug, message);
110
+ if (!r.ok) {
111
+ writeRequests(file, before);
112
+ return { ok: false, error: r.error ?? "não deu para falar com o agente do vídeo" };
113
+ }
114
+ return {
115
+ ok: true,
116
+ output: change
117
+ ? `pedi a alteração da ${target} ao agente do vídeo: acompanhe na sessão acima`
118
+ : manual
119
+ ? "pedi a sua versão ao agente do vídeo: acompanhe na sessão acima"
120
+ : "pedi as três versões ao agente do vídeo: acompanhe na sessão acima",
121
+ };
122
+ }
123
+
124
+ export async function chooseThumbnail(dir: string, version: unknown): Promise<Result> {
125
+ const v = String(version ?? "");
126
+ if (v !== "none" && !VERSION.test(v)) return { ok: false, error: `versão inválida: ${v || "(vazia)"}` };
127
+ if (v !== "none" && !existsSync(join(dir, "thumbnail", `${v}.png`)))
128
+ return { ok: false, error: `a versão ${v} ainda não foi renderizada` };
129
+ const r = await run([NODE, join(TOOLS_DIR, "thumbnail.mjs"), dir, "choose", v]);
130
+ return r.code === 0
131
+ ? { ok: true, output: r.stdout.trim() }
132
+ : { ok: false, error: (r.stderr || r.stdout).trim() || `thumbnail.mjs saiu com ${r.code}` };
133
+ }
@@ -0,0 +1,27 @@
1
+ /* Usage of the paid voices (Fish Audio and Cartesia). The accounting lives in tools/usage.py,
2
+ which the chat and the terminal also call; the studio only shows what it returns.
3
+ `refresh` asks the platforms now (and records the reading in .usage/). */
4
+
5
+ import { join } from "node:path";
6
+ import { PYTHON, TOOLS_DIR, run } from "./root";
7
+
8
+ let cached: { at: number; data: unknown } | null = null;
9
+
10
+ export async function getUsage(refresh = false): Promise<unknown> {
11
+ /* the UI reloads on every queue change; the local summary is cheap, but it doesn't need one Python per click */
12
+ if (!refresh && cached && Date.now() - cached.at < 3000) return cached.data;
13
+ const r = await run([PYTHON, join(TOOLS_DIR, "usage.py"), "summary", "--json", ...(refresh ? ["--live"] : [])]);
14
+ if (r.code !== 0) return { error: r.stderr.trim().split("\n").pop() || `usage.py saiu com código ${r.code}` };
15
+ try {
16
+ const data = JSON.parse(r.stdout);
17
+ cached = { at: Date.now(), data };
18
+ return data;
19
+ } catch {
20
+ return { error: "usage.py devolveu algo que não é JSON" };
21
+ }
22
+ }
23
+
24
+ /* the config or .env changed: the next summary asks usage.py again */
25
+ export function forgetUsage() {
26
+ cached = null;
27
+ }