@tamyla/clodo-framework 3.0.13 ā 3.0.14
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 +12 -2
- package/bin/clodo-service.js +94 -1
- package/bin/shared/security/secret-generator.js +7 -2
- package/dist/config/customers.js +8 -2
- package/dist/config/domains.js +8 -2
- package/dist/config/features.js +7 -2
- package/dist/index.js +8 -0
- package/dist/service-management/GenerationEngine.js +23 -14
- package/dist/service-management/InputCollector.js +4 -97
- package/dist/service-management/ServiceCreator.js +9 -1
- package/dist/service-management/ServiceInitializer.js +14 -5
- package/dist/service-management/ServiceOrchestrator.js +1 -269
- package/dist/service-management/index.js +7 -3
- package/dist/shared/security/secret-generator.js +7 -2
- package/dist/worker/integration.js +8 -2
- package/package.json +5 -3
- package/dist/service-management/AssessmentCache.js +0 -303
- package/dist/service-management/CapabilityAssessmentEngine.js +0 -902
- package/dist/service-management/ServiceAutoDiscovery.js +0 -745
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
## [3.0.
|
|
1
|
+
## [3.0.14](https://github.com/tamylaa/clodo-framework/compare/v3.0.13...v3.0.14) (2025-10-20)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Bug Fixes
|
|
5
5
|
|
|
6
|
-
*
|
|
6
|
+
* add test environment compatibility fixes for ES modules ([71a033d](https://github.com/tamylaa/clodo-framework/commit/71a033d5d959480879c1a4771005553116e8671f))
|
|
7
|
+
* ignore deployment artifacts in deployments/ directory ([768f453](https://github.com/tamylaa/clodo-framework/commit/768f453cbabb984509613a382d86875c1309bcd2))
|
|
8
|
+
* resolve circular dependency in FeatureFlagManager ([d04956f](https://github.com/tamylaa/clodo-framework/commit/d04956f83527d3236fce2fe9750f71cdf0ba8d8e))
|
|
9
|
+
* resolve ESLint errors and update test expectations ([b1188be](https://github.com/tamylaa/clodo-framework/commit/b1188be66d3723bfff62431f6e0eabec685b0111))
|
|
10
|
+
* revert Jest config to working configuration that passes tests ([35a2846](https://github.com/tamylaa/clodo-framework/commit/35a28466c8a48c78011c128f89695399e8500341))
|
|
11
|
+
* update Jest config to properly handle ES modules ([1a951c7](https://github.com/tamylaa/clodo-framework/commit/1a951c7ae147ddb8bef0ec1508c858ac044423b7))
|
|
12
|
+
* update package-lock.json to sync with package.json dependencies ([a3ef884](https://github.com/tamylaa/clodo-framework/commit/a3ef8844cba2b5657a3493b8339c98049a57dd72))
|
|
13
|
+
* update package.json semantic release config to support main branch ([a06b2e8](https://github.com/tamylaa/clodo-framework/commit/a06b2e899ceb7699b67292157991d64c88dedae3))
|
|
14
|
+
* update semantic release config to support main branch ([4102e6c](https://github.com/tamylaa/clodo-framework/commit/4102e6c4cb4f52d065750239c2a0c5a89b733ac0))
|
|
15
|
+
* update version to 3.0.13 to sync with release history ([f9bb4d4](https://github.com/tamylaa/clodo-framework/commit/f9bb4d463a3884b82e972962e5fcd21a272c3acb))
|
|
16
|
+
* use os.tmpdir() for test paths to fix CI permission errors ([022c771](https://github.com/tamylaa/clodo-framework/commit/022c771994635002410c27d8eb7ec8f0614acf6f))
|
|
7
17
|
|
|
8
18
|
## [3.0.12](https://github.com/tamylaa/clodo-framework/compare/v3.0.11...v3.0.12) (2025-10-14)
|
|
9
19
|
|
package/bin/clodo-service.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Clodo Framework - Unified Three-Tier Service Management CLI
|
|
@@ -527,6 +527,86 @@ program
|
|
|
527
527
|
}
|
|
528
528
|
});
|
|
529
529
|
|
|
530
|
+
// Professional Edition: assess command (from clodo-orchestration)
|
|
531
|
+
program
|
|
532
|
+
.command('assess [service-path]')
|
|
533
|
+
.description('Run intelligent capability assessment (requires @tamyla/clodo-orchestration)')
|
|
534
|
+
.option('--export <file>', 'Export assessment results to JSON file')
|
|
535
|
+
.option('--domain <domain>', 'Domain name for assessment')
|
|
536
|
+
.option('--service-type <type>', 'Service type for assessment')
|
|
537
|
+
.option('--token <token>', 'Cloudflare API token')
|
|
538
|
+
.action(async (servicePath, options) => {
|
|
539
|
+
try {
|
|
540
|
+
// Try to load professional orchestration package
|
|
541
|
+
let orchestrationModule;
|
|
542
|
+
try {
|
|
543
|
+
orchestrationModule = await import('@tamyla/clodo-orchestration');
|
|
544
|
+
} catch (err) {
|
|
545
|
+
console.error(chalk.red('ā clodo-orchestration package not found'));
|
|
546
|
+
console.error(chalk.yellow('š” Install with: npm install @tamyla/clodo-orchestration'));
|
|
547
|
+
process.exit(1);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const {
|
|
551
|
+
CapabilityAssessmentEngine,
|
|
552
|
+
ServiceAutoDiscovery,
|
|
553
|
+
runAssessmentWorkflow
|
|
554
|
+
} = orchestrationModule;
|
|
555
|
+
|
|
556
|
+
const targetPath = servicePath || process.cwd();
|
|
557
|
+
console.log(chalk.cyan('\nš§ Professional Capability Assessment'));
|
|
558
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
559
|
+
console.log(chalk.white(`Service Path: ${targetPath}`));
|
|
560
|
+
|
|
561
|
+
if (options.domain) {
|
|
562
|
+
console.log(chalk.white(`Domain: ${options.domain}`));
|
|
563
|
+
}
|
|
564
|
+
if (options.serviceType) {
|
|
565
|
+
console.log(chalk.white(`Service Type: ${options.serviceType}`));
|
|
566
|
+
}
|
|
567
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
568
|
+
|
|
569
|
+
// Use the assessment workflow
|
|
570
|
+
const assessment = await runAssessmentWorkflow({
|
|
571
|
+
servicePath: targetPath,
|
|
572
|
+
domain: options.domain,
|
|
573
|
+
serviceType: options.serviceType,
|
|
574
|
+
token: options.token || process.env.CLOUDFLARE_API_TOKEN
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
// Display results
|
|
578
|
+
console.log(chalk.cyan('\nā
Assessment Results'));
|
|
579
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
580
|
+
console.log(chalk.white(`Service Type: ${assessment.mergedInputs?.serviceType || assessment.serviceType || 'Not determined'}`));
|
|
581
|
+
console.log(chalk.white(`Confidence: ${assessment.confidence}%`));
|
|
582
|
+
|
|
583
|
+
if (assessment.gapAnalysis?.missing) {
|
|
584
|
+
console.log(chalk.white(`Missing Capabilities: ${assessment.gapAnalysis.missing.length}`));
|
|
585
|
+
if (assessment.gapAnalysis.missing.length > 0) {
|
|
586
|
+
console.log(chalk.yellow('\nā ļø Missing:'));
|
|
587
|
+
assessment.gapAnalysis.missing.forEach(gap => {
|
|
588
|
+
console.log(chalk.yellow(` ⢠${gap.capability}: ${gap.reason || 'Not available'}`));
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
594
|
+
|
|
595
|
+
// Export results if requested
|
|
596
|
+
if (options.export) {
|
|
597
|
+
require('fs').writeFileSync(options.export, JSON.stringify(assessment, null, 2));
|
|
598
|
+
console.log(chalk.green(`\nš Results exported to: ${options.export}`));
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
} catch (error) {
|
|
602
|
+
console.error(chalk.red(`Assessment failed: ${error.message}`));
|
|
603
|
+
if (process.env.DEBUG) {
|
|
604
|
+
console.error(chalk.gray(error.stack));
|
|
605
|
+
}
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
|
|
530
610
|
// Deploy command - using existing InputCollector + CustomerConfigLoader (reusable pattern)
|
|
531
611
|
program
|
|
532
612
|
.command('deploy')
|
|
@@ -698,6 +778,19 @@ program
|
|
|
698
778
|
// Tier 3: Execute deployment
|
|
699
779
|
console.log(chalk.cyan('\nāļø Tier 3: Automated Deployment\n'));
|
|
700
780
|
|
|
781
|
+
// OPTIONAL: Try to load professional orchestration package if available
|
|
782
|
+
let professionalOrchestration = null;
|
|
783
|
+
try {
|
|
784
|
+
const { runAssessmentWorkflow } = await import('@tamyla/clodo-orchestration');
|
|
785
|
+
professionalOrchestration = { runAssessmentWorkflow };
|
|
786
|
+
console.log(chalk.cyan('š Professional Edition (clodo-orchestration) detected'));
|
|
787
|
+
} catch (err) {
|
|
788
|
+
// clodo-orchestration not installed, continue with standard assessment
|
|
789
|
+
if (process.env.DEBUG) {
|
|
790
|
+
console.log(chalk.gray(` ā¹ļø clodo-orchestration not available: ${err.message}`));
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
701
794
|
// INTEGRATION: Add intelligent service discovery and assessment
|
|
702
795
|
console.log(chalk.cyan('š§ Performing Intelligent Service Assessment...'));
|
|
703
796
|
const { CapabilityAssessmentEngine } = await import('../dist/service-management/CapabilityAssessmentEngine.js');
|
|
@@ -17,8 +17,13 @@ import { execSync } from 'child_process';
|
|
|
17
17
|
import { fileURLToPath } from 'url';
|
|
18
18
|
|
|
19
19
|
const __dirname = (() => {
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
try {
|
|
21
|
+
const filename = fileURLToPath(import.meta.url);
|
|
22
|
+
return dirname(filename);
|
|
23
|
+
} catch (error) {
|
|
24
|
+
// Fallback for test environments - use current working directory
|
|
25
|
+
return process.cwd();
|
|
26
|
+
}
|
|
22
27
|
})();
|
|
23
28
|
|
|
24
29
|
const SECRET_CONFIGS = {
|
package/dist/config/customers.js
CHANGED
|
@@ -3,10 +3,16 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSy
|
|
|
3
3
|
import { resolve, join } from 'path';
|
|
4
4
|
import toml from '@iarna/toml';
|
|
5
5
|
import { createDomainConfigSchema, validateDomainConfig, createDomainRegistry } from './domains.js';
|
|
6
|
-
import { createLogger } from '../utils/index.js';
|
|
7
6
|
import { getDirname } from '../utils/esm-helper.js';
|
|
8
7
|
const __dirname = getDirname(import.meta.url, 'src/config');
|
|
9
|
-
|
|
8
|
+
|
|
9
|
+
// Simple inline logger to avoid circular dependency with index.js
|
|
10
|
+
const logger = {
|
|
11
|
+
info: (message, ...args) => console.log(`[CustomerConfig] ${message}`, ...args),
|
|
12
|
+
error: (message, ...args) => console.error(`[CustomerConfig] ${message}`, ...args),
|
|
13
|
+
warn: (message, ...args) => console.warn(`[CustomerConfig] ${message}`, ...args),
|
|
14
|
+
debug: (message, ...args) => console.debug(`[CustomerConfig] ${message}`, ...args)
|
|
15
|
+
};
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
18
|
* Customer Configuration Manager
|
package/dist/config/domains.js
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// Simple inline logger to avoid circular dependency with index.js
|
|
2
|
+
import { validateRequired, deepMerge } from '../utils/index.js';
|
|
3
|
+
const logger = {
|
|
4
|
+
info: (message, ...args) => console.log(`[DomainConfig] ${message}`, ...args),
|
|
5
|
+
error: (message, ...args) => console.error(`[DomainConfig] ${message}`, ...args),
|
|
6
|
+
warn: (message, ...args) => console.warn(`[DomainConfig] ${message}`, ...args),
|
|
7
|
+
debug: (message, ...args) => console.debug(`[DomainConfig] ${message}`, ...args)
|
|
8
|
+
};
|
|
3
9
|
|
|
4
10
|
/**
|
|
5
11
|
* Creates a base domain configuration schema
|
package/dist/config/features.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
const logger =
|
|
1
|
+
// Simple inline logger to avoid circular dependency with index.js
|
|
2
|
+
const logger = {
|
|
3
|
+
info: (message, ...args) => console.log(`[FeatureFlagManager] ${message}`, ...args),
|
|
4
|
+
error: (message, ...args) => console.error(`[FeatureFlagManager] ${message}`, ...args),
|
|
5
|
+
warn: (message, ...args) => console.warn(`[FeatureFlagManager] ${message}`, ...args),
|
|
6
|
+
debug: (message, ...args) => console.debug(`[FeatureFlagManager] ${message}`, ...args)
|
|
7
|
+
};
|
|
3
8
|
|
|
4
9
|
/**
|
|
5
10
|
* Feature Flag Manager Class
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,14 @@ export { WranglerDeployer } from './deployment/wrangler-deployer.js';
|
|
|
24
24
|
// Security components
|
|
25
25
|
export * from './security/index.js';
|
|
26
26
|
|
|
27
|
+
// Service management components
|
|
28
|
+
export { ServiceCreator, createService } from './service-management/ServiceCreator.js';
|
|
29
|
+
export { ServiceOrchestrator } from './service-management/ServiceOrchestrator.js';
|
|
30
|
+
export { InputHandler } from './service-management/handlers/InputHandler.js';
|
|
31
|
+
export { ConfirmationHandler } from './service-management/handlers/ConfirmationHandler.js';
|
|
32
|
+
export { GenerationHandler } from './service-management/handlers/GenerationHandler.js';
|
|
33
|
+
export { ValidationHandler } from './service-management/handlers/ValidationHandler.js';
|
|
34
|
+
|
|
27
35
|
// Framework version info
|
|
28
36
|
export const FRAMEWORK_VERSION = '1.0.0';
|
|
29
37
|
export const FRAMEWORK_NAME = 'Clodo Framework';
|
|
@@ -36,8 +36,13 @@ import { fileURLToPath } from 'url';
|
|
|
36
36
|
import { dirname, join, relative } from 'path';
|
|
37
37
|
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
38
38
|
const __dirname = (() => {
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
try {
|
|
40
|
+
const filename = fileURLToPath(import.meta.url);
|
|
41
|
+
return dirname(filename);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
// Fallback for test environments - use current working directory
|
|
44
|
+
return process.cwd();
|
|
45
|
+
}
|
|
41
46
|
})();
|
|
42
47
|
export class GenerationEngine {
|
|
43
48
|
constructor(options = {}) {
|
|
@@ -148,12 +153,14 @@ export class GenerationEngine {
|
|
|
148
153
|
const wranglerConfig = serviceInitializer.generateWranglerConfig(coreInputs.serviceName, {
|
|
149
154
|
type: coreInputs.serviceType,
|
|
150
155
|
env: coreInputs.environment
|
|
151
|
-
},
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
156
|
+
}, {
|
|
157
|
+
domains: [{
|
|
158
|
+
domain: coreInputs.domainName,
|
|
159
|
+
accountId: coreInputs.cloudflareAccountId,
|
|
160
|
+
zoneId: coreInputs.cloudflareZoneId,
|
|
161
|
+
name: `${coreInputs.serviceName}-${coreInputs.environment}`
|
|
162
|
+
}]
|
|
163
|
+
});
|
|
157
164
|
|
|
158
165
|
// Write wrangler.toml
|
|
159
166
|
const wranglerPath = join(servicePath, 'wrangler.toml');
|
|
@@ -177,12 +184,14 @@ export class GenerationEngine {
|
|
|
177
184
|
const domainsContent = serviceInitializer.generateDomainsConfig(coreInputs.serviceName, {
|
|
178
185
|
type: coreInputs.serviceType,
|
|
179
186
|
env: coreInputs.environment
|
|
180
|
-
},
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
187
|
+
}, {
|
|
188
|
+
domains: [{
|
|
189
|
+
domain: coreInputs.domainName,
|
|
190
|
+
accountId: coreInputs.cloudflareAccountId,
|
|
191
|
+
zoneId: coreInputs.cloudflareZoneId,
|
|
192
|
+
name: `${coreInputs.serviceName}-${coreInputs.environment}`
|
|
193
|
+
}]
|
|
194
|
+
});
|
|
186
195
|
const domainsPath = join(servicePath, 'src', 'config', 'domains.js');
|
|
187
196
|
writeFileSync(domainsPath, domainsContent, 'utf8');
|
|
188
197
|
files.push(domainsPath);
|
|
@@ -15,7 +15,9 @@ 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
|
-
|
|
18
|
+
|
|
19
|
+
// Assessment capabilities moved to @tamyla/clodo-orchestration (professional edition)
|
|
20
|
+
|
|
19
21
|
export class InputCollector {
|
|
20
22
|
constructor(options = {}) {
|
|
21
23
|
this.interactive = options.interactive !== false;
|
|
@@ -82,10 +84,7 @@ export class InputCollector {
|
|
|
82
84
|
required: true
|
|
83
85
|
};
|
|
84
86
|
|
|
85
|
-
//
|
|
86
|
-
if (inputDef.id === 'cloudflare-api-token' && value) {
|
|
87
|
-
await this.runDeploymentReadinessAssessment(result.coreInputs);
|
|
88
|
-
}
|
|
87
|
+
// Assessment moved to professional edition (@tamyla/clodo-orchestration)
|
|
89
88
|
}
|
|
90
89
|
}
|
|
91
90
|
|
|
@@ -579,98 +578,6 @@ export class InputCollector {
|
|
|
579
578
|
});
|
|
580
579
|
}
|
|
581
580
|
|
|
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
|
-
|
|
674
581
|
/**
|
|
675
582
|
* Close readline interface and clean up
|
|
676
583
|
*/
|
|
@@ -9,7 +9,15 @@ import { fileURLToPath } from 'url';
|
|
|
9
9
|
const SERVICE_TYPES = ['data-service', 'auth-service', 'content-service', 'api-gateway', 'generic'];
|
|
10
10
|
export class ServiceCreator {
|
|
11
11
|
constructor(options = {}) {
|
|
12
|
-
|
|
12
|
+
const templatesDir = (() => {
|
|
13
|
+
try {
|
|
14
|
+
return join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'templates');
|
|
15
|
+
} catch (error) {
|
|
16
|
+
// Fallback for test environments - use current working directory
|
|
17
|
+
return join(process.cwd(), 'templates');
|
|
18
|
+
}
|
|
19
|
+
})();
|
|
20
|
+
this.templatesDir = options.templatesDir || templatesDir;
|
|
13
21
|
this.serviceTypes = options.serviceTypes || SERVICE_TYPES;
|
|
14
22
|
}
|
|
15
23
|
|
|
@@ -6,11 +6,20 @@
|
|
|
6
6
|
import { existsSync, readFileSync, writeFileSync, mkdirSync, cpSync, readdirSync } from 'fs';
|
|
7
7
|
import { join, dirname, resolve } from 'path';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
|
|
10
|
+
// Get framework root - handle both ES module and CommonJS environments
|
|
11
|
+
const getFrameworkRoot = () => {
|
|
12
|
+
try {
|
|
13
|
+
// Try ES module approach
|
|
14
|
+
const filename = fileURLToPath(import.meta.url);
|
|
15
|
+
const dirname_ = dirname(filename);
|
|
16
|
+
return resolve(dirname_, '..', '..');
|
|
17
|
+
} catch (error) {
|
|
18
|
+
// Fallback for test environments - use current working directory
|
|
19
|
+
return process.cwd();
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const FRAMEWORK_ROOT = getFrameworkRoot();
|
|
14
23
|
const TEMPLATES_DIR = join(FRAMEWORK_ROOT, 'templates');
|
|
15
24
|
const SERVICE_TYPES = ['generic', 'data-service', 'auth-service', 'content-service', 'api-gateway'];
|
|
16
25
|
export class ServiceInitializer {
|