@l4yercak3/cli 1.2.15 → 1.2.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@l4yercak3/cli",
3
- "version": "1.2.15",
3
+ "version": "1.2.18",
4
4
  "description": "Icing on the L4yercak3 - The sweet finishing touch for your Layer Cake integration",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -405,17 +405,83 @@ async function handleSpread() {
405
405
  choices: [
406
406
  { name: 'CRM (contacts, organizations)', value: 'crm', checked: true },
407
407
  { name: 'Events (event management, registrations)', value: 'events', checked: false },
408
- { name: 'Products (product catalog)', value: 'products', checked: false },
409
- { name: 'Checkout (payment processing)', value: 'checkout', checked: false },
410
- { name: 'Tickets (ticket generation)', value: 'tickets', checked: false },
411
- { name: 'Invoicing (invoice creation)', value: 'invoicing', checked: false },
412
- { name: 'Forms (dynamic forms)', value: 'forms', checked: false },
413
- { name: 'Projects (project management)', value: 'projects', checked: false },
408
+ { name: 'Forms (form builder, submissions)', value: 'forms', checked: false },
409
+ { name: 'Products (product catalog, inventory)', value: 'products', checked: false },
410
+ { name: 'Checkout (cart, payments)', value: 'checkout', checked: false },
411
+ { name: 'Invoicing (B2B/B2C invoices)', value: 'invoicing', checked: false },
412
+ { name: 'Benefits (claims, commissions)', value: 'benefits', checked: false },
413
+ { name: 'Certificates (CME, attendance)', value: 'certificates', checked: false },
414
+ { name: 'Projects (task management)', value: 'projects', checked: false },
414
415
  { name: 'OAuth Authentication', value: 'oauth', checked: false },
415
416
  ],
416
417
  },
417
418
  ]);
418
419
 
420
+ // Step 4.5: Integration path selection
421
+ console.log(chalk.cyan('\n đŸ›¤ī¸ Integration Path\n'));
422
+ const { integrationPath } = await inquirer.prompt([
423
+ {
424
+ type: 'list',
425
+ name: 'integrationPath',
426
+ message: 'Choose your integration approach:',
427
+ choices: [
428
+ {
429
+ name: 'Quick Start (Recommended) - Full-stack with UI components & database',
430
+ value: 'quickstart',
431
+ },
432
+ {
433
+ name: 'API Only - Just the typed API client, you build the UI',
434
+ value: 'api-only',
435
+ },
436
+ {
437
+ name: 'MCP-Assisted - AI-powered custom generation with Claude Code',
438
+ value: 'mcp-assisted',
439
+ },
440
+ ],
441
+ },
442
+ ]);
443
+ console.log(chalk.green(` ✅ Path: ${integrationPath === 'quickstart' ? 'Quick Start' : integrationPath === 'api-only' ? 'API Only' : 'MCP-Assisted'}\n`));
444
+
445
+ // Step 4.6: Database selection (for Quick Start path when no DB detected)
446
+ let selectedDatabase = null;
447
+ if (integrationPath === 'quickstart') {
448
+ const dbDetection = detection.database || { hasDatabase: false };
449
+
450
+ if (!dbDetection.hasDatabase) {
451
+ console.log(chalk.yellow(' â„šī¸ No database detected in your project.\n'));
452
+
453
+ const { database } = await inquirer.prompt([
454
+ {
455
+ type: 'list',
456
+ name: 'database',
457
+ message: 'Which database would you like to use?',
458
+ choices: [
459
+ {
460
+ name: 'Convex (Recommended) - Real-time, serverless, TypeScript-first',
461
+ value: 'convex',
462
+ },
463
+ {
464
+ name: 'Supabase - PostgreSQL with Auth, Storage, and Edge Functions',
465
+ value: 'supabase',
466
+ },
467
+ {
468
+ name: 'None - I\'ll set up my own database later',
469
+ value: 'none',
470
+ },
471
+ ],
472
+ },
473
+ ]);
474
+
475
+ selectedDatabase = database !== 'none' ? database : null;
476
+ if (selectedDatabase) {
477
+ console.log(chalk.green(` ✅ Database: ${selectedDatabase}\n`));
478
+ }
479
+ } else {
480
+ console.log(chalk.green(` ✅ Detected ${dbDetection.primary?.type || 'existing'} database\n`));
481
+ selectedDatabase = dbDetection.primary?.type || 'existing';
482
+ }
483
+ }
484
+
419
485
  // Step 5: OAuth provider selection (if OAuth enabled)
