@tamyla/clodo-framework 3.1.13 ā 3.1.15
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 +14 -0
- package/dist/bin/commands/assess.js +46 -31
- package/dist/bin/commands/create.js +45 -24
- package/dist/bin/commands/deploy.js +260 -101
- package/dist/bin/commands/diagnose.js +45 -32
- package/dist/bin/commands/update.js +39 -19
- package/dist/bin/commands/validate.js +33 -8
- package/dist/bin/shared/config/cloudflare-service-validator.js +3 -5
- package/dist/bin/shared/config/manifest-loader.js +9 -2
- package/dist/bin/shared/deployment/credential-collector.js +228 -0
- package/dist/bin/shared/routing/domain-router.js +596 -0
- package/dist/bin/shared/utils/ErrorHandler.js +122 -2
- package/dist/bin/shared/utils/cli-options.js +136 -0
- package/dist/bin/shared/utils/config-loader.js +275 -0
- package/dist/bin/shared/utils/output-formatter.js +273 -0
- package/dist/bin/shared/utils/progress-manager.js +335 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [3.1.15](https://github.com/tamylaa/clodo-framework/compare/v3.1.14...v3.1.15) (2025-10-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Complete comprehensive clodo-framework refactoring (Tasks 3.1-3.4) ([0949b8b](https://github.com/tamylaa/clodo-framework/commit/0949b8be5f4f6522c0e4e4050e858ce82be5d034))
|
|
7
|
+
|
|
8
|
+
## [3.1.14](https://github.com/tamylaa/clodo-framework/compare/v3.1.13...v3.1.14) (2025-10-27)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* restore smart credential collection flow in deploy command ([a3e94f6](https://github.com/tamylaa/clodo-framework/commit/a3e94f6efe4a41c380badfc7a104e32bfba9fe9a))
|
|
14
|
+
|
|
1
15
|
## [3.1.13](https://github.com/tamylaa/clodo-framework/compare/v3.1.12...v3.1.13) (2025-10-27)
|
|
2
16
|
|
|
3
17
|
|
|
@@ -4,16 +4,43 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
+
import { StandardOptions } from '../shared/utils/cli-options.js';
|
|
8
|
+
import { ConfigLoader } from '../shared/utils/config-loader.js';
|
|
7
9
|
export function registerAssessCommand(program) {
|
|
8
|
-
program.command('assess [service-path]').description('Run intelligent capability assessment (requires @tamyla/clodo-orchestration)').option('--export <file>', 'Export assessment results to JSON file').option('--domain <domain>', 'Domain name for assessment').option('--service-type <type>', 'Service type for assessment').option('--token <token>', 'Cloudflare API token')
|
|
10
|
+
const command = program.command('assess [service-path]').description('Run intelligent capability assessment (requires @tamyla/clodo-orchestration)').option('--export <file>', 'Export assessment results to JSON file').option('--domain <domain>', 'Domain name for assessment').option('--service-type <type>', 'Service type for assessment').option('--token <token>', 'Cloudflare API token');
|
|
11
|
+
|
|
12
|
+
// Add standard options (--verbose, --quiet, --json, --no-color, --config-file)
|
|
13
|
+
StandardOptions.define(command).action(async (servicePath, options) => {
|
|
9
14
|
try {
|
|
15
|
+
const output = new (await import('../shared/utils/output-formatter.js')).OutputFormatter(options);
|
|
16
|
+
const configLoader = new ConfigLoader({
|
|
17
|
+
verbose: options.verbose,
|
|
18
|
+
quiet: options.quiet,
|
|
19
|
+
json: options.json
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Load config from file if specified
|
|
23
|
+
let configFileData = {};
|
|
24
|
+
if (options.configFile) {
|
|
25
|
+
configFileData = configLoader.loadSafe(options.configFile, {});
|
|
26
|
+
if (options.verbose && !options.quiet) {
|
|
27
|
+
output.info(`Loaded configuration from: ${options.configFile}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Substitute environment variables
|
|
32
|
+
configFileData = configLoader.substituteEnvironmentVariables(configFileData);
|
|
33
|
+
|
|
34
|
+
// Merge config file defaults with CLI options (CLI takes precedence)
|
|
35
|
+
const mergedOptions = configLoader.merge(configFileData, options);
|
|
36
|
+
|
|
10
37
|
// Try to load professional orchestration package
|
|
11
38
|
let orchestrationModule;
|
|
12
39
|
try {
|
|
13
40
|
orchestrationModule = await import('@tamyla/clodo-orchestration');
|
|
14
41
|
} catch (err) {
|
|
15
|
-
|
|
16
|
-
|
|
42
|
+
output.error('ā clodo-orchestration package not found');
|
|
43
|
+
output.info('š” Install with: npm install @tamyla/clodo-orchestration');
|
|
17
44
|
process.exit(1);
|
|
18
45
|
}
|
|
19
46
|
const {
|
|
@@ -22,53 +49,41 @@ export function registerAssessCommand(program) {
|
|
|
22
49
|
runAssessmentWorkflow
|
|
23
50
|
} = orchestrationModule;
|
|
24
51
|
const targetPath = servicePath || process.cwd();
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
console.log(chalk.white(`Service Path: ${targetPath}`));
|
|
28
|
-
if (options.domain) {
|
|
29
|
-
console.log(chalk.white(`Domain: ${options.domain}`));
|
|
30
|
-
}
|
|
31
|
-
if (options.serviceType) {
|
|
32
|
-
console.log(chalk.white(`Service Type: ${options.serviceType}`));
|
|
33
|
-
}
|
|
34
|
-
console.log(chalk.gray('ā'.repeat(60)));
|
|
52
|
+
output.section('Professional Capability Assessment');
|
|
53
|
+
output.list([`Service Path: ${targetPath}`, mergedOptions.domain ? `Domain: ${mergedOptions.domain}` : null, mergedOptions.serviceType ? `Service Type: ${mergedOptions.serviceType}` : null].filter(Boolean));
|
|
35
54
|
|
|
36
55
|
// Use the assessment workflow
|
|
37
56
|
const assessment = await runAssessmentWorkflow({
|
|
38
57
|
servicePath: targetPath,
|
|
39
|
-
domain:
|
|
40
|
-
serviceType:
|
|
41
|
-
token:
|
|
58
|
+
domain: mergedOptions.domain,
|
|
59
|
+
serviceType: mergedOptions.serviceType,
|
|
60
|
+
token: mergedOptions.token || process.env.CLOUDFLARE_API_TOKEN
|
|
42
61
|
});
|
|
43
62
|
|
|
44
63
|
// Display results
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
console.log(chalk.white(`Service Type: ${assessment.mergedInputs?.serviceType || assessment.serviceType || 'Not determined'}`));
|
|
48
|
-
console.log(chalk.white(`Confidence: ${assessment.confidence}%`));
|
|
64
|
+
output.section('ā
Assessment Results');
|
|
65
|
+
output.list([`Service Type: ${assessment.mergedInputs?.serviceType || assessment.serviceType || 'Not determined'}`, `Confidence: ${assessment.confidence}%`]);
|
|
49
66
|
if (assessment.gapAnalysis?.missing) {
|
|
50
|
-
console.log(chalk.white(`Missing Capabilities: ${assessment.gapAnalysis.missing.length}`));
|
|
51
67
|
if (assessment.gapAnalysis.missing.length > 0) {
|
|
52
|
-
|
|
53
|
-
assessment.gapAnalysis.missing.
|
|
54
|
-
|
|
55
|
-
});
|
|
68
|
+
output.warning('ā ļø Missing Capabilities:');
|
|
69
|
+
const missingItems = assessment.gapAnalysis.missing.map(gap => `${gap.capability}: ${gap.reason || 'Not available'}`);
|
|
70
|
+
output.list(missingItems);
|
|
56
71
|
}
|
|
57
72
|
}
|
|
58
|
-
console.log(chalk.gray('ā'.repeat(60)));
|
|
59
73
|
|
|
60
74
|
// Export results if requested
|
|
61
|
-
if (
|
|
75
|
+
if (mergedOptions.export) {
|
|
62
76
|
const {
|
|
63
77
|
writeFileSync
|
|
64
78
|
} = await import('fs');
|
|
65
|
-
writeFileSync(
|
|
66
|
-
|
|
79
|
+
writeFileSync(mergedOptions.export, JSON.stringify(assessment, null, 2));
|
|
80
|
+
output.success(`š Results exported to: ${mergedOptions.export}`);
|
|
67
81
|
}
|
|
68
82
|
} catch (error) {
|
|
69
|
-
|
|
83
|
+
const output = new (await import('../shared/utils/output-formatter.js')).OutputFormatter(options || {});
|
|
84
|
+
output.error(`Assessment failed: ${error.message}`);
|
|
70
85
|
if (process.env.DEBUG) {
|
|
71
|
-
|
|
86
|
+
output.debug(error.stack);
|
|
72
87
|
}
|
|
73
88
|
process.exit(1);
|
|
74
89
|
}
|
|
@@ -7,48 +7,69 @@
|
|
|
7
7
|
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import { ServiceOrchestrator } from "../../service-management/ServiceOrchestrator.js";
|
|
10
|
+
import { StandardOptions } from '../shared/utils/cli-options.js';
|
|
11
|
+
import { ConfigLoader } from '../shared/utils/config-loader.js';
|
|
10
12
|
export function registerCreateCommand(program) {
|
|
11
|
-
program.command('create').description('Create a new Clodo service with conversational setup').option('-n, --non-interactive', 'Run in non-interactive mode with all required parameters').option('--service-name <name>', 'Service name (required in non-interactive mode)').option('--service-type <type>', 'Service type: data-service, auth-service, content-service, api-gateway, generic', 'generic').option('--domain-name <domain>', 'Domain name (required in non-interactive mode)').option('--cloudflare-token <token>', 'Cloudflare API token (required in non-interactive mode)').option('--cloudflare-account-id <id>', 'Cloudflare account ID (required in non-interactive mode)').option('--cloudflare-zone-id <id>', 'Cloudflare zone ID (required in non-interactive mode)').option('--environment <env>', 'Target environment: development, staging, production', 'development').option('--output-path <path>', 'Output directory for generated service', '.').option('--template-path <path>', 'Path to service templates', './templates').
|
|
13
|
+
const command = program.command('create').description('Create a new Clodo service with conversational setup').option('-n, --non-interactive', 'Run in non-interactive mode with all required parameters').option('--service-name <name>', 'Service name (required in non-interactive mode)').option('--service-type <type>', 'Service type: data-service, auth-service, content-service, api-gateway, generic', 'generic').option('--domain-name <domain>', 'Domain name (required in non-interactive mode)').option('--cloudflare-token <token>', 'Cloudflare API token (required in non-interactive mode)').option('--cloudflare-account-id <id>', 'Cloudflare account ID (required in non-interactive mode)').option('--cloudflare-zone-id <id>', 'Cloudflare zone ID (required in non-interactive mode)').option('--environment <env>', 'Target environment: development, staging, production', 'development').option('--output-path <path>', 'Output directory for generated service', '.').option('--template-path <path>', 'Path to service templates', './templates').option('--force', 'Skip confirmation prompts').option('--validate', 'Validate service after creation');
|
|
14
|
+
|
|
15
|
+
// Add standard options (--verbose, --quiet, --json, --no-color, --config-file)
|
|
16
|
+
StandardOptions.define(command).action(async options => {
|
|
12
17
|
try {
|
|
18
|
+
const output = new (await import('../shared/utils/output-formatter.js')).OutputFormatter(options);
|
|
19
|
+
const configLoader = new ConfigLoader({
|
|
20
|
+
verbose: options.verbose,
|
|
21
|
+
quiet: options.quiet,
|
|
22
|
+
json: options.json
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Load config from file if specified
|
|
26
|
+
let configFileData = {};
|
|
27
|
+
if (options.configFile) {
|
|
28
|
+
configFileData = configLoader.loadSafe(options.configFile, {});
|
|
29
|
+
if (options.verbose && !options.quiet) {
|
|
30
|
+
output.info(`Loaded configuration from: ${options.configFile}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Merge config file defaults with CLI options (CLI takes precedence)
|
|
35
|
+
const mergedOptions = configLoader.merge(configFileData, options);
|
|
13
36
|
const orchestrator = new ServiceOrchestrator({
|
|
14
|
-
interactive: !
|
|
15
|
-
outputPath:
|
|
16
|
-
templatePath:
|
|
37
|
+
interactive: !mergedOptions.nonInteractive,
|
|
38
|
+
outputPath: mergedOptions.outputPath,
|
|
39
|
+
templatePath: mergedOptions.templatePath
|
|
17
40
|
});
|
|
18
|
-
if (
|
|
41
|
+
if (mergedOptions.nonInteractive) {
|
|
19
42
|
// Validate required parameters for non-interactive mode
|
|
20
43
|
const required = ['serviceName', 'domainName', 'cloudflareToken', 'cloudflareAccountId', 'cloudflareZoneId'];
|
|
21
|
-
const missing = required.filter(key => !
|
|
44
|
+
const missing = required.filter(key => !mergedOptions[key]);
|
|
22
45
|
if (missing.length > 0) {
|
|
23
|
-
|
|
24
|
-
|
|
46
|
+
output.error(`Missing required parameters: ${missing.join(', ')}`);
|
|
47
|
+
output.info('Use --help for parameter details');
|
|
25
48
|
process.exit(1);
|
|
26
49
|
}
|
|
27
50
|
|
|
28
|
-
// Convert
|
|
51
|
+
// Convert merged options to core inputs
|
|
29
52
|
const coreInputs = {
|
|
30
|
-
serviceName:
|
|
31
|
-
serviceType:
|
|
32
|
-
domainName:
|
|
33
|
-
cloudflareToken:
|
|
34
|
-
cloudflareAccountId:
|
|
35
|
-
cloudflareZoneId:
|
|
36
|
-
environment:
|
|
53
|
+
serviceName: mergedOptions.serviceName,
|
|
54
|
+
serviceType: mergedOptions.serviceType,
|
|
55
|
+
domainName: mergedOptions.domainName,
|
|
56
|
+
cloudflareToken: mergedOptions.cloudflareToken,
|
|
57
|
+
cloudflareAccountId: mergedOptions.cloudflareAccountId,
|
|
58
|
+
cloudflareZoneId: mergedOptions.cloudflareZoneId,
|
|
59
|
+
environment: mergedOptions.environment
|
|
37
60
|
};
|
|
38
61
|
await orchestrator.runNonInteractive(coreInputs);
|
|
39
62
|
} else {
|
|
40
63
|
await orchestrator.runInteractive();
|
|
41
64
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
console.log(chalk.white(' 2. Run npm install'));
|
|
46
|
-
console.log(chalk.white(' 3. Configure additional settings in src/config/domains.js'));
|
|
47
|
-
console.log(chalk.white(' 4. Run npm run deploy to deploy to Cloudflare'));
|
|
65
|
+
output.success('Service creation completed successfully!');
|
|
66
|
+
output.section('Next steps');
|
|
67
|
+
output.list(['cd into your new service directory', 'Run npm install', 'Configure additional settings in src/config/domains.js', 'Run npm run deploy to deploy to Cloudflare']);
|
|
48
68
|
} catch (error) {
|
|
49
|
-
|
|
69
|
+
const output = new (await import('../shared/utils/output-formatter.js')).OutputFormatter(options || {});
|
|
70
|
+
output.error(`Service creation failed: ${error.message}`);
|
|
50
71
|
if (error.details) {
|
|
51
|
-
|
|
72
|
+
output.warning(`Details: ${error.details}`);
|
|
52
73
|
}
|
|
53
74
|
process.exit(1);
|
|
54
75
|
}
|