@tamyla/clodo-framework 4.0.13 → 4.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +7 -0
  3. package/dist/cli/commands/create.js +2 -1
  4. package/dist/middleware/Composer.js +38 -0
  5. package/dist/middleware/Registry.js +14 -0
  6. package/dist/middleware/index.js +3 -0
  7. package/dist/middleware/shared/basicAuth.js +21 -0
  8. package/dist/middleware/shared/cors.js +28 -0
  9. package/dist/middleware/shared/index.js +3 -0
  10. package/dist/middleware/shared/logging.js +14 -0
  11. package/dist/service-management/GenerationEngine.js +13 -2
  12. package/dist/service-management/ServiceOrchestrator.js +6 -2
  13. package/dist/service-management/generators/code/ServiceMiddlewareGenerator.js +156 -10
  14. package/dist/service-management/generators/code/WorkerIndexGenerator.js +75 -9
  15. package/dist/simple-api.js +32 -1
  16. package/docs/MIDDLEWARE_MIGRATION_SUMMARY.md +121 -0
  17. package/package.json +4 -1
  18. package/scripts/DEPLOY_COMMAND_NEW.js +128 -0
  19. package/scripts/README-automated-testing-suite.md +356 -0
  20. package/scripts/README-test-clodo-deployment.md +157 -0
  21. package/scripts/README.md +50 -0
  22. package/scripts/analyze-imports.ps1 +104 -0
  23. package/scripts/analyze-mixed-code.js +163 -0
  24. package/scripts/analyze-mixed-rationale.js +149 -0
  25. package/scripts/automated-testing-suite.js +776 -0
  26. package/scripts/deployment/README.md +31 -0
  27. package/scripts/deployment/deploy-domain.ps1 +449 -0
  28. package/scripts/deployment/deploy-staging.js +120 -0
  29. package/scripts/deployment/validate-staging.js +166 -0
  30. package/scripts/diagnose-imports.js +362 -0
  31. package/scripts/framework-diagnostic.js +368 -0
  32. package/scripts/migration/migrate-middleware-legacy-to-contract.js +47 -0
  33. package/scripts/post-publish-test.js +663 -0
  34. package/scripts/scan-worker-issues.js +52 -0
  35. package/scripts/service-management/README.md +27 -0
  36. package/scripts/service-management/setup-interactive.ps1 +693 -0
  37. package/scripts/test-clodo-deployment.js +588 -0
  38. package/scripts/test-downstream-install.js +237 -0
  39. package/scripts/test-local-package.ps1 +126 -0
  40. package/scripts/test-local-package.sh +166 -0
  41. package/scripts/test-package.js +339 -0
  42. package/scripts/testing/README.md +49 -0
  43. package/scripts/testing/test-first.ps1 +0 -0
  44. package/scripts/testing/test-first50.ps1 +0 -0
  45. package/scripts/testing/test.ps1 +0 -0
  46. package/scripts/utilities/README.md +61 -0
  47. package/scripts/utilities/check-bin.js +8 -0
  48. package/scripts/utilities/check-bundle.js +23 -0
  49. package/scripts/utilities/check-dist-imports.js +65 -0
  50. package/scripts/utilities/check-import-paths.js +191 -0
  51. package/scripts/utilities/cleanup-cli.js +159 -0
  52. package/scripts/utilities/deployment-helpers.ps1 +199 -0
  53. package/scripts/utilities/fix-dist-imports.js +135 -0
  54. package/scripts/utilities/generate-secrets.js +159 -0
  55. package/scripts/utilities/safe-push.ps1 +51 -0
  56. package/scripts/utilities/setup-helpers.ps1 +206 -0
  57. package/scripts/utilities/test-packaged-artifact.js +92 -0
  58. package/scripts/utilities/validate-dist-imports.js +189 -0
  59. package/scripts/utilities/validate-schema.js +102 -0
  60. package/scripts/verify-exports.js +193 -0
  61. package/scripts/verify-worker-safety.js +73 -0
  62. package/types/middleware.d.ts +1 -0
