vibefast-cli 1.1.5 → 1.3.0
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/CHANGELOG.md +32 -0
- package/README.md +63 -169
- package/dist/__tests__/recipes.test.js +89 -85
- package/dist/__tests__/recipes.test.js.map +1 -1
- package/dist/commands/add.d.ts +1 -1
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +576 -588
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/checklist.d.ts +1 -1
- package/dist/commands/checklist.d.ts.map +1 -1
- package/dist/commands/checklist.js +40 -39
- package/dist/commands/checklist.js.map +1 -1
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +22 -22
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/env.d.ts +1 -1
- package/dist/commands/env.d.ts.map +1 -1
- package/dist/commands/env.js +58 -53
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/health.d.ts +1 -1
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +101 -93
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +416 -296
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/remove.d.ts +1 -1
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +77 -64
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +15 -14
- package/dist/commands/status.js.map +1 -1
- package/dist/core/__tests__/detect.test.js +68 -34
- package/dist/core/__tests__/detect.test.js.map +1 -1
- package/dist/core/ast.d.ts +14 -0
- package/dist/core/ast.d.ts.map +1 -0
- package/dist/core/ast.js +239 -0
- package/dist/core/ast.js.map +1 -0
- package/dist/core/codemod.d.ts.map +1 -1
- package/dist/core/codemod.js +62 -44
- package/dist/core/codemod.js.map +1 -1
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +51 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/detect.d.ts +8 -2
- package/dist/core/detect.d.ts.map +1 -1
- package/dist/core/detect.js +52 -21
- package/dist/core/detect.js.map +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +9 -8
- package/dist/core/errors.js.map +1 -1
- package/dist/core/exec.d.ts +16 -0
- package/dist/core/exec.d.ts.map +1 -0
- package/dist/core/exec.js +48 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/manualSteps.d.ts +7 -0
- package/dist/core/manualSteps.d.ts.map +1 -0
- package/dist/core/manualSteps.js +59 -0
- package/dist/core/manualSteps.js.map +1 -0
- package/dist/core/paths.d.ts +3 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +14 -10
- package/dist/core/paths.js.map +1 -1
- package/dist/core/spinner.d.ts +1 -1
- package/dist/core/spinner.d.ts.map +1 -1
- package/dist/core/spinner.js +38 -8
- package/dist/core/spinner.js.map +1 -1
- package/dist/core/vosk.d.ts.map +1 -1
- package/dist/core/vosk.js +50 -39
- package/dist/core/vosk.js.map +1 -1
- package/docs/manual-testing.md +91 -0
- package/package.json +6 -3
- package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
- package/recipes/audio-recorder/recipe.json +3 -3
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/index.ts +4 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
- package/recipes/audio-recorder-supabase/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
- package/recipes/audio-recorder-supabase/packages/backend/src/services/recordings.ts +369 -0
- package/recipes/audio-recorder-supabase/packages/backend/supabase/migrations/recordings.sql +70 -0
- package/recipes/audio-recorder-supabase/recipe.json +52 -0
- package/recipes/audio-recorder-supabase@latest.zip +0 -0
- package/recipes/audio-recorder@latest.zip +0 -0
- package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +3 -3
- package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +2 -2
- package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +5 -5
- package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +3 -3
- package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +20 -4
- package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +7 -6
- package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +6 -4
- package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +1 -1
- package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +5 -4
- package/recipes/charts/recipe.json +4 -13
- package/recipes/charts@latest.zip +0 -0
- package/recipes/chatbot/apps/native/src/app/chatbot/index.tsx +1 -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 +86 -53
- package/recipes/chatbot/recipe.json +26 -92
- package/recipes/chatbot-supabase/apps/native/src/api-client/supabase/chatbot.ts +515 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/app/index.tsx +257 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-input-bar.tsx +485 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +223 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/image-preview-list.tsx +116 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/message-list.tsx +170 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/models.ts +20 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +142 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-config.ts +458 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +429 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-conversation.ts +90 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +213 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/index.ts +86 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/models.ts +162 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/providers.ts +62 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/models/types.ts +40 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/file-uploader.ts +287 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/services/message-handler-service.ts +189 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/types/index.ts +70 -0
- package/recipes/chatbot-supabase/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
- package/recipes/chatbot-supabase/packages/backend/src/services/conversations.ts +243 -0
- package/recipes/chatbot-supabase/packages/backend/src/services/messages.ts +327 -0
- package/recipes/chatbot-supabase/packages/backend/supabase/functions/chat-stream/index.ts +347 -0
- package/recipes/chatbot-supabase/packages/backend/supabase/migrations/chatbot.sql +104 -0
- package/recipes/chatbot-supabase/recipe.json +106 -0
- package/recipes/chatbot-supabase@latest.zip +0 -0
- package/recipes/chatbot.zip +0 -0
- package/recipes/chatbot@latest.zip +0 -0
- package/recipes/image-analysis/packages/backend/convex/imageAnalysis/index.ts +2 -2
- package/recipes/image-analysis/packages/backend/convex/imageAnalysis.ts +0 -1
- package/recipes/image-analysis/recipe.json +15 -55
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/analysis-options-screen.tsx +304 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/camera.tsx +221 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/image-capture-screen.tsx +333 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading-screen.tsx +214 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/loading.tsx +191 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/results.tsx +137 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/trait-details.tsx +172 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-analysis-data.ts +160 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/app/use-results-screen.ts +151 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-badge.tsx +77 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-card.tsx +75 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievement-unlocked-modal.tsx +162 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/achievements-section.tsx +44 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/advice-list.tsx +42 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/circular-progress.tsx +233 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/content-card.tsx +38 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/error-state.tsx +42 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/index.ts +9 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/loading-state.tsx +26 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/profile-image.tsx +60 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/results-header.tsx +62 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/score-display.tsx +54 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/share-options-modal.tsx +110 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/components/results/traits-grid.tsx +74 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/analysis-config.ts +80 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/config/master-analysis-config.ts +157 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/index.ts +1 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-analysis.ts +38 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/hooks/use-image-analysis.ts +208 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/analysis-service.ts +262 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/share-service.ts +176 -0
- package/recipes/image-analysis-supabase/apps/native/src/features/image-analyzer/services/trait-details-service.ts +289 -0
- package/recipes/image-analysis-supabase/packages/backend/src/services/image-analyses.ts +132 -0
- package/recipes/image-analysis-supabase/packages/backend/supabase/functions/analyze-image/index.ts +312 -0
- package/recipes/image-analysis-supabase/packages/backend/supabase/migrations/image_analysis.sql +42 -0
- package/recipes/image-analysis-supabase/recipe.json +90 -0
- package/recipes/image-analysis-supabase@latest.zip +0 -0
- package/recipes/image-analysis@latest.zip +0 -0
- package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +16 -2
- package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +11 -5
- package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +11 -5
- package/recipes/image-generator/packages/backend/convex/imageGeneration/index.ts +2 -2
- package/recipes/image-generator/recipe.json +16 -39
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/_layout.tsx +26 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/app/index.tsx +251 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/gallery-image.tsx +25 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-model-selector.tsx +216 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/hooks/use-image-generator.ts +103 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/models/models.ts +66 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-gallery-service.ts +96 -0
- package/recipes/image-generator-supabase/apps/native/src/features/image-generator/services/image-save-service.ts +120 -0
- package/recipes/image-generator-supabase/packages/backend/supabase/functions/generate-image/index.ts +291 -0
- package/recipes/image-generator-supabase/packages/backend/supabase/migrations/image_generator.sql +71 -0
- package/recipes/image-generator-supabase/recipe.json +86 -0
- package/recipes/image-generator-supabase@latest.zip +0 -0
- package/recipes/image-generator@latest.zip +0 -0
- package/recipes/ios-widget/recipe.json +15 -24
- package/recipes/ios-widget@latest.zip +0 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/analytics/index.ts +9 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding-with-analytics.tsx +141 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/components/onboarding.tsx +173 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/config/onboarding-flow-config.ts +189 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/app/index.tsx +42 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/demo-one/data.ts +32 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/app/index.tsx +43 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/interactive-onboarding.tsx +222 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/ai-tone-step.tsx +133 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/currency-step.tsx +165 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-ai-step.tsx +199 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-chatbot-step.tsx +154 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-manual-step.tsx +156 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/feature-scan-step.tsx +158 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/main-reason-step.tsx +139 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/notification-step.tsx +129 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/overspend-step.tsx +138 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/personalizing-step.tsx +190 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/rating-step.tsx +98 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/reminder-step.tsx +181 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/safety-step.tsx +110 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/struggle-step.tsx +139 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/steps/welcome-step.tsx +217 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/components/ui/onboarding-header.tsx +58 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/expense-tracker/constants.ts +179 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/hooks/use-onboarding-analytics.ts +323 -0
- package/recipes/onboarding/apps/native/src/features/onboarding/services/onboarding-analytics.ts +432 -0
- package/recipes/onboarding/recipe.json +15 -0
- package/recipes/onboarding@latest.zip +0 -0
- package/recipes/payments/recipe.json +28 -61
- package/recipes/payments-supabase/apps/native/src/features/payments/README.md +200 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/app/local-paywall.tsx +194 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/app/remote-paywall.tsx +79 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/payment-initializer.tsx +95 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-error-state.tsx +60 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-local-mode.tsx +116 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-product-card.tsx +133 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/components/paywall-remote-mode.tsx +146 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/hooks/use-entitlement.ts +63 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/index.ts +8 -0
- package/recipes/payments-supabase/apps/native/src/features/payments/services/revenuecat-adapter.ts +407 -0
- package/recipes/payments-supabase/packages/backend/src/services/payments.ts +201 -0
- package/recipes/payments-supabase/packages/backend/supabase/migrations/payments.sql +35 -0
- package/recipes/payments-supabase/recipe.json +72 -0
- package/recipes/payments-supabase@latest.zip +0 -0
- package/recipes/payments@latest.zip +0 -0
- package/recipes/quiz/apps/native/src/features/quiz/index.tsx +1 -2
- package/recipes/quiz/recipe.json +6 -9
- package/recipes/quiz@latest.zip +0 -0
- package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +1 -2
- package/recipes/tracker-app/recipe.json +7 -10
- package/recipes/tracker-app@latest.zip +0 -0
- package/recipes/voice-bot/recipe.json +8 -68
- package/recipes/voice-bot.zip +0 -0
- package/recipes/voice-bot@latest.zip +0 -0
- package/recipes/wake-word/recipe.json +10 -9
- package/recipes/wake-word.zip +0 -0
- package/recipes/wake-word@latest.zip +0 -0
- package/recipes/charts/apps/native/src/app/(root)/(protected)/charts/index.tsx +0 -3
- package/recipes/chatbot/packages/backend/convex/lib/rateLimit.ts +0 -100
- package/recipes/chatbot/packages/backend/convex/lib/telemetry.ts +0 -29
- package/recipes/chatbot/packages/backend/convex/ragKnowledge.ts +0 -0
- package/recipes/image-analysis/apps/native/assets/features/image-analyzer/front.jpg +0 -0
- package/recipes/image-analysis/apps/native/assets/features/image-analyzer/side.jpg +0 -0
- package/recipes/image-analysis/apps/native/assets/features/image-analyzer/threeQuarter.jpg +0 -0
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/_layout.tsx +0 -5
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/analysis-options.tsx +0 -50
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/camera.tsx +0 -2
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/index.tsx +0 -50
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/loading.tsx +0 -50
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/results.tsx +0 -2
- package/recipes/image-analysis/apps/native/src/app/(root)/(protected)/analysis/[type]/trait-details.tsx +0 -3
- package/recipes/image-analysis/packages/backend/convex/imageAnalysisFunctions.ts +0 -325
- package/recipes/image-analysis/packages/backend/convex/lib/ai/imageAnalysisAdapter.ts +0 -200
- package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/index.tsx +0 -74
- package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/local.tsx +0 -25
- package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/remote.tsx +0 -23
- package/recipes/quiz/apps/native/src/app/(root)/(protected)/quiz/index.tsx +0 -47
- package/recipes/tracker-app/apps/native/src/app/(root)/(protected)/tracker-app/index.tsx +0 -1
- package/recipes/voice-bot/apps/native/src/app/(root)/(protected)/voice-bot/index.tsx +0 -27
- package/recipes/voice-bot/packages/backend/convex/router.ts +0 -81
- /package/recipes/{chatbot/apps/native/src/app/(root)/(protected) → chatbot-supabase/apps/native/src/app}/chatbot/index.tsx +0 -0
- /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/gallery.tsx +0 -0
- /package/recipes/{image-generator/apps/native/src/app/(root)/(protected) → image-generator-supabase/apps/native/src/app}/image-generator/index.tsx +0 -0
package/dist/commands/init.js
CHANGED
|
@@ -1,330 +1,430 @@
|
|
|
1
|
-
import { Command } from
|
|
2
|
-
import { log } from
|
|
3
|
-
import { withSpinner } from
|
|
4
|
-
import { promptSelectAsync, promptUser, promptYesNo } from
|
|
5
|
-
import simpleGit from
|
|
6
|
-
import { existsSync } from
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { Command, Option } from "commander";
|
|
2
|
+
import { log } from "../core/log.js";
|
|
3
|
+
import { withSpinner } from "../core/spinner.js";
|
|
4
|
+
import { promptSelectAsync, promptUser, promptYesNo, } from "../core/prompt.js";
|
|
5
|
+
import simpleGit from "simple-git";
|
|
6
|
+
import { existsSync } from "fs";
|
|
7
|
+
import { readFile } from "fs/promises";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { runCommand, spawnCommand } from "../core/exec.js";
|
|
10
|
+
import { appendManualSteps } from "../core/manualSteps.js";
|
|
11
|
+
/**
|
|
12
|
+
* Sync Convex environment variables from backend to native/web .env.local files.
|
|
13
|
+
* Reads CONVEX_URL from packages/backend/.env.local, derives CONVEX_SITE_URL,
|
|
14
|
+
* and REPLACES placeholder values in apps/native/.env.local and apps/web/.env.local.
|
|
15
|
+
*/
|
|
16
|
+
async function syncConvexEnvToFrontends(projectPath, platforms) {
|
|
17
|
+
const backendEnvPath = join(projectPath, "packages/backend/.env.local");
|
|
18
|
+
// Check if backend env exists
|
|
19
|
+
if (!existsSync(backendEnvPath)) {
|
|
20
|
+
return; // No backend env to sync
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
const backendEnv = await readFile(backendEnvPath, "utf-8");
|
|
24
|
+
// Extract CONVEX_URL from backend env
|
|
25
|
+
const convexUrlMatch = backendEnv.match(/CONVEX_URL=(.+)/);
|
|
26
|
+
if (!convexUrlMatch) {
|
|
27
|
+
return; // No CONVEX_URL found
|
|
28
|
+
}
|
|
29
|
+
const convexUrl = convexUrlMatch[1].trim();
|
|
30
|
+
// Derive CONVEX_SITE_URL by replacing .cloud with .site
|
|
31
|
+
const convexSiteUrl = convexUrl.replace(".convex.cloud", ".convex.site");
|
|
32
|
+
// Helper function to replace placeholder values in env file
|
|
33
|
+
const replaceEnvValues = async (envPath) => {
|
|
34
|
+
if (!existsSync(envPath))
|
|
35
|
+
return false;
|
|
36
|
+
let envContent = await readFile(envPath, "utf-8");
|
|
37
|
+
let changed = false;
|
|
38
|
+
// Replace CONVEX_URL=replace_me or any placeholder with actual value
|
|
39
|
+
if (envContent.match(/CONVEX_URL=.*/)) {
|
|
40
|
+
const newContent = envContent.replace(/CONVEX_URL=.*/g, `CONVEX_URL=${convexUrl}`);
|
|
41
|
+
if (newContent !== envContent) {
|
|
42
|
+
envContent = newContent;
|
|
43
|
+
changed = true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Replace CONVEX_SITE_URL=replace_me or any placeholder with actual value
|
|
47
|
+
if (envContent.match(/CONVEX_SITE_URL=.*/)) {
|
|
48
|
+
const newContent = envContent.replace(/CONVEX_SITE_URL=.*/g, `CONVEX_SITE_URL=${convexSiteUrl}`);
|
|
49
|
+
if (newContent !== envContent) {
|
|
50
|
+
envContent = newContent;
|
|
51
|
+
changed = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (changed) {
|
|
55
|
+
const { writeFile } = await import("fs/promises");
|
|
56
|
+
await writeFile(envPath, envContent, "utf-8");
|
|
57
|
+
}
|
|
58
|
+
return changed;
|
|
59
|
+
};
|
|
60
|
+
// Sync to native if platform selected
|
|
61
|
+
if (platforms.includes("native")) {
|
|
62
|
+
const nativeEnvPath = join(projectPath, "apps/native/.env.local");
|
|
63
|
+
const synced = await replaceEnvValues(nativeEnvPath);
|
|
64
|
+
if (synced) {
|
|
65
|
+
log.info("✓ Synced Convex URLs to apps/native/.env.local");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Sync to web if platform selected
|
|
69
|
+
if (platforms.includes("web")) {
|
|
70
|
+
const webEnvPath = join(projectPath, "apps/web/.env.local");
|
|
71
|
+
const synced = await replaceEnvValues(webEnvPath);
|
|
72
|
+
if (synced) {
|
|
73
|
+
log.info("✓ Synced Convex URLs to apps/web/.env.local");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Silently fail - env sync is best-effort
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export const initCommand = new Command("init")
|
|
82
|
+
.description("Initialize a new VibeFast project")
|
|
83
|
+
.option("--license <key>", "Your VibeFast license key")
|
|
84
|
+
.option("--branch <branch>", "Branch to clone (clean or main, default: clean)")
|
|
85
|
+
.addOption(new Option("--backend <backend>", "Backend type")
|
|
86
|
+
.choices(["convex", "supabase"])
|
|
87
|
+
.default("convex"))
|
|
88
|
+
.option("--yes", "Skip all prompts and use defaults")
|
|
89
|
+
.option("--skip-install", "Skip dependency installation")
|
|
17
90
|
.action(async (options) => {
|
|
18
91
|
try {
|
|
19
|
-
log.plain(
|
|
20
|
-
log.info(
|
|
21
|
-
log.plain(
|
|
92
|
+
log.plain("");
|
|
93
|
+
log.info("🚀 VibeFast Project Initialization");
|
|
94
|
+
log.plain("");
|
|
22
95
|
// Check if already in a VibeFast project
|
|
23
|
-
if (existsSync(
|
|
24
|
-
log.error(
|
|
25
|
-
log.info(
|
|
96
|
+
if (existsSync(".vibefast-signature.json")) {
|
|
97
|
+
log.error("Already in a VibeFast project!");
|
|
98
|
+
log.info("This directory already contains a VibeFast project.");
|
|
26
99
|
process.exit(1);
|
|
27
100
|
}
|
|
28
101
|
// Step 0: Check License Key (REQUIRED)
|
|
29
102
|
let licenseKey = options.license;
|
|
30
103
|
// Check if user already has a license key saved
|
|
31
104
|
if (!licenseKey) {
|
|
32
|
-
const { getToken } = await import(
|
|
105
|
+
const { getToken } = await import("../core/auth.js");
|
|
33
106
|
const existingToken = await getToken();
|
|
34
107
|
if (existingToken) {
|
|
35
|
-
log.info(
|
|
108
|
+
log.info("✓ Using existing license key");
|
|
36
109
|
licenseKey = existingToken;
|
|
37
110
|
}
|
|
38
111
|
}
|
|
39
112
|
if (!licenseKey) {
|
|
40
|
-
log.plain(
|
|
41
|
-
log.info(
|
|
42
|
-
log.plain(
|
|
43
|
-
log.info(
|
|
44
|
-
log.info(
|
|
45
|
-
log.plain(
|
|
113
|
+
log.plain("");
|
|
114
|
+
log.info("🔑 VibeFast License Key Required");
|
|
115
|
+
log.plain("");
|
|
116
|
+
log.info("To use VibeFast, you need a valid license key.");
|
|
117
|
+
log.info("Get one at: https://vibefast.pro");
|
|
118
|
+
log.plain("");
|
|
46
119
|
if (options.yes) {
|
|
47
120
|
log.error('License key is required. Use --license <key> or run "vf login" first');
|
|
48
121
|
process.exit(1);
|
|
49
122
|
}
|
|
50
|
-
licenseKey = await promptUser(
|
|
51
|
-
if (!licenseKey || licenseKey.trim() ===
|
|
52
|
-
log.error(
|
|
123
|
+
licenseKey = await promptUser("Enter your license key: ");
|
|
124
|
+
if (!licenseKey || licenseKey.trim() === "") {
|
|
125
|
+
log.error("License key cannot be empty");
|
|
53
126
|
process.exit(1);
|
|
54
127
|
}
|
|
55
128
|
// Save globally for future use
|
|
56
|
-
const { saveToken } = await import(
|
|
129
|
+
const { saveToken } = await import("../core/auth.js");
|
|
57
130
|
await saveToken(licenseKey);
|
|
58
131
|
}
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
if (options.branch &&
|
|
132
|
+
// Note: Branch will be derived from backend choice after selection
|
|
133
|
+
// For now just validate if branch is passed explicitly
|
|
134
|
+
if (options.branch &&
|
|
135
|
+
options.branch !== "clean" &&
|
|
136
|
+
options.branch !== "main") {
|
|
62
137
|
log.error('Invalid branch. Use "clean" or "main".');
|
|
63
138
|
process.exit(1);
|
|
64
139
|
}
|
|
65
140
|
// Step 1.5: Choose platforms
|
|
66
|
-
let platforms = [
|
|
141
|
+
let platforms = ["native", "web"];
|
|
67
142
|
if (!options.yes) {
|
|
68
|
-
const platformChoice = await promptSelectAsync(
|
|
143
|
+
const platformChoice = (await promptSelectAsync("Which platforms do you want to include?", [
|
|
69
144
|
{
|
|
70
|
-
value:
|
|
71
|
-
label:
|
|
72
|
-
description:
|
|
145
|
+
value: "both",
|
|
146
|
+
label: "Both (Native + Web)",
|
|
147
|
+
description: "Full monorepo with mobile and web app",
|
|
73
148
|
},
|
|
74
149
|
{
|
|
75
|
-
value:
|
|
76
|
-
label:
|
|
77
|
-
description:
|
|
150
|
+
value: "native",
|
|
151
|
+
label: "Native Only (Expo)",
|
|
152
|
+
description: "Mobile app only (iOS & Android)",
|
|
78
153
|
},
|
|
79
154
|
{
|
|
80
|
-
value:
|
|
81
|
-
label:
|
|
82
|
-
description:
|
|
155
|
+
value: "web",
|
|
156
|
+
label: "Web Only (Next.js)",
|
|
157
|
+
description: "Web app only",
|
|
83
158
|
},
|
|
84
|
-
]);
|
|
85
|
-
if (platformChoice ===
|
|
86
|
-
platforms = [
|
|
87
|
-
log.info(
|
|
159
|
+
]));
|
|
160
|
+
if (platformChoice === "native") {
|
|
161
|
+
platforms = ["native"];
|
|
162
|
+
log.info("Selected: Native (Expo) only");
|
|
88
163
|
}
|
|
89
|
-
else if (platformChoice ===
|
|
90
|
-
platforms = [
|
|
91
|
-
log.info(
|
|
164
|
+
else if (platformChoice === "web") {
|
|
165
|
+
platforms = ["web"];
|
|
166
|
+
log.info("Selected: Web (Next.js) only");
|
|
92
167
|
}
|
|
93
168
|
else {
|
|
94
|
-
platforms = [
|
|
95
|
-
log.info(
|
|
169
|
+
platforms = ["native", "web"];
|
|
170
|
+
log.info("Selected: Both platforms");
|
|
96
171
|
}
|
|
97
172
|
}
|
|
98
173
|
else {
|
|
99
|
-
log.info(
|
|
174
|
+
log.info("Using default: Both platforms");
|
|
175
|
+
}
|
|
176
|
+
log.plain("");
|
|
177
|
+
// Step 1.6: Choose backend
|
|
178
|
+
let backend = options.backend || "convex";
|
|
179
|
+
if (!options.yes) {
|
|
180
|
+
backend = (await promptSelectAsync("Which backend do you want to use?", [
|
|
181
|
+
{
|
|
182
|
+
value: "convex",
|
|
183
|
+
label: "Convex",
|
|
184
|
+
description: "Real-time sync, serverless functions",
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
value: "supabase",
|
|
188
|
+
label: "Supabase",
|
|
189
|
+
description: "PostgreSQL, auth, storage",
|
|
190
|
+
},
|
|
191
|
+
]));
|
|
192
|
+
log.info(`Selected: ${backend === "convex" ? "Convex" : "Supabase"} backend`);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
log.info(`Using backend: ${backend}`);
|
|
100
196
|
}
|
|
101
|
-
log.plain(
|
|
197
|
+
log.plain("");
|
|
198
|
+
// Derive the branch based on backend (both clean and custom clone the appropriate clean branch)
|
|
199
|
+
const branch = backend === "supabase" ? "supabase-clean" : "clean";
|
|
102
200
|
// Step 1: Choose starter type (after platform selection)
|
|
103
|
-
let starterType =
|
|
201
|
+
let starterType = "clean";
|
|
104
202
|
let selectedFeatures = [];
|
|
105
203
|
if (!options.yes) {
|
|
106
|
-
starterType = await promptSelectAsync(
|
|
204
|
+
starterType = (await promptSelectAsync("How would you like to start?", [
|
|
107
205
|
{
|
|
108
|
-
value:
|
|
109
|
-
label:
|
|
110
|
-
description:
|
|
206
|
+
value: "clean",
|
|
207
|
+
label: "Clean",
|
|
208
|
+
description: "Minimal setup - add features later with vf add",
|
|
111
209
|
},
|
|
112
210
|
{
|
|
113
|
-
value:
|
|
114
|
-
label:
|
|
115
|
-
description:
|
|
211
|
+
value: "custom",
|
|
212
|
+
label: "Custom",
|
|
213
|
+
description: "Choose features now - one-shot setup",
|
|
116
214
|
},
|
|
117
|
-
]);
|
|
118
|
-
log.info(`Selected: ${starterType ===
|
|
119
|
-
log.plain(
|
|
215
|
+
]));
|
|
216
|
+
log.info(`Selected: ${starterType === "clean" ? "Clean starter" : "Custom setup"}`);
|
|
217
|
+
log.plain("");
|
|
120
218
|
// If custom, let them choose features (only when native is present; current feature set is native-only)
|
|
121
|
-
if (starterType ===
|
|
122
|
-
if (!platforms.includes(
|
|
123
|
-
log.warn(
|
|
219
|
+
if (starterType === "custom") {
|
|
220
|
+
if (!platforms.includes("native")) {
|
|
221
|
+
log.warn("⚠ No installable features for Web-only at the moment. Skipping feature selection.");
|
|
124
222
|
}
|
|
125
223
|
else {
|
|
126
|
-
const { promptMultiSelectAsync } = await import(
|
|
127
|
-
const { getRecipesByCategory } = await import(
|
|
128
|
-
log.info(
|
|
129
|
-
log.plain(
|
|
130
|
-
const nativeFeatures = getRecipesByCategory(
|
|
224
|
+
const { promptMultiSelectAsync } = await import("../core/prompt.js");
|
|
225
|
+
const { getRecipesByCategory } = await import("../core/recipes.js");
|
|
226
|
+
log.info("📦 Select features to include:");
|
|
227
|
+
log.plain("");
|
|
228
|
+
const nativeFeatures = getRecipesByCategory("feature").map((r) => ({
|
|
131
229
|
value: r.name,
|
|
132
230
|
label: `${r.icon} ${r.name}`,
|
|
133
231
|
description: r.description,
|
|
134
232
|
}));
|
|
135
|
-
selectedFeatures = await promptMultiSelectAsync(
|
|
233
|
+
selectedFeatures = await promptMultiSelectAsync("Select features (use space to toggle, enter to confirm):", nativeFeatures);
|
|
136
234
|
if (selectedFeatures.length > 0) {
|
|
137
|
-
log.info(`Selected ${selectedFeatures.length} feature(s): ${selectedFeatures.join(
|
|
235
|
+
log.info(`Selected ${selectedFeatures.length} feature(s): ${selectedFeatures.join(", ")}`);
|
|
138
236
|
}
|
|
139
237
|
else {
|
|
140
|
-
log.info(
|
|
238
|
+
log.info("No features selected - starting with clean setup");
|
|
141
239
|
}
|
|
142
|
-
log.plain(
|
|
240
|
+
log.plain("");
|
|
143
241
|
}
|
|
144
242
|
}
|
|
145
243
|
}
|
|
146
244
|
else {
|
|
147
|
-
log.info(
|
|
148
|
-
log.plain(
|
|
245
|
+
log.info("Using default: Clean starter");
|
|
246
|
+
log.plain("");
|
|
149
247
|
}
|
|
150
248
|
// Step 2: Get project name
|
|
151
|
-
const defaultName =
|
|
249
|
+
const defaultName = "vibefast-app";
|
|
152
250
|
let projectName = defaultName;
|
|
153
251
|
if (!options.yes) {
|
|
154
|
-
projectName = await promptUser(
|
|
252
|
+
projectName = (await promptUser("Project name: ")) || defaultName;
|
|
155
253
|
}
|
|
156
254
|
projectName = (projectName || defaultName).trim();
|
|
157
255
|
if (!projectName) {
|
|
158
256
|
projectName = defaultName;
|
|
159
257
|
}
|
|
160
258
|
if (!/^[a-zA-Z0-9_-]+$/.test(projectName)) {
|
|
161
|
-
log.error(
|
|
259
|
+
log.error("Project name must use only letters, numbers, hyphens, and underscores.");
|
|
162
260
|
process.exit(1);
|
|
163
261
|
}
|
|
164
262
|
// Validate project name
|
|
165
263
|
if (existsSync(projectName)) {
|
|
166
264
|
log.error(`Directory "${projectName}" already exists!`);
|
|
167
|
-
log.info(
|
|
265
|
+
log.info("Please choose a different name or remove the existing directory.");
|
|
168
266
|
process.exit(1);
|
|
169
267
|
}
|
|
170
|
-
log.plain(
|
|
268
|
+
log.plain("");
|
|
171
269
|
// Step 3: Clone repository
|
|
172
270
|
// Note: This is a private repo, so we need GitHub credentials
|
|
173
271
|
// Users can authenticate via:
|
|
174
272
|
// 1. SSH key (recommended)
|
|
175
273
|
// 2. GitHub CLI (gh auth)
|
|
176
274
|
// 3. Personal access token in URL
|
|
177
|
-
const repoUrl =
|
|
275
|
+
const repoUrl = "https://github.com/mzafarr/vibefast-pro.git";
|
|
178
276
|
await withSpinner(`Cloning VibeFast monorepo (${branch} branch)...`, async () => {
|
|
179
277
|
const git = simpleGit();
|
|
180
|
-
const cloneOptions = [
|
|
278
|
+
const cloneOptions = ["--depth", "1"];
|
|
181
279
|
// Use selected branch (default: clean)
|
|
182
|
-
cloneOptions.unshift(
|
|
280
|
+
cloneOptions.unshift("--branch", branch, "--single-branch");
|
|
183
281
|
try {
|
|
184
282
|
await git.clone(repoUrl, projectName, cloneOptions);
|
|
185
283
|
}
|
|
186
284
|
catch (error) {
|
|
187
285
|
// Handle authentication errors
|
|
188
|
-
if (error.message.includes(
|
|
189
|
-
error.message.includes(
|
|
190
|
-
error.message.includes(
|
|
191
|
-
throw new Error(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
286
|
+
if (error.message.includes("Authentication failed") ||
|
|
287
|
+
error.message.includes("permission denied") ||
|
|
288
|
+
error.message.includes("fatal: could not read Username")) {
|
|
289
|
+
throw new Error("GitHub authentication failed. This is a private repository.\n\n" +
|
|
290
|
+
"To access it, you need to authenticate with GitHub:\n\n" +
|
|
291
|
+
"1. SSH Key (Recommended):\n" +
|
|
292
|
+
" - Set up SSH: https://docs.github.com/en/authentication/connecting-to-github-with-ssh\n" +
|
|
293
|
+
" - Then try again\n\n" +
|
|
294
|
+
"2. GitHub CLI:\n" +
|
|
295
|
+
" - Install: https://cli.github.com\n" +
|
|
296
|
+
" - Run: gh auth login\n" +
|
|
297
|
+
" - Then try again\n\n" +
|
|
298
|
+
"3. Personal Access Token:\n" +
|
|
299
|
+
" - Create token: https://github.com/settings/tokens\n" +
|
|
300
|
+
" - Use: https://YOUR_TOKEN@github.com/mzafarr/vibefast-pro.git");
|
|
203
301
|
}
|
|
204
302
|
throw error;
|
|
205
303
|
}
|
|
206
304
|
}, {
|
|
207
305
|
successText: `✓ Repository cloned successfully`,
|
|
208
306
|
});
|
|
209
|
-
log.plain(
|
|
307
|
+
log.plain("");
|
|
210
308
|
// Step 3.5: Remove unwanted platforms
|
|
211
309
|
const projectPath = join(process.cwd(), projectName);
|
|
212
310
|
if (platforms.length < 2) {
|
|
213
|
-
await withSpinner(
|
|
214
|
-
const { rmSync } = await import(
|
|
215
|
-
const { join } = await import(
|
|
216
|
-
if (!platforms.includes(
|
|
311
|
+
await withSpinner("Cleaning up unwanted platforms...", async () => {
|
|
312
|
+
const { rmSync } = await import("fs");
|
|
313
|
+
const { join } = await import("path");
|
|
314
|
+
if (!platforms.includes("native")) {
|
|
217
315
|
// Remove native app
|
|
218
|
-
const nativePath = join(projectPath,
|
|
316
|
+
const nativePath = join(projectPath, "apps/native");
|
|
219
317
|
if (existsSync(nativePath)) {
|
|
220
318
|
rmSync(nativePath, { recursive: true, force: true });
|
|
221
319
|
}
|
|
222
|
-
log.info(
|
|
320
|
+
log.info(" ✓ Removed native app");
|
|
223
321
|
}
|
|
224
|
-
if (!platforms.includes(
|
|
322
|
+
if (!platforms.includes("web")) {
|
|
225
323
|
// Remove web app
|
|
226
|
-
const webPath = join(projectPath,
|
|
324
|
+
const webPath = join(projectPath, "apps/web");
|
|
227
325
|
if (existsSync(webPath)) {
|
|
228
326
|
rmSync(webPath, { recursive: true, force: true });
|
|
229
327
|
}
|
|
230
|
-
log.info(
|
|
328
|
+
log.info(" ✓ Removed web app");
|
|
231
329
|
}
|
|
232
330
|
// Update package.json workspaces
|
|
233
|
-
const rootPackageJsonPath = join(projectPath,
|
|
331
|
+
const rootPackageJsonPath = join(projectPath, "package.json");
|
|
234
332
|
if (existsSync(rootPackageJsonPath)) {
|
|
235
|
-
const { readFileSync, writeFileSync } = await import(
|
|
236
|
-
const packageJson = JSON.parse(readFileSync(rootPackageJsonPath,
|
|
333
|
+
const { readFileSync, writeFileSync } = await import("fs");
|
|
334
|
+
const packageJson = JSON.parse(readFileSync(rootPackageJsonPath, "utf-8"));
|
|
237
335
|
if (packageJson.workspaces) {
|
|
238
336
|
const workspaces = packageJson.workspaces.filter((ws) => {
|
|
239
|
-
if (!platforms.includes(
|
|
337
|
+
if (!platforms.includes("native") &&
|
|
338
|
+
ws.includes("apps/native"))
|
|
240
339
|
return false;
|
|
241
|
-
if (!platforms.includes(
|
|
340
|
+
if (!platforms.includes("web") && ws.includes("apps/web"))
|
|
242
341
|
return false;
|
|
243
342
|
return true;
|
|
244
343
|
});
|
|
245
344
|
packageJson.workspaces = workspaces;
|
|
246
345
|
writeFileSync(rootPackageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
247
|
-
log.info(
|
|
346
|
+
log.info(" ✓ Updated workspace configuration");
|
|
248
347
|
}
|
|
249
348
|
}
|
|
250
349
|
// Update turbo.json
|
|
251
|
-
const turboJsonPath = join(projectPath,
|
|
350
|
+
const turboJsonPath = join(projectPath, "turbo.json");
|
|
252
351
|
if (existsSync(turboJsonPath)) {
|
|
253
|
-
const { readFileSync, writeFileSync } = await import(
|
|
254
|
-
const turboJson = JSON.parse(readFileSync(turboJsonPath,
|
|
352
|
+
const { readFileSync, writeFileSync } = await import("fs");
|
|
353
|
+
const turboJson = JSON.parse(readFileSync(turboJsonPath, "utf-8"));
|
|
255
354
|
if (turboJson.pipeline) {
|
|
256
355
|
// Remove platform-specific tasks
|
|
257
356
|
const tasksToRemove = [];
|
|
258
|
-
if (!platforms.includes(
|
|
259
|
-
tasksToRemove.push(
|
|
357
|
+
if (!platforms.includes("native")) {
|
|
358
|
+
tasksToRemove.push("native:*", "dev:native", "build:native");
|
|
260
359
|
}
|
|
261
|
-
if (!platforms.includes(
|
|
262
|
-
tasksToRemove.push(
|
|
360
|
+
if (!platforms.includes("web")) {
|
|
361
|
+
tasksToRemove.push("web:*", "dev:web", "build:web");
|
|
263
362
|
}
|
|
264
|
-
tasksToRemove.forEach(task => {
|
|
363
|
+
tasksToRemove.forEach((task) => {
|
|
265
364
|
if (turboJson.pipeline[task]) {
|
|
266
365
|
delete turboJson.pipeline[task];
|
|
267
366
|
}
|
|
268
367
|
});
|
|
269
368
|
writeFileSync(turboJsonPath, JSON.stringify(turboJson, null, 2));
|
|
270
|
-
log.info(
|
|
369
|
+
log.info(" ✓ Updated Turbo configuration");
|
|
271
370
|
}
|
|
272
371
|
}
|
|
273
372
|
}, {
|
|
274
|
-
successText:
|
|
373
|
+
successText: "✓ Platform cleanup complete",
|
|
275
374
|
});
|
|
276
|
-
log.plain(
|
|
375
|
+
log.plain("");
|
|
277
376
|
}
|
|
278
377
|
// Step 4: Check for pnpm and install dependencies
|
|
279
378
|
if (!options.skipInstall) {
|
|
280
379
|
// Check if pnpm is installed
|
|
281
|
-
log.info(
|
|
380
|
+
log.info("Checking for pnpm...");
|
|
282
381
|
try {
|
|
283
|
-
await
|
|
284
|
-
log.info(
|
|
382
|
+
await runCommand("pnpm --version");
|
|
383
|
+
log.info("✓ pnpm is installed");
|
|
285
384
|
}
|
|
286
385
|
catch {
|
|
287
|
-
log.warn(
|
|
288
|
-
log.plain(
|
|
289
|
-
const shouldInstallPnpm = options.yes ||
|
|
386
|
+
log.warn("pnpm is not installed");
|
|
387
|
+
log.plain("");
|
|
388
|
+
const shouldInstallPnpm = options.yes ||
|
|
389
|
+
(await promptYesNo("Would you like to install pnpm globally?", true));
|
|
290
390
|
if (shouldInstallPnpm) {
|
|
291
|
-
log.plain(
|
|
292
|
-
await withSpinner(
|
|
293
|
-
await
|
|
391
|
+
log.plain("");
|
|
392
|
+
await withSpinner("Installing pnpm globally...", async () => {
|
|
393
|
+
await runCommand("npm install -g pnpm");
|
|
294
394
|
}, {
|
|
295
|
-
successText:
|
|
395
|
+
successText: "✓ pnpm installed",
|
|
296
396
|
});
|
|
297
397
|
}
|
|
298
398
|
else {
|
|
299
|
-
log.warn(
|
|
300
|
-
log.plain(
|
|
301
|
-
log.plain(
|
|
399
|
+
log.warn("Skipping pnpm installation. You can install it later with:");
|
|
400
|
+
log.plain(" npm install -g pnpm");
|
|
401
|
+
log.plain("");
|
|
302
402
|
}
|
|
303
403
|
}
|
|
304
|
-
log.plain(
|
|
305
|
-
await withSpinner(
|
|
306
|
-
await
|
|
404
|
+
log.plain("");
|
|
405
|
+
await withSpinner("Installing dependencies...", async () => {
|
|
406
|
+
await runCommand("pnpm install", { cwd: projectPath });
|
|
307
407
|
}, {
|
|
308
|
-
successText:
|
|
408
|
+
successText: "✓ Dependencies installed",
|
|
309
409
|
});
|
|
310
|
-
log.plain(
|
|
410
|
+
log.plain("");
|
|
311
411
|
}
|
|
312
412
|
// Step 5: Create .env files from examples (before starter setup)
|
|
313
|
-
log.plain(
|
|
314
|
-
log.info(
|
|
413
|
+
log.plain("");
|
|
414
|
+
log.info("📝 Setting up environment files...");
|
|
315
415
|
const envFiles = [
|
|
316
|
-
{ example:
|
|
317
|
-
{ example:
|
|
318
|
-
{ example:
|
|
416
|
+
{ example: ".env.local.example", target: ".env.local" },
|
|
417
|
+
{ example: ".env.staging.example", target: ".env.staging" },
|
|
418
|
+
{ example: ".env.production.example", target: ".env.production" },
|
|
319
419
|
];
|
|
320
420
|
let envFilesCreated = 0;
|
|
321
421
|
// Setup Native Env Files
|
|
322
|
-
if (platforms.includes(
|
|
422
|
+
if (platforms.includes("native")) {
|
|
323
423
|
for (const { example, target } of envFiles) {
|
|
324
|
-
const examplePath = join(projectPath,
|
|
325
|
-
const targetPath = join(projectPath,
|
|
424
|
+
const examplePath = join(projectPath, "apps/native", example);
|
|
425
|
+
const targetPath = join(projectPath, "apps/native", target);
|
|
326
426
|
if (existsSync(examplePath) && !existsSync(targetPath)) {
|
|
327
|
-
const { copyFileSync } = await import(
|
|
427
|
+
const { copyFileSync } = await import("fs");
|
|
328
428
|
copyFileSync(examplePath, targetPath);
|
|
329
429
|
log.info(`✓ Created apps/native/${target}`);
|
|
330
430
|
envFilesCreated++;
|
|
@@ -332,12 +432,12 @@ export const initCommand = new Command('init')
|
|
|
332
432
|
}
|
|
333
433
|
}
|
|
334
434
|
// Setup Web Env Files
|
|
335
|
-
if (platforms.includes(
|
|
435
|
+
if (platforms.includes("web")) {
|
|
336
436
|
for (const { example, target } of envFiles) {
|
|
337
|
-
const examplePath = join(projectPath,
|
|
338
|
-
const targetPath = join(projectPath,
|
|
437
|
+
const examplePath = join(projectPath, "apps/web", example);
|
|
438
|
+
const targetPath = join(projectPath, "apps/web", target);
|
|
339
439
|
if (existsSync(examplePath) && !existsSync(targetPath)) {
|
|
340
|
-
const { copyFileSync } = await import(
|
|
440
|
+
const { copyFileSync } = await import("fs");
|
|
341
441
|
copyFileSync(examplePath, targetPath);
|
|
342
442
|
log.info(`✓ Created apps/web/${target}`);
|
|
343
443
|
envFilesCreated++;
|
|
@@ -345,95 +445,124 @@ export const initCommand = new Command('init')
|
|
|
345
445
|
}
|
|
346
446
|
}
|
|
347
447
|
if (envFilesCreated > 0) {
|
|
348
|
-
log.plain(
|
|
349
|
-
log.warn(
|
|
350
|
-
log.info(
|
|
351
|
-
log.plain(
|
|
448
|
+
log.plain("");
|
|
449
|
+
log.warn("⚠️ Environment files created with placeholder values");
|
|
450
|
+
log.info("You will need to fill in your actual API keys and credentials");
|
|
451
|
+
log.plain("");
|
|
452
|
+
// Add base manual steps for env filling
|
|
453
|
+
const baseSteps = [];
|
|
454
|
+
if (platforms.includes("native")) {
|
|
455
|
+
baseSteps.push({
|
|
456
|
+
title: "Fill native env values",
|
|
457
|
+
description: "apps/native/.env.local (and staging/production) were created with placeholders. Add your real values (bundle IDs, URLs, keys).",
|
|
458
|
+
file: "apps/native/.env.local",
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
if (platforms.includes("web")) {
|
|
462
|
+
baseSteps.push({
|
|
463
|
+
title: "Fill web env values",
|
|
464
|
+
description: "apps/web/.env.local (and staging/production) were created with placeholders. Add your real values (NEXT auth keys, URLs, etc.).",
|
|
465
|
+
file: "apps/web/.env.local",
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
// Backend env file is common; add if present
|
|
469
|
+
const backendEnvPath = join(projectPath, "packages/backend/.env.local");
|
|
470
|
+
if (existsSync(backendEnvPath)) {
|
|
471
|
+
baseSteps.push({
|
|
472
|
+
title: "Fill backend env values",
|
|
473
|
+
description: "packages/backend/.env.local exists with placeholders. Add Convex/Sentry/PostHog/other backend keys.",
|
|
474
|
+
file: "packages/backend/.env.local",
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
if (baseSteps.length > 0) {
|
|
478
|
+
const rel = appendManualSteps(projectPath, "init", baseSteps);
|
|
479
|
+
if (rel) {
|
|
480
|
+
log.info(`Manual steps saved to ${rel}`);
|
|
481
|
+
log.plain("");
|
|
482
|
+
}
|
|
483
|
+
}
|
|
352
484
|
}
|
|
353
485
|
else {
|
|
354
|
-
log.info(
|
|
355
|
-
log.plain(
|
|
486
|
+
log.info("ℹ️ No .env example files found to copy");
|
|
487
|
+
log.plain("");
|
|
356
488
|
}
|
|
357
489
|
// Step 6: Run starter setup script (optional)
|
|
358
|
-
const nativeSetupPath = join(projectPath,
|
|
359
|
-
const rootSetupPath = join(projectPath,
|
|
360
|
-
const setupScriptPath = existsSync(rootSetupPath)
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
log.info(
|
|
365
|
-
log.plain(
|
|
366
|
-
log.
|
|
367
|
-
log.plain(
|
|
368
|
-
log.plain(
|
|
369
|
-
|
|
490
|
+
const nativeSetupPath = join(projectPath, "apps/native/scripts/starter-setup.mjs");
|
|
491
|
+
const rootSetupPath = join(projectPath, "scripts/starter-setup.mjs");
|
|
492
|
+
const setupScriptPath = existsSync(rootSetupPath)
|
|
493
|
+
? rootSetupPath
|
|
494
|
+
: nativeSetupPath;
|
|
495
|
+
if (platforms.includes("native") && existsSync(setupScriptPath)) {
|
|
496
|
+
log.info("📋 Starter Setup Available");
|
|
497
|
+
log.plain("");
|
|
498
|
+
log.info("The starter includes a setup script that will:");
|
|
499
|
+
log.plain(" • Fix Expo SDK dependencies");
|
|
500
|
+
log.plain(" • Set up Convex backend (if available)");
|
|
501
|
+
log.plain(" • Configure Convex Auth");
|
|
502
|
+
log.plain("");
|
|
503
|
+
const runSetup = options.yes ||
|
|
504
|
+
(await promptYesNo("Would you like to run the starter setup now?", true));
|
|
370
505
|
if (runSetup) {
|
|
371
|
-
log.plain(
|
|
372
|
-
log.info(
|
|
373
|
-
log.plain(
|
|
506
|
+
log.plain("");
|
|
507
|
+
log.info("Running starter setup...");
|
|
508
|
+
log.plain("");
|
|
374
509
|
try {
|
|
375
|
-
// Use
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
cwd: projectPath,
|
|
380
|
-
stdio: 'inherit',
|
|
381
|
-
});
|
|
382
|
-
child.on('close', (code) => {
|
|
383
|
-
if (code === 0)
|
|
384
|
-
resolve();
|
|
385
|
-
else
|
|
386
|
-
reject(new Error(`Setup script exited with code ${code}`));
|
|
387
|
-
});
|
|
388
|
-
child.on('error', reject);
|
|
510
|
+
// Use spawnCommand for interactive scripts
|
|
511
|
+
await spawnCommand("node", [setupScriptPath], {
|
|
512
|
+
cwd: projectPath,
|
|
513
|
+
stdio: "inherit",
|
|
389
514
|
});
|
|
390
|
-
log.plain(
|
|
391
|
-
log.success(
|
|
515
|
+
log.plain("");
|
|
516
|
+
log.success("✓ Starter setup completed");
|
|
517
|
+
// Sync Convex env vars to frontend .env.local files
|
|
518
|
+
if (backend === "convex") {
|
|
519
|
+
await syncConvexEnvToFrontends(projectPath, platforms);
|
|
520
|
+
}
|
|
392
521
|
}
|
|
393
522
|
catch (error) {
|
|
394
|
-
log.warn(
|
|
395
|
-
log.info(
|
|
523
|
+
log.warn("⚠ Starter setup had some issues");
|
|
524
|
+
log.info("You can run it manually later with:");
|
|
396
525
|
log.plain(` cd ${projectName}/apps/native`);
|
|
397
|
-
log.plain(
|
|
526
|
+
log.plain(" node scripts/starter-setup.mjs");
|
|
398
527
|
}
|
|
399
528
|
}
|
|
400
529
|
else {
|
|
401
|
-
log.info(
|
|
530
|
+
log.info("You can run the setup script later with:");
|
|
402
531
|
log.plain(` cd ${projectName}/apps/native`);
|
|
403
|
-
log.plain(
|
|
532
|
+
log.plain(" node scripts/starter-setup.mjs");
|
|
404
533
|
}
|
|
405
|
-
log.plain(
|
|
534
|
+
log.plain("");
|
|
406
535
|
}
|
|
407
|
-
else if (platforms.includes(
|
|
536
|
+
else if (platforms.includes("native")) {
|
|
408
537
|
// Native platform selected but script missing
|
|
409
|
-
log.warn(
|
|
410
|
-
log.info(
|
|
411
|
-
log.plain(
|
|
538
|
+
log.warn("⚠ Setup script not found at apps/native/scripts/starter-setup.mjs");
|
|
539
|
+
log.info("Skipping automated setup.");
|
|
540
|
+
log.plain("");
|
|
412
541
|
}
|
|
413
542
|
// Step 6.5: Install selected features (if custom setup)
|
|
414
|
-
if (starterType ===
|
|
415
|
-
log.plain(
|
|
416
|
-
log.info(
|
|
417
|
-
log.plain(
|
|
543
|
+
if (starterType === "custom" && selectedFeatures.length > 0) {
|
|
544
|
+
log.plain("");
|
|
545
|
+
log.info("📦 Installing selected features...");
|
|
546
|
+
log.plain("");
|
|
418
547
|
// We need to be in the project directory for feature installation
|
|
419
548
|
const originalCwd = process.cwd();
|
|
420
549
|
process.chdir(projectPath);
|
|
421
550
|
try {
|
|
422
551
|
for (const featureName of selectedFeatures) {
|
|
423
552
|
try {
|
|
424
|
-
log.plain(
|
|
425
|
-
log.plain(
|
|
553
|
+
log.plain("");
|
|
554
|
+
log.plain("━".repeat(60));
|
|
426
555
|
log.info(`Installing ${featureName}...`);
|
|
427
|
-
log.plain(
|
|
428
|
-
if (!platforms.includes(
|
|
556
|
+
log.plain("");
|
|
557
|
+
if (!platforms.includes("native")) {
|
|
429
558
|
log.warn(`⚠ Skipping ${featureName} (requires native platform)`);
|
|
430
559
|
continue;
|
|
431
560
|
}
|
|
432
561
|
// Reuse the full add command logic to ensure env, deps, nav, and journal are handled consistently.
|
|
433
|
-
const { installFeature } = await import(
|
|
434
|
-
const { getPaths } = await import(
|
|
435
|
-
const paths = getPaths(projectPath);
|
|
436
|
-
await installFeature(featureName, { yes: true, force: true, target:
|
|
562
|
+
const { installFeature } = await import("./add.js");
|
|
563
|
+
const { getPaths } = await import("../core/paths.js");
|
|
564
|
+
const paths = await getPaths(projectPath);
|
|
565
|
+
await installFeature(featureName, { yes: true, force: true, target: "native" }, paths);
|
|
437
566
|
log.success(`✓ ${featureName} installed successfully!`);
|
|
438
567
|
}
|
|
439
568
|
catch (error) {
|
|
@@ -446,98 +575,89 @@ export const initCommand = new Command('init')
|
|
|
446
575
|
// Go back to original directory even if installation fails
|
|
447
576
|
process.chdir(originalCwd);
|
|
448
577
|
}
|
|
449
|
-
log.plain(
|
|
450
|
-
log.plain(
|
|
578
|
+
log.plain("");
|
|
579
|
+
log.plain("━".repeat(60));
|
|
451
580
|
log.success(`✓ Installed ${selectedFeatures.length} feature(s)`);
|
|
452
|
-
log.plain(
|
|
453
|
-
}
|
|
454
|
-
// Step 7:
|
|
455
|
-
//
|
|
456
|
-
log.plain('');
|
|
457
|
-
await withSpinner('Saving license key...', async () => {
|
|
458
|
-
// Save token to auth file in the new project
|
|
459
|
-
const { writeFileContent } = await import('../core/fsx.js');
|
|
460
|
-
const authPath = join(projectPath, '.vibefast-auth.json');
|
|
461
|
-
await writeFileContent(authPath, JSON.stringify({ token: licenseKey }, null, 2), { force: true });
|
|
462
|
-
}, {
|
|
463
|
-
successText: '✓ License key saved',
|
|
464
|
-
});
|
|
465
|
-
log.plain('');
|
|
581
|
+
log.plain("");
|
|
582
|
+
}
|
|
583
|
+
// Step 7: License key was already validated and saved globally in Step 0 (line 86-87)
|
|
584
|
+
// No need to write to project directory - this avoids accidental secret commits
|
|
466
585
|
// Success!
|
|
467
|
-
log.plain(
|
|
468
|
-
log.success(
|
|
469
|
-
log.plain(
|
|
470
|
-
log.info(`Setup: ${starterType ===
|
|
471
|
-
log.info(`Platforms: ${platforms.join(
|
|
472
|
-
if (starterType ===
|
|
473
|
-
log.info(`Features: ${selectedFeatures.join(
|
|
474
|
-
}
|
|
475
|
-
log.plain(
|
|
476
|
-
log.info(
|
|
586
|
+
log.plain("");
|
|
587
|
+
log.success("🎉 Project initialized successfully!");
|
|
588
|
+
log.plain("");
|
|
589
|
+
log.info(`Setup: ${starterType === "clean" ? "Clean" : "Custom"}`);
|
|
590
|
+
log.info(`Platforms: ${platforms.join(" + ")}`);
|
|
591
|
+
if (starterType === "custom" && selectedFeatures.length > 0) {
|
|
592
|
+
log.info(`Features: ${selectedFeatures.join(", ")}`);
|
|
593
|
+
}
|
|
594
|
+
log.plain("");
|
|
595
|
+
log.info("Next steps:");
|
|
477
596
|
log.plain(` 1. cd ${projectName}`);
|
|
478
597
|
// Check if setup script exists (only for native)
|
|
479
|
-
const setupScriptExists = platforms.includes(
|
|
480
|
-
existsSync(join(projectPath,
|
|
598
|
+
const setupScriptExists = platforms.includes("native") &&
|
|
599
|
+
existsSync(join(projectPath, "apps/native/scripts/starter-setup.mjs"));
|
|
481
600
|
if (setupScriptExists && !options.skipInstall) {
|
|
482
|
-
log.plain(
|
|
483
|
-
if (platforms.includes(
|
|
484
|
-
log.plain(
|
|
485
|
-
log.plain(
|
|
486
|
-
log.plain(
|
|
601
|
+
log.plain(" 2. Start developing:");
|
|
602
|
+
if (platforms.includes("native")) {
|
|
603
|
+
log.plain(" • pnpm dev:native (start native dev server)");
|
|
604
|
+
log.plain(" • pnpm native:ios (run on iOS)");
|
|
605
|
+
log.plain(" • pnpm native:android (run on Android)");
|
|
487
606
|
}
|
|
488
|
-
if (platforms.includes(
|
|
489
|
-
log.plain(
|
|
490
|
-
log.plain(
|
|
607
|
+
if (platforms.includes("web")) {
|
|
608
|
+
log.plain(" • pnpm dev:web (start web dev server)");
|
|
609
|
+
log.plain(" • pnpm web:build (build for production)");
|
|
491
610
|
}
|
|
492
611
|
}
|
|
493
612
|
else {
|
|
494
613
|
if (setupScriptExists) {
|
|
495
|
-
log.plain(
|
|
614
|
+
log.plain(" 2. Run starter setup (if not done):");
|
|
496
615
|
log.plain(` cd ${projectName}/apps/native`);
|
|
497
|
-
log.plain(
|
|
616
|
+
log.plain(" node scripts/starter-setup.mjs");
|
|
498
617
|
}
|
|
499
|
-
log.plain(` ${setupScriptExists ?
|
|
500
|
-
if (platforms.includes(
|
|
501
|
-
log.plain(
|
|
502
|
-
log.plain(
|
|
503
|
-
log.plain(
|
|
618
|
+
log.plain(` ${setupScriptExists ? "3" : "2"}. Start developing:`);
|
|
619
|
+
if (platforms.includes("native")) {
|
|
620
|
+
log.plain(" • pnpm dev:native (start native dev server)");
|
|
621
|
+
log.plain(" • pnpm native:ios (run on iOS)");
|
|
622
|
+
log.plain(" • pnpm native:android (run on Android)");
|
|
504
623
|
}
|
|
505
|
-
if (platforms.includes(
|
|
506
|
-
log.plain(
|
|
507
|
-
log.plain(
|
|
624
|
+
if (platforms.includes("web")) {
|
|
625
|
+
log.plain(" • pnpm dev:web (start web dev server)");
|
|
626
|
+
log.plain(" • pnpm web:build (build for production)");
|
|
508
627
|
}
|
|
509
628
|
}
|
|
510
|
-
log.plain(
|
|
511
|
-
log.info(
|
|
512
|
-
log.plain(
|
|
513
|
-
if (platforms.includes(
|
|
514
|
-
log.plain(
|
|
629
|
+
log.plain("");
|
|
630
|
+
log.info("Add features:");
|
|
631
|
+
log.plain(" • vf list # See available features");
|
|
632
|
+
if (platforms.includes("native")) {
|
|
633
|
+
log.plain(" • vf add chatbot # Add native feature");
|
|
515
634
|
}
|
|
516
|
-
if (platforms.includes(
|
|
517
|
-
log.plain(
|
|
635
|
+
if (platforms.includes("web")) {
|
|
636
|
+
log.plain(" • vf add quiz --target web # Add web feature");
|
|
518
637
|
}
|
|
519
|
-
log.plain(
|
|
520
|
-
log.info(
|
|
521
|
-
log.info(
|
|
522
|
-
log.plain(
|
|
638
|
+
log.plain("");
|
|
639
|
+
log.info("📚 Documentation: https://vibefast.pro/docs");
|
|
640
|
+
log.info("💬 Support: support@vibefast.pro");
|
|
641
|
+
log.plain("");
|
|
523
642
|
}
|
|
524
643
|
catch (error) {
|
|
525
|
-
log.plain(
|
|
644
|
+
log.plain("");
|
|
526
645
|
log.error(`Initialization failed: ${error.message}`);
|
|
527
|
-
if (error.message.includes(
|
|
528
|
-
log.plain(
|
|
529
|
-
log.info(
|
|
530
|
-
log.plain(
|
|
531
|
-
log.plain(
|
|
532
|
-
log.plain(
|
|
533
|
-
}
|
|
534
|
-
if (error.message.includes(
|
|
535
|
-
|
|
536
|
-
log.
|
|
537
|
-
log.
|
|
538
|
-
log.plain(
|
|
539
|
-
|
|
540
|
-
|
|
646
|
+
if (error.message.includes("git")) {
|
|
647
|
+
log.plain("");
|
|
648
|
+
log.info("Make sure Git is installed:");
|
|
649
|
+
log.plain(" • macOS: brew install git");
|
|
650
|
+
log.plain(" • Windows: https://git-scm.com/download/win");
|
|
651
|
+
log.plain(" • Linux: sudo apt install git");
|
|
652
|
+
}
|
|
653
|
+
if (error.message.includes("EACCES") ||
|
|
654
|
+
error.message.includes("permission")) {
|
|
655
|
+
log.plain("");
|
|
656
|
+
log.info("Permission denied. Try:");
|
|
657
|
+
log.plain(" • Run without sudo");
|
|
658
|
+
log.plain(" • Check directory permissions");
|
|
659
|
+
}
|
|
660
|
+
log.plain("");
|
|
541
661
|
process.exit(1);
|
|
542
662
|
}
|
|
543
663
|
});
|