vibefast-cli 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/FEATURE-DEPENDENCY-SPEC.md +338 -0
  2. package/dist/__tests__/integration.test.d.ts +2 -0
  3. package/dist/__tests__/integration.test.d.ts.map +1 -0
  4. package/dist/__tests__/integration.test.js +219 -0
  5. package/dist/__tests__/integration.test.js.map +1 -0
  6. package/dist/__tests__/recipes.test.d.ts +2 -0
  7. package/dist/__tests__/recipes.test.d.ts.map +1 -0
  8. package/dist/__tests__/recipes.test.js +143 -0
  9. package/dist/__tests__/recipes.test.js.map +1 -0
  10. package/dist/commands/__tests__/init.test.d.ts +2 -0
  11. package/dist/commands/__tests__/init.test.d.ts.map +1 -0
  12. package/dist/commands/__tests__/init.test.js +95 -0
  13. package/dist/commands/__tests__/init.test.js.map +1 -0
  14. package/dist/commands/__tests__/platform.test.d.ts +2 -0
  15. package/dist/commands/__tests__/platform.test.d.ts.map +1 -0
  16. package/dist/commands/__tests__/platform.test.js +123 -0
  17. package/dist/commands/__tests__/platform.test.js.map +1 -0
  18. package/dist/commands/add.d.ts.map +1 -1
  19. package/dist/commands/add.js +8 -5
  20. package/dist/commands/add.js.map +1 -1
  21. package/dist/core/journal.d.ts.map +1 -1
  22. package/dist/core/journal.js +36 -19
  23. package/dist/core/journal.js.map +1 -1
  24. package/dist/core/recipes.d.ts +1 -1
  25. package/dist/core/recipes.d.ts.map +1 -1
  26. package/dist/core/recipes.js +12 -41
  27. package/dist/core/recipes.js.map +1 -1
  28. package/package.json +1 -1
  29. package/recipes/ios-widget/recipe.json +78 -0
  30. package/recipes/ios-widget/targets/widget/AppIntent.swift +46 -0
  31. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@1x.png +0 -0
  32. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@2x.png +0 -0
  33. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-20x20@3x.png +0 -0
  34. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@1x.png +0 -0
  35. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@2x.png +0 -0
  36. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-29x29@3x.png +0 -0
  37. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@1x.png +0 -0
  38. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@2x.png +0 -0
  39. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-40x40@3x.png +0 -0
  40. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@2x.png +0 -0
  41. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-60x60@3x.png +0 -0
  42. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@1x.png +0 -0
  43. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-76x76@2x.png +0 -0
  44. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/App-Icon-83.5x83.5@2x.png +0 -0
  45. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/Contents.json +122 -0
  46. package/recipes/ios-widget/targets/widget/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png +0 -0
  47. package/recipes/ios-widget/targets/widget/CalorieTrackerWidget.swift +424 -0
  48. package/recipes/ios-widget/targets/widget/HabitTrackerWidget.swift +305 -0
  49. package/recipes/ios-widget/targets/widget/Info.plist +11 -0
  50. package/recipes/ios-widget/targets/widget/WidgetLiveActivity.swift +75 -0
  51. package/recipes/ios-widget/targets/widget/expo-target.config.js +10 -0
  52. package/recipes/ios-widget/targets/widget/generated.entitlements +5 -0
  53. package/recipes/ios-widget/targets/widget/index.swift +18 -0
  54. package/recipes/ios-widget/targets/widget/widgets.swift +96 -0
  55. package/recipes/ios-widget@latest.zip +0 -0
  56. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/index.tsx +74 -0
  57. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/local.tsx +25 -0
  58. package/recipes/payments/apps/native/src/app/(root)/(protected)/paywall/remote.tsx +23 -0
  59. package/recipes/payments/apps/native/src/features/payments/README.md +200 -0
  60. package/recipes/payments/apps/native/src/features/payments/app/local-paywall.tsx +194 -0
  61. package/recipes/payments/apps/native/src/features/payments/app/remote-paywall.tsx +79 -0
  62. package/recipes/payments/apps/native/src/features/payments/components/payment-initializer.tsx +95 -0
  63. package/recipes/payments/apps/native/src/features/payments/components/paywall-error-state.tsx +60 -0
  64. package/recipes/payments/apps/native/src/features/payments/components/paywall-local-mode.tsx +116 -0
  65. package/recipes/payments/apps/native/src/features/payments/components/paywall-product-card.tsx +133 -0
  66. package/recipes/payments/apps/native/src/features/payments/components/paywall-remote-mode.tsx +146 -0
  67. package/recipes/payments/apps/native/src/features/payments/hooks/use-entitlement.ts +63 -0
  68. package/recipes/payments/apps/native/src/features/payments/index.ts +8 -0
  69. package/recipes/payments/apps/native/src/features/payments/services/revenuecat-adapter.ts +407 -0
  70. package/recipes/payments/recipe.json +58 -0
  71. package/recipes/payments@latest.zip +0 -0
  72. package/src/__tests__/integration.test.ts +249 -0
  73. package/src/__tests__/recipes.test.ts +168 -0
  74. package/src/commands/__tests__/init.test.ts +112 -0
  75. package/src/commands/__tests__/platform.test.ts +141 -0
  76. package/src/commands/add.ts +9 -5
  77. package/src/core/journal.ts +42 -25
  78. package/src/core/recipes.ts +12 -42
