@friggframework/devtools 2.0.0--canary.545.e256e95.0 → 2.0.0--canary.553.dc5f898.0

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 (129) hide show
  1. package/frigg-cli/README.md +1 -1
  2. package/frigg-cli/__tests__/unit/commands/build.test.js +1 -1
  3. package/frigg-cli/__tests__/unit/commands/doctor.test.js +2 -0
  4. package/frigg-cli/__tests__/unit/commands/install.test.js +19 -23
  5. package/frigg-cli/__tests__/unit/dependencies.test.js +2 -2
  6. package/frigg-cli/build-command/index.js +11 -123
  7. package/frigg-cli/deploy-command/index.js +1 -83
  8. package/frigg-cli/doctor-command/index.js +16 -37
  9. package/frigg-cli/generate-iam-command.js +1 -21
  10. package/frigg-cli/index.js +6 -21
  11. package/frigg-cli/index.test.js +2 -7
  12. package/frigg-cli/init-command/backend-first-handler.js +42 -124
  13. package/frigg-cli/init-command/index.js +1 -2
  14. package/frigg-cli/init-command/template-handler.js +3 -13
  15. package/frigg-cli/install-command/backend-js.js +3 -3
  16. package/frigg-cli/install-command/environment-variables.js +19 -16
  17. package/frigg-cli/install-command/environment-variables.test.js +13 -12
  18. package/frigg-cli/install-command/index.js +9 -14
  19. package/frigg-cli/install-command/integration-file.js +3 -3
  20. package/frigg-cli/install-command/logger.js +12 -0
  21. package/frigg-cli/install-command/validate-package.js +9 -5
  22. package/frigg-cli/jest.config.js +1 -4
  23. package/frigg-cli/repair-command/index.js +128 -121
  24. package/frigg-cli/start-command/index.js +2 -324
  25. package/frigg-cli/ui-command/index.js +36 -58
  26. package/frigg-cli/utils/repo-detection.js +37 -85
  27. package/infrastructure/create-frigg-infrastructure.js +0 -93
  28. package/infrastructure/docs/iam-policy-templates.md +1 -1
  29. package/infrastructure/domains/integration/integration-builder.js +3 -2
  30. package/infrastructure/domains/integration/integration-builder.test.js +54 -2
  31. package/infrastructure/domains/networking/vpc-builder.test.js +4 -2
  32. package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
  33. package/infrastructure/domains/shared/resource-discovery.js +5 -5
  34. package/infrastructure/domains/shared/types/app-definition.js +0 -35
  35. package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
  36. package/infrastructure/domains/shared/utilities/base-definition-factory.js +1 -10
  37. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
  38. package/infrastructure/infrastructure-composer.js +0 -2
  39. package/infrastructure/infrastructure-composer.test.js +6 -5
  40. package/management-ui/README.md +109 -245
  41. package/package.json +7 -8
  42. package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +0 -326
  43. package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +0 -337
  44. package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +0 -373
  45. package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +0 -313
  46. package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +0 -269
  47. package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +0 -82
  48. package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +0 -408
  49. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +0 -583
  50. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +0 -314
  51. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +0 -383
  52. package/frigg-cli/__tests__/unit/commands/init.test.js +0 -406
  53. package/frigg-cli/__tests__/unit/commands/provider-dispatch.test.js +0 -383
  54. package/frigg-cli/__tests__/unit/commands/repair.test.js +0 -275
  55. package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +0 -411
  56. package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +0 -405
  57. package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +0 -496
  58. package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +0 -474
  59. package/frigg-cli/__tests__/unit/utils/output.test.js +0 -196
  60. package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +0 -93
  61. package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +0 -93
  62. package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +0 -103
  63. package/frigg-cli/container.js +0 -172
  64. package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +0 -286
  65. package/frigg-cli/domain/entities/ApiModule.js +0 -272
  66. package/frigg-cli/domain/entities/AppDefinition.js +0 -227
  67. package/frigg-cli/domain/entities/Integration.js +0 -198
  68. package/frigg-cli/domain/exceptions/DomainException.js +0 -24
  69. package/frigg-cli/domain/ports/IApiModuleRepository.js +0 -53
  70. package/frigg-cli/domain/ports/IAppDefinitionRepository.js +0 -43
  71. package/frigg-cli/domain/ports/IIntegrationRepository.js +0 -61
  72. package/frigg-cli/domain/services/IntegrationValidator.js +0 -185
  73. package/frigg-cli/domain/value-objects/IntegrationId.js +0 -42
  74. package/frigg-cli/domain/value-objects/IntegrationName.js +0 -60
  75. package/frigg-cli/domain/value-objects/SemanticVersion.js +0 -70
  76. package/frigg-cli/infrastructure/UnitOfWork.js +0 -46
  77. package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +0 -197
  78. package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +0 -224
  79. package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +0 -249
  80. package/frigg-cli/infrastructure/adapters/SchemaValidator.js +0 -92
  81. package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +0 -373
  82. package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +0 -116
  83. package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +0 -277
  84. package/frigg-cli/package-lock.json +0 -16226
  85. package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +0 -376
  86. package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +0 -591
  87. package/frigg-cli/start-command/infrastructure/DockerAdapter.js +0 -306
  88. package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +0 -329
  89. package/frigg-cli/templates/backend/.env.example +0 -62
  90. package/frigg-cli/templates/backend/.eslintrc.json +0 -12
  91. package/frigg-cli/templates/backend/.prettierrc +0 -6
  92. package/frigg-cli/templates/backend/docker-compose.yml +0 -22
  93. package/frigg-cli/templates/backend/index.js +0 -96
  94. package/frigg-cli/templates/backend/infrastructure.js +0 -12
  95. package/frigg-cli/templates/backend/jest.config.js +0 -17
  96. package/frigg-cli/templates/backend/package.json +0 -50
  97. package/frigg-cli/templates/backend/src/api-modules/.gitkeep +0 -10
  98. package/frigg-cli/templates/backend/src/base/.gitkeep +0 -7
  99. package/frigg-cli/templates/backend/src/integrations/.gitkeep +0 -10
  100. package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +0 -65
  101. package/frigg-cli/templates/backend/src/utils/.gitkeep +0 -7
  102. package/frigg-cli/templates/backend/test/setup.js +0 -30
  103. package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
  104. package/frigg-cli/templates/backend/ui-extensions/README.md +0 -77
  105. package/frigg-cli/utils/__tests__/provider-helper.test.js +0 -55
  106. package/frigg-cli/utils/__tests__/repo-detection.test.js +0 -436
  107. package/frigg-cli/utils/output.js +0 -382
  108. package/frigg-cli/utils/provider-helper.js +0 -75
  109. package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +0 -205
  110. package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +0 -104
  111. package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +0 -153
  112. package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +0 -162
  113. package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +0 -152
  114. package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +0 -332
  115. package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +0 -191
  116. package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +0 -146
  117. package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +0 -155
  118. package/frigg-cli/validate-command/adapters/cli/validate-command.js +0 -199
  119. package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +0 -35
  120. package/frigg-cli/validate-command/domain/entities/validation-result.js +0 -74
  121. package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +0 -74
  122. package/frigg-cli/validate-command/domain/value-objects/validation-error.js +0 -68
  123. package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +0 -181
  124. package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +0 -145
  125. package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +0 -113
  126. package/infrastructure/domains/admin-scripts/admin-script-builder.js +0 -200
  127. package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +0 -499
  128. package/infrastructure/domains/admin-scripts/index.js +0 -5
  129. package/infrastructure/jest.config.js +0 -16