420
486
  let oauthProviders = [];
421
487
  if (features.includes('oauth')) {
@@ -489,15 +555,38 @@ async function handleSpread() {
489
555
  isTypeScript,
490
556
  routerType,
491
557
  frameworkType: detection.framework.type || 'unknown',
558
+ integrationPath,
559
+ selectedDatabase,
492
560
  };
493
561
 
494
562
  const generatedFiles = await fileGenerator.generate(generationOptions);
495
563
 
496
564
  // Display results
497
565
  console.log(chalk.green(' ✅ Files generated:\n'));
566
+
567
+ // API client files (api-only and quickstart paths)
498
568
  if (generatedFiles.apiClient) {
499
569
  console.log(chalk.gray(` â€ĸ ${path.relative(process.cwd(), generatedFiles.apiClient)}`));
500
570
  }
571
+ if (generatedFiles.types) {
572
+ console.log(chalk.gray(` â€ĸ ${path.relative(process.cwd(), generatedFiles.types)}`));
573
+ }
574
+ if (generatedFiles.webhooks) {
575
+ console.log(chalk.gray(` â€ĸ ${path.relative(process.cwd(), generatedFiles.webhooks)}`));
576
+ }
577
+ if (generatedFiles.index) {
578
+ console.log(chalk.gray(` â€ĸ ${path.relative(process.cwd(), generatedFiles.index)}`));
579
+ }
580
+
581
+ // MCP files (mcp-assisted path)
582
+ if (generatedFiles.mcpConfig) {
583
+ console.log(chalk.gray(` â€ĸ ${path.relative(process.cwd(), generatedFiles.mcpConfig)}`));
584
+ }
585
+ if (generatedFiles.mcpGuide) {
586
+ console.log(chalk.gray(` â€ĸ ${path.relative(process.cwd(), generatedFiles.mcpGuide)}`));
587
+ }
588
+
589
+ // Common files
501
590
  if (generatedFiles.envFile) {
502
591
  console.log(chalk.gray(` â€ĸ ${path.relative(process.cwd(), generatedFiles.envFile)}`));
503
592
  }
@@ -641,6 +730,8 @@ async function handleSpread() {
641
730
  oauthProviders,
642
731
  productionDomain,
643
732
  frameworkType: detection.framework.type,
733
+ integrationPath,
734
+ selectedDatabase,
644
735
  createdAt: Date.now(),
645
736
  updatedAt: isUpdate ? Date.now() : undefined,
646
737
  };
@@ -678,6 +769,10 @@ async function handleSpread() {
678
769
 
679
770
  console.log(chalk.gray(' Your project is now connected to L4YERCAK3! 🍰\n'));
680
771
 
772
+ // Show menu for next actions
773
+ const action = await showMainMenu({ isLoggedIn: true, isInProject: true, hasExistingConfig: true });
774
+ await executeMenuAction(action);
775
+
681
776
  } catch (error) {
682
777
  console.error(chalk.red(`\n ❌ Error: ${error.message}\n`));
683
778
  if (error.stack) {
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Database Detector
3
+ * Detects existing database configurations in a project
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ /**
10
+ * Check if a file exists
11
+ * @param {string} filePath - Path to check
12
+ * @returns {boolean}
13
+ */
14
+ function fileExists(filePath) {
15
+ try {
16
+ return fs.existsSync(filePath);
17
+ } catch {
18
+ return false;
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Read and parse package.json
24
+ * @param {string} projectPath - Project root path
25
+ * @returns {object|null}
26
+ */
27
+ function readPackageJson(projectPath) {
28
+ try {
29
+ const packagePath = path.join(projectPath, 'package.json');
30
+ if (fileExists(packagePath)) {
31
+ const content = fs.readFileSync(packagePath, 'utf8');
32
+ return JSON.parse(content);
33
+ }
34
+ } catch {
35
+ // Ignore parse errors
36
+ }
37
+ return null;
38
+ }
39
+
40
+ /**
41
+ * Detect database configuration in a project
42
+ * @param {string} projectPath - Project root path
43
+ * @returns {object} Detection result
44
+ */
45
+ function detectDatabase(projectPath = process.cwd()) {
46
+ const detections = [];
47
+
48
+ // Check for Convex
49
+ const convexDir = path.join(projectPath, 'convex');
50
+ if (fileExists(convexDir)) {
51
+ const hasSchema = fileExists(path.join(convexDir, 'schema.ts')) ||
52
+ fileExists(path.join(convexDir, 'schema.js'));
53
+ detections.push({
54
+ type: 'convex',
55
+ confidence: 'high',
56
+ configPath: 'convex/',
57
+ hasSchema,
58
+ details: {
59
+ schemaFile: hasSchema ? 'convex/schema.ts' : null,
60
+ },
61
+ });
62
+ }
63
+
64
+ // Check for Supabase
65
+ const supabaseDir = path.join(projectPath, 'supabase');
66
+ if (fileExists(supabaseDir)) {
67
+ const hasMigrations = fileExists(path.join(supabaseDir, 'migrations'));
68
+ detections.push({
69
+ type: 'supabase',
70
+ confidence: 'high',
71
+ configPath: 'supabase/',
72
+ hasMigrations,
73
+ details: {
74
+ migrationsDir: hasMigrations ? 'supabase/migrations/' : null,
75
+ },
76
+ });
77
+ }
78
+
79
+ // Check for Prisma
80
+ const prismaDir = path.join(projectPath, 'prisma');
81
+ if (fileExists(prismaDir)) {
82
+ const hasSchema = fileExists(path.join(prismaDir, 'schema.prisma'));
83
+ detections.push({
84
+ type: 'prisma',
85
+ confidence: 'high',
86
+ configPath: 'prisma/',
87
+ hasSchema,
88
+ details: {
89
+ schemaFile: hasSchema ? 'prisma/schema.prisma' : null,
90
+ },
91
+ });
92
+ }
93
+
94
+ // Check for Drizzle config
95
+ const drizzleConfig = [
96
+ 'drizzle.config.ts',
97
+ 'drizzle.config.js',
98
+ 'drizzle.config.mjs',
99
+ ].find(f => fileExists(path.join(projectPath, f)));
100
+ if (drizzleConfig) {
101
+ detections.push({
102
+ type: 'drizzle',
103
+ confidence: 'high',
104
+ configPath: drizzleConfig,
105
+ details: {
106
+ configFile: drizzleConfig,
107
+ },
108
+ });
109
+ }
110
+
111
+ // Check package.json for database dependencies
112
+ const packageJson = readPackageJson(projectPath);
113
+ if (packageJson) {
114
+ const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
115
+
116
+ // Convex from package.json
117
+ if (deps['convex'] && !detections.find(d => d.type === 'convex')) {
118
+ detections.push({
119
+ type: 'convex',
120
+ confidence: 'medium',
121
+ source: 'package.json',
122
+ details: {
123
+ version: deps['convex'],
124
+ },
125
+ });
126
+ }
127
+
128
+ // Supabase from package.json
129
+ if (deps['@supabase/supabase-js'] && !detections.find(d => d.type === 'supabase')) {
130
+ detections.push({
131
+ type: 'supabase',
132
+ confidence: 'medium',
133
+ source: 'package.json',
134
+ details: {
135
+ version: deps['@supabase/supabase-js'],
136
+ },
137
+ });
138
+ }
139
+
140
+ // Prisma from package.json
141
+ if ((deps['prisma'] || deps['@prisma/client']) && !detections.find(d => d.type === 'prisma')) {
142
+ detections.push({
143
+ type: 'prisma',
144
+ confidence: 'medium',
145
+ source: 'package.json',
146
+ details: {
147
+ version: deps['prisma'] || deps['@prisma/client'],
148
+ },
149
+ });
150
+ }
151
+
152
+ // Drizzle from package.json
153
+ if (deps['drizzle-orm'] && !detections.find(d => d.type === 'drizzle')) {
154
+ detections.push({
155
+ type: 'drizzle',
156
+ confidence: 'medium',
157
+ source: 'package.json',
158
+ details: {
159
+ version: deps['drizzle-orm'],
160
+ },
161
+ });
162
+ }
163
+
164
+ // MongoDB/Mongoose
165
+ if (deps['mongoose']) {
166
+ detections.push({
167
+ type: 'mongodb',
168
+ confidence: 'medium',
169
+ source: 'package.json',
170
+ details: {
171
+ client: 'mongoose',
172
+ version: deps['mongoose'],
173
+ },
174
+ });
175
+ }
176
+
177
+ if (deps['mongodb'] && !detections.find(d => d.type === 'mongodb')) {
178
+ detections.push({
179
+ type: 'mongodb',
180
+ confidence: 'medium',
181
+ source: 'package.json',
182
+ details: {
183
+ client: 'mongodb',
184
+ version: deps['mongodb'],
185
+ },
186
+ });
187
+ }
188
+
189
+ // Firebase/Firestore
190
+ if (deps['firebase'] || deps['firebase-admin']) {
191
+ detections.push({
192
+ type: 'firebase',
193
+ confidence: 'medium',
194
+ source: 'package.json',
195
+ details: {
196
+ client: deps['firebase'] ? 'firebase' : 'firebase-admin',
197
+ version: deps['firebase'] || deps['firebase-admin'],
198
+ },
199
+ });
200
+ }
201
+
202
+ // PostgreSQL (pg)
203
+ if (deps['pg'] && !detections.find(d => ['prisma', 'drizzle', 'supabase'].includes(d.type))) {
204
+ detections.push({
205
+ type: 'postgresql',
206
+ confidence: 'low',
207
+ source: 'package.json',
208
+ details: {
209
+ client: 'pg',
210
+ version: deps['pg'],
211
+ },
212
+ });
213
+ }
214
+
215
+ // MySQL
216
+ if (deps['mysql2'] || deps['mysql']) {
217
+ detections.push({
218
+ type: 'mysql',
219
+ confidence: 'low',
220
+ source: 'package.json',
221
+ details: {
222
+ client: deps['mysql2'] ? 'mysql2' : 'mysql',
223
+ version: deps['mysql2'] || deps['mysql'],
224
+ },
225
+ });
226
+ }
227
+ }
228
+
229
+ // Sort by confidence (high first)
230
+ const sortedDetections = detections.sort((a, b) => {
231
+ const confidenceOrder = { high: 2, medium: 1, low: 0 };
232
+ return (confidenceOrder[b.confidence] || 0) - (confidenceOrder[a.confidence] || 0);
233
+ });
234
+
235
+ return {
236
+ hasDatabase: sortedDetections.length > 0,
237
+ detections: sortedDetections,
238
+ primary: sortedDetections[0] || null,
239
+ };
240
+ }
241
+
242
+ module.exports = {
243
+ detect: detectDatabase,
244
+ detectDatabase,
245
+ };
@@ -10,6 +10,7 @@ const registry = require('./registry');
10
10
  const githubDetector = require('./github-detector');
11
11
  const apiClientDetector = require('./api-client-detector');
12
12
  const oauthDetector = require('./oauth-detector');
13
+ const databaseDetector = require('./database-detector');
13
14
 
14
15
  class ProjectDetector {
15
16
  /**
@@ -26,9 +27,10 @@ class ProjectDetector {
26
27
  const githubInfo = githubDetector.detect(projectPath);
27
28
  const apiClientInfo = apiClientDetector.detect(projectPath);
28
29
  const oauthInfo = oauthDetector.detect(projectPath);
30
+ const databaseInfo = databaseDetector.detect(projectPath);
29
31
 
30
32
  // Get detector instance if we have a match
31
- const detector = frameworkDetection.detected
33
+ const detector = frameworkDetection.detected
32
34
  ? registry.getDetector(frameworkDetection.detected)
33
35
  : null;
34
36
 
@@ -41,22 +43,33 @@ class ProjectDetector {
41
43
  supportedFeatures: detector?.getSupportedFeatures() || {},
42
44
  availableGenerators: detector?.getAvailableGenerators() || [],
43
45
  },
44
-
46
+
45
47
  // Project metadata (framework-agnostic)
46
48
  github: githubInfo,
47
49
  apiClient: apiClientInfo,
48
50
  oauth: oauthInfo,
49
-
51
+ database: databaseInfo,
52
+
50
53
  // Raw detection results (for debugging)
51
54
  _raw: {
52
55
  frameworkResults: frameworkDetection.allResults,
53
56
  },
54
-
57
+
55
58
  // Project path
56
59
  projectPath,
57
60
  };
58
61
  }
59
62
 
63
+ /**
64
+ * Detect database configuration in a project
65
+ *
66
+ * @param {string} projectPath - Path to project directory
67
+ * @returns {object} Database detection results
68
+ */
69
+ detectDatabase(projectPath = process.cwd()) {
70
+ return databaseDetector.detect(projectPath);
71
+ }
72
+
60
73
  /**
61
74
  * Get detector for a specific project type
62
75
  *