vibefast-cli 1.3.0 → 1.3.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 (348) hide show
  1. package/README.md +30 -95
  2. package/dist/__tests__/recipes.test.js +8 -9
  3. package/dist/__tests__/recipes.test.js.map +1 -1
  4. package/dist/commands/add.d.ts.map +1 -1
  5. package/dist/commands/add.js +271 -125
  6. package/dist/commands/add.js.map +1 -1
  7. package/dist/commands/checklist.d.ts.map +1 -1
  8. package/dist/commands/checklist.js +85 -44
  9. package/dist/commands/checklist.js.map +1 -1
  10. package/dist/commands/health.d.ts.map +1 -1
  11. package/dist/commands/health.js +13 -4
  12. package/dist/commands/health.js.map +1 -1
  13. package/dist/commands/init.d.ts.map +1 -1
  14. package/dist/commands/init.js +118 -26
  15. package/dist/commands/init.js.map +1 -1
  16. package/dist/commands/migrate.d.ts +3 -0
  17. package/dist/commands/migrate.d.ts.map +1 -0
  18. package/dist/commands/migrate.js +202 -0
  19. package/dist/commands/migrate.js.map +1 -0
  20. package/dist/commands/remove.d.ts.map +1 -1
  21. package/dist/commands/remove.js +61 -3
  22. package/dist/commands/remove.js.map +1 -1
  23. package/dist/core/auth.d.ts.map +1 -1
  24. package/dist/core/auth.js +20 -18
  25. package/dist/core/auth.js.map +1 -1
  26. package/dist/core/codemod.d.ts +33 -0
  27. package/dist/core/codemod.d.ts.map +1 -1
  28. package/dist/core/codemod.js +116 -0
  29. package/dist/core/codemod.js.map +1 -1
  30. package/dist/core/detect.d.ts.map +1 -1
  31. package/dist/core/detect.js +24 -7
  32. package/dist/core/detect.js.map +1 -1
  33. package/dist/core/journal.d.ts +1 -0
  34. package/dist/core/journal.d.ts.map +1 -1
  35. package/dist/core/journal.js.map +1 -1
  36. package/dist/core/recipes.d.ts.map +1 -1
  37. package/dist/core/recipes.js +25 -7
  38. package/dist/core/recipes.js.map +1 -1
  39. package/dist/index.js +2 -2
  40. package/dist/index.js.map +1 -1
  41. package/docs/architecture.md +50 -0
  42. package/docs/commands.md +78 -0
  43. package/docs/contributing.md +27 -0
  44. package/docs/quickstart.md +50 -0
  45. package/docs/recipes.md +57 -0
  46. package/docs/troubleshooting.md +31 -0
  47. package/package.json +2 -2
  48. package/recipes/0/apps/native/src/components/advanced-ui/timeline/demo.tsx +445 -0
  49. package/recipes/0/apps/native/src/components/advanced-ui/timeline/timeline-view.tsx +355 -0
  50. package/recipes/0/apps/native/src/components/advanced-ui/timeline/types.ts +31 -0
  51. package/recipes/0/recipe.json +18 -0
  52. package/recipes/animated-chip/apps/native/src/components/advanced-ui/chip/demo.tsx +2 -1
  53. package/recipes/animated-chip/recipe.json +5 -2
  54. package/recipes/animated-chip-native@latest.zip +0 -0
  55. package/recipes/animated-chip@latest.zip +0 -0
  56. package/recipes/animated-switch/apps/native/src/components/advanced-ui/switch/demo.tsx +1 -1
  57. package/recipes/animated-switch/recipe.json +5 -2
  58. package/recipes/animated-switch-native@latest.zip +0 -0
  59. package/recipes/animated-switch@latest.zip +0 -0
  60. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +2 -1
  61. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +2 -2
  62. package/recipes/audio-recorder/recipe.json +7 -2
  63. package/recipes/audio-recorder-native@latest.zip +0 -0
  64. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +2 -1
  65. package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +2 -1
  66. package/recipes/audio-recorder-supabase/recipe.json +12 -33
  67. package/recipes/audio-recorder-supabase-native@latest.zip +0 -0
  68. package/recipes/audio-recorder-supabase@latest.zip +0 -0
  69. package/recipes/audio-recorder@latest.zip +0 -0
  70. package/recipes/charts/apps/native/src/app/charts/index.tsx +3 -0
  71. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -1
  72. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +3 -1
  73. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -1
  74. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +3 -1
  75. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +3 -1
  76. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +3 -1
  77. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +3 -1
  78. package/recipes/charts/recipe.json +13 -4
  79. package/recipes/charts-native@latest.zip +0 -0
  80. package/recipes/charts@latest.zip +0 -0
  81. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +86 -86
  82. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +4 -4
  83. package/recipes/chatbot/recipe.json +3 -40
  84. package/recipes/chatbot-native@latest.zip +0 -0
  85. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +4 -1
  86. package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +86 -53
  87. package/recipes/chatbot-supabase/recipe.json +3 -69
  88. package/recipes/chatbot-supabase-native@latest.zip +0 -0
  89. package/recipes/chatbot-supabase@latest.zip +0 -0
  90. package/recipes/chatbot@latest.zip +0 -0
  91. package/recipes/glowing-button/recipe.json +6 -2
  92. package/recipes/glowing-button-native@latest.zip +0 -0
  93. package/recipes/glowing-button@latest.zip +0 -0
  94. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/_layout.tsx +5 -0
  95. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/analysis-options.tsx +50 -0
  96. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/camera.tsx +2 -0
  97. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/index.tsx +50 -0
  98. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/loading.tsx +50 -0
  99. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/results.tsx +2 -0
  100. package/recipes/image-analysis/apps/native/src/app/analysis/[type]/trait-details.tsx +3 -0
  101. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +2 -2
  102. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/camera.tsx +72 -65
  103. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +65 -47
  104. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/loading-screen.tsx +43 -2
  105. package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/loading.tsx +34 -1
  106. package/recipes/image-analysis/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +83 -2
  107. package/recipes/image-analysis/recipe.json +11 -19
  108. package/recipes/image-analysis-native@latest.zip +0 -0
  109. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/_layout.tsx +5 -0
  110. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/analysis-options.tsx +50 -0
  111. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/camera.tsx +2 -0
  112. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/index.tsx +50 -0
  113. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/loading.tsx +50 -0
  114. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/results.tsx +2 -0
  115. package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/trait-details.tsx +3 -0
  116. package/recipes/image-analysis-supabase/recipe.json +10 -70
  117. package/recipes/image-analysis-supabase-native@latest.zip +0 -0
  118. package/recipes/image-analysis-supabase@latest.zip +0 -0
  119. package/recipes/image-analysis@latest.zip +0 -0
  120. package/recipes/image-analyzer/apps/native/src/app/(root)/(protected)/image-analyzer/index.tsx +2 -0
  121. package/recipes/image-generator/apps/native/src/app/image-generator/gallery.tsx +3 -0
  122. package/recipes/image-generator/apps/native/src/app/image-generator/index.tsx +3 -0
  123. package/recipes/image-generator/recipe.json +8 -18
  124. package/recipes/image-generator-native@latest.zip +0 -0
  125. package/recipes/image-generator-supabase/recipe.json +6 -62
  126. package/recipes/image-generator-supabase-native@latest.zip +0 -0
  127. package/recipes/image-generator-supabase@latest.zip +0 -0
  128. package/recipes/image-generator@latest.zip +0 -0
  129. package/recipes/ios-widget/recipe.json +18 -119
  130. package/recipes/ios-widget-native@latest.zip +0 -0
  131. package/recipes/ios-widget@latest.zip +0 -0
  132. package/recipes/number-stepper/apps/native/src/components/advanced-ui/stepper/demo.tsx +1 -1
  133. package/recipes/number-stepper/recipe.json +5 -2
  134. package/recipes/number-stepper-native@latest.zip +0 -0
  135. package/recipes/number-stepper@latest.zip +0 -0
  136. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +11 -18
  137. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +5 -7
  138. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +9 -7
  139. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +8 -7
  140. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +6 -5
  141. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +4 -3
  142. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +6 -5
  143. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +5 -7
  144. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +7 -6
  145. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +5 -7
  146. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +8 -7
  147. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +6 -5
  148. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +5 -6
  149. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +5 -4
  150. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +5 -7
  151. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +7 -6
  152. package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +4 -3
  153. package/recipes/onboarding/recipe.json +9 -6
  154. package/recipes/onboarding-native@latest.zip +0 -0
  155. package/recipes/onboarding@latest.zip +0 -0
  156. package/recipes/payments/apps/native/src/app/paywall/index.tsx +74 -0
  157. package/recipes/payments/apps/native/src/app/paywall/local.tsx +25 -0
  158. package/recipes/payments/apps/native/src/app/paywall/remote.tsx +23 -0
  159. package/recipes/payments/packages/backend/convex/payments.ts +21 -3
  160. package/recipes/payments/recipe.json +14 -34
  161. package/recipes/payments-native@latest.zip +0 -0
  162. package/recipes/payments-supabase/apps/native/src/app/paywall/index.tsx +74 -0
  163. package/recipes/payments-supabase/apps/native/src/app/paywall/local.tsx +25 -0
  164. package/recipes/payments-supabase/apps/native/src/app/paywall/remote.tsx +23 -0
  165. package/recipes/payments-supabase/recipe.json +16 -44
  166. package/recipes/payments-supabase-native@latest.zip +0 -0
  167. package/recipes/payments-supabase@latest.zip +0 -0
  168. package/recipes/payments@latest.zip +0 -0
  169. package/recipes/posthog/apps/native/src/components/analytics/navigation-tracker.tsx +14 -0
  170. package/recipes/posthog/apps/native/src/lib/hooks/use-navigation-analytics.ts +44 -0
  171. package/recipes/posthog/apps/native/src/providers/posthog-provider.tsx +51 -0
  172. package/recipes/posthog/recipe.json +60 -0
  173. package/recipes/posthog-native@latest.zip +0 -0
  174. package/recipes/progress-circle/apps/native/src/components/advanced-ui/progress-bars/progress-circle-page.tsx +1 -1
  175. package/recipes/progress-circle/recipe.json +5 -2
  176. package/recipes/progress-circle-native@latest.zip +0 -0
  177. package/recipes/progress-circle@latest.zip +0 -0
  178. package/recipes/quiz/apps/native/src/app/quiz/index.tsx +47 -0
  179. package/recipes/quiz/recipe.json +9 -6
  180. package/recipes/quiz-native@latest.zip +0 -0
  181. package/recipes/quiz@latest.zip +0 -0
  182. package/recipes/screen-kits/apps/native/src/app/screen-kits/_layout.tsx +12 -0
  183. package/recipes/screen-kits/apps/native/src/app/screen-kits/index.tsx +114 -0
  184. package/recipes/screen-kits/apps/native/src/features/screen-kits/index.ts +1 -0
  185. package/recipes/screen-kits/apps/native/src/features/screen-kits/types.ts +28 -0
  186. package/recipes/screen-kits/recipe.json +26 -0
  187. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/_layout.tsx +12 -0
  188. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/home.tsx +5 -0
  189. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/index.tsx +5 -0
  190. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson-complete.tsx +5 -0
  191. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson-fail.tsx +5 -0
  192. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson.tsx +5 -0
  193. package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/skill-tree.tsx +5 -0
  194. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/duo-button.tsx +174 -0
  195. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/skill-button.tsx +186 -0
  196. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/xp-header.tsx +115 -0
  197. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/constants.ts +89 -0
  198. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/index.ts +3 -0
  199. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/home-screen.tsx +225 -0
  200. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-complete-screen.tsx +485 -0
  201. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-fail-screen.tsx +105 -0
  202. package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-screen.tsx +384 -0
  203. package/recipes/screen-kits-duolingo/recipe.json +58 -0
  204. package/recipes/screen-kits-duolingo-native@latest.zip +0 -0
  205. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/_layout.tsx +45 -0
  206. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/asset-detail.tsx +3 -0
  207. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/notifications.tsx +3 -0
  208. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/receive.tsx +3 -0
  209. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/send.tsx +3 -0
  210. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/swap.tsx +3 -0
  211. package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/wallet.tsx +3 -0
  212. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/ActionButtons.tsx +78 -0
  213. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/AssetRow.tsx +94 -0
  214. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/BalanceCard.tsx +118 -0
  215. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/constants.ts +85 -0
  216. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/asset-detail.tsx +378 -0
  217. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/notifications.tsx +210 -0
  218. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/receive-modal.tsx +317 -0
  219. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/send-modal.tsx +420 -0
  220. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/swap-modal.tsx +363 -0
  221. package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/wallet-dashboard.tsx +281 -0
  222. package/recipes/screen-kits-finance/recipe.json +46 -0
  223. package/recipes/screen-kits-finance-native@latest.zip +0 -0
  224. package/recipes/screen-kits-fitness/apps/native/assets/sounds/timer-beep.wav +0 -0
  225. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/_layout.tsx +10 -0
  226. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/index.tsx +6 -0
  227. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/timer.tsx +3 -0
  228. package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/workout.tsx +3 -0
  229. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/timer-components.tsx +500 -0
  230. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/timer-settings-modal.tsx +352 -0
  231. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/workout-card.tsx +105 -0
  232. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/constants.ts +189 -0
  233. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/hooks/use-timer.ts +307 -0
  234. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/index.ts +1 -0
  235. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/screens/timer-screen.tsx +278 -0
  236. package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/screens/workout-dashboard.tsx +350 -0
  237. package/recipes/screen-kits-fitness/recipe.json +63 -0
  238. package/recipes/screen-kits-fitness-native@latest.zip +0 -0
  239. package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/habits.tsx +1 -0
  240. package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/kanban.tsx +1 -0
  241. package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/routes.ts +4 -0
  242. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/AddTaskModal.tsx +246 -0
  243. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/DraggableTaskCard.tsx +92 -0
  244. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/KanbanColumn.tsx +238 -0
  245. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/TaskCard.tsx +144 -0
  246. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/add-habit-modal.tsx +271 -0
  247. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/constants.ts +295 -0
  248. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/kanban-utils.ts +62 -0
  249. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/screens/habit-tracker.tsx +1160 -0
  250. package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/screens/kanban-board.tsx +432 -0
  251. package/recipes/screen-kits-habits/recipe.json +52 -0
  252. package/recipes/screen-kits-habits-native@latest.zip +0 -0
  253. package/recipes/screen-kits-native@latest.zip +0 -0
  254. package/recipes/sentry/apps/native/src/providers/sentry-provider.tsx +64 -0
  255. package/recipes/sentry/recipe.json +39 -0
  256. package/recipes/sentry-native@latest.zip +0 -0
  257. package/recipes/swipe-slider/apps/native/src/components/advanced-ui/sliders/swipe-slider-page.tsx +1 -1
  258. package/recipes/swipe-slider/recipe.json +5 -2
  259. package/recipes/swipe-slider-native@latest.zip +0 -0
  260. package/recipes/swipe-slider@latest.zip +0 -0
  261. package/recipes/timeline/apps/native/src/components/advanced-ui/timeline/demo.tsx +2 -1
  262. package/recipes/timeline/recipe.json +5 -2
  263. package/recipes/timeline-native@latest.zip +0 -0
  264. package/recipes/timeline@latest.zip +0 -0
  265. package/recipes/tracker-app/apps/native/src/app/tracker-app/index.tsx +1 -0
  266. package/recipes/tracker-app/recipe.json +10 -7
  267. package/recipes/tracker-app-native@latest.zip +0 -0
  268. package/recipes/tracker-app@latest.zip +0 -0
  269. package/recipes/upload-all.sh +8 -31
  270. package/recipes/voice-bot/apps/native/src/app/voice-bot/index.tsx +56 -0
  271. package/recipes/voice-bot/recipe.json +31 -7
  272. package/recipes/voice-bot-native@latest.zip +0 -0
  273. package/recipes/voice-bot@latest.zip +0 -0
  274. package/recipes/wake-word/apps/native/src/app/{(root)/(protected)/test-wake-word.tsx → test-wake-word.tsx} +43 -4
  275. package/recipes/wake-word/recipe.json +16 -26
  276. package/recipes/wake-word-native@latest.zip +0 -0
  277. package/recipes/wake-word@latest.zip +0 -0
  278. package/scripts/create-advanced-ui-recipes.sh +46 -19
  279. package/scripts/create-recipes.mjs +471 -117
  280. package/scripts/package-recipes.mjs +76 -0
  281. package/scripts/publish-all.sh +6 -2
  282. package/CHANGELOG.md +0 -198
  283. package/docs/archive/AUTO-DETECT-DEPS.md +0 -607
  284. package/docs/archive/FINAL-PACKAGE-STRATEGY.md +0 -583
  285. package/docs/archive/FINAL-SIMPLE-PLAN.md +0 -487
  286. package/docs/archive/FINAL-STATUS.md +0 -144
  287. package/docs/archive/FLOW-DIAGRAM.md +0 -1629
  288. package/docs/archive/GOTCHAS-AND-RISKS.md +0 -801
  289. package/docs/archive/IMPLEMENTATION-PLAN.md +0 -1360
  290. package/docs/archive/PLAN.md +0 -453
  291. package/docs/archive/PRODUCTION-READINESS.md +0 -684
  292. package/docs/archive/PRODUCTION-TEST-RESULTS.md +0 -465
  293. package/docs/archive/SIMPLIFIED-PLAN.md +0 -578
  294. package/docs/archive/STATUS.md +0 -199
  295. package/docs/archive/SUCCESS.md +0 -259
  296. package/docs/archive/TEST-SUMMARY.md +0 -261
  297. package/docs/archive/TESTING-CHECKLIST.md +0 -450
  298. package/docs/archive/USER-MODIFICATIONS.md +0 -448
  299. package/docs/decisions.md +0 -55
  300. package/docs/manual-testing.md +0 -91
  301. package/docs/next-steps.md +0 -12
  302. package/recipes/README.md +0 -156
  303. package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +0 -369
  304. package/recipes/chatbot/apps/native/src/api-client/chatbot.ts +0 -83
  305. package/recipes/chatbot/packages/backend/convex/agents.ts +0 -115
  306. package/recipes/chatbot/packages/backend/convex/tools/index.ts +0 -18
  307. package/recipes/chatbot/packages/backend/convex/tools/knowledgeRetrieval.ts +0 -97
  308. package/recipes/chatbot/packages/backend/convex/tools/tavilySearch.ts +0 -83
  309. package/recipes/chatbot/packages/backend/convex/tools/userProfile.ts +0 -72
  310. package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +0 -515
  311. package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +0 -243
  312. package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +0 -327
  313. package/recipes/image-analysis/apps/native/src/api-client/image-analyzer.ts +0 -62
  314. package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +0 -132
  315. package/recipes/image-generator/apps/native/src/api-client/image-generator.ts +0 -34
  316. package/recipes/payments/apps/native/src/api-client/payments.ts +0 -44
  317. package/recipes/payments-supabase/packages/backend/src/services/payments.ts +0 -201
  318. package/recipes/posthog.json +0 -47
  319. package/recipes/revenuecat.json +0 -43
  320. package/recipes/sentry.json +0 -47
  321. package/recipes/wake-word/apps/native/assets/vosk-model/README.md +0 -103
  322. package/recipes/wake-word/apps/native/scripts/download-vosk-model.mjs +0 -127
  323. /package/recipes/{audio-recorder/apps/native/src/app/(root)/(protected) → audio-recorder-supabase/apps/native/src/app}/audio-recorder/index.tsx +0 -0
  324. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/AppIntent.swift +0 -0
  325. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png +0 -0
  326. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png +0 -0
  327. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png +0 -0
  328. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png +0 -0
  329. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png +0 -0
  330. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png +0 -0
  331. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png +0 -0
  332. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png +0 -0
  333. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png +0 -0
  334. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png +0 -0
  335. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png +0 -0
  336. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png +0 -0
  337. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png +0 -0
  338. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png +0 -0
  339. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  340. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png +0 -0
  341. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/CalorieTrackerWidget.swift +0 -0
  342. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/HabitTrackerWidget.swift +0 -0
  343. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Info.plist +0 -0
  344. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/WidgetLiveActivity.swift +0 -0
  345. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/expo-target.config.js +0 -0
  346. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/generated.entitlements +0 -0
  347. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/index.swift +0 -0
  348. /package/recipes/ios-widget/{targets → apps/native/targets}/widget/widgets.swift +0 -0
