@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,218 @@
1
+ /* Schedule page helpers: the scheduled publications of every video (publication.json `schedule`,
2
+ written by `publish.mjs schedule`) and the ones already up (on the day and time they were
3
+ published), as calendar posts; dates in this Mac's time; drag to reschedule; and picking a
4
+ day for a publish draft (lib/publish-draft.ts). */
5
+
6
+ import { createContext, useState, type DragEvent } from "react";
7
+ import { mediaUrl } from "./media";
8
+ import { platformName, type PlatformId } from "./platforms";
9
+ import type { PublishDraft } from "./publish-draft";
10
+ import type { ScheduledPost, VideoSummary } from "../types/api";
11
+
12
+ export type CalendarView = "month" | "week" | "day";
13
+ export const VIEWS: [CalendarView, string][] = [
14
+ ["month", "Mês"],
15
+ ["week", "Semana"],
16
+ ["day", "Dia"],
17
+ ];
18
+
19
+ export type Post = {
20
+ /* a video can have the published post and a new schedule: the key tells them apart */
21
+ key: string;
22
+ slug: string;
23
+ title: string;
24
+ when: Date;
25
+ platforms: PlatformId[];
26
+ state: ScheduledPost["state"] | "published";
27
+ error: string | null;
28
+ img: string | null;
29
+ portrait: boolean;
30
+ /* comes from the schedule (drags and reschedules); the published one stays where it went up */
31
+ scheduled: boolean;
32
+ };
33
+
34
+ export const STATE_LABEL: Record<Post["state"], string> = {
35
+ scheduled: "Agendado",
36
+ publishing: "Publicando agora",
37
+ failed: "Falhou",
38
+ missed: "Perdeu a hora",
39
+ published: "Publicado",
40
+ };
41
+ const PLATFORM_IDS: PlatformId[] = ["youtube", "instagram", "tiktok"];
42
+
43
+ /* what already went up: one post on the day and time of the first publication, with the platforms
44
+ where it is live; a platform that failed later (or never went up) leaves the post with an error.
45
+ A failure with nothing live, with a schedule, already shows on the schedule's post */
46
+ export function publishedPostsOf(v: VideoSummary): Post[] {
47
+ const pub = v.publication;
48
+ if (!pub) return [];
49
+ const done = PLATFORM_IDS.filter(k => pub[k]?.published_at);
50
+ const failed = PLATFORM_IDS.filter(k => {
51
+ const p = pub[k];
52
+ return !!p?.last_error && (!p.published_at || p.last_error.at > p.published_at);
53
+ });
54
+ if (!done.length && (!failed.length || pub.schedule)) return [];
55
+ const when = done.length
56
+ ? done.map(k => pub[k]!.published_at!).sort()[0]
57
+ : failed
58
+ .map(k => pub[k]!.last_error!.at)
59
+ .sort()
60
+ .at(-1)!;
61
+ return [
62
+ {
63
+ key: `${v.slug}:published`,
64
+ slug: v.slug,
65
+ title: v.title,
66
+ when: new Date(when),
67
+ platforms: [...done, ...failed.filter(k => !done.includes(k))],
68
+ state: failed.length ? "failed" : "published",
69
+ error: failed.length ? failed.map(k => `${platformName(k)}: ${pub[k]!.last_error!.message}`).join(" · ") : null,
70
+ img: mediaUrl(v, v.thumbnail ?? v.cover),
71
+ portrait: !!v.format && v.format.h > v.format.w,
72
+ scheduled: false,
73
+ },
74
+ ];
75
+ }
76
+
77
+ /* `moved`: the new time while publication.json has not come back with it */
78
+ export function postsOf(videos: VideoSummary[], moved: Record<string, Date>): Post[] {
79
+ return videos
80
+ .flatMap(v => {
81
+ const s = v.publication?.schedule;
82
+ if (!s) return publishedPostsOf(v);
83
+ return [
84
+ ...publishedPostsOf(v),
85
+ {
86
+ key: `${v.slug}:scheduled`,
87
+ scheduled: true,
88
+ slug: v.slug,
89
+ title: v.title,
90
+ when: moved[v.slug] ?? new Date(s.when),
91
+ platforms: s.platforms as PlatformId[],
92
+ state: (moved[v.slug] ? "scheduled" : s.state) as Post["state"],
93
+ error: moved[v.slug] ? null : (s.last_error?.message ?? null),
94
+ img: mediaUrl(v, v.thumbnail ?? v.cover),
95
+ portrait: !!v.format && v.format.h > v.format.w,
96
+ },
97
+ ];
98
+ })
99
+ .sort((a, b) => a.when.getTime() - b.when.getTime());
100
+ }
101
+
102
+ /* --- dates (this Mac's time, the same as the scheduler's) ---------------------------------- */
103
+ export const startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate());
104
+ export const addDays = (d: Date, n: number) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
105
+ export const sameDay = (a: Date, b: Date) =>
106
+ a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
107
+ export const startOfWeek = (d: Date) => addDays(startOfDay(d), -d.getDay());
108
+ export const hourOf = (d: Date) => d.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit" });
109
+ export const withHour = (day: Date, minutes: number) =>
110
+ new Date(day.getFullYear(), day.getMonth(), day.getDate(), Math.floor(minutes / 60), minutes % 60);
111
+ export const WEEKDAYS = ["dom", "seg", "ter", "qua", "qui", "sex", "sáb"];
112
+
113
+ export function titleFor(view: CalendarView, cursor: Date) {
114
+ if (view === "month") return cursor.toLocaleDateString("pt-BR", { month: "long", year: "numeric" });
115
+ if (view === "day")
116
+ return cursor.toLocaleDateString("pt-BR", { weekday: "long", day: "numeric", month: "long", year: "numeric" });
117
+ const start = startOfWeek(cursor),
118
+ end = addDays(start, 6);
119
+ const short = (d: Date) => d.toLocaleDateString("pt-BR", { day: "numeric", month: "short" });
120
+ return `${short(start)} – ${short(end)} de ${end.getFullYear()}`;
121
+ }
122
+
123
+ export function stepCursor(view: CalendarView, cursor: Date, step: number) {
124
+ if (view === "month") return new Date(cursor.getFullYear(), cursor.getMonth() + step, 1);
125
+ return addDays(cursor, step * (view === "week" ? 7 : 1));
126
+ }
127
+
128
+ /* the day view grid */
129
+ export const HOUR_HEIGHT = 64; /* px per hour */
130
+ export const CARD_HEIGHT = 58; /* px: posts closer than this share the width */
131
+ export const STEP_MIN = 5; /* dropping rounds to 5 min */
132
+
133
+ /* --- drag ----------------------------------------------------------------------------------- */
134
+ /* what is being dragged and where it was grabbed (px from the card top), for the day view */
135
+ export type Drag = { post: Post; grabY: number } | null;
136
+ export type DragController = {
137
+ /* for drawing (arrives one frame after dragstart) */
138
+ drag: Drag;
139
+ /* for deciding inside events: valid from dragstart on */
140
+ current: () => Drag;
141
+ start: (p: Post, e: DragEvent) => void;
142
+ end: () => void;
143
+ };
144
+ export const canDrag = (p: Post) => p.scheduled && p.state !== "publishing";
145
+
146
+ export function draggable(p: Post, c: DragController) {
147
+ return {
148
+ draggable: canDrag(p),
149
+ onDragStart: (e: DragEvent) => c.start(p, e),
150
+ onDragEnd: c.end,
151
+ };
152
+ }
153
+
154
+ /* a day that takes the post: highlighted while the post is over it; a past day doesn't take it.
155
+ `className` is " target" while hovered */
156
+ export function useDayDropTarget(d: Date, today: Date, c: DragController, drop: (p: Post, d: Date) => void) {
157
+ const [over, setOver] = useState(false);
158
+ const accepts = () => !!c.current() && d >= today;
159
+ return {
160
+ className: over && c.drag ? " target" : "",
161
+ props: {
162
+ onDragOver: (e: DragEvent) => {
163
+ if (!accepts()) return;
164
+ e.preventDefault();
165
+ e.dataTransfer.dropEffect = "move";
166
+ if (!over) setOver(true);
167
+ },
168
+ onDragLeave: (e: DragEvent) => {
169
+ if (!(e.currentTarget as Node).contains(e.relatedTarget as Node)) setOver(false);
170
+ },
171
+ onDrop: (e: DragEvent) => {
172
+ e.preventDefault();
173
+ setOver(false);
174
+ const cur = c.current();
175
+ if (accepts() && cur) drop(cur.post, d);
176
+ },
177
+ },
178
+ };
179
+ }
180
+
181
+ /* the link params that open a post's video on the Publish stage */
182
+ export const postLink = (p: Post) => ({
183
+ to: "/videos/$slug/$stage" as const,
184
+ params: { slug: p.slug, stage: "publish" },
185
+ });
186
+
187
+ /* picking a video's day: clicking the calendar picks the day (and, in the day view, the time) instead of opening */
188
+ export type PickHandler = ((day: Date, minutes?: number) => void) | null;
189
+ export const PickContext = createContext<PickHandler>(null);
190
+
191
+ /* the video that came from the Publish stage to pick a day, as a post (for the modal) */
192
+ export function postFromDraft(r: PublishDraft, videos: VideoSummary[] | null): Post {
193
+ const v = videos?.find(x => x.slug === r.slug);
194
+ return {
195
+ key: `${r.slug}:draft`,
196
+ scheduled: true,
197
+ slug: r.slug,
198
+ title: r.title,
199
+ when: r.when ? new Date(r.when) : new Date(),
200
+ platforms: Object.entries(r.checked)
201
+ .filter(([, yes]) => yes)
202
+ .map(([id]) => id as PlatformId),
203
+ state: "scheduled",
204
+ error: null,
205
+ img: v ? mediaUrl(v, v.thumbnail ?? v.cover) : null,
206
+ portrait: !!v?.format && v.format.h > v.format.w,
207
+ };
208
+ }
209
+
210
+ /* the suggested time when picking a day: the draft's; today, the next full hour; else 9h */
211
+ export function suggestedHour(day: Date, now: Date, r: PublishDraft) {
212
+ if (r.when) {
213
+ const q = new Date(r.when);
214
+ if (withHour(day, q.getHours() * 60 + q.getMinutes()).getTime() > now.getTime() + 60_000) return hourOf(q);
215
+ }
216
+ if (sameDay(day, now)) return `${String(Math.min(23, now.getHours() + 1)).padStart(2, "0")}:00`;
217
+ return "09:00";
218
+ }
@@ -0,0 +1,249 @@
1
+ /* The burned-in caption's position and style (CaptionPositionEditor): the draft's types, the
2
+ video → scene → caption resolution the template does, and the draft edits, as pure functions. */
3
+
4
+ export type NumericStyleKey =
5
+ | "background_opacity"
6
+ | "outline"
7
+ | "shadow_opacity"
8
+ | "shadow_blur"
9
+ | "shadow_x"
10
+ | "shadow_y";
11
+ export type ColorStyleKey = "color" | "background" | "outline_color" | "shadow_color";
12
+ export type CaptionStyle = Partial<Record<NumericStyleKey, number> & Record<ColorStyleKey, string>>;
13
+ /* `hidden`: only at the caption level; a caption turned off is not burned into the video */
14
+ export type CaptionOverride = { anchor?: string; x?: number; y?: number; hidden?: boolean } & CaptionStyle;
15
+ export type EffectiveOverride = CaptionOverride & { anchor: string; x: number; y: number };
16
+ export type Side = "top" | "bottom" | "left" | "right";
17
+ export type Margins = Record<Side, number>;
18
+ export type CaptionPosition = CaptionOverride & {
19
+ platform: string;
20
+ style: string;
21
+ safe?: Partial<Margins>;
22
+ scenes?: Record<string, CaptionOverride>;
23
+ individual?: Record<string, CaptionOverride>;
24
+ };
25
+ /* `original`: the text the line generated, when the text was edited in the UI */
26
+ export type CaptionItem = {
27
+ id: string;
28
+ scene: string | null;
29
+ line: string | null;
30
+ s: number;
31
+ e: number;
32
+ text: string;
33
+ hidden?: boolean;
34
+ original?: string;
35
+ };
36
+ export type CaptionsData = {
37
+ format: { w: number; h: number; fps: number; aspect?: string };
38
+ safes: Record<string, Margins>;
39
+ anchors: string[];
40
+ styles: string[];
41
+ defaults: Record<string, Required<CaptionStyle>>;
42
+ limits: Record<string, number[]> /* [min, max, step] per style key */;
43
+ max_chars: number | null;
44
+ position: CaptionPosition;
45
+ captions_in_motion: boolean;
46
+ scenes: { id: string; title: string | null; start: number; duration: number; mp4: boolean }[];
47
+ captions: CaptionItem[];
48
+ error?: string;
49
+ };
50
+ export type Scope = "video" | "scene" | "caption";
51
+ export type CaptionBox = {
52
+ id: string;
53
+ outside: boolean;
54
+ sides?: { side: Side; px: number }[];
55
+ x: number;
56
+ y: number;
57
+ w: number;
58
+ h: number;
59
+ } | null;
60
+ export type Message = { ok: boolean; text: string } | null;
61
+ /* one save request: a level of the position that changed */
62
+ export type PositionRequest = { scope: Scope; target?: string; value: unknown };
63
+
64
+ export const SAFE_AREA_LABEL: Record<string, string> = {
65
+ all: "Todas",
66
+ shorts: "Shorts",
67
+ tiktok: "TikTok",
68
+ reels: "Reels",
69
+ youtube: "YouTube",
70
+ };
71
+ export const SIDES: Side[] = ["top", "bottom", "left", "right"];
72
+ export const SIDE_LABEL: Record<Side, string> = { top: "Topo", bottom: "Base", left: "Esquerda", right: "Direita" };
73
+ export const OPPOSITE_SIDE: Record<Side, Side> = { top: "bottom", bottom: "top", left: "right", right: "left" };
74
+ export const clone = <T>(o: T): T => JSON.parse(JSON.stringify(o));
75
+ const STYLE_KEYS = [
76
+ "anchor",
77
+ "x",
78
+ "y",
79
+ "hidden",
80
+ "color",
81
+ "background",
82
+ "background_opacity",
83
+ "outline",
84
+ "outline_color",
85
+ "shadow_color",
86
+ "shadow_opacity",
87
+ "shadow_blur",
88
+ "shadow_x",
89
+ "shadow_y",
90
+ ];
91
+ export const pick = (o?: CaptionOverride) =>
92
+ Object.fromEntries(
93
+ Object.entries(o ?? {}).filter(([k, v]) => STYLE_KEYS.includes(k) && v != null),
94
+ ) as CaptionOverride;
95
+
96
+ /* the same resolution as the template: video → scene → caption */
97
+ export function effectiveStyle(
98
+ p: CaptionPosition,
99
+ c: CaptionItem | undefined,
100
+ upTo: Scope = "caption",
101
+ ): EffectiveOverride {
102
+ const base = { anchor: "bottom-center", x: 0, y: 0, ...pick(p) };
103
+ if (!c || upTo === "video") return base as EffectiveOverride;
104
+ const withScene = { ...base, ...pick(c.scene ? p.scenes?.[c.scene] : undefined) };
105
+ return (upTo === "scene" ? withScene : { ...withScene, ...pick(p.individual?.[c.id]) }) as EffectiveOverride;
106
+ }
107
+
108
+ /* the captions an edit in the "caption" scope applies to: all the checked ones when sel is among them */
109
+ export const targetCaptionsOf = (sel: string | null, checked: string[]) =>
110
+ sel ? (checked.length > 1 && checked.includes(sel) ? checked : [sel]) : [];
111
+
112
+ /* sets a key on the scope's level (for every target in scene and caption) */
113
+ export function withChange(
114
+ r: CaptionPosition,
115
+ scope: Scope,
116
+ targets: string[],
117
+ field: keyof CaptionOverride,
118
+ value: string | number,
119
+ ): CaptionPosition {
120
+ const n = clone(r);
121
+ if (scope === "video") (n as any)[field] = value;
122
+ else {
123
+ const group = scope === "scene" ? "scenes" : "individual";
124
+ for (const target of targets)
125
+ n[group] = { ...(n[group] ?? {}), [target]: { ...(n[group]?.[target] ?? {}), [field]: value } };
126
+ }
127
+ return n;
128
+ }
129
+
130
+ /* removes the key from this level only: back to the level above or to the style default */
131
+ export function withoutField(
132
+ r: CaptionPosition,
133
+ scope: Scope,
134
+ targets: string[],
135
+ field: keyof CaptionOverride,
136
+ ): CaptionPosition {
137
+ const n = clone(r);
138
+ if (scope === "video") delete (n as any)[field];
139
+ else {
140
+ const group = scope === "scene" ? "scenes" : "individual";
141
+ for (const target of targets) {
142
+ const o = n[group]?.[target];
143
+ if (!o) continue;
144
+ delete o[field];
145
+ if (!Object.keys(pick(o)).length) delete n[group]![target];
146
+ }
147
+ }
148
+ return n;
149
+ }
150
+
151
+ /* drops the whole override of the targets (scene or caption level) */
152
+ export function withoutOverride(r: CaptionPosition, scope: Scope, targets: string[]): CaptionPosition {
153
+ const n = clone(r);
154
+ const group = scope === "scene" ? "scenes" : "individual";
155
+ for (const target of targets) if (n[group]) delete n[group]![target];
156
+ return n;
157
+ }
158
+
159
+ /* turns the captions on or off in the video; on is the default, so only off is saved */
160
+ export function withCaptionsShown(r: CaptionPosition, ids: string[], on: boolean): CaptionPosition {
161
+ const n = clone(r);
162
+ const map: Record<string, CaptionOverride> = { ...(n.individual ?? {}) };
163
+ for (const id of ids) {
164
+ const o: CaptionOverride = { ...(map[id] ?? {}) };
165
+ if (on) delete o.hidden;
166
+ else o.hidden = true;
167
+ if (Object.keys(pick(o)).length) map[id] = o;
168
+ else delete map[id];
169
+ }
170
+ if (Object.keys(map).length) n.individual = map;
171
+ else delete n.individual;
172
+ return n;
173
+ }
174
+
175
+ /* switching the platform restarts from it: the margin overrides were about the previous one */
176
+ export function withGeneral(r: CaptionPosition, field: "platform" | "style", value: string): CaptionPosition {
177
+ const n = { ...r, [field]: value };
178
+ if (field === "platform") delete n.safe;
179
+ return n;
180
+ }
181
+
182
+ /* one safe-area margin: equal to the platform's, it stops being an override */
183
+ export function withMargin(
184
+ r: CaptionPosition,
185
+ safes: Record<string, Margins>,
186
+ side: Side,
187
+ value: number,
188
+ ): CaptionPosition {
189
+ const n = clone(r);
190
+ const platformValue = safes[n.platform]?.[side] ?? 0;
191
+ const v = Math.round(value * 1000) / 1000;
192
+ const safe = { ...(n.safe ?? {}) };
193
+ if (v === platformValue) delete safe[side];
194
+ else safe[side] = v;
195
+ if (Object.keys(safe).length) n.safe = safe;
196
+ else delete n.safe;
197
+ return n;
198
+ }
199
+
200
+ /* the largest a margin may get: 80 %, and at least 10 % of the frame left between it and the opposite one */
201
+ export const marginMax = (oppositeValue: number) => Math.min(0.8, Math.round((0.9 - oppositeValue) * 1000) / 1000);
202
+
203
+ /* the save requests: one per level that changed between the saved position and the draft */
204
+ export function saveRequests(saved: CaptionPosition, draft: CaptionPosition): PositionRequest[] {
205
+ const requests: PositionRequest[] = [];
206
+ const general = (p: CaptionPosition) => JSON.stringify([p.platform, p.style, pick(p), p.safe ?? null]);
207
+ if (general(saved) !== general(draft))
208
+ requests.push({
209
+ scope: "video",
210
+ value: { platform: draft.platform, style: draft.style, ...pick(draft), safe: draft.safe ?? null },
211
+ });
212
+ for (const [group, s] of [
213
+ ["scenes", "scene"],
214
+ ["individual", "caption"],
215
+ ] as const) {
216
+ const a = saved[group] ?? {},
217
+ b = draft[group] ?? {};
218
+ for (const id of new Set([...Object.keys(a), ...Object.keys(b)])) {
219
+ if (JSON.stringify(pick(a[id])) !== JSON.stringify(pick(b[id])))
220
+ requests.push({ scope: s, target: id, value: Object.keys(pick(b[id])).length ? pick(b[id]) : null });
221
+ }
222
+ }
223
+ return requests;
224
+ }
225
+
226
+ /* a click in the list: alone picks one; shift checks the range; ⌘/ctrl checks or unchecks one.
227
+ Returns only what changes (null: nothing does) */
228
+ export function chooseCaption(
229
+ ids: string[],
230
+ state: { sel: string | null; checked: string[]; rangeStart: string | null },
231
+ id: string,
232
+ keys: { shift: boolean; toggle: boolean },
233
+ ): { sel?: string; checked?: string[]; scope?: Scope; rangeStart?: string } | null {
234
+ const { sel, checked, rangeStart } = state;
235
+ const currentIds = sel ? (checked.includes(sel) ? checked : [sel]) : [];
236
+ if (keys.shift && (rangeStart ?? sel)) {
237
+ const [a, b] = [ids.indexOf((rangeStart ?? sel)!), ids.indexOf(id)].sort((x, y) => x - y);
238
+ return { checked: ids.slice(Math.max(a, 0), b + 1), sel: id, scope: "caption" };
239
+ }
240
+ if (keys.toggle) {
241
+ if (currentIds.includes(id)) {
242
+ const rest = currentIds.filter(x => x !== id);
243
+ if (!rest.length) return null;
244
+ return { checked: rest, ...(id === sel ? { sel: rest.at(-1)! } : {}), rangeStart: id, scope: "caption" };
245
+ }
246
+ return { checked: ids.filter(x => x === id || currentIds.includes(x)), sel: id, rangeStart: id, scope: "caption" };
247
+ }
248
+ return { sel: id, checked: [id], rangeStart: id };
249
+ }
@@ -0,0 +1,24 @@
1
+ /* Shared bits of the carousel stages (pages/VideoPage/components/Carousel*.tsx). */
2
+
3
+ import type { CarouselSlide } from "../types/api";
4
+
5
+ export const ROLE_LABEL: Record<NonNullable<CarouselSlide["role"]>, string> = {
6
+ cover: "Capa",
7
+ content: "Conteúdo",
8
+ payoff: "Payoff",
9
+ cta: "CTA",
10
+ };
11
+ export const roleLabel = (role: string) => ROLE_LABEL[role as keyof typeof ROLE_LABEL] ?? role;
12
+
13
+ /* carousel.json `goal` (EN enum on disk), shown as the PT word the file used to hold */
14
+ const GOAL_LABEL: Record<string, string> = {
15
+ saves: "salvamento",
16
+ shares: "compartilhamento",
17
+ followers: "seguidor",
18
+ lead: "lead",
19
+ };
20
+ export const goalLabel = (goal: string) => GOAL_LABEL[goal] ?? goal;
21
+
22
+ /* the slide's aspect ratio, 4:5 when the format is unknown */
23
+ export const slideAspect = (format: { w: number; h: number } | null) =>
24
+ format ? `${format.w} / ${format.h}` : "4 / 5";
@@ -0,0 +1,42 @@
1
+ /* A synthesized chime (Web Audio) for approval rounds. The browser only plays after some click
2
+ on the page, so the tab title is the notice that always arrives. */
3
+
4
+ let ctx: AudioContext | null = null;
5
+ const audioContext = () => (ctx ??= new AudioContext());
6
+
7
+ /* without a gesture on the page, Chrome keeps the context suspended */
8
+ const unlockAudio = () => {
9
+ try {
10
+ void audioContext().resume();
11
+ } catch {
12
+ /* no audio */
13
+ }
14
+ };
15
+ window.addEventListener("pointerdown", unlockAudio, { once: true });
16
+ window.addEventListener("keydown", unlockAudio, { once: true });
17
+
18
+ /* two short rising notes: get attention without startling */
19
+ export function playChime() {
20
+ try {
21
+ const c = audioContext();
22
+ void c.resume();
23
+ const t0 = c.currentTime + 0.02;
24
+ for (const [freq, delay] of [
25
+ [880, 0],
26
+ [1318.5, 0.16],
27
+ ]) {
28
+ const osc = c.createOscillator();
29
+ const gain = c.createGain();
30
+ osc.type = "sine";
31
+ osc.frequency.value = freq;
32
+ gain.gain.setValueAtTime(0, t0 + delay);
33
+ gain.gain.linearRampToValueAtTime(0.22, t0 + delay + 0.012);
34
+ gain.gain.exponentialRampToValueAtTime(0.0001, t0 + delay + 0.6);
35
+ osc.connect(gain).connect(c.destination);
36
+ osc.start(t0 + delay);
37
+ osc.stop(t0 + delay + 0.65);
38
+ }
39
+ } catch {
40
+ /* browser without Web Audio: the title remains */
41
+ }
42
+ }
@@ -0,0 +1,55 @@
1
+ /* The voice clone's pure rules (CloneVoiceDialog): the speech limits, the providers that clone
2
+ through the API, the pace of the guided reading, the file checks and the provider priority. */
3
+
4
+ /* 30 s to 3 min of speech; the server checks the same limits (api/services/clone.ts) */
5
+ export const MIN_S = 30;
6
+ export const MAX_S = 180;
7
+ export const MAX_FILE = 10 * 1024 ** 2;
8
+ /* the providers that clone through the API; each one's account is in lib/providers (PROVIDER_ACCOUNT_URL) */
9
+ export const PROVIDERS = [
10
+ { id: "fish", name: "Fish Audio" },
11
+ { id: "cartesia", name: "Cartesia" },
12
+ ] as const;
13
+ export type CloneProviderId = (typeof PROVIDERS)[number]["id"];
14
+
15
+ export const clock = (s: number) => `${Math.floor(s / 60)}:${String(Math.floor(s % 60)).padStart(2, "0")}`;
16
+
17
+ /* Pace of the guided reading: each word lasts a bit longer the longer it is, and punctuation holds
18
+ the breath. ~2.7 words/s, the pace of natural, fluid speech for the clone to learn. Tune here to
19
+ speed up or slow down. */
20
+ export const PACE = { base: 0.14, perLetter: 0.045, comma: 0.2, period: 0.35 };
21
+
22
+ export function wordStarts(words: string[]): number[] {
23
+ let t = 0;
24
+ return words.map(w => {
25
+ const start = t;
26
+ t += PACE.base + PACE.perLetter * w.replace(/[^\p{L}\p{N}]/gu, "").length;
27
+ if (/[.!?…]["')»]*$/.test(w)) t += PACE.period;
28
+ else if (/[,;:—–]["')»]*$/.test(w)) t += PACE.comma;
29
+ return start;
30
+ });
31
+ }
32
+
33
+ /* the context's phrases as one continuous script, word by word */
34
+ export const scriptWords = (phrases: { text: string }[]) =>
35
+ phrases
36
+ .map(f => f.text)
37
+ .join(" ")
38
+ .split(/\s+/)
39
+ .filter(Boolean);
40
+
41
+ /* why a picked file can't be attached (too big, or not audio); null when it can */
42
+ export function fileRefusal(f: { name: string; size: number; type: string }): string | null {
43
+ if (f.size > MAX_FILE) return `${f.name} passa de 10 MB`;
44
+ if (!/^(audio|video)\//.test(f.type) && !/\.(wav|mp3|m4a|webm|ogg|flac)$/i.test(f.name))
45
+ return `${f.name} não parece áudio`;
46
+ return null;
47
+ }
48
+
49
+ /* swaps the checked provider at `i` with its neighbour (`d`): the new priority keeps the unchecked
50
+ ones after the checked */
51
+ export function reorderPriority(order: string[], priority: string[], i: number, d: -1 | 1): string[] {
52
+ const o = [...order];
53
+ [o[i], o[i + d]] = [o[i + d], o[i]];
54
+ return [...o, ...priority.filter(x => !o.includes(x))];
55
+ }
@@ -0,0 +1,11 @@
1
+ import type { FileEntry, VideoDetail } from "../types/api";
2
+
3
+ /* the current export: the one assembly.json names, else Premiere's, else the newest mp4 in export/ */
4
+ export function currentExport(video: VideoDetail): FileEntry | null {
5
+ const mp4s = video.files.filter(f => f.path.startsWith("export/") && /\.(mp4|mov)$/i.test(f.path));
6
+ const fromAssembly = video.assembly?.mp4 ? mp4s.find(f => f.path === video.assembly!.mp4) : undefined;
7
+ const fromPremiere = video.premiere?.export
8
+ ? mp4s.find(f => String(video.premiere!.export).endsWith(`/${f.path}`))
9
+ : undefined;
10
+ return fromAssembly ?? fromPremiere ?? [...mp4s].sort((a, b) => b.mtime - a.mtime)[0] ?? null;
11
+ }
@@ -0,0 +1,8 @@
1
+ /* a Blob as base64 (without the data: prefix), for JSON uploads */
2
+ export const blobToBase64 = (b: Blob) =>
3
+ new Promise<string>((resolve, reject) => {
4
+ const r = new FileReader();
5
+ r.onload = () => resolve(String(r.result).split(",")[1] ?? "");
6
+ r.onerror = () => reject(r.error);
7
+ r.readAsDataURL(b);
8
+ });