@tamyla/clodo-framework 3.0.11 → 3.0.13

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.
@@ -81,10 +81,10 @@ export class ConfirmationEngine {
81
81
  version: '1.0.0',
82
82
  // 4. Author - Default framework author
83
83
  author: 'Clodo Framework',
84
- // 5-7. URLs - Derived from domain
85
- productionUrl: `https://api.${domainName}`,
86
- stagingUrl: `https://staging-api.${domainName}`,
87
- developmentUrl: `https://dev-api.${domainName}`,
84
+ // 5-7. URLs - Derived from domain and service name
85
+ productionUrl: `https://${serviceName}.${domainName}`,
86
+ stagingUrl: `https://${serviceName}-staging.${domainName}`,
87
+ developmentUrl: `https://${serviceName}-dev.${domainName}`,
88
88
  // 8. Features - Based on service type
89
89
  features: this.generateFeaturesForType(serviceType),
90
90
  // 9. Database Name - Cloudflare D1 naming
@@ -15,6 +15,7 @@ import { createInterface } from 'readline';
15
15
  import chalk from 'chalk';
16
16
  import { validateServiceName, validateDomainName } from '../utils/validation.js';
17
17
  import { uiStructuresLoader } from '../utils/ui-structures-loader.js';
18
+ import { CapabilityAssessmentEngine } from './CapabilityAssessmentEngine.js';
18
19
  export class InputCollector {
19
20
  constructor(options = {}) {
20
21
  this.interactive = options.interactive !== false;
@@ -80,6 +81,11 @@ export class InputCollector {
80
81
  source: 'user-provided',
81
82
  required: true
82
83
  };
84
+
85
+ // Run assessment after API token is collected
86
+ if (inputDef.id === 'cloudflare-api-token' && value) {
87
+ await this.runDeploymentReadinessAssessment(result.coreInputs);
88
+ }
83
89
  }
84
90
  }
85
91
 
@@ -158,9 +164,9 @@ export class InputCollector {
158
164
  case 'production-url':
159
165
  return domainName ? `https://api.${domainName}` : '';
160
166
  case 'staging-url':
161
- return domainName ? `https://staging-api.${domainName}` : '';
167
+ return domainName && serviceName ? `https://${serviceName}-staging.${domainName}` : '';
162
168
  case 'development-url':
163
- return domainName ? `https://dev-api.${domainName}` : '';
169
+ return domainName && serviceName ? `https://${serviceName}-dev.${domainName}` : '';
164
170
  case 'service-directory':
165
171
  return serviceName ? `./services/${serviceName}` : '';
166
172
  case 'database-name':
@@ -386,8 +392,25 @@ export class InputCollector {
386
392
  CloudflareAPI
387
393
  } = await import('../utils/cloudflare/api.js');
388
394
  const cfApi = new CloudflareAPI(token);
389
- const isValid = await cfApi.verifyToken();
390
- if (isValid) {
395
+ const tokenCheck = await cfApi.verifyToken();
396
+ if (tokenCheck.valid) {
397
+ // Check D1 permissions
398
+ const permissionCheck = await cfApi.checkD1Permissions();
399
+ if (!permissionCheck.hasPermission) {
400
+ console.log(chalk.yellow(`⚠️ ${permissionCheck.error}`));
401
+ console.log(chalk.white(' 💡 You can update permissions at: https://dash.cloudflare.com/profile/api-tokens'));
402
+ console.log(chalk.white(' 💡 Or continue and the framework will fall back to OAuth authentication'));
403
+ console.log('');
404
+ const {
405
+ askYesNo
406
+ } = await import('../utils/interactive-prompts.js');
407
+ const continueAnyway = await askYesNo('Continue with limited API token permissions?', false);
408
+ if (!continueAnyway) {
409
+ console.log(chalk.blue('Please update your API token permissions and try again.'));
410
+ process.exit(0);
411
+ }
412
+ console.log(chalk.yellow('⚠️ Proceeding with limited permissions - database operations will use OAuth'));
413
+ }
391
414
  console.log(chalk.green('✓ API token verified successfully'));
392
415
  return token;
393
416
  }
@@ -556,6 +579,98 @@ export class InputCollector {
556
579
  });
557
580
  }
558
581
 
582
+ /**
583
+ * Run deployment readiness assessment after API token collection
584
+ */
585
+ async runDeploymentReadinessAssessment(coreInputs) {
586
+ console.log(chalk.cyan('\n🔍 Running Deployment Readiness Assessment...'));
587
+ console.log(chalk.gray('Analyzing your inputs for deployment feasibility...\n'));
588
+ try {
589
+ // Convert core inputs to assessment format
590
+ const assessmentInputs = {
591
+ serviceName: coreInputs['service-name']?.value,
592
+ serviceType: coreInputs['service-type']?.value || 'generic',
593
+ domainName: coreInputs['domain-name']?.value,
594
+ environment: coreInputs['environment']?.value || 'development',
595
+ cloudflareToken: coreInputs['cloudflare-api-token']?.value,
596
+ customerName: coreInputs['customer-name']?.value
597
+ };
598
+
599
+ // Create assessment engine with caching enabled
600
+ const assessmentEngine = new CapabilityAssessmentEngine(process.cwd(), {
601
+ cacheEnabled: true,
602
+ cache: {
603
+ ttl: 10 * 60 * 1000
604
+ } // 10 minutes for interactive sessions
605
+ });
606
+
607
+ // Run assessment
608
+ const assessment = await assessmentEngine.assessCapabilities(assessmentInputs);
609
+
610
+ // Display results
611
+ this.displayAssessmentResults(assessment);
612
+
613
+ // Store assessment in result for later use
614
+ return assessment;
615
+ } catch (error) {
616
+ console.log(chalk.yellow(`⚠️ Assessment failed: ${error.message}`));
617
+ console.log(chalk.gray('Continuing with service creation...'));
618
+ return null;
619
+ }
620
+ }
621
+
622
+ /**
623
+ * Display assessment results in user-friendly format
624
+ */
625
+ displayAssessmentResults(assessment) {
626
+ const {
627
+ capabilityManifest,
628
+ gapAnalysis,
629
+ confidence,
630
+ cached
631
+ } = assessment;
632
+ console.log(chalk.cyan('\n📊 Assessment Results:'));
633
+ console.log(chalk.gray('─'.repeat(40)));
634
+
635
+ // Service type and confidence
636
+ console.log(chalk.white(`Service Type: ${capabilityManifest.serviceType}`));
637
+ console.log(chalk.white(`Confidence: ${confidence.toFixed(1)}%`));
638
+ if (cached) {
639
+ console.log(chalk.gray('(Results loaded from cache)'));
640
+ }
641
+
642
+ // Gap analysis summary
643
+ const missingCount = gapAnalysis.missing.length;
644
+ const blockedCount = gapAnalysis.missing.filter(gap => gap.priority === 'blocked').length;
645
+ if (missingCount === 0) {
646
+ console.log(chalk.green('✅ All required capabilities detected'));
647
+ } else {
648
+ console.log(chalk.yellow(`⚠️ ${missingCount} capability gap(s) found`));
649
+ if (blockedCount > 0) {
650
+ console.log(chalk.red(`🚫 ${blockedCount} deployment blocker(s) detected`));
651
+ }
652
+
653
+ // Show top 3 gaps
654
+ gapAnalysis.missing.slice(0, 3).forEach(gap => {
655
+ const icon = gap.priority === 'blocked' ? '🚫' : '⚠️';
656
+ console.log(chalk.gray(` ${icon} ${gap.capability}: ${gap.reason}`));
657
+ });
658
+ if (gapAnalysis.missing.length > 3) {
659
+ console.log(chalk.gray(` ... and ${gapAnalysis.missing.length - 3} more`));
660
+ }
661
+ }
662
+
663
+ // Recommendations
664
+ if (assessment.recommendations && assessment.recommendations.length > 0) {
665
+ console.log(chalk.blue('\n💡 Recommendations:'));
666
+ assessment.recommendations.slice(0, 2).forEach(rec => {
667
+ console.log(chalk.gray(` • ${rec.message}`));
668
+ });
669
+ }
670
+ console.log(chalk.gray('\n─'.repeat(40)));
671
+ console.log(chalk.white('Continue with service creation? (Assessment will run again before generation)'));
672
+ }
673
+
559
674
  /**
560
675
  * Close readline interface and clean up
561
676
  */