@@ -7,7 +7,7 @@ import { fetchRecipe, downloadZip } from "../core/http.js";
7
7
  import { addEntry, getEntry } from "../core/journal.js";
8
8
  import { copyTree, readFileContent, exists, } from "../core/fsx.js";
9
9
  import { hasEnvKey } from "../core/env.js";
10
- import { insertEnvSnippets, insertNavLinkNative, insertNavLinkWeb, ENV_BUILD_TIME_ENV_END, ENV_BUILD_TIME_ENV_START, ENV_BUILD_TIME_SCHEMA_END, ENV_BUILD_TIME_SCHEMA_START, ENV_CLIENT_ENV_END, ENV_CLIENT_ENV_START, ENV_CLIENT_SCHEMA_END, ENV_CLIENT_SCHEMA_START, ENV_CONSTANTS_END, ENV_CONSTANTS_START, } from "../core/codemod.js";
10
+ import { insertEnvSnippets, insertMarkedSnippets, insertNavLinkNative, insertNavLinkWeb, insertScreenKit, ENV_BUILD_TIME_ENV_END, ENV_BUILD_TIME_ENV_START, ENV_BUILD_TIME_SCHEMA_END, ENV_BUILD_TIME_SCHEMA_START, ENV_CLIENT_ENV_END, ENV_CLIENT_ENV_START, ENV_CLIENT_SCHEMA_END, ENV_CLIENT_SCHEMA_START, ENV_CONSTANTS_END, ENV_CONSTANTS_START, TELEMETRY_IMPORTS_END, TELEMETRY_IMPORTS_START, TELEMETRY_WRAPS_END, TELEMETRY_WRAPS_START, LAYOUT_COMPONENTS_END, LAYOUT_COMPONENTS_START, LAYOUT_IMPORTS_END, LAYOUT_IMPORTS_START, } from "../core/codemod.js";
11
11
  import { join, resolve, relative } from "path";
