@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,81 @@
1
+ # VoiceStudio
2
+
3
+ Repository and environment in a folder of yours (`voicestudio.repo` in the
4
+ config; a clone of `debpalash/VoiceStudio` v0.5.7, called `<repo>` below).
5
+ Local FastAPI backend at `http://127.0.0.1:3900`, OmniVoice model on the Mac's
6
+ GPU (MPS). No API key: everything runs locally.
7
+
8
+ ## Start
9
+
10
+ - App: `cd <repo> && bun run dev` (opens Electron, which starts the backend).
11
+ - Backend only: `bun run dev:api`.
12
+ - Check: `curl -s http://127.0.0.1:3900/health`.
13
+
14
+ ## Voice
15
+
16
+ **Always the profile named "Pedro".** The id changes every time the clone is
17
+ redone, so the config keeps the name (`voicestudio.profile`) and
18
+ `omnivideo.py voice` looks up the id in `GET /profiles` on every run. Zero or
19
+ more than one profile with that name is an error.
20
+
21
+ > **Trap:** `POST /generate` with a `profile_id` that doesn't exist **does not
22
+ > error**. It generates with a generic voice, no clone, and faster. That is how
23
+ > a test came out with the wrong voice without any warning. That's why the id
24
+ > is never hardcoded.
25
+
26
+ Current profile (2026-10-12): `c75067ce`, 66 s reference, language
27
+ Portuguese, no saved transcription. OmniVoice uses at most 20 s of the
28
+ reference: with a longer clip, it picks the 15 s excerpt with the most speech
29
+ by itself.
30
+
31
+ ## Generate
32
+
33
+ `POST /generate` (multipart), response `audio/wav` 24 kHz mono:
34
+
35
+ | field | value in omnivideo |
36
+ |---|---|
37
+ | `text` | the line |
38
+ | `profile_id` | resolved by name |
39
+ | `language` | `Portuguese` |
40
+ | `num_step` | 16 (8 = quick draft, 32 = quality) |
41
+ | `speed` | 1.0 |
42
+ | `instruct` | optional, per line |
43
+
44
+ Every generation goes through the default mastering (`broadcast` preset),
45
+ gets an inaudible watermark (AudioSeal) and goes into the app's history.
46
+
47
+ ## Measured performance (M4, 16 GB)
48
+
49
+ | situation | cost |
50
+ |---|---|
51
+ | "Pedro" profile, model already loaded | ~20 s fixed per line + 4 to 5 s per second of audio |
52
+ | first line after being idle | +10 s (loading the model; it unloads after 5 min idle) |
53
+ | memory full (swap ≥ 90 %) | up to 9 s per second of audio; long lines blow the limit |
54
+
55
+ The limit is **305 s of compute per generation**. If it blows: the abandoned
56
+ job keeps running until it finishes, and retrying right away competes with
57
+ it. Wait, split the line, and warn the user about memory
58
+ (`sysctl vm.swapusage`).
59
+
60
+ Pace of Pedro's voice: 2.3 to 3.4 words per second; the config uses 3.0 to
61
+ estimate.
62
+
63
+ ## Pronunciation
64
+
65
+ A word coming out wrong goes into the pronunciation dictionary, which applies
66
+ to every generation:
67
+
68
+ ```bash
69
+ curl -s -X POST http://127.0.0.1:3900/pronunciation -H 'content-type: application/json' \
70
+ -d '{"term": "MCP", "replacement": "éme cê pê", "language": "*"}'
71
+ curl -s http://127.0.0.1:3900/pronunciation # list
72
+ ```
73
+
74
+ You can also fix a single occurrence, in the text: `[[éme cê pê]]`. But in
75
+ omnivideo the line's text is also the caption, so prefer the dictionary.
76
+
77
+ ## MCP
78
+
79
+ VoiceStudio also exposes MCP at `http://localhost:3900/mcp/` (registered in
80
+ Claude Code as `voicestudio`). For omnivideo use the API: the MCP returns the
81
+ audio in base64 inside the conversation, which is very heavy.
@@ -0,0 +1,67 @@
1
+ # Writing for the voice
2
+
3
+ The line goes straight to the cloned voice (Fish Audio by default). The voice
4
+ reads punctuation as intonation: each mark becomes a pause, a rise or a break.
5
+ Text that looks good written can come out choppy spoken. The rule is to write
6
+ the way Pedro would speak in a conversation, not the way he would write a post.
7
+
8
+ Applies to `script.md` (stage 1) and, above all, to the lines in
9
+ `scenes.json` (stage 4). `omnivideo.py status` warns when a
10
+ line breaks the objective rules below.
11
+
12
+ The narration is Portuguese, so the examples below stay in Portuguese.
13
+
14
+ ## Punctuation
15
+
16
+ - **The period is the only safe mark.** One sentence, one idea, period.
17
+ - **No colons.** The voice stops and changes tone mid-sentence. Whatever would
18
+ come after the colon becomes another sentence.
19
+ - **At most one comma**, and only where people naturally breathe ("No
20
+ Upwork, …"). A comma before a colon is the worst case: two breaks in a row
21
+ in the middle of one idea.
22
+ - **No appositives or parenthetical clauses** ("que pede, por escrito, …").
23
+ The voice breaks the intonation at the parenthetical and never recovers.
24
+ - **No semicolons, dashes, parentheses, slashes or ellipses.**
25
+ - **A list becomes a sentence.** "história curta, referência visual e som"
26
+ after a colon sounds like reading bullet points. Write it with a verb and
27
+ articles: "Você precisa de uma história curta, uma referência visual e um som."
28
+
29
+ ## Order and rhythm
30
+
31
+ - **Direct order:** subject, verb, complement. Don't open with a long
32
+ circumstance.
33
+ - **One idea per sentence.** Two price ranges in one sentence become two
34
+ sentences (and two lines, which the motion can separate).
35
+ - **Short sentences.** Up to ~15 words sounds natural; 22 is the stage's ceiling.
36
+ - **Colloquial:** "pra", "a gente", "tá", contractions the way people speak.
37
+
38
+ ## Words
39
+
40
+ - **Numbers as spoken:** "500 dólares", "2 mil", "15 segundos". Ranges with
41
+ "de … a …", never a hyphen or dash.
42
+ - **Don't end the sentence on a bare number.** "chega a 2 mil." left the voice
43
+ without a clear ending, and it tacked on an extra sound. Complete it with
44
+ the unit: "chega a 2 mil dólares."
45
+ - **Version numbers, mixed acronyms and hard foreign words** ("Opus 5.5",
46
+ "SaaS") have no pronunciation dictionary in Fish. Leave them on screen and
47
+ say them in Portuguese ("o Opus", "demo de produto"). The motion shows the
48
+ exact term.
49
+ - **No symbols:** "%" becomes "por cento", "x" becomes "vezes", "→" doesn't exist.
50
+ - AI terms Pedro says in English (prompt, agent, token) stay.
51
+
52
+ ## Real example (2026-10-12)
53
+
54
+ | written | what the voice did | rewritten |
55
+ |---|---|---|
56
+ | E tem vaga que pede, por escrito: domínio do Opus 5.5. | two breaks in a row (comma and colon) and "5.5" read as a number | E já tem vaga pedindo quem domine o Opus. |
57
+ | No Upwork, vai de 100 dólares por um logo animado até 2 mil por uma demo de SaaS. | long sentence, two ranges | Um logo animado no Upwork sai por 100 dólares. / Uma demo de produto chega a 2 mil dólares. |
58
+ | Começa por demo de SaaS: história curta, referência visual e som. | colon and a bullet-point list | O melhor jeito de começar é a demo de produto. / Você precisa de uma história curta, uma referência visual e um som. |
59
+ | Tem gente vendendo animação a 129 dólares, feita em menos de uma hora. | parenthetical at the end | Tem gente cobrando 129 dólares por uma animação que leva menos de uma hora. |
60
+ | Uma demo de produto chega a 2 mil. | ended on a bare number; the voice tacked a sound onto the end | Uma demo de produto chega a 2 mil dólares. |
61
+
62
+ ## How to check
63
+
64
+ Read the line out loud, for real, once. If you stopped or changed tone
65
+ anywhere other than the period, rewrite it. After the voice, the voice stage
66
+ marks `← ritmo estranho` (odd rhythm) when a line comes out too fast or too
67
+ slow: it is almost always a hard sentence, not a voice error.
@@ -0,0 +1,3 @@
1
+ requests>=2.31
2
+ soundfile>=0.12
3
+ numpy>=1.26
@@ -0,0 +1,87 @@
1
+ /* The studio's HTTP API (the local runner API): every /api route plus the file routes (/media,
2
+ /ref, /kit, /sound-draft, /docs). Bun keeps serving the HTML bundle (studio.ts) and hands these
3
+ paths here. `AppType` types the web client (web/lib/api.ts, hono/client).
4
+
5
+ Routers are domain modules under routes/; the cloud candidates (publish, schedule, omnichat,
6
+ analytics) only reach their own services, so they can move to an edge function as they are. */
7
+
8
+ import { router } from "./lib/hono";
9
+ import { notFoundResponse, onError } from "./lib/errors";
10
+ import { localOnly } from "./middleware/local-only";
11
+ import { jsonCharset } from "./middleware/json-charset";
12
+ import { admin } from "./routes/admin";
13
+ import { agent } from "./routes/agent";
14
+ import { agentCascade } from "./routes/agent-cascade";
15
+ import { agentHistory } from "./routes/agent-history";
16
+ import { analytics } from "./routes/analytics";
17
+ import { approval } from "./routes/approval";
18
+ import { archive } from "./routes/archive";
19
+ import { captions } from "./routes/captions";
20
+ import { carousel } from "./routes/carousel";
21
+ import { clone } from "./routes/clone";
22
+ import { create, UPLOAD_PATH } from "./routes/create";
23
+ import { events } from "./routes/events";
24
+ import { exportRoutes } from "./routes/export";
25
+ import { media } from "./routes/media";
26
+ import { omnichat } from "./routes/omnichat";
27
+ import { onboarding } from "./routes/onboarding";
28
+ import { publish } from "./routes/publish";
29
+ import { queue } from "./routes/queue";
30
+ import { references } from "./routes/references";
31
+ import { runner } from "./routes/runner";
32
+ import { schedule } from "./routes/schedule";
33
+ import { services } from "./routes/services";
34
+ import { sessions } from "./routes/sessions";
35
+ import { settings } from "./routes/settings";
36
+ import { sound } from "./routes/sound";
37
+ import { thumbnail } from "./routes/thumbnail";
38
+ import { usage } from "./routes/usage";
39
+ import { videos } from "./routes/videos";
40
+ import { voices } from "./routes/voices";
41
+
42
+ /* the path prefixes studio.ts hands to this app */
43
+ export const API_PREFIXES = ["/api", "/media", "/ref", "/kit", "/sound-draft", "/docs"] as const;
44
+
45
+ export type AppOptions = { port: number };
46
+
47
+ export function createApp({ port }: AppOptions) {
48
+ const api = router()
49
+ .route("/", create)
50
+ .route("/", videos)
51
+ .route("/", captions)
52
+ .route("/", sound)
53
+ .route("/", exportRoutes)
54
+ .route("/", voices)
55
+ .route("/", approval)
56
+ .route("/", archive)
57
+ .route("/", thumbnail)
58
+ .route("/", carousel)
59
+ .route("/", publish)
60
+ .route("/", schedule)
61
+ .route("/", omnichat)
62
+ .route("/", sessions)
63
+ .route("/", references)
64
+ .route("/", queue)
65
+ .route("/", runner)
66
+ .route("/", services)
67
+ .route("/", usage)
68
+ .route("/", analytics)
69
+ .route("/", settings)
70
+ .route("/", clone)
71
+ .route("/", onboarding)
72
+ .route("/", admin)
73
+ .route("/", agent)
74
+ .route("/", agentCascade)
75
+ .route("/", agentHistory)
76
+ .route("/", events);
77
+ const app = router()
78
+ .use(localOnly({ port, uploadPaths: [UPLOAD_PATH] }))
79
+ .use(jsonCharset)
80
+ .route("/api", api)
81
+ .route("/", media);
82
+ app.onError(onError);
83
+ app.notFound(() => notFoundResponse());
84
+ return app;
85
+ }
86
+
87
+ export type AppType = ReturnType<typeof createApp>;
@@ -0,0 +1,33 @@
1
+ /* One error format. HttpError carries a status; 404 stays the plain "não encontrado" text the
2
+ studio always answered, everything else is the { ok: false, error } envelope. */
3
+
4
+ import type { Context } from "hono";
5
+ import { HTTPException } from "hono/http-exception";
6
+
7
+ export class HttpError extends Error {
8
+ constructor(
9
+ readonly status: 400 | 403 | 404 | 415 | 500,
10
+ message: string,
11
+ ) {
12
+ super(message);
13
+ }
14
+ }
15
+
16
+ export const NOT_FOUND_TEXT = "não encontrado";
17
+ export const notFoundResponse = () => new Response(NOT_FOUND_TEXT, { status: 404 });
18
+
19
+ /* throw from a handler: answered by onError as the plain 404 */
20
+ export const notFound = () => new HttpError(404, NOT_FOUND_TEXT);
21
+
22
+ export function onError(e: Error, c: Context): Response {
23
+ if (e instanceof HttpError) {
24
+ if (e.status === 404) return notFoundResponse();
25
+ return c.json({ ok: false, error: e.message }, e.status);
26
+ }
27
+ /* the validator's malformed JSON */
28
+ if (e instanceof HTTPException && e.status === 400) {
29
+ return c.json({ ok: false, error: "corpo da requisição: JSON inválido" }, 400);
30
+ }
31
+ console.error(e);
32
+ return c.json({ ok: false, error: e.message || String(e) }, 500);
33
+ }
@@ -0,0 +1,41 @@
1
+ /* Files served as they are (media, reference files, docs, sound drafts, kit). Bun answers Range
2
+ by itself for Bun.file (206 with Content-Range): it is what video and audio players ask for
3
+ to seek into the middle of the file. */
4
+
5
+ import { extname } from "node:path";
6
+ import { notFoundResponse } from "./errors";
7
+
8
+ const TEXT_CONTENT_TYPES: Record<string, string> = {
9
+ ".srt": "text/plain; charset=utf-8",
10
+ ".md": "text/plain; charset=utf-8",
11
+ ".txt": "text/plain; charset=utf-8",
12
+ ".json": "application/json; charset=utf-8",
13
+ ".css": "text/plain; charset=utf-8",
14
+ };
15
+
16
+ /* the path segments after the first `skip` ones, decoded: /media/<slug>/<a>/<b> → [slug, a, b] */
17
+ export const pathSegments = (url: string, skip = 2) =>
18
+ new URL(url).pathname
19
+ .split("/")
20
+ .slice(skip)
21
+ .map(p => decodeURIComponent(p));
22
+
23
+ /* `?v=` (the file's mtime) makes the URL immutable */
24
+ export async function serveFile(abs: string | null, url: string): Promise<Response> {
25
+ if (!abs) return notFoundResponse();
26
+ const file = Bun.file(abs);
27
+ if (!(await file.exists())) return notFoundResponse();
28
+ const headers: Record<string, string> = {
29
+ "cache-control": new URL(url).searchParams.has("v") ? "private, max-age=31536000, immutable" : "no-cache",
30
+ "x-content-type-options": "nosniff",
31
+ };
32
+ const type = TEXT_CONTENT_TYPES[extname(abs).toLowerCase()];
33
+ if (type) headers["content-type"] = type;
34
+ return new Response(file, { headers });
35
+ }
36
+
37
+ /* a stored WAV (voice samples, original recordings): 404 when missing or empty */
38
+ export function serveWav(abs: string | null): Response {
39
+ const f = abs ? Bun.file(abs) : null;
40
+ return f?.size ? new Response(f, { headers: { "content-type": "audio/wav" } }) : notFoundResponse();
41
+ }
@@ -0,0 +1,9 @@
1
+ /* The Hono env every router shares: Bun's server (for server.timeout on long requests and
2
+ the SSE stream) arrives as c.env.server; tests pass none. */
3
+
4
+ import { Hono } from "hono";
5
+ import type { Server } from "bun";
6
+
7
+ export type AppEnv = { Bindings: { server?: Server<unknown> } };
8
+
9
+ export const router = () => new Hono<AppEnv>();
@@ -0,0 +1,14 @@
1
+ /* Envelope helpers. A service result ({ ok, output?, error?, … }) answers 200 when ok and 400
2
+ when not, as the studio always did. */
3
+
4
+ import type { Context } from "hono";
5
+
6
+ export const result = <T extends { ok: boolean }>(c: Context, r: T) => c.json(r, r.ok ? 200 : 400);
7
+
8
+ /* a failed result with this message (400) */
9
+ export const fail = (c: Context, error: string) => c.json({ ok: false as const, error }, 400);
10
+
11
+ /* A service value under the response type the UI reads (shared/types/api.ts). Services build these
12
+ from the video's files and the tools' JSON output, so the shared type is the contract between
13
+ the two sides rather than something TS can prove from the service code. */
14
+ export const shaped = <T>(value: unknown) => value as T;
@@ -0,0 +1,31 @@
1
+ /* zod validators for JSON bodies and query strings: a failure answers 400
2
+ { ok: false, error: "<campo>: <mensagem>" }, in Portuguese since it may reach the UI. */
3
+
4
+ import { zValidator } from "@hono/zod-validator";
5
+ import { z } from "zod";
6
+
7
+ z.config(z.locales.pt());
8
+ /* a missing field reads better as "obrigatório" than as "recebeu undefined" */
9
+ z.config({
10
+ customError: issue => (issue.code === "invalid_type" && issue.input === undefined ? "obrigatório" : undefined),
11
+ });
12
+
13
+ export function validationMessage(issues: readonly z.core.$ZodIssue[]): string {
14
+ const issue = issues[0];
15
+ if (!issue) return "requisição inválida";
16
+ const field = issue.path.map(String).join(".") || "corpo";
17
+ return `${field}: ${issue.message}`;
18
+ }
19
+
20
+ const invalid = (issues: readonly z.core.$ZodIssue[]) =>
21
+ Response.json({ ok: false, error: validationMessage(issues) }, { status: 400 });
22
+
23
+ export const json = <S extends z.ZodType>(schema: S) =>
24
+ zValidator("json", schema, r => {
25
+ if (!r.success) return invalid(r.error.issues);
26
+ });
27
+
28
+ export const query = <S extends z.ZodType>(schema: S) =>
29
+ zValidator("query", schema, r => {
30
+ if (!r.success) return invalid(r.error.issues);
31
+ });
@@ -0,0 +1,10 @@
1
+ /* The dir of the video a route names, or the plain 404 every video route answers when it is gone. */
2
+
3
+ import { videoDirs } from "../services/videos";
4
+ import { notFound } from "./errors";
5
+
6
+ export function videoDir(slug: string): string {
7
+ const dir = videoDirs().get(slug);
8
+ if (!dir) throw notFound();
9
+ return dir;
10
+ }
@@ -0,0 +1,11 @@
1
+ /* JSON answers keep the content-type Bun's Response.json gave them before the Hono move
2
+ ("application/json;charset=utf-8"), so nothing downstream sees a different header. */
3
+
4
+ import { createMiddleware } from "hono/factory";
5
+ import type { AppEnv } from "../lib/hono";
6
+
7
+ export const jsonCharset = createMiddleware<AppEnv>(async (c, next) => {
8
+ await next();
9
+ if (c.res.headers.get("content-type") === "application/json")
10
+ c.res.headers.set("content-type", "application/json;charset=utf-8");
11
+ });
@@ -0,0 +1,32 @@
1
+ /* Only this machine and only the studio UI. Host blocks DNS rebinding; Origin and mandatory
2
+ JSON block another page open in the browser from posting here. The upload paths take a raw
3
+ body instead: their custom x-file-name header makes the browser send a preflight from any
4
+ other origin, which this server doesn't answer. */
5
+
6
+ import { createMiddleware } from "hono/factory";
7
+ import type { AppEnv } from "../lib/hono";
8
+
9
+ export type LocalOnlyOptions = { port: number; uploadPaths?: string[] };
10
+
11
+ const text = (body: string, status: number) => new Response(body, { status });
12
+
13
+ export function rejectForeign(req: Request, hosts: Set<string>, origins: Set<string>, upload: boolean) {
14
+ if (!hosts.has(req.headers.get("host") ?? "")) return text("host não permitido", 403);
15
+ if (req.method === "GET" || req.method === "HEAD") return null;
16
+ const origin = req.headers.get("origin");
17
+ if (origin && !origins.has(origin)) return text("origem não permitida", 403);
18
+ if (upload) return req.headers.get("x-file-name") ? null : text("falta o nome do arquivo", 415);
19
+ if (!req.headers.get("content-type")?.startsWith("application/json")) return text("só JSON", 415);
20
+ return null;
21
+ }
22
+
23
+ export function localOnly({ port, uploadPaths = [] }: LocalOnlyOptions) {
24
+ const hosts = new Set([`127.0.0.1:${port}`, `localhost:${port}`]);
25
+ const origins = new Set([...hosts].map(h => `http://${h}`));
26
+ const uploads = new Set(uploadPaths);
27
+ return createMiddleware<AppEnv>(async (c, next) => {
28
+ const rejected = rejectForeign(c.req.raw, hosts, origins, uploads.has(c.req.path));
29
+ if (rejected) return rejected;
30
+ await next();
31
+ });
32
+ }
@@ -0,0 +1,10 @@
1
+ /* Long requests (Instagram reads, uploads, clone, connect, collect, streams): lifts Bun's 10 s
2
+ idle timeout for this request. */
3
+
4
+ import { createMiddleware } from "hono/factory";
5
+ import type { AppEnv } from "../lib/hono";
6
+
7
+ export const noTimeout = createMiddleware<AppEnv>(async (c, next) => {
8
+ c.env?.server?.timeout(c.req.raw, 0);
9
+ await next();
10
+ });
@@ -0,0 +1,18 @@
1
+ /* The admin panel (services/admin.ts): who is looking, and Omni's settings for every user. A
2
+ non-admin only learns that it isn't one; a change from one is refused. */
3
+
4
+ import { json } from "../lib/validate";
5
+ import { router } from "../lib/hono";
6
+ import { omniAdmin, setOmniAdmin, viewerOf } from "../services/admin";
7
+ import { omniAdminBody } from "../../shared/schemas/admin";
8
+
9
+ export const admin = router()
10
+ .get("/admin", c => {
11
+ const viewer = viewerOf(c.req.raw);
12
+ return c.json({ ...viewer, omni: viewer.admin ? omniAdmin() : null });
13
+ })
14
+ .post("/admin/omni", json(omniAdminBody), c => {
15
+ if (!viewerOf(c.req.raw).admin) return c.json({ ok: false as const, error: "só o admin muda a Omni" }, 403);
16
+ const r = setOmniAdmin(c.req.valid("json"));
17
+ return r.ok ? c.json(r) : c.json(r, 400);
18
+ });
@@ -0,0 +1,100 @@
1
+ /* Omni in cascade mode (services/agent-cascade.ts): the session, the STT token to reconnect, each
2
+ turn streamed back as NDJSON (text, tools, staged actions, audio) and the browser's measurements. */
3
+
4
+ import { json } from "../lib/validate";
5
+ import { router } from "../lib/hono";
6
+ import { fail } from "../lib/result";
7
+ import { noTimeout } from "../middleware/no-timeout";
8
+ import { logEvent } from "../services/agent";
9
+ import {
10
+ cascadeClip,
11
+ commitTurn,
12
+ endCascade,
13
+ hasCascade,
14
+ resolveUiCall,
15
+ runTurn,
16
+ startCascade,
17
+ sttSocket,
18
+ } from "../services/agent-cascade";
19
+ import { emptyBody } from "../../shared/schemas/common";
20
+ import {
21
+ cascadeLogBody,
22
+ cascadeSessionBody,
23
+ cascadeTurnBody,
24
+ cascadeUiResultBody,
25
+ } from "../../shared/schemas/agent-cascade";
26
+
27
+ export const agentCascade = router()
28
+ .post("/agent/cascade/session", json(cascadeSessionBody), async c => {
29
+ try {
30
+ const b = c.req.valid("json");
31
+ return c.json({ ok: true as const, ...(await startCascade(b.mode, b.history)) });
32
+ } catch (e) {
33
+ return fail(c, String((e as Error)?.message ?? e));
34
+ }
35
+ })
36
+ .post("/agent/cascade/:id/stt", json(emptyBody), async c => {
37
+ if (!hasCascade(c.req.param("id"))) return fail(c, "sessão desconhecida");
38
+ try {
39
+ return c.json({ ok: true as const, ...(await sttSocket()) });
40
+ } catch (e) {
41
+ return fail(c, String((e as Error)?.message ?? e));
42
+ }
43
+ })
44
+ /* one NDJSON line per event; the page aborting the request (the user spoke over Omni) stops the turn */
45
+ .post("/agent/cascade/:id/turn", noTimeout, json(cascadeTurnBody), c => {
46
+ const id = c.req.param("id");
47
+ const { text, speculative, screen } = c.req.valid("json");
48
+ const ctrl = new AbortController();
49
+ c.req.raw.signal.addEventListener("abort", () => ctrl.abort());
50
+ const enc = new TextEncoder();
51
+ const body = new ReadableStream<Uint8Array>({
52
+ async start(stream) {
53
+ let open = true;
54
+ await runTurn(
55
+ id,
56
+ text,
57
+ ctrl.signal,
58
+ e => {
59
+ if (!open) return;
60
+ try {
61
+ stream.enqueue(enc.encode(`${JSON.stringify(e)}\n`));
62
+ } catch {
63
+ open = false;
64
+ }
65
+ },
66
+ speculative === true,
67
+ screen,
68
+ );
69
+ if (open) stream.close();
70
+ },
71
+ cancel() {
72
+ ctrl.abort();
73
+ },
74
+ });
75
+ return new Response(body, { headers: { "content-type": "application/x-ndjson", "cache-control": "no-store" } });
76
+ })
77
+ /* the speculative turn in flight was right: the user had finished */
78
+ .post("/agent/cascade/:id/commit", json(emptyBody), c => c.json({ ok: commitTurn(c.req.param("id")) }))
79
+ .post("/agent/cascade/:id/ui-result", json(cascadeUiResultBody), c => {
80
+ const b = c.req.valid("json");
81
+ return c.json({ ok: resolveUiCall(c.req.param("id"), b.call_id, b.output) });
82
+ })
83
+ /* "Ainda tá aí?" and the goodbye, in Omni's voice (raw PCM16 24 kHz) */
84
+ .get("/agent/cascade/:id/clip/:name", async c => {
85
+ try {
86
+ const pcm = await cascadeClip(c.req.param("id"), c.req.param("name"));
87
+ return new Response(new Blob([pcm as Uint8Array<ArrayBuffer>]), {
88
+ headers: { "content-type": "application/octet-stream", "cache-control": "no-store" },
89
+ });
90
+ } catch (e) {
91
+ return fail(c, String((e as Error)?.message ?? e));
92
+ }
93
+ })
94
+ .post("/agent/cascade/:id/log", json(cascadeLogBody), c => {
95
+ const id = c.req.param("id");
96
+ const b = c.req.valid("json");
97
+ if (b.type === "end") endCascade(id, b.duration_s, b.stt_audio_s, b.reason);
98
+ else logEvent({ session: id, ...b, ...(b.type === "turn" ? { mode: "cascade" } : {}) });
99
+ return c.json({ ok: true as const });
100
+ });
@@ -0,0 +1,23 @@
1
+ /* Omni's conversation history (services/agent-history.ts): the list, one conversation, the browser's
2
+ save as the call goes, and deleting one. */
3
+
4
+ import { json } from "../lib/validate";
5
+ import { router } from "../lib/hono";
6
+ import { fail, result } from "../lib/result";
7
+ import { notFound } from "../lib/errors";
8
+ import { deleteConversation, getConversation, listConversations, saveConversation } from "../services/agent-history";
9
+ import { emptyBody } from "../../shared/schemas/common";
10
+ import { conversationSaveBody } from "../../shared/schemas/agent-history";
11
+
12
+ export const agentHistory = router()
13
+ .get("/agent/conversations", c => c.json(listConversations()))
14
+ .get("/agent/conversations/:id", c => {
15
+ const conv = getConversation(c.req.param("id"));
16
+ if (!conv) throw notFound();
17
+ return c.json(conv);
18
+ })
19
+ .post("/agent/conversations/:id", json(conversationSaveBody), c => {
20
+ const r = saveConversation(c.req.param("id"), c.req.valid("json"));
21
+ return r.ok ? c.json(r) : fail(c, r.error);
22
+ })
23
+ .post("/agent/conversations/:id/delete", json(emptyBody), c => result(c, deleteConversation(c.req.param("id"))));