@@ -0,0 +1,588 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Clodo Service Deployment Testing Script
5
+ *
6
+ * Comprehensive local testing script for clodo-service deployment process.
7
+ * Tests information collection, consolidation, and deployment execution phases
8
+ * without making actual Cloudflare API calls or deployments.
9
+ *
10
+ * Usage:
11
+ * node test-clodo-deployment.js [options]
12
+ *
13
+ * Options:
14
+ * --service-path <path> Path to service directory (default: current dir)
15
+ * --dry-run Simulate deployment without changes (default: true)
16
+ * --verbose Detailed logging output
17
+ * --mock-credentials Use mock credentials instead of prompting
18
+ * --test-phase <phase> Test specific phase: all, collection, consolidation, execution
19
+ *
20
+ * Testing Phases:
21
+ * 1. Information Collection - Service detection and manifest parsing
22
+ * 2. Consolidation - Credential gathering and configuration validation
23
+ * 3. Execution - Deployment simulation with detailed logging
24
+ */
25
+
26
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
27
+ import { resolve, join, dirname } from 'path';
28
+ import { fileURLToPath } from 'url';
29
+ import chalk from 'chalk';
30
+
31
+ const __filename = fileURLToPath(import.meta.url);
32
+ const __dirname = dirname(__filename);
33
+
34
+ // Mock credentials for testing
35
+ const MOCK_CREDENTIALS = {
36
+ token: 'mock-api-token-for-testing-purposes-only',
37
+ accountId: 'mock-account-id-123456789',
38
+ zoneId: 'mock-zone-id-987654321'
39
+ };
40
+
41
+ // Mock service manifest template
42
+ const MOCK_MANIFEST = {
43
+ serviceName: 'test-clodo-service',
44
+ serviceType: 'data-service',
45
+ version: '1.0.0',
46
+ configuration: {
47
+ domain: 'test-service.example.com',
48
+ domainName: 'test-service.example.com',
49
+ environment: 'staging',
50
+ cloudflare: {
51
+ accountId: MOCK_CREDENTIALS.accountId,
52
+ zoneId: MOCK_CREDENTIALS.zoneId
53
+ }
54
+ },
55
+ metadata: {
56
+ created: new Date().toISOString(),
57
+ framework: 'clodo-framework',
58
+ version: '3.1.5'
59
+ }
60
+ };
61
+
62
+ class ClodoDeploymentTester {
63
+ constructor(options = {}) {
64
+ this.options = {
65
+ servicePath: options.servicePath || process.cwd(),
66
+ dryRun: options.dryRun !== false, // Default to true for safety
67
+ verbose: options.verbose || false,
68
+ mockCredentials: options.mockCredentials !== false, // Default to true
69
+ testPhase: options.testPhase || 'all',
70
+ ...options
71
+ };
72
+
73
+ this.testResults = {
74
+ phases: {
75
+ collection: { status: 'pending', duration: 0, details: {} },
76
+ consolidation: { status: 'pending', duration: 0, details: {} },
77
+ execution: { status: 'pending', duration: 0, details: {} }
78
+ },
79
+ overall: { status: 'running', startTime: Date.now() }
80
+ };
81
+
82
+ this.serviceInfo = {};
83
+ this.credentials = {};
84
+ this.deploymentPlan = {};
85
+ }
86
+
87
+ log(message, level = 'info') {
88
+ const timestamp = new Date().toISOString().substr(11, 8);
89
+ const prefix = `[${timestamp}]`;
90
+
91
+ switch (level) {
92
+ case 'error':
93
+ console.error(chalk.red(`${prefix} āŒ ${message}`));
94
+ break;
95
+ case 'warning':
96
+ console.warn(chalk.yellow(`${prefix} āš ļø ${message}`));
97
+ break;
98
+ case 'success':
99
+ console.log(chalk.green(`${prefix} āœ… ${message}`));
100
+ break;
101
+ case 'phase':
102
+ console.log(chalk.cyan(`${prefix} šŸš€ ${message}`));
103
+ break;
104
+ case 'step':
105
+ console.log(chalk.blue(`${prefix} šŸ“‹ ${message}`));
106
+ break;
107
+ default:
108
+ if (this.options.verbose) {
109
+ console.log(chalk.gray(`${prefix} ā„¹ļø ${message}`));
110
+ }
111
+ }
112
+ }
113
+
114
+ async run() {
115
+ this.log('Starting Clodo Service Deployment Testing', 'phase');
116
+ this.log(`Test Phase: ${this.options.testPhase}`, 'step');
117
+ this.log(`Service Path: ${this.options.servicePath}`, 'step');
118
+ this.log(`Dry Run: ${this.options.dryRun}`, 'step');
119
+ this.log('');
120
+
121
+ try {
122
+ // Phase 1: Information Collection
123
+ if (this.shouldRunPhase('collection')) {
124
+ await this.runInformationCollection();
125
+ }
126
+
127
+ // Phase 2: Consolidation
128
+ if (this.shouldRunPhase('consolidation')) {
129
+ await this.runConsolidation();
130
+ }
131
+
132
+ // Phase 3: Execution
133
+ if (this.shouldRunPhase('execution')) {
134
+ await this.runExecution();
135
+ }
136
+
137
+ // Final Results
138
+ this.displayFinalResults();
139
+
140
+ } catch (error) {
141
+ this.log(`Test failed: ${error.message}`, 'error');
142
+ if (this.options.verbose) {
143
+ console.error(chalk.gray(error.stack));
144
+ }
145
+ this.testResults.overall.status = 'failed';
146
+ process.exit(1);
147
+ }
148
+ }
149
+
150
+ shouldRunPhase(phase) {
151
+ return this.options.testPhase === 'all' || this.options.testPhase === phase;
152
+ }
153
+
154
+ async runInformationCollection() {
155
+ const phaseStart = Date.now();
156
+ this.log('Phase 1: Information Collection', 'phase');
157
+ this.testResults.phases.collection.status = 'running';
158
+
159
+ try {
160
+ // Step 1: Service Detection
161
+ this.log('Step 1: Detecting service project...', 'step');
162
+ const manifestPath = join(this.options.servicePath, 'clodo-service-manifest.json');
163
+
164
+ let manifest;
165
+ if (existsSync(manifestPath)) {
166
+ this.log('Found existing service manifest', 'success');
167
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
168
+ } else {
169
+ this.log('No manifest found, creating mock service for testing', 'warning');
170
+ // Create mock manifest for testing
171
+ writeFileSync(manifestPath, JSON.stringify(MOCK_MANIFEST, null, 2));
172
+ manifest = MOCK_MANIFEST;
173
+ this.log('Created mock service manifest', 'success');
174
+ }
175
+
176
+ // Step 2: Parse Service Information
177
+ this.log('Step 2: Parsing service information...', 'step');
178
+ this.serviceInfo = {
179
+ name: manifest.serviceName,
180
+ type: manifest.serviceType,
181
+ version: manifest.version,
182
+ domain: manifest.configuration?.domain || manifest.configuration?.domainName,
183
+ environment: manifest.configuration?.environment,
184
+ path: this.options.servicePath
185
+ };
186
+
187
+ // Validate required information
188
+ if (!this.serviceInfo.name) {
189
+ throw new Error('Service name not found in manifest');
190
+ }
191
+ if (!this.serviceInfo.domain) {
192
+ throw new Error('Domain not configured in manifest');
193
+ }
194
+
195
+ this.log(`Service Name: ${this.serviceInfo.name}`, 'step');
196
+ this.log(`Service Type: ${this.serviceInfo.type}`, 'step');
197
+ this.log(`Domain: ${this.serviceInfo.domain}`, 'step');
198
+ this.log(`Environment: ${this.serviceInfo.environment}`, 'step');
199
+
200
+ // Step 3: Validate Project Structure
201
+ this.log('Step 3: Validating project structure...', 'step');
202
+ const requiredFiles = ['package.json', 'wrangler.toml'];
203
+ const missingFiles = requiredFiles.filter(file => !existsSync(join(this.options.servicePath, file)));
204
+
205
+ if (missingFiles.length > 0) {
206
+ this.log(`Missing files: ${missingFiles.join(', ')}`, 'warning');
207
+ this.log('This may cause deployment issues in real scenarios', 'warning');
208
+ } else {
209
+ this.log('Project structure validation passed', 'success');
210
+ }
211
+
212
+ this.testResults.phases.collection.status = 'completed';
213
+ this.testResults.phases.collection.duration = Date.now() - phaseStart;
214
+ this.testResults.phases.collection.details = {
215
+ serviceInfo: this.serviceInfo,
216
+ manifestFound: existsSync(manifestPath),
217
+ missingFiles: missingFiles
218
+ };
219
+
220
+ this.log(`Information collection completed in ${this.testResults.phases.collection.duration}ms`, 'success');
221
+ this.log('');
222
+
223
+ } catch (error) {
224
+ this.testResults.phases.collection.status = 'failed';
225
+ this.testResults.phases.collection.details.error = error.message;
226
+ throw error;
227
+ }
228
+ }
229
+
230
+ async runConsolidation() {
231
+ const phaseStart = Date.now();
232
+ this.log('Phase 2: Information Consolidation', 'phase');
233
+ this.testResults.phases.consolidation.status = 'running';
234
+
235
+ try {
236
+ // Step 1: Credential Gathering Strategy
237
+ this.log('Step 1: Analyzing credential gathering strategy...', 'step');
238
+
239
+ const credentialSources = {
240
+ flags: { token: false, accountId: false, zoneId: false },
241
+ environment: { token: false, accountId: false, zoneId: false },
242
+ mock: { token: false, accountId: false, zoneId: false }
243
+ };
244
+
245
+ // Check environment variables
246
+ credentialSources.environment.token = !!process.env.CLOUDFLARE_API_TOKEN;
247
+ credentialSources.environment.accountId = !!process.env.CLOUDFLARE_ACCOUNT_ID;
248
+ credentialSources.environment.zoneId = !!process.env.CLOUDFLARE_ZONE_ID;
249
+
250
+ // Use mock credentials if enabled
251
+ if (this.options.mockCredentials) {
252
+ this.credentials = { ...MOCK_CREDENTIALS };
253
+ credentialSources.mock = { token: true, accountId: true, zoneId: true };
254
+ this.log('Using mock credentials for testing', 'step');
255
+ } else {
256
+ // In real scenarios, would check command line flags here
257
+ this.log('Mock credentials disabled - would require real credentials', 'warning');
258
+ }
259
+
260
+ this.log('Credential Sources:', 'step');
261
+ this.log(` Environment Variables: ${credentialSources.environment.token && credentialSources.environment.accountId && credentialSources.environment.zoneId ? 'āœ…' : 'āŒ'}`, 'step');
262
+ this.log(` Mock Credentials: ${credentialSources.mock.token ? 'āœ…' : 'āŒ'}`, 'step');
263
+
264
+ // Step 2: Configuration Consolidation
265
+ this.log('Step 2: Consolidating deployment configuration...', 'step');
266
+
267
+ this.deploymentPlan = {
268
+ service: this.serviceInfo,
269
+ credentials: {
270
+ token: this.credentials.token ? `${this.credentials.token.substring(0, 8)}...` : 'NOT SET',
271
+ accountId: this.credentials.accountId ? `${this.credentials.accountId.substring(0, 8)}...` : 'NOT SET',
272
+ zoneId: this.credentials.zoneId ? `${this.credentials.zoneId.substring(0, 8)}...` : 'NOT SET'
273
+ },
274
+ deployment: {
275
+ domain: this.serviceInfo.domain,
276
+ environment: this.serviceInfo.environment,
277
+ dryRun: this.options.dryRun,
278
+ type: 'simulated'
279
+ },
280
+ metadata: {
281
+ deploymentId: `test-${Date.now()}`,
282
+ timestamp: new Date().toISOString(),
283
+ tester: 'clodo-deployment-tester'
284
+ }
285
+ };
286
+
287
+ // Step 3: Validation Checks
288
+ this.log('Step 3: Running validation checks...', 'step');
289
+
290
+ const validations = {
291
+ serviceInfo: !!this.serviceInfo.name && !!this.serviceInfo.domain,
292
+ credentials: !!(this.credentials.token && this.credentials.accountId && this.credentials.zoneId),
293
+ configuration: !!this.deploymentPlan.deployment.domain,
294
+ environment: true // Mock validation
295
+ };
296
+
297
+ const failedValidations = Object.entries(validations)
298
+ .filter(([key, passed]) => !passed)
299
+ .map(([key]) => key);
300
+
301
+ if (failedValidations.length > 0) {
302
+ throw new Error(`Validation failed for: ${failedValidations.join(', ')}`);
303
+ }
304
+
305
+ this.log('All validations passed', 'success');
306
+
307
+ // Display consolidated information
308
+ this.log('Consolidated Deployment Plan:', 'step');
309
+ this.log(` Service: ${this.deploymentPlan.service.name} (${this.deploymentPlan.service.type})`, 'step');
310
+ this.log(` Domain: ${this.deploymentPlan.deployment.domain}`, 'step');
311
+ this.log(` Environment: ${this.deploymentPlan.deployment.environment}`, 'step');
312
+ this.log(` Dry Run: ${this.deploymentPlan.deployment.dryRun}`, 'step');
313
+ this.log(` Credentials: ${this.deploymentPlan.credentials.token !== 'NOT SET' ? 'āœ… Configured' : 'āŒ Missing'}`, 'step');
314
+
315
+ this.testResults.phases.consolidation.status = 'completed';
316
+ this.testResults.phases.consolidation.duration = Date.now() - phaseStart;
317
+ this.testResults.phases.consolidation.details = {
318
+ credentialSources,
319
+ deploymentPlan: this.deploymentPlan,
320
+ validations
321
+ };
322
+
323
+ this.log(`Information consolidation completed in ${this.testResults.phases.consolidation.duration}ms`, 'success');
324
+ this.log('');
325
+
326
+ } catch (error) {
327
+ this.testResults.phases.consolidation.status = 'failed';
328
+ this.testResults.phases.consolidation.details.error = error.message;
329
+ throw error;
330
+ }
331
+ }
332
+
333
+ async runExecution() {
334
+ const phaseStart = Date.now();
335
+ this.log('Phase 3: Deployment Execution Simulation', 'phase');
336
+ this.testResults.phases.execution.status = 'running';
337
+
338
+ try {
339
+ // Step 1: Pre-deployment Checks
340
+ this.log('Step 1: Running pre-deployment checks...', 'step');
341
+
342
+ const preChecks = {
343
+ dryRunMode: this.options.dryRun,
344
+ credentialsValid: !!(this.credentials.token && this.credentials.accountId && this.credentials.zoneId),
345
+ serviceReady: !!this.serviceInfo.name,
346
+ domainConfigured: !!this.serviceInfo.domain
347
+ };
348
+
349
+ this.log('Pre-deployment Status:', 'step');
350
+ Object.entries(preChecks).forEach(([check, status]) => {
351
+ this.log(` ${check}: ${status ? 'āœ…' : 'āŒ'}`, 'step');
352
+ });
353
+
354
+ // Step 2: Simulate Deployment Phases
355
+ this.log('Step 2: Simulating deployment phases...', 'step');
356
+
357
+ const deploymentPhases = [
358
+ { name: 'Initialization', duration: 500, status: 'success' },
359
+ { name: 'Configuration Validation', duration: 300, status: 'success' },
360
+ { name: 'Environment Setup', duration: 800, status: 'success' },
361
+ { name: 'Cloudflare API Calls', duration: 1200, status: 'success' },
362
+ { name: 'Resource Deployment', duration: 1500, status: 'success' },
363
+ { name: 'DNS Configuration', duration: 600, status: 'success' },
364
+ { name: 'Health Checks', duration: 400, status: 'success' },
365
+ { name: 'Final Validation', duration: 300, status: 'success' }
366
+ ];
367
+
368
+ for (const phase of deploymentPhases) {
369
+ this.log(` Executing: ${phase.name}...`, 'step');
370
+ await this.delay(phase.duration);
371
+
372
+ if (phase.status === 'success') {
373
+ this.log(` āœ… ${phase.name} completed`, 'success');
374
+ } else {
375
+ this.log(` āŒ ${phase.name} failed`, 'error');
376
+ }
377
+ }
378
+
379
+ // Step 3: Generate Mock Results
380
+ this.log('Step 3: Generating deployment results...', 'step');
381
+
382
+ const mockResults = {
383
+ success: true,
384
+ deploymentId: this.deploymentPlan.metadata.deploymentId,
385
+ url: `https://${this.serviceInfo.domain}`,
386
+ workerId: `worker-${Math.random().toString(36).substr(2, 9)}`,
387
+ status: 'Deployed successfully',
388
+ timestamp: new Date().toISOString(),
389
+ details: {
390
+ service: this.serviceInfo.name,
391
+ type: this.serviceInfo.type,
392
+ domain: this.serviceInfo.domain,
393
+ environment: this.serviceInfo.environment,
394
+ dryRun: this.options.dryRun
395
+ }
396
+ };
397
+
398
+ // Step 4: Post-deployment Validation
399
+ this.log('Step 4: Running post-deployment validation...', 'step');
400
+
401
+ const postChecks = {
402
+ urlAccessible: true, // Mock
403
+ workerRunning: true, // Mock
404
+ dnsConfigured: true, // Mock
405
+ healthChecks: true // Mock
406
+ };
407
+
408
+ this.log('Post-deployment Status:', 'step');
409
+ Object.entries(postChecks).forEach(([check, status]) => {
410
+ this.log(` ${check}: ${status ? 'āœ…' : 'āŒ'}`, 'step');
411
+ });
412
+
413
+ this.testResults.phases.execution.status = 'completed';
414
+ this.testResults.phases.execution.duration = Date.now() - phaseStart;
415
+ this.testResults.phases.execution.details = {
416
+ phases: deploymentPhases,
417
+ results: mockResults,
418
+ postChecks
419
+ };
420
+
421
+ this.log(`Deployment execution simulation completed in ${this.testResults.phases.execution.duration}ms`, 'success');
422
+ this.log('');
423
+
424
+ } catch (error) {
425
+ this.testResults.phases.execution.status = 'failed';
426
+ this.testResults.phases.execution.details.error = error.message;
427
+ throw error;
428
+ }
429
+ }
430
+
431
+ displayFinalResults() {
432
+ this.log('šŸŽ‰ Clodo Service Deployment Testing Complete', 'phase');
433
+ this.log('');
434
+
435
+ // Overall Summary
436
+ const totalDuration = Date.now() - this.testResults.overall.startTime;
437
+ this.testResults.overall.status = 'completed';
438
+
439
+ this.log('šŸ“Š Test Summary:', 'step');
440
+ this.log(` Total Duration: ${totalDuration}ms`, 'step');
441
+ this.log(` Phases Tested: ${this.options.testPhase}`, 'step');
442
+ this.log(` Dry Run: ${this.options.dryRun}`, 'step');
443
+ this.log('');
444
+
445
+ // Phase Results
446
+ this.log('šŸ“‹ Phase Results:', 'step');
447
+ Object.entries(this.testResults.phases).forEach(([phase, result]) => {
448
+ if (result.status !== 'pending') {
449
+ const statusIcon = result.status === 'completed' ? 'āœ…' : 'āŒ';
450
+ const duration = result.duration > 0 ? ` (${result.duration}ms)` : '';
451
+ this.log(` ${phase}: ${statusIcon} ${result.status}${duration}`, 'step');
452
+ }
453
+ });
454
+ this.log('');
455
+
456
+ // Service Information
457
+ if (Object.keys(this.serviceInfo).length > 0) {
458
+ this.log('šŸ—ļø Service Information:', 'step');
459
+ this.log(` Name: ${this.serviceInfo.name}`, 'step');
460
+ this.log(` Type: ${this.serviceInfo.type}`, 'step');
461
+ this.log(` Domain: ${this.serviceInfo.domain}`, 'step');
462
+ this.log(` Environment: ${this.serviceInfo.environment}`, 'step');
463
+ this.log('');
464
+ }
465
+
466
+ // Deployment Plan
467
+ if (Object.keys(this.deploymentPlan).length > 0) {
468
+ this.log('šŸš€ Deployment Plan:', 'step');
469
+ this.log(` Service: ${this.deploymentPlan.service?.name} (${this.deploymentPlan.service?.type})`, 'step');
470
+ this.log(` Domain: ${this.deploymentPlan.deployment?.domain}`, 'step');
471
+ this.log(` Environment: ${this.deploymentPlan.deployment?.environment}`, 'step');
472
+ this.log(` Dry Run: ${this.deploymentPlan.deployment?.dryRun}`, 'step');
473
+ this.log(` Credentials: ${this.deploymentPlan.credentials?.token !== 'NOT SET' ? 'Configured' : 'Missing'}`, 'step');
474
+ this.log('');
475
+ }
476
+
477
+ // Recommendations
478
+ this.log('šŸ’” Recommendations:', 'step');
479
+ if (this.options.dryRun) {
480
+ this.log(' • Test completed in dry-run mode - safe for development', 'step');
481
+ }
482
+ if (this.options.mockCredentials) {
483
+ this.log(' • Mock credentials used - test real deployment with actual credentials', 'step');
484
+ }
485
+ this.log(' • Review test output for any warnings or validation issues', 'step');
486
+ this.log(' • Use --verbose flag for detailed logging in future tests', 'step');
487
+ }
488
+
489
+ delay(ms) {
490
+ return new Promise(resolve => setTimeout(resolve, ms));
491
+ }
492
+ }
493
+
494
+ // CLI Interface
495
+ function parseArgs() {
496
+ const args = process.argv.slice(2);
497
+ const options = {};
498
+
499
+ for (let i = 0; i < args.length; i++) {
500
+ const arg = args[i];
501
+ switch (arg) {
502
+ case '--service-path':
503
+ options.servicePath = args[++i];
504
+ break;
505
+ case '--dry-run':
506
+ options.dryRun = true;
507
+ break;
508
+ case '--no-dry-run':
509
+ options.dryRun = false;
510
+ break;
511
+ case '--verbose':
512
+ options.verbose = true;
513
+ break;
514
+ case '--mock-credentials':
515
+ options.mockCredentials = true;
516
+ break;
517
+ case '--no-mock-credentials':
518
+ options.mockCredentials = false;
519
+ break;
520
+ case '--test-phase':
521
+ options.testPhase = args[++i];
522
+ break;
523
+ case '--help':
524
+ showHelp();
525
+ process.exit(0);
526
+ break;
527
+ default:
528
+ if (arg.startsWith('--')) {
529
+ console.error(`Unknown option: ${arg}`);
530
+ showHelp();
531
+ process.exit(1);
532
+ }
533
+ }
534
+ }
535
+
536
+ return options;
537
+ }
538
+
539
+ function showHelp() {
540
+ console.log(`
541
+ Clodo Service Deployment Testing Script
542
+
543
+ Usage:
544
+ node test-clodo-deployment.js [options]
545
+
546
+ Options:
547
+ --service-path <path> Path to service directory (default: current dir)
548
+ --dry-run Simulate deployment without changes (default: true)
549
+ --no-dry-run Actually perform deployment (use with caution)
550
+ --verbose Detailed logging output
551
+ --mock-credentials Use mock credentials instead of prompting (default: true)
552
+ --no-mock-credentials Require real credentials
553
+ --test-phase <phase> Test specific phase: all, collection, consolidation, execution
554
+ --help Show this help message
555
+
556
+ Examples:
557
+ # Test all phases with mock data
558
+ node test-clodo-deployment.js
559
+
560
+ # Test only information collection
561
+ node test-clodo-deployment.js --test-phase collection --verbose
562
+
563
+ # Test with real credentials (dangerous!)
564
+ node test-clodo-deployment.js --no-mock-credentials --no-dry-run
565
+ `);
566
+ }
567
+
568
+ // Main execution
569
+ async function main() {
570
+ try {
571
+ const options = parseArgs();
572
+ const tester = new ClodoDeploymentTester(options);
573
+ await tester.run();
574
+ } catch (error) {
575
+ console.error(chalk.red(`\nāŒ Test script failed: ${error.message}`));
576
+ if (process.env.DEBUG) {
577
+ console.error(chalk.gray(error.stack));
578
+ }
579
+ process.exit(1);
580
+ }
581
+ }
582
+
583
+ // Run if called directly
584
+ if (import.meta.url === `file://${process.argv[1]}`) {
585
+ main();
586
+ }
587
+
588
+ export { ClodoDeploymentTester };