12
12
  import { ensureWithinBase } from "../core/pathGuard.js";
13
13
  import { extractZipSafe } from "../core/archive.js";
@@ -15,7 +15,6 @@ import { hashFiles } from "../core/hash.js";
15
15
  import { promptYesNo } from "../core/prompt.js";
16
16
  import { detectTarget, detectBackendType } from "../core/detect.js";
17
17
  import { withSpinner } from "../core/spinner.js";
18
- import { getBundledRecipeZipPath } from "../core/recipes.js";
19
18
  import { tmpdir } from "os";
20
19
  import { randomUUID } from "crypto";
21
20
  import { appendManualSteps } from "../core/manualSteps.js";
@@ -71,6 +70,30 @@ export const addCommand = new Command("add")
71
70
  process.stdin.setMaxListeners(50);
72
71
  process.stdout.setMaxListeners(50);
73
72
  const paths = await getPaths();
73
+ const ensured = new Set();
74
+ const ensureScreenKitsCore = async () => {
75
+ const coreName = "screen-kits";
76
+ if (ensured.has(coreName))
77
+ return;
78
+ let target = options.target;
79
+ if (!target) {
80
+ const detected = await detectTarget(paths.cwd);
81
+ if (detected) {
82
+ target = detected;
83
+ }
84
+ }
85
+ if (!target) {
86
+ log.error("Could not auto-detect target (native/web)");
87
+ log.info("Please specify with --target native or --target web");
88
+ process.exit(1);
89
+ }
90
+ const existing = await getEntry(paths.journalFile, coreName, target);
91
+ if (!existing) {
92
+ log.info("Installing Screen Kits hub...");
93
+ await installFeature(coreName, options, paths);
94
+ }
95
+ ensured.add(coreName);
96
+ };
74
97
  // Interactive mode if no feature specified
