vibefast-cli 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 (250) hide show
  1. package/FINAL-STATUS.md +144 -0
  2. package/HOW-IT-WORKS.md +559 -0
  3. package/PLAN.md +453 -0
  4. package/README.md +129 -0
  5. package/RECIPES-READY.md +172 -0
  6. package/STATUS.md +199 -0
  7. package/SUCCESS.md +259 -0
  8. package/TESTING-CHECKLIST.md +450 -0
  9. package/cloudflare-worker/.wrangler/state/v3/kv/64907821e2634080acce34618d2f3d4c/blobs/11f2769953c717e188062bc644da97c1fd1e4d6d0813a226ce7567dba759afab0000019a736fb8d4 +1 -0
  10. package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite +0 -0
  11. package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite-shm +0 -0
  12. package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite-wal +0 -0
  13. package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite +0 -0
  14. package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite-shm +0 -0
  15. package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite-wal +0 -0
  16. package/cloudflare-worker/.wrangler/state/v3/r2/vibefast-recipes/blobs/620e8cf7c35d9806da25dee237e1d7e8b2432bd98f755b60e2c7f08a48d2c7b90000019a73736484 +0 -0
  17. package/cloudflare-worker/MIGRATION.md +160 -0
  18. package/cloudflare-worker/QUICKSTART.md +200 -0
  19. package/cloudflare-worker/README.md +242 -0
  20. package/cloudflare-worker/generate-token.js +32 -0
  21. package/cloudflare-worker/mini-native@latest.zip +0 -0
  22. package/cloudflare-worker/setup.sh +143 -0
  23. package/cloudflare-worker/test-recipe/apps/native/src/app/mini/index.tsx +15 -0
  24. package/cloudflare-worker/test-recipe/recipe.json +16 -0
  25. package/cloudflare-worker/worker.js +308 -0
  26. package/cloudflare-worker/wrangler.toml +13 -0
  27. package/dist/commands/add.d.ts +3 -0
  28. package/dist/commands/add.d.ts.map +1 -0
  29. package/dist/commands/add.js +149 -0
  30. package/dist/commands/add.js.map +1 -0
  31. package/dist/commands/devices.d.ts +3 -0
  32. package/dist/commands/devices.d.ts.map +1 -0
  33. package/dist/commands/devices.js +35 -0
  34. package/dist/commands/devices.js.map +1 -0
  35. package/dist/commands/doctor.d.ts +3 -0
  36. package/dist/commands/doctor.d.ts.map +1 -0
  37. package/dist/commands/doctor.js +67 -0
  38. package/dist/commands/doctor.js.map +1 -0
  39. package/dist/commands/list.d.ts +3 -0
  40. package/dist/commands/list.d.ts.map +1 -0
  41. package/dist/commands/list.js +40 -0
  42. package/dist/commands/list.js.map +1 -0
  43. package/dist/commands/login.d.ts +3 -0
  44. package/dist/commands/login.d.ts.map +1 -0
  45. package/dist/commands/login.js +23 -0
  46. package/dist/commands/login.js.map +1 -0
  47. package/dist/commands/logout.d.ts +3 -0
  48. package/dist/commands/logout.d.ts.map +1 -0
  49. package/dist/commands/logout.js +16 -0
  50. package/dist/commands/logout.js.map +1 -0
  51. package/dist/commands/remove.d.ts +3 -0
  52. package/dist/commands/remove.d.ts.map +1 -0
  53. package/dist/commands/remove.js +67 -0
  54. package/dist/commands/remove.js.map +1 -0
  55. package/dist/core/__tests__/journal.test.d.ts +2 -0
  56. package/dist/core/__tests__/journal.test.d.ts.map +1 -0
  57. package/dist/core/__tests__/journal.test.js +101 -0
  58. package/dist/core/__tests__/journal.test.js.map +1 -0
  59. package/dist/core/__tests__/validate.test.d.ts +2 -0
  60. package/dist/core/__tests__/validate.test.d.ts.map +1 -0
  61. package/dist/core/__tests__/validate.test.js +53 -0
  62. package/dist/core/__tests__/validate.test.js.map +1 -0
  63. package/dist/core/archive.d.ts +2 -0
  64. package/dist/core/archive.d.ts.map +1 -0
  65. package/dist/core/archive.js +59 -0
  66. package/dist/core/archive.js.map +1 -0
  67. package/dist/core/auth.d.ts +15 -0
  68. package/dist/core/auth.d.ts.map +1 -0
  69. package/dist/core/auth.js +76 -0
  70. package/dist/core/auth.js.map +1 -0
  71. package/dist/core/codemod.d.ts +20 -0
  72. package/dist/core/codemod.d.ts.map +1 -0
  73. package/dist/core/codemod.js +150 -0
  74. package/dist/core/codemod.js.map +1 -0
  75. package/dist/core/fsx.d.ts +12 -0
  76. package/dist/core/fsx.d.ts.map +1 -0
  77. package/dist/core/fsx.js +70 -0
  78. package/dist/core/fsx.js.map +1 -0
  79. package/dist/core/http.d.ts +30 -0
  80. package/dist/core/http.d.ts.map +1 -0
  81. package/dist/core/http.js +95 -0
  82. package/dist/core/http.js.map +1 -0
  83. package/dist/core/journal.d.ts +18 -0
  84. package/dist/core/journal.d.ts.map +1 -0
  85. package/dist/core/journal.js +34 -0
  86. package/dist/core/journal.js.map +1 -0
  87. package/dist/core/log.d.ts +8 -0
  88. package/dist/core/log.d.ts.map +1 -0
  89. package/dist/core/log.js +9 -0
  90. package/dist/core/log.js.map +1 -0
  91. package/dist/core/pathGuard.d.ts +3 -0
  92. package/dist/core/pathGuard.d.ts.map +1 -0
  93. package/dist/core/pathGuard.js +18 -0
  94. package/dist/core/pathGuard.js.map +1 -0
  95. package/dist/core/paths.d.ts +11 -0
  96. package/dist/core/paths.d.ts.map +1 -0
  97. package/dist/core/paths.js +22 -0
  98. package/dist/core/paths.js.map +1 -0
  99. package/dist/core/validate.d.ts +8 -0
  100. package/dist/core/validate.d.ts.map +1 -0
  101. package/dist/core/validate.js +27 -0
  102. package/dist/core/validate.js.map +1 -0
  103. package/dist/index.d.ts +3 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +23 -0
  106. package/dist/index.js.map +1 -0
  107. package/docs/decisions.md +55 -0
  108. package/package.json +39 -0
  109. package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
  110. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
  111. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
  112. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
  113. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/index.ts +4 -0
  114. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
  115. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
  116. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
  117. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
  118. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
  119. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
  120. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
  121. package/recipes/audio-recorder/recipe.json +22 -0
  122. package/recipes/audio-recorder@latest.zip +0 -0
  123. package/recipes/charts/apps/native/src/app/charts/index.tsx +3 -0
  124. package/recipes/charts/apps/native/src/features/charts/README.md +185 -0
  125. package/recipes/charts/apps/native/src/features/charts/app/preview.tsx +223 -0
  126. package/recipes/charts/apps/native/src/features/charts/components/area-chart.tsx +40 -0
  127. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +143 -0
  128. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +196 -0
  129. package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +65 -0
  130. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +143 -0
  131. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +246 -0
  132. package/recipes/charts/apps/native/src/features/charts/components/index.ts +10 -0
  133. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +308 -0
  134. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +180 -0
  135. package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +188 -0
  136. package/recipes/charts/apps/native/src/features/charts/components/stacked-area-chart.tsx +265 -0
  137. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +322 -0
  138. package/recipes/charts/apps/native/src/features/charts/data/mock-data.ts +183 -0
  139. package/recipes/charts/apps/native/src/features/charts/types/index.ts +66 -0
  140. package/recipes/charts/recipe.json +22 -0
  141. package/recipes/charts@latest.zip +0 -0
  142. package/recipes/chatbot/apps/native/src/app/chatbot/index.tsx +1 -0
  143. package/recipes/chatbot/apps/native/src/features/chatbot/app/index.tsx +302 -0
  144. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
  145. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-input-bar.tsx +469 -0
  146. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
  147. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +246 -0
  148. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
  149. package/recipes/chatbot/apps/native/src/features/chatbot/components/image-preview-list.tsx +115 -0
  150. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
  151. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
  152. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
  153. package/recipes/chatbot/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
  154. package/recipes/chatbot/apps/native/src/features/chatbot/components/message-list.tsx +173 -0
  155. package/recipes/chatbot/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
  156. package/recipes/chatbot/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
  157. package/recipes/chatbot/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
  158. package/recipes/chatbot/apps/native/src/features/chatbot/constants/models.ts +20 -0
  159. package/recipes/chatbot/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
  160. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +143 -0
  161. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-config.ts +664 -0
  162. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +359 -0
  163. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
  164. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-conversation.ts +79 -0
  165. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
  166. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
  167. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +207 -0
  168. package/recipes/chatbot/apps/native/src/features/chatbot/models/index.ts +86 -0
  169. package/recipes/chatbot/apps/native/src/features/chatbot/models/models.ts +162 -0
  170. package/recipes/chatbot/apps/native/src/features/chatbot/models/providers.ts +62 -0
  171. package/recipes/chatbot/apps/native/src/features/chatbot/models/types.ts +40 -0
  172. package/recipes/chatbot/apps/native/src/features/chatbot/services/file-uploader.ts +238 -0
  173. package/recipes/chatbot/apps/native/src/features/chatbot/services/message-handler-service.ts +180 -0
  174. package/recipes/chatbot/apps/native/src/features/chatbot/types/index.ts +60 -0
  175. package/recipes/chatbot/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
  176. package/recipes/chatbot/recipe.json +22 -0
  177. package/recipes/chatbot@latest.zip +0 -0
  178. package/recipes/image-generator/apps/native/src/app/image-generator/gallery.tsx +3 -0
  179. package/recipes/image-generator/apps/native/src/app/image-generator/index.tsx +3 -0
  180. package/recipes/image-generator/apps/native/src/features/image-generator/app/_layout.tsx +25 -0
  181. package/recipes/image-generator/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
  182. package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +237 -0
  183. package/recipes/image-generator/apps/native/src/features/image-generator/components/gallery-image.tsx +26 -0
  184. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
  185. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +210 -0
  186. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
  187. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
  188. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
  189. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +93 -0
  190. package/recipes/image-generator/apps/native/src/features/image-generator/models/models.ts +66 -0
  191. package/recipes/image-generator/apps/native/src/features/image-generator/services/image-gallery-service.ts +98 -0
  192. package/recipes/image-generator/apps/native/src/features/image-generator/services/image-save-service.ts +121 -0
  193. package/recipes/image-generator/recipe.json +22 -0
  194. package/recipes/image-generator@latest.zip +0 -0
  195. package/recipes/quiz/apps/native/src/app/quiz/index.tsx +47 -0
  196. package/recipes/quiz/apps/native/src/features/quiz/components/question.tsx +67 -0
  197. package/recipes/quiz/apps/native/src/features/quiz/config.ts +11 -0
  198. package/recipes/quiz/apps/native/src/features/quiz/index.tsx +133 -0
  199. package/recipes/quiz/recipe.json +22 -0
  200. package/recipes/quiz@latest.zip +0 -0
  201. package/recipes/tracker-app/apps/native/src/app/tracker-app/index.tsx +1 -0
  202. package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +108 -0
  203. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/animated-number.tsx +102 -0
  204. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/calorie-card.tsx +66 -0
  205. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/circular-progress.tsx +97 -0
  206. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/floating-add-button.tsx +27 -0
  207. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/macro-card.tsx +80 -0
  208. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/promo-banner.tsx +98 -0
  209. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/recently-logged.tsx +64 -0
  210. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/week-calendar.tsx +68 -0
  211. package/recipes/tracker-app/recipe.json +22 -0
  212. package/recipes/tracker-app@latest.zip +0 -0
  213. package/recipes/upload-all.sh +32 -0
  214. package/recipes/voice-bot/apps/native/src/app/voice-bot/index.tsx +27 -0
  215. package/recipes/voice-bot/apps/native/src/features/voice-bot/README.md +185 -0
  216. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/conversation-status.tsx +76 -0
  217. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/index.ts +4 -0
  218. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/message-input.tsx +98 -0
  219. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/voice-bot-screen.tsx +173 -0
  220. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/voice-controls.tsx +73 -0
  221. package/recipes/voice-bot/apps/native/src/features/voice-bot/index.ts +3 -0
  222. package/recipes/voice-bot/apps/native/src/features/voice-bot/services/index.ts +1 -0
  223. package/recipes/voice-bot/apps/native/src/features/voice-bot/services/use-voice-bot.ts +161 -0
  224. package/recipes/voice-bot/apps/native/src/features/voice-bot/types.ts +29 -0
  225. package/recipes/voice-bot/recipe.json +22 -0
  226. package/recipes/voice-bot@latest.zip +0 -0
  227. package/scripts/create-recipes.mjs +189 -0
  228. package/src/commands/add.ts +183 -0
  229. package/src/commands/devices.ts +38 -0
  230. package/src/commands/doctor.ts +67 -0
  231. package/src/commands/list.ts +45 -0
  232. package/src/commands/login.ts +24 -0
  233. package/src/commands/logout.ts +15 -0
  234. package/src/commands/remove.ts +78 -0
  235. package/src/core/__tests__/journal.test.ts +119 -0
  236. package/src/core/__tests__/validate.test.ts +64 -0
  237. package/src/core/archive.ts +69 -0
  238. package/src/core/auth.ts +103 -0
  239. package/src/core/codemod.ts +211 -0
  240. package/src/core/fsx.ts +80 -0
  241. package/src/core/http.ts +136 -0
  242. package/src/core/journal.ts +64 -0
  243. package/src/core/log.ts +9 -0
  244. package/src/core/pathGuard.ts +22 -0
  245. package/src/core/paths.ts +33 -0
  246. package/src/core/validate.ts +44 -0
  247. package/src/index.ts +27 -0
  248. package/test-critical-cases.mjs +258 -0
  249. package/tsconfig.json +21 -0
  250. package/vitest.config.mts +12 -0