@@ -12,7 +12,7 @@
12
12
  */
13
13
 
14
14
  const path = require('path');
15
- const output = require('../utils/output');
15
+ const readline = require('readline');
16
16
 
17
17
  // Domain and Application Layer
18
18
  const StackIdentifier = require('../../infrastructure/domains/health/domain/value-objects/stack-identifier');
@@ -34,6 +34,33 @@ const { TemplateParser } = require('../../infrastructure/domains/health/domain/s
34
34
  const { ImportTemplateGenerator } = require('../../infrastructure/domains/health/domain/services/import-template-generator');
35
35
  const { ImportProgressMonitor } = require('../../infrastructure/domains/health/domain/services/import-progress-monitor');
36
36
 
37
+ /**
38
+ * Create readline interface for user prompts
39
+ * @returns {readline.Interface}
40
+ */
41
+ function createReadlineInterface() {
42
+ return readline.createInterface({
43
+ input: process.stdin,
44
+ output: process.stdout,
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Prompt user for confirmation
50
+ * @param {string} question - Question to ask
51
+ * @returns {Promise<boolean>} User confirmed
52
+ */
53
+ function confirm(question) {
54
+ const rl = createReadlineInterface();
55
+
56
+ return new Promise((resolve) => {
57
+ rl.question(`${question} (y/N): `, (answer) => {
58
+ rl.close();
59
+ resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
60
+ });
61
+ });
62
+ }
63
+
37
64
  /**
38
65
  * Handle import repair operation using template comparison
39
66
  * @param {StackIdentifier} stackIdentifier - Stack identifier
@@ -44,13 +71,13 @@ async function handleImportRepair(stackIdentifier, report, options) {
44
71
  const orphanedResources = report.getOrphanedResources();
45
72
 
46
73
  if (orphanedResources.length === 0) {
47
- output.success(' No orphaned resources to import');
74
+ console.log('\nāœ“ No orphaned resources to import');
48
75
  return { imported: 0, failed: 0 };
49
76
  }
50
77
 
51
- output.info(`šŸ“¦ Found ${orphanedResources.length} orphaned resource(s) to import:`);
78
+ console.log(`\nšŸ“¦ Found ${orphanedResources.length} orphaned resource(s) to import:`);
52
79
  orphanedResources.forEach((resource, idx) => {
53
- output.log(` ${idx + 1}. ${resource.resourceType} - ${resource.physicalId}`);
80
+ console.log(` ${idx + 1}. ${resource.resourceType} - ${resource.physicalId}`);
54
81
  });
55
82
 
56
83
  // Check for build template
@@ -58,12 +85,12 @@ async function handleImportRepair(stackIdentifier, report, options) {
58
85
  const buildTemplateExists = TemplateParser.buildTemplateExists();
59
86
 
60
87
  if (!buildTemplateExists) {
61
- output.warn('ļø Build template not found. Generating sequential logical IDs (not recommended).');
62
- output.log(` Run one of the following to generate build template:`);
63
- output.log(` • serverless package`);
64
- output.log(` • frigg build`);
65
- output.log(` • frigg deploy --stage dev`);
66
- output.log(` Then run 'frigg repair --import ${stackIdentifier.stackName}' again for correct logical IDs.\n`);
88
+ console.log('\nāš ļø Build template not found. Generating sequential logical IDs (not recommended).');
89
+ console.log(` Run one of the following to generate build template:`);
90
+ console.log(` • serverless package`);
91
+ console.log(` • frigg build`);
92
+ console.log(` • frigg deploy --stage dev`);
93
+ console.log(` Then run 'frigg repair --import ${stackIdentifier.stackName}' again for correct logical IDs.\n`);
67
94
 
68
95
  // Fallback to sequential IDs (old behavior)
69
96
  const resourcesToImport = orphanedResources.map((resource, idx) => ({
@@ -73,9 +100,9 @@ async function handleImportRepair(stackIdentifier, report, options) {
73
100
  }));
74
101
 
75
102
  if (!options.yes) {
76
- const confirmed = await output.confirm(`\nImport ${orphanedResources.length} orphaned resource(s) with sequential IDs?`);
103
+ const confirmed = await confirm(`\nImport ${orphanedResources.length} orphaned resource(s) with sequential IDs?`);
77
104
  if (!confirmed) {
78
- output.log('Import cancelled');
105
+ console.log('Import cancelled by user');
79
106
  return { imported: 0, failed: 0, cancelled: true };
80
107
  }
81
108
  }
@@ -84,20 +111,20 @@ async function handleImportRepair(stackIdentifier, report, options) {
84
111
  const resourceImporter = new AWSResourceImporter({ region: stackIdentifier.region });
85
112
  const repairUseCase = new RepairViaImportUseCase({ resourceDetector, resourceImporter });
86
113
 
87
- output.info('šŸ”§ Importing resources with sequential IDs...');
114
+ console.log('\nšŸ”§ Importing resources with sequential IDs...');
88
115
  const importResult = await repairUseCase.importMultipleResources({
89
116
  stackIdentifier,
90
117
  resources: resourcesToImport,
91
118
  });
92
119
 
93
120
  if (importResult.success) {
94
- output.success(` Successfully imported ${importResult.importedCount} resource(s)`);
121
+ console.log(`\nāœ“ Successfully imported ${importResult.importedCount} resource(s)`);
95
122
  } else {
96
- output.log(`\nāœ— Import failed: ${importResult.message}`);
123
+ console.log(`\nāœ— Import failed: ${importResult.message}`);
97
124
  if (importResult.validationErrors && importResult.validationErrors.length > 0) {
98
- output.log('\nValidation errors:');
125
+ console.log('\nValidation errors:');
99
126
  importResult.validationErrors.forEach((error) => {
100
- output.log(` • ${error.logicalId}: ${error.reason}`);
127
+ console.log(` • ${error.logicalId}: ${error.reason}`);
101
128
  });
102
129
  }
103
130
  }
@@ -110,9 +137,9 @@ async function handleImportRepair(stackIdentifier, report, options) {
110
137
  }
111
138
 
112
139
  // Use template comparison to find correct logical IDs
113
- output.info(`šŸ” Analyzing templates to map orphaned resources to correct logical IDs...`);
114
- output.log(` Build template: ${buildTemplatePath}`);
115
- output.log(` Deployed template: CloudFormation (via AWS API)`);
140
+ console.log(`\nšŸ” Analyzing templates to map orphaned resources to correct logical IDs...`);
141
+ console.log(` Build template: ${buildTemplatePath}`);
142
+ console.log(` Deployed template: CloudFormation (via AWS API)`);
116
143
 
117
144
  // Wire up use case with template comparison
118
145
  const stackRepository = new AWSStackRepository({ region: stackIdentifier.region });
@@ -132,31 +159,31 @@ async function handleImportRepair(stackIdentifier, report, options) {
132
159
  });
133
160
 
134
161
  if (!mappingResult.success) {
135
- output.log(`\nāœ— Mapping failed: ${mappingResult.message}`);
162
+ console.log(`\nāœ— Mapping failed: ${mappingResult.message}`);
136
163
  return { imported: 0, failed: 0, success: false };
137
164
  }
138
165
 
139
166
  // Display mapping results
140
- output.success(` Successfully mapped ${mappingResult.mappedCount} resource(s) to logical IDs:`);
167
+ console.log(`\nāœ… Successfully mapped ${mappingResult.mappedCount} resource(s) to logical IDs:`);
141
168
  mappingResult.mappings.forEach((mapping) => {
142
- output.log(` • ${mapping.logicalId} ← ${mapping.physicalId} (${mapping.matchMethod}, ${mapping.confidence} confidence)`);
169
+ console.log(` • ${mapping.logicalId} ← ${mapping.physicalId} (${mapping.matchMethod}, ${mapping.confidence} confidence)`);
143
170
  });
144
171
 
145
172
  if (mappingResult.unmappedCount > 0) {
146
- output.warn(`ļø Could not map ${mappingResult.unmappedCount} resource(s):`);
173
+ console.log(`\nāš ļø Could not map ${mappingResult.unmappedCount} resource(s):`);
147
174
  mappingResult.unmappedResources.forEach((resource) => {
148
- output.log(` • ${resource.resourceType} - ${resource.physicalId}`);
175
+ console.log(` • ${resource.resourceType} - ${resource.physicalId}`);
149
176
  });
150
177
  }
151
178
 
152
179
  // Display warnings for multiple resources of same type
153
180
  if (mappingResult.warnings && mappingResult.warnings.length > 0) {
154
- output.warn(`ļø Warnings:`);
181
+ console.log(`\nāš ļø Warnings:`);
155
182
  mappingResult.warnings.forEach((warning) => {
156
- output.log(` • ${warning.message}`);
183
+ console.log(` • ${warning.message}`);
157
184
  if (warning.type === 'MULTIPLE_RESOURCES') {
158
185
  warning.resources.forEach((res) => {
159
- output.log(` - ${res.logicalId} ← ${res.physicalId} (${res.matchMethod}, ${res.confidence})`);
186
+ console.log(` - ${res.logicalId} ← ${res.physicalId} (${res.matchMethod}, ${res.confidence})`);
160
187
  });
161
188
  }
162
189
  });
@@ -164,20 +191,20 @@ async function handleImportRepair(stackIdentifier, report, options) {
164
191
 
165
192
  // Confirm with user (unless --yes flag)
166
193
  if (!options.yes) {
167
- output.info(`šŸ“‹ The following will be imported into CloudFormation:`);
194
+ console.log(`\nšŸ“‹ The following will be imported into CloudFormation:`);
168
195
  mappingResult.resourcesToImport.forEach((resource) => {
169
- output.log(` • ${resource.LogicalResourceId} (${resource.ResourceType})`);
196
+ console.log(` • ${resource.LogicalResourceId} (${resource.ResourceType})`);
170
197
  });
171
198
 
172
- const confirmed = await output.confirm(`\nProceed with import of ${mappingResult.mappedCount} resource(s)?`);
199
+ const confirmed = await confirm(`\nProceed with import of ${mappingResult.mappedCount} resource(s)?`);
173
200
  if (!confirmed) {
174
- output.log('Import cancelled');
201
+ console.log('Import cancelled by user');
175
202
  return { imported: 0, failed: 0, cancelled: true };
176
203
  }
177
204
  }
178
205
 
179
206
  // Execute actual CloudFormation import operation
180
- output.info(`šŸ”§ Preparing CloudFormation import operation...`);
207
+ console.log(`\nšŸ”§ Preparing CloudFormation import operation...`);
181
208
 
182
209
  // Wire up ExecuteResourceImportUseCase
183
210
  const templateParser = new TemplateParser();
@@ -210,38 +237,38 @@ async function handleImportRepair(stackIdentifier, report, options) {
210
237
  buildTemplatePath,
211
238
  onProgress: (progress) => {
212
239
  if (progress.step === 'generate_template' && progress.status === 'in_progress') {
213
- output.log(' • Generating import template...');
240
+ console.log(' • Generating import template...');
214
241
  } else if (progress.step === 'generate_template' && progress.status === 'complete') {
215
- output.log(' āœ“ Template generated');
242
+ console.log(' āœ“ Template generated');
216
243
  } else if (progress.step === 'create_change_set' && progress.status === 'in_progress') {
217
- output.log(' • Creating CloudFormation change set...');
244
+ console.log(' • Creating CloudFormation change set...');
218
245
  } else if (progress.step === 'create_change_set' && progress.status === 'complete') {
219
- output.log(` āœ“ Change set created: ${progress.changeSetName}`);
246
+ console.log(` āœ“ Change set created: ${progress.changeSetName}`);
220
247
  } else if (progress.step === 'wait_change_set' && progress.status === 'in_progress') {
221
- output.log(' • Waiting for change set...');
248
+ console.log(' • Waiting for change set...');
222
249
  } else if (progress.step === 'wait_change_set' && progress.status === 'complete') {
223
- output.log(' āœ“ Change set ready');
250
+ console.log(' āœ“ Change set ready');
224
251
  } else if (progress.step === 'execute_import' && progress.status === 'in_progress') {
225
252
  if (progress.resourceProgress) {
226
253
  const { logicalId, status, progress: resourceProgress, total } = progress.resourceProgress;
227
- output.log(` • Importing resource ${resourceProgress}/${total}: ${logicalId} (${status})`);
254
+ console.log(` • Importing resource ${resourceProgress}/${total}: ${logicalId} (${status})`);
228
255
  } else {
229
- output.log(' • Executing import operation...');
256
+ console.log(' • Executing import operation...');
230
257
  }
231
258
  } else if (progress.step === 'execute_import' && progress.status === 'complete') {
232
- output.log(' āœ“ Import operation complete');
259
+ console.log(' āœ“ Import operation complete');
233
260
  } else if (progress.step === 'verify' && progress.status === 'in_progress') {
234
- output.log(' • Verifying imported resources...');
261
+ console.log(' • Verifying imported resources...');
235
262
  } else if (progress.step === 'verify' && progress.status === 'complete') {
236
- output.log(' āœ“ Verification complete');
263
+ console.log(' āœ“ Verification complete');
237
264
  }
238
265
  },
239
266
  });
240
267
 
241
268
  if (importResult.success) {
242
- output.success(` Successfully imported ${importResult.importedCount} resource(s) into CloudFormation!`);
243
- output.log(` Stack status: ${importResult.stackStatus}`);
244
- output.log(` Change set: ${importResult.changeSetName}`);
269
+ console.log(`\nāœ… Successfully imported ${importResult.importedCount} resource(s) into CloudFormation!`);
270
+ console.log(` Stack status: ${importResult.stackStatus}`);
271
+ console.log(` Change set: ${importResult.changeSetName}`);
245
272
 
246
273
  return {
247
274
  imported: importResult.importedCount,
@@ -249,8 +276,8 @@ async function handleImportRepair(stackIdentifier, report, options) {
249
276
  success: true,
250
277
  };
251
278
  } else {
252
- output.error(` Import operation failed: ${importResult.error}`);
253
- output.error(` Failed at step: ${importResult.step}`);
279
+ console.error(`\nāŒ Import operation failed: ${importResult.error}`);
280
+ console.error(` Failed at step: ${importResult.step}`);
254
281
 
255
282
  return {
256
283
  imported: 0,
@@ -271,7 +298,7 @@ async function handleReconcileRepair(stackIdentifier, report, options) {
271
298
  const driftedResources = report.getDriftedResources();
272
299
 
273
300
  if (driftedResources.length === 0) {
274
- output.success(' No property drift to reconcile');
301
+ console.log('\nāœ“ No property drift to reconcile');
275
302
  return { reconciled: 0, failed: 0 };
276
303
  }
277
304
 
@@ -284,12 +311,12 @@ async function handleReconcileRepair(stackIdentifier, report, options) {
284
311
  totalMismatches += issues.length;
285
312
  });
286
313
 
287
- output.info(`šŸ”§ Found ${driftedResources.length} drifted resource(s) with ${totalMismatches} property mismatch(es):`);
314
+ console.log(`\nšŸ”§ Found ${driftedResources.length} drifted resource(s) with ${totalMismatches} property mismatch(es):`);
288
315
  driftedResources.forEach((resource) => {
289
316
  const issues = report.issues.filter(
290
317
  (issue) => issue.type === 'PROPERTY_MISMATCH' && issue.resourceId === resource.physicalId
291
318
  );
292
- output.log(` • ${resource.logicalId} (${resource.resourceType}): ${issues.length} mismatch(es)`);
319
+ console.log(` • ${resource.logicalId} (${resource.resourceType}): ${issues.length} mismatch(es)`);
293
320
  });
294
321
 
295
322
  // Determine mode (template or resource)
@@ -298,14 +325,14 @@ async function handleReconcileRepair(stackIdentifier, report, options) {
298
325
  ? 'Update CloudFormation template to match actual resource state'
299
326
  : 'Update cloud resources to match CloudFormation template';
300
327
 
301
- output.log(`\nReconciliation mode: ${mode}`);
302
- output.log(` ${modeDescription}`);
328
+ console.log(`\nReconciliation mode: ${mode}`);
329
+ console.log(` ${modeDescription}`);
303
330
 
304
331
  // Confirm with user (unless --yes flag)
305
332
  if (!options.yes) {
306
- const confirmed = await output.confirm(`\nReconcile ${totalMismatches} property mismatch(es) in ${mode} mode?`);
333
+ const confirmed = await confirm(`\nReconcile ${totalMismatches} property mismatch(es) in ${mode} mode?`);
307
334
  if (!confirmed) {
308
- output.log('Reconciliation cancelled');
335
+ console.log('Reconciliation cancelled by user');
309
336
  return { reconciled: 0, failed: 0, cancelled: true };
310
337
  }
311
338
  }
@@ -319,7 +346,7 @@ async function handleReconcileRepair(stackIdentifier, report, options) {
319
346
  const reconcileUseCase = new ReconcilePropertiesUseCase({ propertyReconciler });
320
347
 
321
348
  // Execute reconciliation for each drifted resource
322
- output.info('šŸ”§ Reconciling property drift...');
349
+ console.log('\nšŸ”§ Reconciling property drift...');
323
350
  let reconciledCount = 0;
324
351
  let failedCount = 0;
325
352
  let skippedImmutableCount = 0;
@@ -364,56 +391,56 @@ async function handleReconcileRepair(stackIdentifier, report, options) {
364
391
  });
365
392
  }
366
393
 
367
- output.log(` āœ“ ${resource.logicalId}: Reconciled ${result.reconciledCount} property(ies)`);
394
+ console.log(` āœ“ ${resource.logicalId}: Reconciled ${result.reconciledCount} property(ies)`);
368
395
  if (result.skippedCount > 0) {
369
- output.log(` ⚠ Skipped ${result.skippedCount} immutable property(ies) - requires manual intervention`);
396
+ console.log(` ⚠ Skipped ${result.skippedCount} immutable property(ies) - requires manual intervention`);
370
397
  }
371
398
 
372
399
  // Debug: Log full result if reconciledCount is 0 but we expected properties
373
400
  if (process.env.DEBUG_RECONCILE && result.reconciledCount === 0 && mismatches.length > 0) {
374
- output.log(` [DEBUG] Expected ${mismatches.length} mismatches, got result:`, JSON.stringify(result, null, 2));
401
+ console.log(` [DEBUG] Expected ${mismatches.length} mismatches, got result:`, JSON.stringify(result, null, 2));
375
402
  }
376
403
  } catch (error) {
377
404
  // Count failed properties, not just the resource
378
405
  failedCount += mismatches.length;
379
- output.log(` āœ— ${resource.logicalId}: ${error.message}`);
406
+ console.log(` āœ— ${resource.logicalId}: ${error.message}`);
380
407
 
381
408
  // Debug: Log full error
382
409
  if (process.env.DEBUG_RECONCILE) {
383
- output.log(` [DEBUG] Error stack:`, error.stack);
410
+ console.log(` [DEBUG] Error stack:`, error.stack);
384
411
  }
385
412
  }
386
413
  }
387
414
 
388
415
  // Report results
389
- output.log(''); // Blank line before summary
416
+ console.log(''); // Blank line before summary
390
417
 
391
418
  if (reconciledCount > 0) {
392
- output.log(`āœ… Reconciled ${reconciledCount} property(ies)`);
419
+ console.log(`āœ… Reconciled ${reconciledCount} property(ies)`);
393
420
  }
394
421
 
395
422
  if (skippedImmutableCount > 0) {
396
- output.warn(` ${skippedImmutableCount} immutable property(ies) require manual intervention:`);
423
+ console.log(`\n⚠ ${skippedImmutableCount} immutable property(ies) require manual intervention:`);
397
424
  immutableProperties.forEach(prop => {
398
- output.log(` • ${prop.logicalId}.${prop.propertyPath}`);
399
- output.log(` Template: ${JSON.stringify(prop.expectedValue)}`);
400
- output.log(` Actual: ${JSON.stringify(prop.actualValue)}`);
425
+ console.log(` • ${prop.logicalId}.${prop.propertyPath}`);
426
+ console.log(` Template: ${JSON.stringify(prop.expectedValue)}`);
427
+ console.log(` Actual: ${JSON.stringify(prop.actualValue)}`);
401
428
  });
402
429
 
403
- output.info(`šŸ’” To resolve immutable property drift:`);
404
- output.log(` 1. These properties require resource replacement (cannot be updated in place)`);
405
- output.log(` 2. Options:`);
406
- output.log(` a) Accept the drift - update your local template to match actual values`);
407
- output.log(` b) Replace the resource - delete and recreate via CloudFormation`);
408
- output.log(` c) Use import workflow - remove from stack, then re-import with correct values`);
409
- output.log(`\n For automated import workflow (coming soon):`);
410
- output.log(` frigg repair --import-drift ${stackIdentifier.stackName}`);
430
+ console.log(`\nšŸ’” To resolve immutable property drift:`);
431
+ console.log(` 1. These properties require resource replacement (cannot be updated in place)`);
432
+ console.log(` 2. Options:`);
433
+ console.log(` a) Accept the drift - update your local template to match actual values`);
434
+ console.log(` b) Replace the resource - delete and recreate via CloudFormation`);
435
+ console.log(` c) Use import workflow - remove from stack, then re-import with correct values`);
436
+ console.log(`\n For automated import workflow (coming soon):`);
437
+ console.log(` frigg repair --import-drift ${stackIdentifier.stackName}`);
411
438
  }
412
439
 
413
440
  if (failedCount === 0 && skippedImmutableCount === 0) {
414
- output.log(`āœ“ Successfully reconciled all ${reconciledCount} property mismatch(es)`);
441
+ console.log(`āœ“ Successfully reconciled all ${reconciledCount} property mismatch(es)`);
415
442
  } else {
416
- output.warn(` Reconciled ${reconciledCount} property(ies), ${failedCount} failed`);
443
+ console.log(`\n⚠ Reconciled ${reconciledCount} property(ies), ${failedCount} failed`);
417
444
  }
418
445
 
419
446
  return { reconciled: reconciledCount, failed: failedCount, success: failedCount === 0 };
@@ -426,28 +453,21 @@ async function handleReconcileRepair(stackIdentifier, report, options) {
426
453
  */
427
454
  async function repairCommand(stackName, options = {}) {
428
455
  try {
429
- // Guard: repair only works with AWS (CloudFormation stacks)
430
- if (isNonAwsProvider()) {
431
- output.error('The repair command is only available for AWS deployments.');
432
- output.log('Your appDefinition uses a non-AWS provider.');
433
- process.exit(1);
434
- }
435
-
436
456
  // Validate required parameter
437
457
  if (!stackName) {
438
- output.error('Error: Stack name is required');
439
- output.log('Usage: frigg repair [options] <stack-name>');
440
- output.log('Options:');
441
- output.log(' --import Import orphaned resources');
442
- output.log(' --reconcile Reconcile property drift');
443
- output.log(' --yes Skip confirmation prompts');
458
+ console.error('Error: Stack name is required');
459
+ console.log('Usage: frigg repair [options] <stack-name>');
460
+ console.log('Options:');
461
+ console.log(' --import Import orphaned resources');
462
+ console.log(' --reconcile Reconcile property drift');
463
+ console.log(' --yes Skip confirmation prompts');
444
464
  process.exit(1);
445
465
  }
446
466
 
447
467
  // Validate at least one repair operation is selected
448
468
  if (!options.import && !options.reconcile) {
449
- output.error('Error: At least one repair operation must be specified (--import or --reconcile)');
450
- output.log('Usage: frigg repair [options] <stack-name>');
469
+ console.error('Error: At least one repair operation must be specified (--import or --reconcile)');
470
+ console.log('Usage: frigg repair [options] <stack-name>');
451
471
  process.exit(1);
452
472
  }
453
473
 
@@ -455,13 +475,13 @@ async function repairCommand(stackName, options = {}) {
455
475
  const region = options.region || process.env.AWS_REGION || 'us-east-1';
456
476
  const verbose = options.verbose || false;
457
477
 
458
- output.info(`šŸ„ Running Frigg Repair on stack: ${stackName} (${region})`);
478
+ console.log(`\nšŸ„ Running Frigg Repair on stack: ${stackName} (${region})`);
459
479
 
460
480
  // 1. Create stack identifier
461
481
  const stackIdentifier = new StackIdentifier({ stackName, region });
462
482
 
463
483
  // 2. Run health check first to identify issues
464
- output.info('šŸ” Running health check to identify issues...');
484
+ console.log('\nšŸ” Running health check to identify issues...');
465
485
 
466
486
  const stackRepository = new AWSStackRepository({ region });
467
487
  const resourceDetector = new AWSResourceDetector({ region });
@@ -477,8 +497,8 @@ async function repairCommand(stackName, options = {}) {
477
497
 
478
498
  const report = await runHealthCheckUseCase.execute({ stackIdentifier });
479
499
 
480
- output.log(`\nHealth Score: ${report.healthScore.value}/100 (${report.healthScore.qualitativeAssessment()})`);
481
- output.log(`Issues: ${report.getIssueCount()} total (${report.getCriticalIssueCount()} critical)`);
500
+ console.log(`\nHealth Score: ${report.healthScore.value}/100 (${report.healthScore.qualitativeAssessment()})`);
501
+ console.log(`Issues: ${report.getIssueCount()} total (${report.getCriticalIssueCount()} critical)`);
482
502
 
483
503
  // 3. Execute requested repair operations
484
504
  const results = {
@@ -504,24 +524,24 @@ async function repairCommand(stackName, options = {}) {
504
524
  }
505
525
 
506
526
  // 4. Final summary
507
- output.log('\n' + '═'.repeat(80));
508
- output.log('Repair Summary:');
527
+ console.log('\n' + '═'.repeat(80));
528
+ console.log('Repair Summary:');
509
529
  if (options.import) {
510
- output.log(` Imported: ${results.imported} resource(s)`);
530
+ console.log(` Imported: ${results.imported} resource(s)`);
511
531
  }
512
532
  if (options.reconcile) {
513
- output.log(` Reconciled: ${results.reconciled} property(ies)`);
533
+ console.log(` Reconciled: ${results.reconciled} property(ies)`);
514
534
  }
515
- output.log(` Failed: ${results.failed}`);
516
- output.log('═'.repeat(80));
535
+ console.log(` Failed: ${results.failed}`);
536
+ console.log('═'.repeat(80));
517
537
 
518
538
  // Run health check again to verify repairs
519
- output.info('šŸ” Running health check to verify repairs...');
539
+ console.log('\nšŸ” Running health check to verify repairs...');
520
540
  const verifyReport = await runHealthCheckUseCase.execute({ stackIdentifier });
521
- output.log(`\nNew Health Score: ${verifyReport.healthScore.value}/100 (${verifyReport.healthScore.qualitativeAssessment()})`);
541
+ console.log(`\nNew Health Score: ${verifyReport.healthScore.value}/100 (${verifyReport.healthScore.qualitativeAssessment()})`);
522
542
 
523
543
  if (verifyReport.healthScore.value > report.healthScore.value) {
524
- output.success(` Health improved by ${verifyReport.healthScore.value - report.healthScore.value} points!`);
544
+ console.log(`\nāœ“ Health improved by ${verifyReport.healthScore.value - report.healthScore.value} points!`);
525
545
  }
526
546
 
527
547
  // 5. Exit with appropriate code
@@ -531,27 +551,14 @@ async function repairCommand(stackName, options = {}) {
531
551
  process.exit(0);
532
552
  }
533
553
  } catch (error) {
534
- output.error(` Repair failed: ${error.message}`);
554
+ console.error(`\nāœ— Repair failed: ${error.message}`);
535
555
 
536
556
  if (options.verbose && error.stack) {
537
- output.error(`\nStack trace:\n${error.stack}`);
557
+ console.error(`\nStack trace:\n${error.stack}`);
538
558
  }
539
559
 
540
560
  process.exit(1);
541
561
  }
542
562
  }
543
563
 
544
- /**
545
- * Check if the current appDefinition uses a non-AWS provider.
546
- */
547
- function isNonAwsProvider() {
548
- try {
549
- const { loadProviderForCli } = require('../utils/provider-helper');
550
- const result = loadProviderForCli();
551
- return result && result.providerName !== 'aws';
552
- } catch {
553
- return false;
554
- }
555
- }
556
-
557
564
  module.exports = { repairCommand };