75
98
  if (!feature) {
76
99
  const { RECIPES, getRecipesByCategory, formatCategory, getCategories } = await import("../core/recipes.js");
@@ -103,6 +126,9 @@ export const addCommand = new Command("add")
103
126
  outro("No items selected");
104
127
  return;
105
128
  }
129
+ if (selectedRecipes.some((r) => r.startsWith("screen-kits-"))) {
130
+ await ensureScreenKitsCore();
131
+ }
106
132
  // Install each selected recipe
107
133
  for (const recipeName of selectedRecipes) {
108
134
  log.plain("");
@@ -130,6 +156,9 @@ export const addCommand = new Command("add")
130
156
  outro("No items selected");
131
157
  return;
132
158
  }
159
+ if (selectedRecipes.some((r) => r.startsWith("screen-kits-"))) {
160
+ await ensureScreenKitsCore();
161
+ }
133
162
  // Install each selected recipe
134
163
  for (const recipeName of selectedRecipes) {
135
164
  log.plain("");
@@ -139,6 +168,9 @@ export const addCommand = new Command("add")
139
168
  outro("✨ Installation complete!");
140
169
  return;
141
170
  }
171
+ if (feature.startsWith("screen-kits-")) {
172
+ await ensureScreenKitsCore();
173
+ }
142
174
  // Install single feature
