@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,743 @@
1
+ /* Omni, a panel that opens from the sidebar's Omni button (the avatar chosen in the settings, always the same
2
+ color; components/Sidebar) and whose top bar drags it to any edge. Open, it has just the avatar and the name in the center
3
+ (the saved greeting plays as it opens; the avatar starts the conversation) and a gear for the
4
+ settings: Omni's avatar and voice. Once the conversation is live: status, transcript with the tools called, the action
5
+ waiting for "Confirmar" and a text field. It lives in the app shell, so the conversation goes on while the
6
+ user moves between screens. The measurements are the /agent page.
7
+
8
+ Conversas (the clock button, outside a call): the earlier conversations that had a genuine request,
9
+ to read again or continue. Waiting (wait_for_work): the call sleeps with only the microphone open,
10
+ the avatar dimmed, until the user speaks or the studio's work ends.
11
+
12
+ Two modes. Voice: Grok Voice, live, up to the day's quota (agent.limits.daily_voice_min).
13
+ Claude: past the quota, the user speaks (or types), the speech is transcribed and the user's own
14
+ Claude answers in text; it costs almost nothing. */
15
+
16
+ import { useEffect, useRef, useState } from "react";
17
+ import { Link } from "@tanstack/react-router";
18
+ import { useAvatarAudioReactive } from "../../hooks/useAvatarAudioReactive";
19
+ import { useOmniDock } from "../../hooks/useOmniDock";
20
+ import {
21
+ type ChatAsk,
22
+ omniLevel,
23
+ publishOmniPanel,
24
+ registerOmniAskChat,
25
+ registerOmniLevel,
26
+ registerOmniToggle,
27
+ } from "../../lib/omni-panel";
28
+ import { useOmniGreeting } from "../../hooks/useOmniGreeting";
29
+ import { useNow } from "../../hooks/useNow";
30
+ import { type OmniMode, useAgentInfo, useOmniConversation } from "../../hooks/useOmniAgent";
31
+ import { OMNI_ENGINES } from "../../../shared/omni-admin";
32
+ import { type ClaudeStatus, useOmniClaude } from "../../hooks/useOmniClaude";
33
+ import type { OmniStatus } from "../../lib/omni-realtime";
34
+ import {
35
+ ArrowLeft,
36
+ ChatCircleText,
37
+ Gear,
38
+ History,
39
+ Microphone,
40
+ Minus,
41
+ PaperPlane,
42
+ PhoneDisconnect,
43
+ Stop,
44
+ X,
45
+ } from "../icons";
46
+ import { VoiceAvatar } from "../VoiceAvatar";
47
+ import { PendingActions } from "./PendingActions";
48
+ import { OmniCards } from "./OmniCards";
49
+ import { clearCards, useOmniCards } from "../../lib/omni-cards";
50
+ import { Transcript } from "./Transcript";
51
+ import { Tip } from "../ui/tooltip";
52
+ import { OmniBeamFrame, type OmniGlowState, OmniVoice } from "./OmniGlow";
53
+ import { OmniAvatarPicker } from "./OmniAvatarPicker";
54
+ import { OmniMicSelect } from "./OmniMicSelect";
55
+ import { OmniHistory } from "./OmniHistory";
56
+ import { OmniHotword } from "./OmniHotword";
57
+ import { useOmniHotword } from "../../hooks/useOmniHotword";
58
+
59
+ /* Omni's face until one is chosen in the settings: the same drawing and color everywhere, whatever the voice */
60
+ export const OMNI_AVATAR = "omni-ara";
61
+
62
+ /* a call where the user says nothing: Omni asks after this many seconds, and hangs up after these */
63
+ const ASK_AFTER_S = 6;
64
+ const CLOSE_AFTER_S = 10;
65
+ /* the call the panel opened by itself: with no word from the user this long after the greeting, it
66
+ ends quietly and the panel shows its buttons */
67
+ const AUTO_CLOSE_S = 10;
68
+
69
+ /* What is left of today's Grok voice. On top "Minutos de conversa" on the left and the % on the right,
70
+ then the bar (full while there is all of it, empty at the quota) and under it, on the right, the time
71
+ left. */
72
+ function VoiceQuota({ leftS, dailyMin }: { leftS: number; dailyMin: number }) {
73
+ if (dailyMin <= 0) return null;
74
+ const pct = Math.round(Math.max(0, Math.min(1, leftS / (dailyMin * 60))) * 100);
75
+ const left = clock(Math.max(0, leftS) * 1000);
76
+ const label = leftS > 0 ? `Minutos de conversa: ${left} restantes` : "A cota de voz de hoje acabou";
77
+ return (
78
+ <div className={`omni-usage${pct <= 20 ? " low" : ""}`} title={label}>
79
+ <div className="omni-usage-line">
80
+ <span>Minutos de conversa</span>
81
+ <span>{pct}%</span>
82
+ </div>
83
+ <div
84
+ className="omni-meter"
85
+ role="progressbar"
86
+ aria-label={label}
87
+ aria-valuenow={pct}
88
+ aria-valuemin={0}
89
+ aria-valuemax={100}
90
+ >
91
+ <i style={{ width: `${pct}%` }} />
92
+ </div>
93
+ <div className="omni-usage-line end">
94
+ <span>{left} restantes</span>
95
+ </div>
96
+ </div>
97
+ );
98
+ }
99
+
100
+ const STATUS_TEXT: Record<OmniStatus, string> = {
101
+ idle: "Agente de voz",
102
+ connecting: "Conectando…",
103
+ listening: "Ouvindo",
104
+ user: "Você está falando",
105
+ thinking: "Pensando…",
106
+ speaking: "Falando",
107
+ waiting: "Esperando o estúdio",
108
+ error: "A conversa parou",
109
+ };
110
+ const CLAUDE_TEXT: Record<ClaudeStatus, string> = {
111
+ idle: "Modo texto · seu Claude responde",
112
+ recording: "Ouvindo… toque para enviar",
113
+ transcribing: "Transcrevendo…",
114
+ thinking: "O Claude está pensando…",
115
+ };
116
+ /* the bubble's ring in Claude mode, in the voice mode's classes */
117
+ const CLAUDE_BUBBLE: Record<ClaudeStatus, OmniStatus> = {
118
+ idle: "idle",
119
+ recording: "user",
120
+ transcribing: "thinking",
121
+ thinking: "thinking",
122
+ };
123
+
124
+ /* how Omni hears and speaks: the admin picks it for everyone (admin panel, agent.engine); the label
125
+ shows in the call's status line */
126
+ const MODES: { id: OmniMode; label: string }[] = OMNI_ENGINES.map(e => ({
127
+ id: e.id,
128
+ label: e.label,
129
+ }));
130
+
131
+ const clock = (ms: number) => {
132
+ const s = Math.max(0, Math.floor(ms / 1000));
133
+ return `${Math.floor(s / 60)}:${String(s % 60).padStart(2, "0")}`;
134
+ };
135
+
136
+ export function OmniWidget({ menuCollapsed }: { menuCollapsed: boolean }) {
137
+ const { info, error: infoError } = useAgentInfo();
138
+ /* Omni's face, as chosen in the settings */
139
+ const face = info?.config.avatar ?? OMNI_AVATAR;
140
+ const [quotaHit, setQuotaHit] = useState(false);
141
+ /* the engine the admin picked, for every user (admin panel) */
142
+ const mode: OmniMode = info?.config.engine ?? "grok";
143
+ const grokOn = mode === "grok";
144
+ const conv = useOmniConversation({ onQuota: () => setQuotaHit(true) });
145
+ const claude = useOmniClaude();
146
+ const [open, setOpen] = useState(false);
147
+ const [settings, setSettings] = useState(false);
148
+ /* the Conversas list in place of the stage */
149
+ const [history, setHistory] = useState(false);
150
+ /* the chat (transcript and text field) is closed by default; the chat button opens it */
151
+ const [chatOpen, setChatOpen] = useState(false);
152
+ const greeting = useOmniGreeting();
153
+ const [text, setText] = useState("");
154
+ const root = useRef<HTMLDivElement>(null);
155
+ const live = conv.status !== "idle" && conv.status !== "error";
156
+ /* what Omni showed in the panel (show_card) goes away with the call */
157
+ const cards = useOmniCards();
158
+ useEffect(() => {
159
+ if (!live) clearCards();
160
+ }, [live]);
161
+ useEffect(() => {
162
+ if (!live) setChatOpen(false);
163
+ }, [live]);
164
+ /* the admin switched Omni off or moved it to another engine: the call on the old one ends here */
165
+ const { stop: stopCall } = conv;
166
+ useEffect(() => {
167
+ if (live && info && (!info.config.enabled || info.config.engine !== conv.mode)) stopCall();
168
+ }, [live, info, conv.mode, stopCall]);
169
+ /* the voice quota is Grok's: the cascade modes go on past it */
170
+ const claudeMode = !live && mode === "grok" && (quotaHit || (!!info && info.voice_left_s <= 0));
171
+ const now = useNow(1000);
172
+ const elapsed = conv.startedAt ? now - conv.startedAt : 0;
173
+ /* The avatar follows the sound wave: Omni's voice while it speaks (the avatar grows a little with
174
+ it) and the user's while Omni listens (it shrinks a little), in a voice conversation and in Claude
175
+ mode alike. In silence it stays at its size. */
176
+ const analyser = useRef<AnalyserNode | null>(null);
177
+ const speaking = greeting.playing || (!claudeMode && conv.status === "speaking");
178
+ const listening = claudeMode ? claude.status === "recording" : conv.status === "listening" || conv.status === "user";
179
+ analyser.current = speaking
180
+ ? greeting.playing
181
+ ? greeting.analyser.current
182
+ : conv.analyser.current
183
+ : claudeMode
184
+ ? claude.analyser.current
185
+ : conv.micAnalyser.current;
186
+ /* Omni's own voice (the greeting or the call), for the glow while it speaks. The analyser's frequency data
187
+ is smoothed over several frames (it would blur the wave), so the level is read from the raw waveform: the
188
+ RMS of the last ~20 ms, with gain and a square root, so quiet syllables already move it and loud ones
189
+ reach the top (voice-glow's own attack and release do the rest). */
190
+ const voiceAnalyser = useRef<AnalyserNode | null>(null);
191
+ voiceAnalyser.current = greeting.playing ? greeting.analyser.current : conv.analyser.current;
192
+ useEffect(() => {
193
+ let wave: Uint8Array<ArrayBuffer> | null = null;
194
+ registerOmniLevel(() => {
195
+ const an = voiceAnalyser.current;
196
+ if (!an) return 0;
197
+ if (wave?.length !== an.fftSize) wave = new Uint8Array(an.fftSize);
198
+ an.getByteTimeDomainData(wave);
199
+ let sum = 0;
200
+ for (let i = 0; i < wave.length; i++) {
201
+ const v = (wave[i] - 128) / 128;
202
+ sum += v * v;
203
+ }
204
+ return Math.min(1, Math.sqrt(Math.sqrt(sum / wave.length) * 5));
205
+ });
206
+ return () => registerOmniLevel(null);
207
+ }, []);
208
+ useAvatarAudioReactive(
209
+ speaking || listening,
210
+ root,
211
+ analyser,
212
+ /* the panel's avatars and the sidebar button's */
213
+ () =>
214
+ Array.from(document.querySelectorAll<HTMLCanvasElement>(".omni-widget .voice-avatar, .menu-omni .voice-avatar")),
215
+ speaking ? "up" : "down",
216
+ );
217
+
218
+ /* an action waiting for Confirmar opens the panel: the button has to be seen */
219
+ const pendingCount = conv.pending.length;
220
+ useEffect(() => {
221
+ if (pendingCount) setOpen(true);
222
+ }, [pendingCount]);
223
+ const collapse = () => {
224
+ greeting.stop();
225
+ setSettings(false);
226
+ setHistory(false);
227
+ setOpen(false);
228
+ };
229
+ /* Esc collapses (the conversation goes on) */
230
+ useEffect(() => {
231
+ if (!open) return;
232
+ const esc = (e: KeyboardEvent) => {
233
+ if (e.key === "Escape") collapse();
234
+ };
235
+ window.addEventListener("keydown", esc);
236
+ return () => window.removeEventListener("keydown", esc);
237
+ }, [open]);
238
+ /* Opening the panel starts the conversation by itself, with the recorded greeting as Omni's first words
239
+ (the voice sample, no model behind it), said through the call: the microphone is open from the start
240
+ and the user can talk over it, which stops it and is heard like any turn. If the user says nothing for
241
+ AUTO_CLOSE_S after it, the call ends quietly and the panel shows Começar and Conversas. Not over a live
242
+ conversation, nor with Omni unavailable or in Claude mode (the voice quota is over): there the greeting
243
+ alone plays, outside any call, as before. */
244
+ const [autoCall, setAutoCall] = useState(false);
245
+ const toggle = () => {
246
+ if (open) return collapse();
247
+ setOpen(true);
248
+ if (live || !info) return;
249
+ if (!info.config.enabled || unavailable || claudeMode) return greeting.play(info.config.gender);
250
+ setAutoCall(true);
251
+ void conv.start(mode, undefined, { greet: info.config.gender, holdIdle: true });
252
+ };
253
+ /* the sidebar's button opens and closes the panel; it shows the ring and the face from here */
254
+ const toggleRef = useRef(toggle);
255
+ toggleRef.current = toggle;
256
+ useEffect(() => {
257
+ registerOmniToggle(() => toggleRef.current());
258
+ return () => registerOmniToggle(null);
259
+ }, []);
260
+ const startConversation = () => {
261
+ greeting.stop();
262
+ setAutoCall(false);
263
+ void conv.start(mode);
264
+ };
265
+
266
+ const submit = () => {
267
+ if (!text.trim()) return;
268
+ /* typing is using the chat: it stays open even if Omni opened it */
269
+ askedChat.current = null;
270
+ if (claudeMode) claude.sendText(text);
271
+ else conv.sendText(text);
272
+ setText("");
273
+ };
274
+ const status = claudeMode
275
+ ? CLAUDE_TEXT[claude.status]
276
+ : live
277
+ ? `${STATUS_TEXT[conv.status]} · ${clock(elapsed)} · ${MODES.find(m => m.id === conv.mode)?.label ?? ""}`
278
+ : STATUS_TEXT[conv.status];
279
+ const unavailable = infoError ?? info?.error ?? null;
280
+ /* A call starts and the user says nothing: at ASK_AFTER_S Omni asks, with the recorded "no que posso
281
+ ajudar?"; at CLOSE_AFTER_S it hangs up. The microphone is muted while the clip plays (it is not on the
282
+ call's output, so echo cancellation can't take it out) and goes back as it was. */
283
+ const userSpoke = conv.status === "user" || conv.entries.some(e => e.kind === "user");
284
+ const callOn = live && conv.status !== "connecting";
285
+ const mutedForPrompt = useRef(false);
286
+ /* the timers fire seconds after the effect ran: they read what is current then, not what was */
287
+ const latest = useRef({ conv, info, greeting });
288
+ latest.current = { conv, info, greeting };
289
+ useEffect(() => {
290
+ /* the cascade modes ask and hang up on their own, in their own voice (lib/omni-cascade) */
291
+ if (!callOn || userSpoke || autoCall || conv.mode !== "grok") return;
292
+ const ask = setTimeout(() => {
293
+ const { conv: c, info: i, greeting: g } = latest.current;
294
+ if (!i) return;
295
+ if (!c.muted) {
296
+ c.setMuted(true);
297
+ mutedForPrompt.current = true;
298
+ }
299
+ g.play(i.config.gender, "prompt");
300
+ }, ASK_AFTER_S * 1000);
301
+ const close = setTimeout(() => latest.current.conv.stop(), CLOSE_AFTER_S * 1000);
302
+ return () => {
303
+ clearTimeout(ask);
304
+ clearTimeout(close);
305
+ };
306
+ }, [callOn, userSpoke, autoCall, conv.mode]);
307
+ const { playing: greetingPlaying } = greeting;
308
+ useEffect(() => {
309
+ if (!greetingPlaying && mutedForPrompt.current) {
310
+ mutedForPrompt.current = false;
311
+ latest.current.conv.setMuted(false);
312
+ }
313
+ }, [greetingPlaying]);
314
+ /* the call the panel opened: once the user speaks it is a conversation like any other (the engine's
315
+ own silence handling comes back); in silence after the greeting, it ends quietly */
316
+ const { holdIdle, discard } = conv;
317
+ useEffect(() => {
318
+ if (!autoCall) return;
319
+ if (conv.status === "error") return setAutoCall(false);
320
+ if (userSpoke) {
321
+ holdIdle(false);
322
+ return setAutoCall(false);
323
+ }
324
+ /* counted from when the greeting ended and Omni listens */
325
+ if (conv.status !== "listening") return;
326
+ const close = setTimeout(() => {
327
+ discard();
328
+ setAutoCall(false);
329
+ }, AUTO_CLOSE_S * 1000);
330
+ return () => clearTimeout(close);
331
+ }, [autoCall, conv.status, userSpoke, holdIdle, discard]);
332
+ /* "Oi, Omni" (the switch in the settings): starts the conversation the way opening the panel does (a
333
+ silent call ends by itself); in Claude mode it starts the recording. With the menu expanded the call
334
+ starts minimized, living in the sidebar card (its icon or a click opens the dock); with the menu
335
+ collapsed there is no card to show it, so the dock opens. Claude mode always opens it: the
336
+ recording's button is there. It sleeps while Omni talks. */
337
+ const callByVoice = () => {
338
+ if (live || !info?.config.enabled || unavailable) return;
339
+ greeting.stop();
340
+ setSettings(false);
341
+ setHistory(false);
342
+ if (menuCollapsed || claudeMode) setOpen(true);
343
+ if (claudeMode) {
344
+ if (claude.status === "idle") void claude.toggleRecording();
345
+ return;
346
+ }
347
+ setAutoCall(true);
348
+ void conv.start(mode, undefined, { greet: info.config.gender, holdIdle: true });
349
+ };
350
+ const hotword = useOmniHotword({
351
+ available: !!info?.config.enabled && !unavailable,
352
+ busy: live || conv.status === "connecting" || greeting.playing || claude.status !== "idle",
353
+ onCall: callByVoice,
354
+ });
355
+ /* in Claude mode the text is the whole conversation, so the chat is always there */
356
+ const chatShown = claudeMode || chatOpen;
357
+ /* the chat open in a call: the dock grows, the avatar and the name go up to the corner, in a line */
358
+ const chatMode = live && chatOpen && !settings;
359
+ const entries = [...conv.entries, ...claude.entries];
360
+ const claudeBusy = claude.status === "transcribing" || claude.status === "thinking";
361
+ const bubble = claudeMode ? CLAUDE_BUBBLE[claude.status] : conv.status;
362
+ /* the panel's top bar drags it to one of the four corners; the corner is remembered */
363
+ const dock = useOmniDock(open);
364
+ /* ask_in_chat: Omni needs a link or a text, so the chat opens with the field focused. It was opened for
365
+ that, so the first thing the user says by voice (a no, another direction) closes it again; typing or
366
+ closing it by hand makes it the user's. askedChat holds the user messages already there. */
367
+ const askedChat = useRef<Set<string> | null>(null);
368
+ const inputRef = useRef<HTMLInputElement>(null);
369
+ const [focusInput, setFocusInput] = useState(0);
370
+ const [asking, setAsking] = useState<ChatAsk | null>(null);
371
+ const userIds = () => new Set(entries.filter(e => e.kind === "user").map(e => e.id));
372
+ const askRef = useRef<(what: ChatAsk) => boolean>(() => false);
373
+ askRef.current = what => {
374
+ if (!live) return false;
375
+ greeting.stop();
376
+ askedChat.current = userIds();
377
+ setSettings(false);
378
+ setHistory(false);
379
+ setOpen(true);
380
+ setChatOpen(true);
381
+ setAsking(what);
382
+ setFocusInput(n => n + 1);
383
+ return true;
384
+ };
385
+ useEffect(() => {
386
+ registerOmniAskChat(what => askRef.current(what));
387
+ return () => registerOmniAskChat(null);
388
+ }, []);
389
+ useEffect(() => {
390
+ if (focusInput && chatMode) inputRef.current?.focus();
391
+ }, [focusInput, chatMode]);
392
+ const spoken = conv.entries;
393
+ useEffect(() => {
394
+ const seen = askedChat.current;
395
+ if (!seen || !spoken.some(e => e.kind === "user" && !seen.has(e.id))) return;
396
+ askedChat.current = null;
397
+ setAsking(null);
398
+ setChatOpen(false);
399
+ }, [spoken]);
400
+ useEffect(() => {
401
+ if (!chatOpen) {
402
+ askedChat.current = null;
403
+ setAsking(null);
404
+ }
405
+ }, [chatOpen]);
406
+ const available = !info || info.config.enabled || live;
407
+ /* the light around the card (and the sidebar button): Omni's voice in the avatar's colors while it
408
+ speaks, a turning gray beam while it thinks, a black line while it listens; none outside a call */
409
+ const glow: OmniGlowState = speaking
410
+ ? "speaking"
411
+ : bubble === "thinking" || bubble === "connecting"
412
+ ? "thinking"
413
+ : bubble === "listening" || bubble === "user" || bubble === "waiting"
414
+ ? "listening"
415
+ : "off";
416
+ useEffect(() => {
417
+ publishOmniPanel({
418
+ available,
419
+ face: info ? face : null,
420
+ open,
421
+ ring: bubble,
422
+ glow,
423
+ });
424
+ }, [available, info, face, open, bubble, glow]);
425
+ /* while the agent works without speaking, the name gives way to a shimmering "pensando…" */
426
+ const omniName = bubble === "thinking" ? <b className="omni-name-thinking">Pensando…</b> : <b>Omni</b>;
427
+ /* agent.enabled false: Omni is off, no button and no panel (a live conversation still ends normally) */
428
+ if (info && !info.config.enabled && !live) return null;
429
+
430
+ const textForm = (
431
+ <form
432
+ className="omni-text"
433
+ onSubmit={e => {
434
+ e.preventDefault();
435
+ submit();
436
+ }}
437
+ >
438
+ <div className="omni-input">
439
+ <input
440
+ value={text}
441
+ onChange={e => setText(e.target.value)}
442
+ ref={inputRef}
443
+ placeholder={asking === "link" ? "Cole o link…" : asking === "text" ? "Escreva o texto…" : "Escreva ou cole…"}
444
+ aria-label="Mensagem para o Omni"
445
+ disabled={(claudeMode && claudeBusy) || conv.status === "connecting"}
446
+ />
447
+ <Tip label="Enviar">
448
+ <button
449
+ className="omni-send"
450
+ type="submit"
451
+ disabled={!text.trim() || (claudeMode && claudeBusy)}
452
+ aria-label="Enviar"
453
+ >
454
+ <PaperPlane />
455
+ </button>
456
+ </Tip>
457
+ </div>
458
+ </form>
459
+ );
460
+
461
+ /* Ajustes ends the call: the greeting (or the conversation) stops and the line hangs up, so the settings
462
+ open on a quiet panel, with the avatar picker free (it is locked while the call is live) */
463
+ const openSettings = () => {
464
+ greeting.stop();
465
+ /* a call the panel opened by itself and nobody spoke in leaves quietly, like its own silence timeout */
466
+ if (autoCall && !userSpoke) discard();
467
+ else if (live) conv.stop();
468
+ setAutoCall(false);
469
+ setSettings(true);
470
+ };
471
+ /* the header's buttons, reused when the chat moves the gear next to the close */
472
+ const gearButton = (
473
+ <button
474
+ type="button"
475
+ className="mini-button omni-icon-button outlined"
476
+ onClick={openSettings}
477
+ aria-label="Configurar o Omni"
478
+ title="Ajustes do Omni"
479
+ >
480
+ <Gear />
481
+ </button>
482
+ );
483
+ /* Minimize (in a call): the panel goes away and the call goes on in the sidebar button alone, which
484
+ carries the same light; the button brings the panel back. Close: ends the call, if there is one. */
485
+ const minimizeButton = live && (
486
+ <button
487
+ type="button"
488
+ className="mini-button omni-icon-button ghost"
489
+ onClick={collapse}
490
+ aria-label="Minimizar o Omni"
491
+ title="Minimizar · a conversa segue no menu (Esc)"
492
+ >
493
+ <Minus />
494
+ </button>
495
+ );
496
+ const closeButton = (
497
+ <button
498
+ type="button"
499
+ className="mini-button omni-icon-button ghost"
500
+ onClick={() => {
501
+ if (live) conv.stop();
502
+ collapse();
503
+ }}
504
+ aria-label={live ? "Encerrar e fechar o Omni" : "Fechar o Omni"}
505
+ title={live ? "Encerrar a conversa e fechar" : "Fechar"}
506
+ >
507
+ <X />
508
+ </button>
509
+ );
510
+ const windowButtons = (
511
+ <span className="omni-top-actions">
512
+ {minimizeButton}
513
+ {closeButton}
514
+ </span>
515
+ );
516
+
517
+ return (
518
+ <div ref={root} className={`omni-widget${open ? " open" : ""}${dock.dragging ? " dragging" : ""}`}>
519
+ {open && (
520
+ <OmniBeamFrame state={glow} radius={16} className="omni-dock" style={dock.cardStyle}>
521
+ <section
522
+ className={`omni-panel ${bubble}${settings ? " settings" : ""}${chatMode ? " chat" : ""}`}
523
+ aria-label="Omni"
524
+ >
525
+ {/* the voice glow rises from the bottom of this block, so it sits above the footer's buttons */}
526
+ <OmniVoice
527
+ active={glow === "speaking"}
528
+ face={face}
529
+ level={omniLevel}
530
+ radius={0}
531
+ frost
532
+ className="omni-voice"
533
+ >
534
+ <header className="omni-panel-top" onPointerDown={dock.start}>
535
+ {settings || history ? (
536
+ <>
537
+ <button
538
+ type="button"
539
+ className="mini-button omni-icon-button ghost back"
540
+ onClick={() => {
541
+ setSettings(false);
542
+ setHistory(false);
543
+ }}
544
+ aria-label="Voltar"
545
+ title="Voltar"
546
+ >
547
+ <ArrowLeft />
548
+ </button>
549
+ <b className="omni-panel-heading">{settings ? "Ajustes do Omni" : "Conversas"}</b>
550
+ </>
551
+ ) : chatMode ? (
552
+ <div className="omni-inline-id">
553
+ <VoiceAvatar seed={face} size={36} />
554
+ {omniName}
555
+ </div>
556
+ ) : (
557
+ gearButton
558
+ )}
559
+ {chatMode ? (
560
+ <span className="omni-top-actions">
561
+ {gearButton}
562
+ {minimizeButton}
563
+ {closeButton}
564
+ </span>
565
+ ) : (
566
+ windowButtons
567
+ )}
568
+ </header>
569
+
570
+ {settings ? (
571
+ <div className="omni-panel-body">
572
+ {info && <OmniAvatarPicker avatar={info.config.avatar} gender={info.config.gender} disabled={live} />}
573
+ {info && grokOn && (
574
+ <VoiceQuota leftS={info.voice_left_s} dailyMin={info.config.limits.daily_voice_min} />
575
+ )}
576
+ <OmniHotword on={hotword.on} onChange={hotword.setOn} status={hotword.status} error={hotword.error} />
577
+ <Link to="/agent" className="omni-measures subtle" onClick={collapse}>
578
+ Ver as medições do Omni
579
+ </Link>
580
+ </div>
581
+ ) : history ? (
582
+ <div className="omni-panel-body">
583
+ <OmniHistory
584
+ canContinue={!live}
585
+ onContinue={c => {
586
+ setHistory(false);
587
+ greeting.stop();
588
+ void conv.start(mode, c);
589
+ setChatOpen(true);
590
+ }}
591
+ />
592
+ </div>
593
+ ) : (
594
+ <>
595
+ {!chatMode && (
596
+ <div className="omni-stage">
597
+ {live || claudeMode ? (
598
+ <VoiceAvatar seed={face} size={claudeMode ? 104 : 136} />
599
+ ) : (
600
+ <button
601
+ type="button"
602
+ className="omni-stage-avatar"
603
+ onClick={() =>
604
+ greeting.playing ? greeting.stop() : info && greeting.play(info.config.gender)
605
+ }
606
+ disabled={!info}
607
+ aria-label={greeting.playing ? "Parar a voz do Omni" : "Ouvir a voz do Omni"}
608
+ title={greeting.playing ? "Parar" : "Ouvir a voz do Omni"}
609
+ >
610
+ <VoiceAvatar seed={face} size={136} />
611
+ </button>
612
+ )}
613
+ {omniName}
614
+ {claudeMode && <small>{status}</small>}
615
+ {conv.status === "waiting" && <small>Esperando o estúdio · é só falar para me chamar</small>}
616
+ </div>
617
+ )}
618
+
619
+ {(claudeMode ||
620
+ conv.pending.length > 0 ||
621
+ cards.length > 0 ||
622
+ (chatShown && (live || entries.length > 0))) && (
623
+ <div className="omni-panel-body">
624
+ {claudeMode && (
625
+ <p className="omni-quota">
626
+ A cota de voz de hoje acabou ({info?.config.limits.daily_voice_min ?? 0} min). Agora você
627
+ fala, eu transcrevo e o seu Claude responde por texto.
628
+ </p>
629
+ )}
630
+ <PendingActions actions={conv.pending} onResolve={conv.resolve} />
631
+ <OmniCards />
632
+ {chatShown && (
633
+ <Transcript
634
+ entries={entries}
635
+ onFeedback={(item, v) =>
636
+ item.startsWith("c-") ? claude.feedback(item, v) : conv.feedback(item, v)
637
+ }
638
+ />
639
+ )}
640
+ </div>
641
+ )}
642
+ </>
643
+ )}
644
+ </OmniVoice>
645
+ {!settings && !history && (
646
+ <footer className="omni-panel-bottom">
647
+ {claudeMode && (
648
+ <>
649
+ {textForm}
650
+ <button
651
+ type="button"
652
+ className={`button ${claude.status === "recording" ? "danger" : "primary"}`}
653
+ onClick={() => void claude.toggleRecording()}
654
+ disabled={claudeBusy}
655
+ >
656
+ {claude.status === "recording" ? (
657
+ <Stop weight="fill" className="ic" />
658
+ ) : (
659
+ <Microphone className="ic" />
660
+ )}
661
+ {claude.status === "recording"
662
+ ? "Enviar agora"
663
+ : claudeBusy
664
+ ? CLAUDE_TEXT[claude.status]
665
+ : "Falar"}
666
+ </button>
667
+ </>
668
+ )}
669
+ {/* chat, [the message field in chat mode], mute, hang up (the wider one) */}
670
+ <div className={`omni-start${chatMode ? " chat" : ""}`}>
671
+ {!claudeMode && (live || entries.length > 0) && (
672
+ <Tip label={chatOpen ? "Fechar o chat" : "Abrir o chat"}>
673
+ <button
674
+ type="button"
675
+ className={`mini-button omni-icon-button outlined${chatOpen ? " on" : ""}`}
676
+ onClick={() => setChatOpen(o => !o)}
677
+ aria-pressed={chatOpen}
678
+ aria-label={chatOpen ? "Fechar o chat" : "Abrir o chat"}
679
+ >
680
+ {chatOpen ? <ArrowLeft /> : <ChatCircleText />}
681
+ </button>
682
+ </Tip>
683
+ )}
684
+ {chatMode && textForm}
685
+ {!live && !claudeMode && (
686
+ <Tip label="Conversas">
687
+ <button
688
+ type="button"
689
+ className="mini-button omni-icon-button outlined"
690
+ onClick={() => {
691
+ greeting.stop();
692
+ setSettings(false);
693
+ setHistory(true);
694
+ }}
695
+ aria-label="Conversas"
696
+ >
697
+ <History />
698
+ </button>
699
+ </Tip>
700
+ )}
701
+ {!live && !claudeMode && (
702
+ <button
703
+ type="button"
704
+ className="button"
705
+ onClick={startConversation}
706
+ disabled={!info || !!unavailable}
707
+ >
708
+ Começar
709
+ </button>
710
+ )}
711
+ <OmniMicSelect
712
+ inCall={live}
713
+ muted={conv.muted}
714
+ onToggleMute={() => conv.setMuted(!conv.muted)}
715
+ muteDisabled={conv.status === "connecting"}
716
+ />
717
+ {live && (
718
+ <Tip label="Encerrar a conversa">
719
+ <button
720
+ type="button"
721
+ className="mini-button omni-icon-button outlined danger hangup"
722
+ onClick={() => {
723
+ setAutoCall(false);
724
+ conv.stop();
725
+ }}
726
+ aria-label="Encerrar a conversa"
727
+ >
728
+ <PhoneDisconnect />
729
+ </button>
730
+ </Tip>
731
+ )}
732
+ </div>
733
+ {(conv.error || claude.error || unavailable) && (
734
+ <p className="response error">{conv.error ?? claude.error ?? unavailable}</p>
735
+ )}
736
+ </footer>
737
+ )}
738
+ </section>
739
+ </OmniBeamFrame>
740
+ )}
741
+ </div>
742
+ );
743
+ }