vibefast-cli 1.2.1 → 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.
- package/README.md +30 -95
- package/dist/__tests__/recipes.test.js +94 -91
- package/dist/__tests__/recipes.test.js.map +1 -1
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +301 -125
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/checklist.d.ts.map +1 -1
- package/dist/commands/checklist.js +85 -44
- package/dist/commands/checklist.js.map +1 -1
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +13 -4
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +118 -26
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate.d.ts +3 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +202 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +61 -3
- package/dist/commands/remove.js.map +1 -1
- package/dist/core/auth.d.ts.map +1 -1
- package/dist/core/auth.js +20 -18
- package/dist/core/auth.js.map +1 -1
- package/dist/core/codemod.d.ts +33 -0
- package/dist/core/codemod.d.ts.map +1 -1
- package/dist/core/codemod.js +116 -0
- package/dist/core/codemod.js.map +1 -1
- package/dist/core/detect.d.ts.map +1 -1
- package/dist/core/detect.js +24 -7
- package/dist/core/detect.js.map +1 -1
- package/dist/core/journal.d.ts +1 -0
- package/dist/core/journal.d.ts.map +1 -1
- package/dist/core/journal.js.map +1 -1
- package/dist/core/recipes.d.ts.map +1 -1
- package/dist/core/recipes.js +25 -7
- package/dist/core/recipes.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/docs/architecture.md +50 -0
- package/docs/commands.md +78 -0
- package/docs/contributing.md +27 -0
- package/docs/quickstart.md +50 -0
- package/docs/recipes.md +57 -0
- package/docs/troubleshooting.md +31 -0
- package/package.json +2 -2
- package/recipes/0/apps/native/src/components/advanced-ui/timeline/demo.tsx +445 -0
- package/recipes/0/apps/native/src/components/advanced-ui/timeline/timeline-view.tsx +355 -0
- package/recipes/0/apps/native/src/components/advanced-ui/timeline/types.ts +31 -0
- package/recipes/0/recipe.json +18 -0
- package/recipes/animated-chip/apps/native/src/components/advanced-ui/chip/demo.tsx +2 -1
- package/recipes/animated-chip/recipe.json +5 -2
- package/recipes/animated-chip-native@latest.zip +0 -0
- package/recipes/animated-chip@latest.zip +0 -0
- package/recipes/animated-switch/apps/native/src/components/advanced-ui/switch/demo.tsx +1 -1
- package/recipes/animated-switch/recipe.json +5 -2
- package/recipes/animated-switch-native@latest.zip +0 -0
- package/recipes/animated-switch@latest.zip +0 -0
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +2 -1
- package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +2 -2
- package/recipes/audio-recorder/recipe.json +7 -2
- package/recipes/audio-recorder-native@latest.zip +0 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +2 -1
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +2 -1
- package/recipes/audio-recorder-supabase/recipe.json +12 -16
- package/recipes/audio-recorder-supabase-native@latest.zip +0 -0
- package/recipes/audio-recorder-supabase@latest.zip +0 -0
- package/recipes/audio-recorder@latest.zip +0 -0
- package/recipes/charts/apps/native/src/app/charts/index.tsx +3 -0
- package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -1
- package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +3 -1
- package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -1
- package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +3 -1
- package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +3 -1
- package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +3 -1
- package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +3 -1
- package/recipes/charts/recipe.json +13 -4
- package/recipes/charts-native@latest.zip +0 -0
- package/recipes/charts@latest.zip +0 -0
- package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +86 -86
- package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +4 -4
- package/recipes/chatbot/recipe.json +3 -40
- package/recipes/chatbot-native@latest.zip +0 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +4 -1
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +86 -53
- package/recipes/chatbot-supabase/recipe.json +3 -42
- package/recipes/chatbot-supabase-native@latest.zip +0 -0
- package/recipes/chatbot-supabase@latest.zip +0 -0
- package/recipes/chatbot@latest.zip +0 -0
- package/recipes/glowing-button/recipe.json +6 -2
- package/recipes/glowing-button-native@latest.zip +0 -0
- package/recipes/glowing-button@latest.zip +0 -0
- package/recipes/image-analysis/apps/native/src/app/analysis/[type]/_layout.tsx +5 -0
- package/recipes/image-analysis/apps/native/src/app/analysis/[type]/analysis-options.tsx +50 -0
- package/recipes/image-analysis/apps/native/src/app/analysis/[type]/camera.tsx +2 -0
- package/recipes/image-analysis/apps/native/src/app/analysis/[type]/index.tsx +50 -0
- package/recipes/image-analysis/apps/native/src/app/analysis/[type]/loading.tsx +50 -0
- package/recipes/image-analysis/apps/native/src/app/analysis/[type]/results.tsx +2 -0
- package/recipes/image-analysis/apps/native/src/app/analysis/[type]/trait-details.tsx +3 -0
- package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +2 -2
- package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/camera.tsx +72 -65
- package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +65 -47
- package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/loading-screen.tsx +43 -2
- package/recipes/image-analysis/apps/native/src/features/image-analyzer/app/loading.tsx +34 -1
- package/recipes/image-analysis/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +83 -2
- package/recipes/image-analysis/recipe.json +11 -19
- package/recipes/image-analysis-native@latest.zip +0 -0
- package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/_layout.tsx +5 -0
- package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/analysis-options.tsx +50 -0
- package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/camera.tsx +2 -0
- package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/index.tsx +50 -0
- package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/loading.tsx +50 -0
- package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/results.tsx +2 -0
- package/recipes/image-analysis-supabase/apps/native/src/app/analysis/[type]/trait-details.tsx +3 -0
- package/recipes/image-analysis-supabase/recipe.json +10 -37
- package/recipes/image-analysis-supabase-native@latest.zip +0 -0
- package/recipes/image-analysis-supabase@latest.zip +0 -0
- package/recipes/image-analysis@latest.zip +0 -0
- package/recipes/image-analyzer/apps/native/src/app/(root)/(protected)/image-analyzer/index.tsx +2 -0
- package/recipes/image-generator/apps/native/src/app/image-generator/gallery.tsx +3 -0
- package/recipes/image-generator/apps/native/src/app/image-generator/index.tsx +3 -0
- package/recipes/image-generator/recipe.json +8 -18
- package/recipes/image-generator-native@latest.zip +0 -0
- package/recipes/image-generator-supabase/recipe.json +6 -35
- package/recipes/image-generator-supabase-native@latest.zip +0 -0
- package/recipes/image-generator-supabase@latest.zip +0 -0
- package/recipes/image-generator@latest.zip +0 -0
- package/recipes/ios-widget/recipe.json +18 -119
- package/recipes/ios-widget-native@latest.zip +0 -0
- package/recipes/ios-widget@latest.zip +0 -0
- package/recipes/number-stepper/apps/native/src/components/advanced-ui/stepper/demo.tsx +1 -1
- package/recipes/number-stepper/recipe.json +5 -2
- package/recipes/number-stepper-native@latest.zip +0 -0
- package/recipes/number-stepper@latest.zip +0 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +11 -18
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +5 -7
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +9 -7
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +8 -7
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +6 -5
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +4 -3
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +6 -5
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +5 -7
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +7 -6
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +5 -7
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +8 -7
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +6 -5
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +5 -6
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +5 -4
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +5 -7
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +7 -6
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +4 -3
- package/recipes/onboarding/recipe.json +9 -6
- package/recipes/onboarding-native@latest.zip +0 -0
- package/recipes/onboarding@latest.zip +0 -0
- package/recipes/payments/apps/native/src/app/paywall/index.tsx +74 -0
- package/recipes/payments/apps/native/src/app/paywall/local.tsx +25 -0
- package/recipes/payments/apps/native/src/app/paywall/remote.tsx +23 -0
- package/recipes/payments/packages/backend/convex/payments.ts +21 -3
- package/recipes/payments/recipe.json +14 -34
- package/recipes/payments-native@latest.zip +0 -0
- package/recipes/payments-supabase/apps/native/src/app/paywall/index.tsx +74 -0
- package/recipes/payments-supabase/apps/native/src/app/paywall/local.tsx +25 -0
- package/recipes/payments-supabase/apps/native/src/app/paywall/remote.tsx +23 -0
- package/recipes/payments-supabase/recipe.json +16 -23
- package/recipes/payments-supabase-native@latest.zip +0 -0
- package/recipes/payments-supabase@latest.zip +0 -0
- package/recipes/payments@latest.zip +0 -0
- package/recipes/posthog/apps/native/src/components/analytics/navigation-tracker.tsx +14 -0
- package/recipes/posthog/apps/native/src/lib/hooks/use-navigation-analytics.ts +44 -0
- package/recipes/posthog/apps/native/src/providers/posthog-provider.tsx +51 -0
- package/recipes/posthog/recipe.json +60 -0
- package/recipes/posthog-native@latest.zip +0 -0
- package/recipes/progress-circle/apps/native/src/components/advanced-ui/progress-bars/progress-circle-page.tsx +1 -1
- package/recipes/progress-circle/recipe.json +5 -2
- package/recipes/progress-circle-native@latest.zip +0 -0
- package/recipes/progress-circle@latest.zip +0 -0
- package/recipes/quiz/apps/native/src/app/quiz/index.tsx +47 -0
- package/recipes/quiz/recipe.json +9 -6
- package/recipes/quiz-native@latest.zip +0 -0
- package/recipes/quiz@latest.zip +0 -0
- package/recipes/screen-kits/apps/native/src/app/screen-kits/_layout.tsx +12 -0
- package/recipes/screen-kits/apps/native/src/app/screen-kits/index.tsx +114 -0
- package/recipes/screen-kits/apps/native/src/features/screen-kits/index.ts +1 -0
- package/recipes/screen-kits/apps/native/src/features/screen-kits/types.ts +28 -0
- package/recipes/screen-kits/recipe.json +26 -0
- package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/_layout.tsx +12 -0
- package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/home.tsx +5 -0
- package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/index.tsx +5 -0
- package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson-complete.tsx +5 -0
- package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson-fail.tsx +5 -0
- package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/lesson.tsx +5 -0
- package/recipes/screen-kits-duolingo/apps/native/src/app/screen-kits/duolingo/skill-tree.tsx +5 -0
- package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/duo-button.tsx +174 -0
- package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/skill-button.tsx +186 -0
- package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/components/xp-header.tsx +115 -0
- package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/constants.ts +89 -0
- package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/index.ts +3 -0
- package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/home-screen.tsx +225 -0
- package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-complete-screen.tsx +485 -0
- package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-fail-screen.tsx +105 -0
- package/recipes/screen-kits-duolingo/apps/native/src/features/screen-kits/duolingo/screens/lesson-screen.tsx +384 -0
- package/recipes/screen-kits-duolingo/recipe.json +58 -0
- package/recipes/screen-kits-duolingo-native@latest.zip +0 -0
- package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/_layout.tsx +45 -0
- package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/asset-detail.tsx +3 -0
- package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/notifications.tsx +3 -0
- package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/receive.tsx +3 -0
- package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/send.tsx +3 -0
- package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/swap.tsx +3 -0
- package/recipes/screen-kits-finance/apps/native/src/app/screen-kits/finance/wallet.tsx +3 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/ActionButtons.tsx +78 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/AssetRow.tsx +94 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/components/BalanceCard.tsx +118 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/constants.ts +85 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/asset-detail.tsx +378 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/notifications.tsx +210 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/receive-modal.tsx +317 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/send-modal.tsx +420 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/swap-modal.tsx +363 -0
- package/recipes/screen-kits-finance/apps/native/src/features/screen-kits/finance/screens/wallet-dashboard.tsx +281 -0
- package/recipes/screen-kits-finance/recipe.json +46 -0
- package/recipes/screen-kits-finance-native@latest.zip +0 -0
- package/recipes/screen-kits-fitness/apps/native/assets/sounds/timer-beep.wav +0 -0
- package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/_layout.tsx +10 -0
- package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/index.tsx +6 -0
- package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/timer.tsx +3 -0
- package/recipes/screen-kits-fitness/apps/native/src/app/screen-kits/fitness/workout.tsx +3 -0
- package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/timer-components.tsx +500 -0
- package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/timer-settings-modal.tsx +352 -0
- package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/components/workout-card.tsx +105 -0
- package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/constants.ts +189 -0
- package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/hooks/use-timer.ts +307 -0
- package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/index.ts +1 -0
- package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/screens/timer-screen.tsx +278 -0
- package/recipes/screen-kits-fitness/apps/native/src/features/screen-kits/fitness/screens/workout-dashboard.tsx +350 -0
- package/recipes/screen-kits-fitness/recipe.json +63 -0
- package/recipes/screen-kits-fitness-native@latest.zip +0 -0
- package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/habits.tsx +1 -0
- package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/kanban.tsx +1 -0
- package/recipes/screen-kits-habits/apps/native/src/app/screen-kits/productivity/routes.ts +4 -0
- package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/AddTaskModal.tsx +246 -0
- package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/DraggableTaskCard.tsx +92 -0
- package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/KanbanColumn.tsx +238 -0
- package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/TaskCard.tsx +144 -0
- package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/components/add-habit-modal.tsx +271 -0
- package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/constants.ts +295 -0
- package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/kanban-utils.ts +62 -0
- package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/screens/habit-tracker.tsx +1160 -0
- package/recipes/screen-kits-habits/apps/native/src/features/screen-kits/productivity/screens/kanban-board.tsx +432 -0
- package/recipes/screen-kits-habits/recipe.json +52 -0
- package/recipes/screen-kits-habits-native@latest.zip +0 -0
- package/recipes/screen-kits-native@latest.zip +0 -0
- package/recipes/sentry/apps/native/src/providers/sentry-provider.tsx +64 -0
- package/recipes/sentry/recipe.json +39 -0
- package/recipes/sentry-native@latest.zip +0 -0
- package/recipes/swipe-slider/apps/native/src/components/advanced-ui/sliders/swipe-slider-page.tsx +1 -1
- package/recipes/swipe-slider/recipe.json +5 -2
- package/recipes/swipe-slider-native@latest.zip +0 -0
- package/recipes/swipe-slider@latest.zip +0 -0
- package/recipes/timeline/apps/native/src/components/advanced-ui/timeline/demo.tsx +2 -1
- package/recipes/timeline/recipe.json +5 -2
- package/recipes/timeline-native@latest.zip +0 -0
- package/recipes/timeline@latest.zip +0 -0
- package/recipes/tracker-app/apps/native/src/app/tracker-app/index.tsx +1 -0
- package/recipes/tracker-app/recipe.json +10 -7
- package/recipes/tracker-app-native@latest.zip +0 -0
- package/recipes/tracker-app@latest.zip +0 -0
- package/recipes/upload-all.sh +8 -31
- package/recipes/voice-bot/apps/native/src/app/voice-bot/index.tsx +56 -0
- package/recipes/voice-bot/recipe.json +31 -7
- package/recipes/voice-bot-native@latest.zip +0 -0
- package/recipes/voice-bot@latest.zip +0 -0
- package/recipes/wake-word/apps/native/src/app/{(root)/(protected)/test-wake-word.tsx → test-wake-word.tsx} +43 -4
- package/recipes/wake-word/recipe.json +16 -26
- package/recipes/wake-word-native@latest.zip +0 -0
- package/recipes/wake-word@latest.zip +0 -0
- package/scripts/create-advanced-ui-recipes.sh +46 -19
- package/scripts/create-recipes.mjs +471 -117
- package/scripts/package-recipes.mjs +76 -0
- package/scripts/publish-all.sh +6 -2
- package/CHANGELOG.md +0 -198
- package/docs/archive/AUTO-DETECT-DEPS.md +0 -607
- package/docs/archive/FINAL-PACKAGE-STRATEGY.md +0 -583
- package/docs/archive/FINAL-SIMPLE-PLAN.md +0 -487
- package/docs/archive/FINAL-STATUS.md +0 -144
- package/docs/archive/FLOW-DIAGRAM.md +0 -1629
- package/docs/archive/GOTCHAS-AND-RISKS.md +0 -801
- package/docs/archive/IMPLEMENTATION-PLAN.md +0 -1360
- package/docs/archive/PLAN.md +0 -453
- package/docs/archive/PRODUCTION-READINESS.md +0 -684
- package/docs/archive/PRODUCTION-TEST-RESULTS.md +0 -465
- package/docs/archive/SIMPLIFIED-PLAN.md +0 -578
- package/docs/archive/STATUS.md +0 -199
- package/docs/archive/SUCCESS.md +0 -259
- package/docs/archive/TEST-SUMMARY.md +0 -261
- package/docs/archive/TESTING-CHECKLIST.md +0 -450
- package/docs/archive/USER-MODIFICATIONS.md +0 -448
- package/docs/decisions.md +0 -55
- package/docs/manual-testing.md +0 -91
- package/docs/next-steps.md +0 -12
- package/recipes/README.md +0 -156
- package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +0 -369
- package/recipes/chatbot/apps/native/src/api-client/chatbot.ts +0 -83
- package/recipes/chatbot/packages/backend/convex/agents.ts +0 -115
- package/recipes/chatbot/packages/backend/convex/tools/index.ts +0 -18
- package/recipes/chatbot/packages/backend/convex/tools/knowledgeRetrieval.ts +0 -97
- package/recipes/chatbot/packages/backend/convex/tools/tavilySearch.ts +0 -83
- package/recipes/chatbot/packages/backend/convex/tools/userProfile.ts +0 -72
- package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +0 -515
- package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +0 -243
- package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +0 -327
- package/recipes/image-analysis/apps/native/src/api-client/image-analyzer.ts +0 -62
- package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +0 -132
- package/recipes/image-generator/apps/native/src/api-client/image-generator.ts +0 -34
- package/recipes/payments/apps/native/src/api-client/payments.ts +0 -44
- package/recipes/payments-supabase/packages/backend/src/services/payments.ts +0 -201
- package/recipes/posthog.json +0 -47
- package/recipes/revenuecat.json +0 -43
- package/recipes/sentry.json +0 -47
- package/recipes/wake-word/apps/native/assets/vosk-model/README.md +0 -103
- package/recipes/wake-word/apps/native/scripts/download-vosk-model.mjs +0 -127
- /package/recipes/{audio-recorder/apps/native/src/app/(root)/(protected) → audio-recorder-supabase/apps/native/src/app}/audio-recorder/index.tsx +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/AppIntent.swift +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/CalorieTrackerWidget.swift +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/HabitTrackerWidget.swift +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/Info.plist +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/WidgetLiveActivity.swift +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/expo-target.config.js +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/generated.entitlements +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/index.swift +0 -0
- /package/recipes/ios-widget/{targets → apps/native/targets}/widget/widgets.swift +0 -0
package/dist/commands/add.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
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
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
log.plain(
|
|
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
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
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
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
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.
|
|
350
|
+
log.plain(`Details: ${message}`);
|
|
310
351
|
}
|
|
311
352
|
log.plain("");
|
|
312
|
-
|
|
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
|
-
//
|
|
365
|
+
// Install recipe
|
|
325
366
|
retry_install: while (true) {
|
|
326
367
|
try {
|
|
327
|
-
// Download and extract
|
|
328
|
-
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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,10 +727,20 @@ 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);
|
|
685
739
|
}
|
|
740
|
+
// Apply backend exports injection
|
|
741
|
+
if (installedManifest?.configuration?.backend) {
|
|
742
|
+
await applyBackendConfiguration(paths, installedManifest.configuration.backend, options);
|
|
743
|
+
}
|
|
686
744
|
// Apply app.config plugin inserts for certain features
|
|
687
745
|
if (installedManifest?.name) {
|
|
688
746
|
await applyAppConfigPlugins(installedManifest, paths, options);
|
|
@@ -712,6 +770,13 @@ export async function installFeature(feature, options, paths) {
|
|
|
712
770
|
completedSteps.push(step.title);
|
|
713
771
|
}
|
|
714
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
|
+
}
|
|
715
780
|
else if (step.file === ".gitignore") {
|
|
716
781
|
if (content.includes("assets/vosk-model/model-en-us")) {
|
|
717
782
|
alreadyDone = true;
|
|
@@ -783,6 +848,13 @@ export async function installFeature(feature, options, paths) {
|
|
|
783
848
|
}
|
|
784
849
|
}
|
|
785
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
|
+
}
|
|
786
858
|
else if (featureName === "wake-word" &&
|
|
787
859
|
step.file === ".gitignore") {
|
|
788
860
|
const filePath = join(paths.cwd, step.file);
|
|
@@ -926,8 +998,88 @@ async function applyEnvConfiguration(paths, envConfig, options) {
|
|
|
926
998
|
}
|
|
927
999
|
}
|
|
928
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
|
+
}
|
|
929
1079
|
const API_CLIENT_EXPORTS_START = "// --- @vibefast:api-client:exports:start ---";
|
|
930
1080
|
const API_CLIENT_EXPORTS_END = "// --- @vibefast:api-client:exports:end ---";
|
|
1081
|
+
const BACKEND_EXPORTS_START = "// --- @vibefast:backend:exports:start ---";
|
|
1082
|
+
const BACKEND_EXPORTS_END = "// --- @vibefast:backend:exports:end ---";
|
|
931
1083
|
async function applyApiClientConfiguration(paths, apiClientConfig, options) {
|
|
932
1084
|
const apiClientIndexPath = join(paths.nativeDir, "src/api-client/index.ts");
|
|
933
1085
|
if (!(await exists(apiClientIndexPath))) {
|
|
@@ -941,6 +1093,30 @@ async function applyApiClientConfiguration(paths, apiClientConfig, options) {
|
|
|
941
1093
|
}
|
|
942
1094
|
}
|
|
943
1095
|
}
|
|
1096
|
+
async function applyBackendConfiguration(paths, backendConfig, options) {
|
|
1097
|
+
// Try to find backend index.ts in common locations
|
|
1098
|
+
const possiblePaths = [
|
|
1099
|
+
join(paths.cwd, "packages/backend/src/index.ts"),
|
|
1100
|
+
join(paths.cwd, "backend/src/index.ts"),
|
|
1101
|
+
];
|
|
1102
|
+
let backendIndexPath = null;
|
|
1103
|
+
for (const p of possiblePaths) {
|
|
1104
|
+
if (await exists(p)) {
|
|
1105
|
+
backendIndexPath = p;
|
|
1106
|
+
break;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
if (!backendIndexPath) {
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1112
|
+
const suffix = options.dryRun ? " (dry run)" : "";
|
|
1113
|
+
if (backendConfig.exports?.length) {
|
|
1114
|
+
const inserted = await insertEnvSnippets(backendIndexPath, BACKEND_EXPORTS_START, BACKEND_EXPORTS_END, backendConfig.exports, options);
|
|
1115
|
+
if (inserted) {
|
|
1116
|
+
log.info(`Updated backend exports${suffix}.`);
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
944
1120
|
async function applyAppConfigPlugins(manifest, paths, options) {
|
|
945
1121
|
const appConfigPath = join(paths.nativeDir, "app.config.ts");
|
|
946
1122
|
if (!(await exists(appConfigPath)))
|