@@ -57,14 +57,17 @@ export const addCommand = new Command('add')
57
57
  log.plain('');
58
58
  log.info('Examples:');
59
59
  log.plain(' vf add # Interactive menu');
60
- log.plain(' vf add feature # Show all features');
61
- log.plain(' vf add integration # Show all integrations');
62
- log.plain(' vf add charts # Add specific feature');
63
- log.plain(' vf add sentry --target native');
64
- log.plain(' vf add chatbot --dry-run');
60
+ log.plain(' vf add chatbot # Add specific feature');
61
+ log.plain(' vf add chatbot --dry-run # Preview changes');
62
+ log.plain(' vf add chatbot --force # Force reinstall');
63
+ log.plain(' vf add chatbot --yes # Skip prompts');
65
64
  })
66
65
  .action(async (feature: string | undefined, options) => {
67
66
  try {
67
+ // Fix MaxListeners warning for batch operations
68
+ process.stdin.setMaxListeners(0);
69
+ process.stdout.setMaxListeners(0);
70
+
68
71
  const paths = getPaths();
69
72
 
70
73
  // Interactive mode if no feature specified
@@ -202,6 +205,7 @@ async function installFeature(feature: string, options: any, paths: any) {
202
205
  if (existing && !options.force) {
203
206
  log.warn(`${feature} is already installed for ${target}`);
204
207
  log.info('Use --force to reinstall');
208
+ log.plain('');
205
209
  return;
206
210
  }
207
211
 
@@ -30,35 +30,52 @@ export async function readJournal(journalPath: string): Promise<Journal> {
30
30
  if (!(await exists(journalPath))) {
31
31
  return { entries: [] };
32
32
  }
33
- const content = await readFileContent(journalPath);
34
- const journal = JSON.parse(content) as Journal;
35
33
 
36
- // Migrate old format to new format
37
- let needsMigration = false;
38
-
39
- for (const entry of journal.entries) {
40
- if (entry.files.length > 0 && typeof entry.files[0] === 'string') {
41
- needsMigration = true;
42
- // Old format: array of strings
43
- const oldFiles = entry.files as string[];
44
-
45
- // Convert to new format with hashes
46
- const newFiles: FileEntry[] = [];
47
- for (const filePath of oldFiles) {
48
- const hash = await hashFile(filePath);
49
- newFiles.push({ path: filePath, hash });
34
+ try {
35
+ const content = await readFileContent(journalPath);
36
+ const journal = JSON.parse(content) as Journal;
37
+
38
+ // Ensure entries is an array
39
+ if (!journal.entries || !Array.isArray(journal.entries)) {
40
+ console.warn('Invalid journal format, resetting to empty journal');
41
+ return { entries: [] };
42
+ }
43
+
44
+ // Migrate old format to new format
45
+ let needsMigration = false;
46
+
47
+ for (const entry of journal.entries) {
48
+ if (entry.files && entry.files.length > 0 && typeof entry.files[0] === 'string') {
49
+ needsMigration = true;
50
+ // Old format: array of strings
51
+ const oldFiles = entry.files as string[];
52
+
53
+ // Convert to new format with hashes
54
+ const newFiles: FileEntry[] = [];
55
+ for (const filePath of oldFiles) {
56
+ try {
57
+ const hash = await hashFile(filePath);
58
+ newFiles.push({ path: filePath, hash });
59
+ } catch (err) {
60
+ // File might not exist anymore, skip it
61
+ console.warn(`Could not hash file ${filePath}, skipping`);
62
+ }
63
+ }
64
+
65
+ entry.files = newFiles;
50
66
  }
51
-
52
- entry.files = newFiles;
53
67
  }
68
+
69
+ // Save migrated journal
70
+ if (needsMigration) {
71
+ await writeJournal(journalPath, journal);
72
+ }
73
+
74
+ return journal;
75
+ } catch (err) {
76
+ console.warn('Failed to read journal, resetting to empty journal:', err);
77
+ return { entries: [] };
54
78
  }
55
-
56
- // Save migrated journal
57
- if (needsMigration) {
58
- await writeJournal(journalPath, journal);
59
- }
60
-
61
- return journal;
62
79
  }
63
80
 
64
81
  export async function writeJournal(journalPath: string, journal: Journal): Promise<void> {
@@ -70,49 +70,17 @@ export const RECIPES: RecipeInfo[] = [
70
70
  description: 'Wake word detection with Vosk',
71
71
  icon: '🎙️',
72
72
  },
73
-
74
- // Advanced UI Components
75
73
  {
76
- name: 'glowing-button',
77
- category: 'advanced-ui',
78
- description: 'Animated glowing button with shimmer effect',
79
- icon: '',
80
- },
81
- {
82
- name: 'animated-switch',
83
- category: 'advanced-ui',
84
- description: 'Smooth animated toggle switch',
85
- icon: '🎚️',
86
- },
87
- {
88
- name: 'animated-chip',
89
- category: 'advanced-ui',
90
- description: 'Animated chip/tag component with press effects',
91
- icon: '🏷️',
92
- },
93
- {
94
- name: 'number-stepper',
95
- category: 'advanced-ui',
96
- description: 'Number input with +/- buttons',
97
- icon: '🔢',
98
- },
99
- {
100
- name: 'progress-circle',
101
- category: 'advanced-ui',
102
- description: 'Circular progress indicator with animation',
103
- icon: '⭕',
104
- },
105
- {
106
- name: 'swipe-slider',
107
- category: 'advanced-ui',
108
- description: 'Interactive swipe-to-confirm slider',
109
- icon: '👆',
74
+ name: 'ios-widget',
75
+ category: 'feature',
76
+ description: 'iOS Home Screen widgets with Live Activities',
77
+ icon: '📱',
110
78
  },
111
79
  {
112
- name: 'timeline',
113
- category: 'advanced-ui',
114
- description: 'Activity timeline view for feeds',
115
- icon: '📅',
80
+ name: 'payments',
81
+ category: 'feature',
82
+ description: 'In-app purchases and subscriptions with RevenueCat',
83
+ icon: '💳',
116
84
  },
117
85
  ];
118
86
 
@@ -124,10 +92,12 @@ export function getRecipesByCategory(category: RecipeCategory): RecipeInfo[] {
124
92
  }
125
93
 
126
94
  /**
127
- * Get all categories
95
+ * Get all categories that have recipes
128
96
  */
129
97
  export function getCategories(): RecipeCategory[] {
130
- return ['feature', 'advanced-ui'];
98
+ const categories = new Set<RecipeCategory>();
99
+ RECIPES.forEach(r => categories.add(r.category));
100
+ return Array.from(categories);
131
101
  }
132
102
 
133
103
  /**