143
175
  await installFeature(feature, options, paths);
144
176
  }
@@ -172,18 +204,13 @@ export async function installFeature(feature, options, paths) {
172
204
  // Detect backend type for recipe selection
173
205
  const backend = await detectBackendType(paths.cwd);
174
206
  log.info(`Target: ${target}, Backend: ${backend}`);
175
- // For Supabase projects, try feature-supabase recipe first
176
- // This allows backend-specific recipes while maintaining backwards compatibility
207
+ // For Supabase projects, try feature-supabase recipe first, then fall back to base
177
208
  let recipeName = feature;
209
+ const recipeCandidates = backend === "supabase"
210
+ ? [`${feature}-supabase`, feature]
211
+ : [feature];
178
212
  if (backend === "supabase") {
179
- // Check if supabase-specific bundled recipe exists
180
- const supabaseRecipe = `${feature}-supabase`;
181
- const supabaseZipPath = await getBundledRecipeZipPath(supabaseRecipe);
182
- if (supabaseZipPath) {
183
- recipeName = supabaseRecipe;
184
- log.info(`Using Supabase-specific recipe: ${recipeName}`);
185
- }
186
- // Otherwise fall back to base recipe (which may work for both backends)
213
+ log.info(`Preferring Supabase-specific recipe: ${recipeCandidates[0]}`);
187
214
  }
188
215
  // Check auth
189
216
  const token = await getToken();
@@ -213,107 +240,121 @@ export async function installFeature(feature, options, paths) {
213
240
  if (options.dryRun) {
214
241
  log.info("[DRY RUN] No changes will be made");
215
242
  }
216
- // Fetch recipe
243
+ // Fetch recipe (try candidates in order)
217
244
  const device = await getDeviceInfo();
218
- const response = await withSpinner(`Fetching ${recipeName} for ${target}...`, async () => {
219
- return await fetchRecipe({
220
- token,
221
- device,
222
- feature: recipeName,
223
- target,
224
- starter: { name: config.name, version: config.version },
245
+ let response = null;
246
+ for (let i = 0; i < recipeCandidates.length; i++) {
247
+ const candidate = recipeCandidates[i];
248
+ const candidateResponse = await withSpinner(`Fetching ${candidate} for ${target}...`, async () => {
249
+ return await fetchRecipe({
250
+ token,
251
+ device,
252
+ feature: candidate,
253
+ target,
254
+ starter: { name: config.name, version: config.version },
255
+ });
256
+ }, {
257
+ successText: `✓ Recipe fetched`,
225
258
  });
226
- }, {
227
- successText: `✓ Recipe fetched`,
228
- });
259
+ const ok = candidateResponse.ok &&
260
+ (candidateResponse.signedUrl || candidateResponse.zipData);
261
+ if (ok) {
262
+ response = candidateResponse;
263
+ recipeName = candidate;
264
+ break;
265
+ }
266
+ const errorText = `${candidateResponse.error || ""} ${candidateResponse.message || ""}`.toLowerCase();
267
+ const isNotFound = errorText.includes("not found") || errorText.includes("404");
268
+ if (isNotFound && i < recipeCandidates.length - 1) {
269
+ log.warn(`⚠ ${candidate} not available. Trying ${recipeCandidates[i + 1]}...`);
270
+ continue;
271
+ }
272
+ response = candidateResponse;
273
+ recipeName = candidate;
274
+ break;
275
+ }
276
+ if (!response) {
277
+ log.error("Failed to fetch recipe");
278
+ process.exit(1);
279
+ }
229
280
  let zipPath = null;
230
281
  let extractDir = null;
231
282
  if (!response.ok || (!response.signedUrl && !response.zipData)) {
232
- // Remote fetch failed; try bundled fallback
233
283
  const error = response.error || "Unknown error";
234
284
  const message = response.message || "";
235
- const localZip = await getBundledRecipeZipPath(recipeName);
236
- if (localZip) {
237
- log.info(`Remote recipe unavailable (${error}). Using bundled recipe.`);
238
- zipPath = localZip;
285
+ log.plain("");
286
+ // User-friendly error messages
287
+ if (error.includes("Invalid") ||
288
+ error.includes("token") ||
289
+ error.includes("license")) {
290
+ log.plain("❌ Invalid or expired license key");
291
+ log.plain("");
292
+ log.info("Your license key may be:");
293
+ log.plain(" • Incorrect or mistyped");
294
+ log.plain(" • Expired");
295
+ log.plain(" • Revoked");
296
+ log.plain("");
297
+ log.info("To fix this:");
298
+ log.plain(" 1. Check your license key from your purchase receipt");
299
+ log.plain(" 2. Run: vf logout");
300
+ log.plain(" 3. Run: vf login --token YOUR_CORRECT_TOKEN");
301
+ log.plain("");
302
+ log.info("Need help? Contact support@vibefast.pro");
239
303
  }
240
- else {
304
+ else if (error.includes("Device limit") ||
305
+ error.includes("device") ||
306
+ message.includes("device")) {
307
+ log.plain("❌ Device limit reached");
241
308
  log.plain("");
242
- // User-friendly error messages
243
- if (error.includes("Invalid") ||
244
- error.includes("token") ||
245
- error.includes("license")) {
246
- log.plain(" Invalid or expired license key");
247
- log.plain("");
248
- log.info("Your license key may be:");
249
- log.plain(" • Incorrect or mistyped");
250
- log.plain(" • Expired");
251
- log.plain(" • Revoked");
252
- log.plain("");
253
- log.info("To fix this:");
254
- log.plain(" 1. Check your license key from your purchase receipt");
255
- log.plain(" 2. Run: vf logout");
256
- log.plain(" 3. Run: vf login --token YOUR_CORRECT_TOKEN");
257
- log.plain("");
258
- log.info("Need help? Contact support@vibefast.pro");
259
- }
260
- else if (error.includes("Device limit") ||
261
- error.includes("device") ||
262
- message.includes("device")) {
263
- log.plain("❌ Device limit reached");
264
- log.plain("");
265
- log.info("You have reached the maximum number of devices for your license");
266
- log.plain("");
267
- log.info("To fix this:");
268
- log.plain(" 1. Run: vf devices");
269
- log.plain(" 2. Deactivate an unused device: vf devices --deactivate <device-id>");
270
- log.plain(" 3. Try again: vf add " + feature);
271
- log.plain("");
272
- if (message) {
273
- log.plain(`Details: ${message}`);
274
- log.plain("");
275
- }
276
- }
277
- else if (error.includes("Network") || error.includes("connect")) {
278
- log.plain("❌ Network error");
279
- log.plain("");
280
- log.info("Could not connect to VibeFast servers");
281
- log.plain("");
282
- log.info("Please check:");
283
- log.plain(" • Your internet connection");
284
- log.plain(" • Firewall settings");
285
- log.plain(" • VPN configuration");
309
+ log.info("You have reached the maximum number of devices for your license");
310
+ log.plain("");
311
+ log.info("To fix this:");
312
+ log.plain(" 1. Run: vf devices");
313
+ log.plain(" 2. Deactivate an unused device: vf devices --deactivate <device-id>");
314
+ log.plain(" 3. Try again: vf add " + feature);
315
+ log.plain("");
316
+ if (message) {
317
+ log.plain(`Details: ${message}`);
286
318
  log.plain("");
287
- if (message) {
288
- log.plain(`Details: ${message}`);
289
- log.plain("");
290
- }
291
319
  }
292
- else if (error.includes("not found") || error.includes("404")) {
293
- log.plain(" Feature not found");
294
- log.plain("");
295
- log.info(`The feature "${feature}" does not exist or is not available for ${target}`);
296
- log.plain("");
297
- log.info("To see available features:");
298
- log.plain(" vf list");
320
+ }
321
+ else if (error.includes("Network") || error.includes("connect")) {
322
+ log.plain("❌ Network error");
323
+ log.plain("");
324
+ log.info("Could not connect to VibeFast servers");
325
+ log.plain("");
326
+ log.info("Please check:");
327
+ log.plain(" • Your internet connection");
328
+ log.plain(" • Firewall settings");
329
+ log.plain(" • VPN configuration");
330
+ log.plain("");
331
+ if (message) {
332
+ log.plain(`Details: ${message}`);
299
333
  log.plain("");
300
334
  }
301
- else {
302
- // Generic error
303
- log.plain(`❌ ${error}`);
304
- if (message) {
305
- log.plain("");
306
- log.plain(`Details: ${message}`);
307
- }
335
+ }
336
+ else if (error.includes("not found") || error.includes("404")) {
337
+ log.plain("❌ Feature not found");
338
+ log.plain("");
339
+ log.info(`The feature "${feature}" does not exist or is not available for ${target}`);
340
+ log.plain("");
341
+ log.info("To see available features:");
342
+ log.plain(" vf list");
343
+ log.plain("");
344
+ }
345
+ else {
346
+ // Generic error
347
+ log.plain(`❌ ${error}`);
348
+ if (message) {
308
349
  log.plain("");
309
- log.info("If this problem persists, contact support@vibefast.pro");
350
+ log.plain(`Details: ${message}`);
310
351
  }
311
352
  log.plain("");
312
- process.exit(1);
353
+ log.info("If this problem persists, contact support@vibefast.pro");
313
354
  }
355
+ log.plain("");
356
+ process.exit(1);
314
357
  }
315
- const fallbackZip = await getBundledRecipeZipPath(recipeName);
316
- let attemptedFallback = false;
317
358
  let installedManifest = null;
318
359
  let installedEnvGroups = [];
319
360
  let installedEnvAttention = [];
@@ -321,29 +362,22 @@ export async function installFeature(feature, options, paths) {
321
362
  let installedNavInserted = false;
322
363
  let installedNavHref;
323
364
  let installedNavLabel;
324
- // Everything below runs inside a retry loop so we can fall back to bundled recipes
365
+ // Install recipe
325
366
  retry_install: while (true) {
326
367
  try {
327
- // Download and extract (or use bundled zip)
328
- if (!zipPath) {
329
- const result = await withSpinner("Downloading and extracting recipe...", async () => {
330
- const zip = response.zipData
331
- ? await downloadZip(response.zipData, true)
332
- : await downloadZip(response.signedUrl);
333
- const dir = join(tmpdir(), "vibefast", randomUUID());
334
- await extractZipSafe(zip, dir);
335
- return { zipPath: zip, extractDir: dir };
336
- }, {
337
- successText: "✓ Recipe downloaded",
338
- });
339
- zipPath = result.zipPath;
340
- extractDir = result.extractDir;
341
- }
342
- else {
343
- // Bundled zip path - extract to temp location
344
- extractDir = join(tmpdir(), "vibefast", randomUUID());
345
- await extractZipSafe(zipPath, extractDir);
346
- }
368
+ // Download and extract recipe
369
+ const result = await withSpinner("Downloading and extracting recipe...", async () => {
370
+ const zip = response.zipData
371
+ ? await downloadZip(response.zipData, true)
372
+ : await downloadZip(response.signedUrl);
373
+ const dir = join(tmpdir(), "vibefast", randomUUID());
374
+ await extractZipSafe(zip, dir);
375
+ return { zipPath: zip, extractDir: dir };
376
+ }, {
377
+ successText: "✓ Recipe downloaded",
378
+ });
379
+ zipPath = result.zipPath;
380
+ extractDir = result.extractDir;
347
381
  // Locate manifest (some archives may nest recipe.json)
348
382
  const findManifest = async (dir) => {
349
383
  const entries = await import("fs/promises").then((m) => m.readdir(dir, { withFileTypes: true }));
@@ -502,6 +536,21 @@ export async function installFeature(feature, options, paths) {
502
536
  log.info("Navigation link already exists");
503
537
  }
504
538
  }
539
+ // Insert screen kit entry (if provided)
540
+ let screenKitInserted = false;
541
+ let screenKitId;
542
+ if (manifest.screenKit) {
543
+ log.info("Registering screen kit...");
544
+ const screenKitsFile = join(paths.nativeDir, "src", "features", "screen-kits", "types.ts");
545
+ screenKitId = manifest.screenKit.id;
546
+ screenKitInserted = await insertScreenKit(screenKitsFile, manifest.screenKit, { dryRun: options.dryRun });
547
+ if (screenKitInserted) {
548
+ log.success("Screen kit registered");
549
+ }
550
+ else {
551
+ log.info("Screen kit already registered");
552
+ }
553
+ }
505
554
  // Hash files and update journal
506
555
  if (!options.dryRun) {
507
556
  log.info("Computing file hashes...");
@@ -524,6 +573,7 @@ export async function installFeature(feature, options, paths) {
524
573
  version: manifest.version,
525
574
  manualSteps: manifest.manualSteps,
526
575
  env: manifest.env,
576
+ screenKitId,
527
577
  },
528
578
  });
529
579
  }
@@ -535,20 +585,12 @@ export async function installFeature(feature, options, paths) {
535
585
  installedNavInserted = navInserted;
536
586
  installedNavHref = navHref;
537
587
  installedNavLabel = navLabel;
588
+ // screen kit insertion is recorded in journal only
538
589
  log.success(`${manifest.name} installed successfully!`);
539
590
  log.info(`Files added: ${copiedFiles.length}`);
540
591
  break retry_install;
541
592
  }
542
593
  catch (err) {
543
- // Don't retry for nav marker errors - bundled recipe will have same problem
544
- const isNavMarkerError = err.message?.includes("Missing navigation markers");
545
- if (!attemptedFallback && fallbackZip && !isNavMarkerError) {
546
- attemptedFallback = true;
547
- zipPath = fallbackZip;
548
- extractDir = null;
549
- log.warn(`⚠ Encountered error "${err.message}". Retrying with bundled recipe...`);
550
- continue retry_install;
551
- }
552
594
  throw err;
553
595
  }
554
596
  }
@@ -598,6 +640,9 @@ export async function installFeature(feature, options, paths) {
598
640
  if (result.error) {
599
641
  throw result.error;
600
642
  }
643
+ if (result.status !== 0) {
644
+ throw new Error(`Expo install exited with code ${result.status}`);
645
+ }
601
646
  }
602
647
  catch (err) {
603
648
  log.warn("⚠ Expo install reported an error (packages may still be installed). Verify dependencies and app.config.ts plugin additions.");
@@ -651,6 +696,9 @@ export async function installFeature(feature, options, paths) {
651
696
  if (result.error) {
652
697
  throw result.error;
653
698
  }
699
+ if (result.status !== 0) {
700
+ throw new Error(`${pkgManager} install exited with code ${result.status}`);
701
+ }
654
702
  }, {
655
703
  successText: "✓ Packages installed",
656
704
  });
@@ -679,6 +727,12 @@ export async function installFeature(feature, options, paths) {
679
727
  if (installedManifest?.configuration?.env) {
680
728
  await applyEnvConfiguration(paths, installedManifest.configuration.env, options);
681
729
  }
730
+ if (installedManifest?.name === "posthog") {
731
+ await applyPosthogIntegration(paths, options);
732
+ }
733
+ if (installedManifest?.name === "sentry") {
734
+ await applySentryIntegration(paths, options);
735
+ }
682
736
  // Apply api-client exports injection
683
737
  if (installedManifest?.configuration?.apiClient) {
684
738
  await applyApiClientConfiguration(paths, installedManifest.configuration.apiClient, options);
@@ -716,6 +770,13 @@ export async function installFeature(feature, options, paths) {
716
770
  completedSteps.push(step.title);
717
771
  }
718
772
  }
773
+ else if (lowerTitle.includes("download vosk")) {
774
+ const modelPath = join(paths.cwd, "apps", "native", "assets", "vosk-model", "model-en-us");
775
+ if (await exists(modelPath)) {
776
+ alreadyDone = true;
777
+ completedSteps.push(step.title);
778
+ }
779
+ }
719
780
  else if (step.file === ".gitignore") {
720
781
  if (content.includes("assets/vosk-model/model-en-us")) {
721
782
  alreadyDone = true;
@@ -787,6 +848,13 @@ export async function installFeature(feature, options, paths) {
787
848
  }
788
849
  }
789
850
  }
851
+ else if (featureName === "wake-word" &&
852
+ step.title.toLowerCase().includes("download vosk")) {
853
+ const modelPath = join(paths.cwd, "apps", "native", "assets", "vosk-model", "model-en-us");
854
+ if (await exists(modelPath)) {
855
+ alreadyDone = true;
856
+ }
857
+ }
790
858
  else if (featureName === "wake-word" &&
791
859
  step.file === ".gitignore") {
792
860
  const filePath = join(paths.cwd, step.file);
@@ -930,6 +998,84 @@ async function applyEnvConfiguration(paths, envConfig, options) {
930
998
  }
931
999
  }
932
1000
  }
1001
+ const POSTHOG_IMPORT_BLOCK = [
1002
+ "// @vibefast:posthog:import:start",
1003
+ "import { AnalyticsProvider } from './posthog-provider';",
1004
+ "// @vibefast:posthog:import:end",
1005
+ ].join("\n");
1006
+ const POSTHOG_WRAP_BLOCK = [
1007
+ " // @vibefast:posthog:wrap:start",
1008
+ " content = <AnalyticsProvider>{content}</AnalyticsProvider>;",
1009
+ " // @vibefast:posthog:wrap:end",
1010
+ ].join("\n");
1011
+ const POSTHOG_LAYOUT_IMPORT_BLOCK = [
1012
+ "// @vibefast:posthog:layout-import:start",
1013
+ "import { NavigationTracker } from '@/components/analytics/navigation-tracker';",
1014
+ "// @vibefast:posthog:layout-import:end",
1015
+ ].join("\n");
1016
+ const POSTHOG_LAYOUT_COMPONENT_BLOCK = [
1017
+ " {/* @vibefast:posthog:layout:start */}",
1018
+ " <NavigationTracker />",
1019
+ " {/* @vibefast:posthog:layout:end */}",
1020
+ ].join("\n");
1021
+ const SENTRY_IMPORT_BLOCK = [
1022
+ "// @vibefast:sentry:import:start",
1023
+ "import { SentryProvider } from './sentry-provider';",
1024
+ "// @vibefast:sentry:import:end",
1025
+ ].join("\n");
1026
+ const SENTRY_WRAP_BLOCK = [
1027
+ " // @vibefast:sentry:wrap:start",
1028
+ " content = <SentryProvider>{content}</SentryProvider>;",
1029
+ " // @vibefast:sentry:wrap:end",
1030
+ ].join("\n");
1031
+ async function applyPosthogIntegration(paths, options) {
1032
+ const telemetryProviderPath = join(paths.nativeDir, "src", "providers", "telemetry-provider.tsx");
1033
+ const layoutPath = join(paths.nativeDir, "src", "app", "_layout.tsx");
1034
+ const suffix = options.dryRun ? " (dry run)" : "";
1035
+ if (!(await exists(telemetryProviderPath))) {
1036
+ throw new Error("TelemetryProvider not found. Please update your starter or add src/providers/telemetry-provider.tsx before installing PostHog.");
1037
+ }
1038
+ if (!(await exists(layoutPath))) {
1039
+ throw new Error("App layout file not found. Expected src/app/_layout.tsx for PostHog integration.");
1040
+ }
1041
+ if (await exists(telemetryProviderPath)) {
1042
+ const insertedImport = await insertMarkedSnippets(telemetryProviderPath, TELEMETRY_IMPORTS_START, TELEMETRY_IMPORTS_END, [POSTHOG_IMPORT_BLOCK], options);
1043
+ if (insertedImport) {
1044
+ log.info(`Updated telemetry provider imports${suffix}.`);
1045
+ }
1046
+ const insertedWrap = await insertMarkedSnippets(telemetryProviderPath, TELEMETRY_WRAPS_START, TELEMETRY_WRAPS_END, [POSTHOG_WRAP_BLOCK], options);
1047
+ if (insertedWrap) {
1048
+ log.info(`Updated telemetry provider wrappers${suffix}.`);
1049
+ }
1050
+ }
1051
+ if (await exists(layoutPath)) {
1052
+ const insertedImport = await insertMarkedSnippets(layoutPath, LAYOUT_IMPORTS_START, LAYOUT_IMPORTS_END, [POSTHOG_LAYOUT_IMPORT_BLOCK], options);
1053
+ if (insertedImport) {
1054
+ log.info(`Updated layout imports${suffix}.`);
1055
+ }
1056
+ const insertedComponent = await insertMarkedSnippets(layoutPath, LAYOUT_COMPONENTS_START, LAYOUT_COMPONENTS_END, [POSTHOG_LAYOUT_COMPONENT_BLOCK], options);
1057
+ if (insertedComponent) {
1058
+ log.info(`Updated layout components${suffix}.`);
1059
+ }
1060
+ }
1061
+ }
1062
+ async function applySentryIntegration(paths, options) {
1063
+ const telemetryProviderPath = join(paths.nativeDir, "src", "providers", "telemetry-provider.tsx");
1064
+ const suffix = options.dryRun ? " (dry run)" : "";
1065
+ if (!(await exists(telemetryProviderPath))) {
1066
+ throw new Error("TelemetryProvider not found. Please update your starter or add src/providers/telemetry-provider.tsx before installing Sentry.");
1067
+ }
1068
+ if (await exists(telemetryProviderPath)) {
1069
+ const insertedImport = await insertMarkedSnippets(telemetryProviderPath, TELEMETRY_IMPORTS_START, TELEMETRY_IMPORTS_END, [SENTRY_IMPORT_BLOCK], options);
1070
+ if (insertedImport) {
1071
+ log.info(`Updated telemetry provider imports${suffix}.`);
1072
+ }
1073
+ const insertedWrap = await insertMarkedSnippets(telemetryProviderPath, TELEMETRY_WRAPS_START, TELEMETRY_WRAPS_END, [SENTRY_WRAP_BLOCK], options);
1074
+ if (insertedWrap) {
1075
+ log.info(`Updated telemetry provider wrappers${suffix}.`);
1076
+ }
1077
+ }
1078
+ }
933
1079
  const API_CLIENT_EXPORTS_START = "// --- @vibefast:api-client:exports:start ---";
934
1080
  const API_CLIENT_EXPORTS_END = "// --- @vibefast:api-client:exports:end ---";
935
1081
  const BACKEND_EXPORTS_START = "// --- @vibefast:backend:exports:start ---";