@@ -0,0 +1,185 @@
1
+ # Voice Bot Feature
2
+
3
+ A real-time voice conversation feature powered by ElevenLabs Conversational AI SDK.
4
+
5
+ ## Features
6
+
7
+ - **Real-time Voice Conversations**: Have natural voice conversations with AI
8
+ - **Text Messaging**: Send text messages and contextual updates during conversations
9
+ - **Feedback System**: Provide feedback on AI responses with like/dislike buttons
10
+ - **Connection Status**: Visual indicators for connection status and speaking state
11
+ - **Auto-Cleanup**: Automatically ends conversations when user leaves the screen to prevent resource waste
12
+ - **VibeFast Integration**: Fully integrated with VibeFast theming and component system
13
+
14
+ ## Setup
15
+
16
+ ### 1. ElevenLabs Account Setup
17
+
18
+ 1. Go to [ElevenLabs](https://elevenlabs.io/)
19
+ 2. Create an account or sign in
20
+ 3. Navigate to **Conversational AI** section
21
+ 4. Create a new agent
22
+ 5. Copy the agent ID from your agent settings
23
+
24
+ ### 2. Environment Configuration
25
+
26
+ Add your ElevenLabs agent ID to your environment file:
27
+
28
+ ```bash
29
+ # .env.local
30
+ ELEVENLABS_AGENT_ID=your_agent_id_here
31
+ ```
32
+
33
+ ### 3. Required Dependencies
34
+
35
+ The following dependencies are automatically installed:
36
+
37
+ - `@elevenlabs/react-native` - ElevenLabs React Native SDK
38
+ - `@livekit/react-native-expo-plugin` - WebRTC support for Expo
39
+ - `@config-plugins/react-native-webrtc` - WebRTC configuration plugin
40
+
41
+ ### 4. Permissions
42
+
43
+ The app.config.ts has been updated with the required permissions:
44
+
45
+ **iOS:**
46
+
47
+ - `NSMicrophoneUsageDescription` - For voice input
48
+
49
+ **Android:**
50
+
51
+ - `android.permission.RECORD_AUDIO` - For voice input
52
+ - `android.permission.ACCESS_NETWORK_STATE` - For network connectivity
53
+ - `android.permission.INTERNET` - For internet access
54
+ - `android.permission.MODIFY_AUDIO_SETTINGS` - For audio configuration
55
+ - `android.permission.BLUETOOTH` - For Bluetooth audio devices
56
+
57
+ ## Usage
58
+
59
+ ### Basic Implementation
60
+
61
+ ```tsx
62
+ import { VoiceBotScreen } from '@/features/voice-bot';
63
+
64
+ function MyVoiceBotScreen() {
65
+ return (
66
+ <VoiceBotScreen
67
+ config={{ agentId: 'your-agent-id' }}
68
+ title="Voice Assistant"
69
+ subtitle="Start a conversation with your AI assistant"
70
+ />
71
+ );
72
+ }
73
+ ```
74
+
75
+ ### Custom Hook Usage
76
+
77
+ ```tsx
78
+ import { useVoiceBot } from '@/features/voice-bot';
79
+
80
+ function CustomVoiceBotComponent() {
81
+ const { state, actions, textInput, setTextInput } = useVoiceBot(
82
+ { agentId: 'your-agent-id' },
83
+ {
84
+ onConnect: (conversationId) => {
85
+ console.log('Connected:', conversationId);
86
+ },
87
+ onMessage: (message) => {
88
+ console.log('New message:', message);
89
+ },
90
+ },
91
+ );
92
+
93
+ return (
94
+ <View>
95
+ <Text>Status: {state.status}</Text>
96
+ <Button
97
+ label="Start Conversation"
98
+ onPress={actions.startConversation}
99
+ disabled={state.status !== 'disconnected'}
100
+ />
101
+ </View>
102
+ );
103
+ }
104
+ ```
105
+
106
+ ## Components
107
+
108
+ ### VoiceBotScreen
109
+
110
+ Main screen component that provides a complete voice bot interface.
111
+
112
+ **Props:**
113
+
114
+ - `config: VoiceBotConfig` - Configuration object with agent ID
115
+ - `title?: string` - Screen title (optional)
116
+ - `subtitle?: string` - Screen subtitle (optional)
117
+
118
+ ### ConversationStatusIndicator
119
+
120
+ Displays the current connection status and conversation information.
121
+
122
+ ### VoiceControls
123
+
124
+ Provides start/stop conversation buttons and feedback controls.
125
+
126
+ ### MessageInput
127
+
128
+ Text input component for sending messages and contextual updates.
129
+
130
+ ## Development Build Required
131
+
132
+ **Important**: This feature requires a development build and cannot run in Expo Go due to WebRTC native dependencies.
133
+
134
+ ### Building for Development
135
+
136
+ ```bash
137
+ # Prebuild (required for native dependencies)
138
+ pnpx expo prebuild
139
+
140
+ # iOS
141
+ pnpm ios -d
142
+
143
+ # Android
144
+ pnpm android -d
145
+ ```
146
+
147
+ ### Simulator Audio Settings
148
+
149
+ When running on simulators, adjust audio settings:
150
+
151
+ **iOS Simulator:**
152
+
153
+ - In I/O menu, set correct audio input/output devices
154
+ - Increase volume (defaults to 0)
155
+
156
+ **Android Emulator:**
157
+
158
+ - In Extended Controls, enable "Virtual microphone uses host audio input"
159
+
160
+ ## Architecture
161
+
162
+ The voice bot feature follows VibeFast architecture patterns:
163
+
164
+ - **Services**: `useVoiceBot` hook for state management and API interactions
165
+ - **Components**: Modular UI components following VibeFast design system
166
+ - **Types**: TypeScript interfaces for type safety
167
+ - **Environment**: Secure configuration through environment variables
168
+ - **Lifecycle Management**: Automatic cleanup on component unmount and screen navigation
169
+
170
+ ## Security Considerations
171
+
172
+ - Agent ID is configured through environment variables
173
+ - For production apps, consider generating short-lived signed URLs server-side
174
+ - See [ElevenLabs Authentication Docs](https://elevenlabs.io/docs/conversational-ai/customization/authentication) for advanced security
175
+
176
+ ## Troubleshooting
177
+
178
+ 1. **Build Errors**: Ensure you're using development builds, not Expo Go
179
+ 2. **Audio Issues**: Check simulator audio settings and permissions
180
+ 3. **Connection Issues**: Verify agent ID and network connectivity
181
+ 4. **WebRTC Errors**: Ensure all native dependencies are properly installed
182
+
183
+ ## API Reference
184
+
185
+ See the [ElevenLabs React Native SDK Documentation](https://elevenlabs.io/docs/conversational-ai/libraries/react-native) for detailed API reference.
@@ -0,0 +1,76 @@
1
+ import type { ConversationStatus } from '@elevenlabs/react-native';
2
+ import React from 'react';
3
+ import { View } from 'react-native';
4
+
5
+ import { Text } from '@/components/ui';
6
+
7
+ interface ConversationStatusIndicatorProps {
8
+ status: ConversationStatus;
9
+ conversationId?: string | null;
10
+ isSpeaking?: boolean;
11
+ }
12
+
13
+ export function ConversationStatusIndicator({
14
+ status,
15
+ conversationId,
16
+ isSpeaking,
17
+ }: ConversationStatusIndicatorProps) {
18
+ const getStatusColor = (status: ConversationStatus): string => {
19
+ switch (status) {
20
+ case 'connected':
21
+ return 'bg-success-500';
22
+ case 'connecting':
23
+ return 'bg-warning-500';
24
+ case 'disconnected':
25
+ return 'bg-neutral-400';
26
+ default:
27
+ return 'bg-neutral-400';
28
+ }
29
+ };
30
+
31
+ const getStatusText = (status: ConversationStatus): string => {
32
+ return status.charAt(0).toUpperCase() + status.slice(1);
33
+ };
34
+
35
+ return (
36
+ <View className="items-center gap-4">
37
+ {/* Status Indicator */}
38
+ <View className="flex-row items-center gap-2">
39
+ <View className={`size-3 rounded-full ${getStatusColor(status)}`} />
40
+ <Text className="text-base font-medium text-foreground">
41
+ {getStatusText(status)}
42
+ </Text>
43
+ </View>
44
+
45
+ {/* Conversation ID Display */}
46
+ {status === 'connected' && conversationId && (
47
+ <View className="w-full rounded-lg border border-border bg-muted p-3">
48
+ <Text className="text-mutedForeground mb-1 text-xs font-semibold">
49
+ Conversation ID:
50
+ </Text>
51
+ <Text className="rounded border border-border bg-background p-2 font-mono text-sm text-foreground">
52
+ {conversationId}
53
+ </Text>
54
+ </View>
55
+ )}
56
+
57
+ {/* Speaking Indicator */}
58
+ {status === 'connected' && (
59
+ <View className="flex-row items-center gap-2">
60
+ <View
61
+ className={`size-3 rounded-full ${
62
+ isSpeaking ? 'bg-success' : 'bg-muted'
63
+ }`}
64
+ />
65
+ <Text
66
+ className={`text-sm font-medium ${
67
+ isSpeaking ? 'text-success' : 'text-mutedForeground'
68
+ }`}
69
+ >
70
+ {isSpeaking ? '🎤 AI Speaking' : '👂 AI Listening'}
71
+ </Text>
72
+ </View>
73
+ )}
74
+ </View>
75
+ );
76
+ }
@@ -0,0 +1,4 @@
1
+ export * from './conversation-status';
2
+ export * from './message-input';
3
+ export * from './voice-bot-screen';
4
+ export * from './voice-controls';
@@ -0,0 +1,98 @@
1
+ import React from 'react';
2
+ import { Keyboard, View } from 'react-native';
3
+
4
+ import { Button, Input, Text } from '@/components/ui';
5
+
6
+ interface MessageInputProps {
7
+ value: string;
8
+ onChangeText: (text: string) => void;
9
+ onSendMessage: () => void;
10
+ onSendContext: () => void;
11
+ onUserActivity: () => void;
12
+ isConnected: boolean;
13
+ }
14
+
15
+ export function MessageInput({
16
+ value,
17
+ onChangeText,
18
+ onSendMessage,
19
+ onSendContext,
20
+ onUserActivity,
21
+ isConnected,
22
+ }: MessageInputProps) {
23
+ const handleTextChange = (text: string) => {
24
+ onChangeText(text);
25
+ // Prevent agent from interrupting while user is typing
26
+ if (text.length > 0) {
27
+ onUserActivity();
28
+ }
29
+ };
30
+
31
+ const handleSendMessage = () => {
32
+ if (value.trim()) {
33
+ onSendMessage();
34
+ Keyboard.dismiss();
35
+ }
36
+ };
37
+
38
+ const handleSendContext = () => {
39
+ if (value.trim()) {
40
+ onSendContext();
41
+ Keyboard.dismiss();
42
+ }
43
+ };
44
+
45
+ const handleSubmitEditing = () => {
46
+ handleSendMessage();
47
+ };
48
+
49
+ if (!isConnected) {
50
+ return (
51
+ <View className="rounded-2xl border border-border/50 bg-card/90 p-6 opacity-50 shadow-lg backdrop-blur-md">
52
+ <Text className="text-mutedForeground text-center">
53
+ Connect to start sending messages
54
+ </Text>
55
+ </View>
56
+ );
57
+ }
58
+
59
+ return (
60
+ <View className="rounded-2xl border border-border/50 bg-card/90 p-6 shadow-lg backdrop-blur-md">
61
+ <View className="w-full gap-4">
62
+ <Text className="text-base font-medium text-foreground">
63
+ Send Text Message
64
+ </Text>
65
+
66
+ <Input
67
+ value={value}
68
+ onChangeText={handleTextChange}
69
+ placeholder="Type your message or context..."
70
+ multiline
71
+ numberOfLines={4}
72
+ textAlignVertical="top"
73
+ onSubmitEditing={handleSubmitEditing}
74
+ returnKeyType="send"
75
+ blurOnSubmit={true}
76
+ testID="message-input"
77
+ />
78
+
79
+ <View className="gap-3">
80
+ <Button
81
+ label="💬 Send Message"
82
+ onPress={handleSendMessage}
83
+ disabled={!value.trim()}
84
+ variant="default"
85
+ testID="send-message-button"
86
+ />
87
+ <Button
88
+ label="📝 Send Context"
89
+ onPress={handleSendContext}
90
+ disabled={!value.trim()}
91
+ variant="secondary"
92
+ testID="send-context-button"
93
+ />
94
+ </View>
95
+ </View>
96
+ </View>
97
+ );
98
+ }
@@ -0,0 +1,173 @@
1
+ import { ElevenLabsProvider } from '@elevenlabs/react-native';
2
+ import { BlurView } from 'expo-blur';
3
+ import React from 'react';
4
+ import {
5
+ Keyboard,
6
+ KeyboardAvoidingView,
7
+ Platform,
8
+ StyleSheet,
9
+ TouchableWithoutFeedback,
10
+ View,
11
+ } from 'react-native';
12
+ import Animated, {
13
+ interpolate,
14
+ useAnimatedRef,
15
+ useAnimatedStyle,
16
+ useScrollOffset,
17
+ } from 'react-native-reanimated';
18
+ import type { AnimatedScrollView } from 'react-native-reanimated/lib/typescript/component/ScrollView';
19
+
20
+ import { Text } from '@/components/ui';
21
+
22
+ import { useVoiceBot } from '../services';
23
+ import type { VoiceBotConfig } from '../types';
24
+ import { ConversationStatusIndicator } from './conversation-status';
25
+ import { MessageInput } from './message-input';
26
+ import { VoiceControls } from './voice-controls';
27
+
28
+ interface VoiceBotScreenProps {
29
+ config: VoiceBotConfig;
30
+ title?: string;
31
+ subtitle?: string;
32
+ }
33
+
34
+ function VoiceBotContent({ config, title, subtitle }: VoiceBotScreenProps) {
35
+ const { state, actions, textInput, setTextInput } = useVoiceBot(config, {
36
+ onConnect: (conversationId) => {
37
+ console.log('Voice bot connected:', conversationId);
38
+ },
39
+ onDisconnect: (details) => {
40
+ console.log('Voice bot disconnected:', details);
41
+ },
42
+ onError: (message, context) => {
43
+ console.error('Voice bot error:', message, context);
44
+ },
45
+ onMessage: (message) => {
46
+ console.log('Voice bot message:', message);
47
+ },
48
+ });
49
+
50
+ // Animated scroll effects (for blur intensity only)
51
+ const ref = useAnimatedRef<AnimatedScrollView>();
52
+ const scroll = useScrollOffset(ref);
53
+
54
+ const blurStyle = useAnimatedStyle(() => {
55
+ return {
56
+ opacity: interpolate(scroll.value, [0, 200], [0, 1], 'clamp'),
57
+ };
58
+ });
59
+
60
+ const handleSendMessage = () => {
61
+ actions.sendMessage(textInput);
62
+ setTextInput('');
63
+ };
64
+
65
+ const handleSendContext = () => {
66
+ actions.sendContextualUpdate(textInput);
67
+ setTextInput('');
68
+ };
69
+
70
+ return (
71
+ <View style={{ flex: 1 }}>
72
+ {/* Blur Overlay */}
73
+ <Animated.View
74
+ style={[StyleSheet.absoluteFill, { zIndex: -1 }, blurStyle]}
75
+ >
76
+ <BlurView
77
+ style={{ flex: 1 }}
78
+ tint="systemUltraThinMaterial"
79
+ intensity={80}
80
+ />
81
+ </Animated.View>
82
+
83
+ <Animated.ScrollView
84
+ ref={ref}
85
+ showsVerticalScrollIndicator={false}
86
+ automaticallyAdjustsScrollIndicatorInsets={true}
87
+ contentInsetAdjustmentBehavior="never"
88
+ style={{ backgroundColor: 'transparent' }}
89
+ >
90
+ <KeyboardAvoidingView
91
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
92
+ style={{ backgroundColor: 'transparent' }}
93
+ >
94
+ <TouchableWithoutFeedback onPress={() => Keyboard.dismiss()}>
95
+ <View style={{ backgroundColor: 'transparent' }}>
96
+ {/* Spacer so the header area feels roomy */}
97
+ <View
98
+ style={{
99
+ alignItems: 'center',
100
+ gap: 8,
101
+ padding: 16,
102
+ flex: 1,
103
+ minHeight: 200,
104
+ backgroundColor: 'transparent',
105
+ }}
106
+ />
107
+
108
+ {/* Voice Bot Content */}
109
+ <View style={{ paddingHorizontal: 24, gap: 24 }}>
110
+ {/* Header */}
111
+ <View className="items-center gap-4 rounded-3xl border border-border/50 bg-card/50 p-6 shadow-lg backdrop-blur-md">
112
+ <View className="mb-2 rounded-full bg-primary/20 p-4">
113
+ <Text className="text-4xl">🗣️</Text>
114
+ </View>
115
+ <Text className="text-center text-3xl font-bold text-foreground">
116
+ {title || 'Voice Assistant'}
117
+ </Text>
118
+ {subtitle && (
119
+ <Text className="text-mutedForeground text-center text-lg leading-6">
120
+ {subtitle}
121
+ </Text>
122
+ )}
123
+ </View>
124
+
125
+ {/* Status Indicator */}
126
+ <View className="rounded-2xl border border-border/50 bg-card/90 p-6 shadow-lg backdrop-blur-md">
127
+ <ConversationStatusIndicator
128
+ status={state.status}
129
+ conversationId={state.conversationId}
130
+ isSpeaking={state.isSpeaking}
131
+ />
132
+ </View>
133
+
134
+ {/* Voice Controls */}
135
+ <View className="rounded-2xl border border-border/50 bg-card/90 p-6 shadow-lg backdrop-blur-md">
136
+ <VoiceControls
137
+ status={state.status}
138
+ isStarting={state.isStarting}
139
+ canSendFeedback={state.canSendFeedback}
140
+ onStartConversation={actions.startConversation}
141
+ onEndConversation={actions.endConversation}
142
+ onSendFeedback={actions.sendFeedback}
143
+ />
144
+ </View>
145
+
146
+ {/* Message Input */}
147
+ <MessageInput
148
+ value={textInput}
149
+ onChangeText={setTextInput}
150
+ onSendMessage={handleSendMessage}
151
+ onSendContext={handleSendContext}
152
+ onUserActivity={actions.sendUserActivity}
153
+ isConnected={state.status === 'connected'}
154
+ />
155
+
156
+ {/* Bottom spacing */}
157
+ <View style={{ height: 80 }} />
158
+ </View>
159
+ </View>
160
+ </TouchableWithoutFeedback>
161
+ </KeyboardAvoidingView>
162
+ </Animated.ScrollView>
163
+ </View>
164
+ );
165
+ }
166
+
167
+ export function VoiceBotScreen(props: VoiceBotScreenProps) {
168
+ return (
169
+ <ElevenLabsProvider>
170
+ <VoiceBotContent {...props} />
171
+ </ElevenLabsProvider>
172
+ );
173
+ }
@@ -0,0 +1,73 @@
1
+ import type { ConversationStatus } from '@elevenlabs/react-native';
2
+ import React from 'react';
3
+ import { View } from 'react-native';
4
+
5
+ import { Button, Text } from '@/components/ui';
6
+
7
+ interface VoiceControlsProps {
8
+ status: ConversationStatus;
9
+ isStarting: boolean;
10
+ canSendFeedback: boolean;
11
+ onStartConversation: () => void;
12
+ onEndConversation: () => void;
13
+ onSendFeedback: (isPositive: boolean) => void;
14
+ }
15
+
16
+ export function VoiceControls({
17
+ status,
18
+ isStarting,
19
+ canSendFeedback,
20
+ onStartConversation,
21
+ onEndConversation,
22
+ onSendFeedback,
23
+ }: VoiceControlsProps) {
24
+ const canStart = status === 'disconnected' && !isStarting;
25
+ const canEnd = status === 'connected';
26
+
27
+ return (
28
+ <View className="w-full gap-2">
29
+ {/* Main Controls - Vertical stack for long button text */}
30
+ <View className="gap-2">
31
+ <Button
32
+ label={isStarting ? 'Starting...' : 'Start Conversation'}
33
+ onPress={onStartConversation}
34
+ disabled={!canStart}
35
+ variant={canStart ? 'default' : 'outline'}
36
+ testID="start-conversation-button"
37
+ />
38
+ <Button
39
+ label="End Conversation"
40
+ onPress={onEndConversation}
41
+ disabled={!canEnd}
42
+ variant={canEnd ? 'destructive' : 'outline'}
43
+ testID="end-conversation-button"
44
+ />
45
+ </View>
46
+
47
+ {/* Feedback Controls */}
48
+ {status === 'connected' && canSendFeedback && (
49
+ <View className="mt-4 items-center gap-3">
50
+ <Text className="text-base font-medium text-foreground">
51
+ How was that response?
52
+ </Text>
53
+ <View className="flex-row gap-4">
54
+ <Button
55
+ label="👍 Like"
56
+ onPress={() => onSendFeedback(true)}
57
+ variant="outline"
58
+ size="sm"
59
+ testID="feedback-like-button"
60
+ />
61
+ <Button
62
+ label="👎 Dislike"
63
+ onPress={() => onSendFeedback(false)}
64
+ variant="outline"
65
+ size="sm"
66
+ testID="feedback-dislike-button"
67
+ />
68
+ </View>
69
+ </View>
70
+ )}
71
+ </View>
72
+ );
73
+ }
@@ -0,0 +1,3 @@
1
+ export * from './components';
2
+ export * from './services';
3
+ export * from './types';
@@ -0,0 +1 @@
1
+ export * from './use-voice-bot';