@friggframework/devtools 2.0.0--canary.545.ae2019f.0 → 2.0.0--canary.549.a579cca.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 (127) 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/networking/vpc-builder.test.js +4 -2
  30. package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
  31. package/infrastructure/domains/shared/resource-discovery.js +5 -5
  32. package/infrastructure/domains/shared/types/app-definition.js +0 -21
  33. package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
  34. package/infrastructure/domains/shared/utilities/base-definition-factory.js +1 -10
  35. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
  36. package/infrastructure/infrastructure-composer.js +0 -2
  37. package/infrastructure/infrastructure-composer.test.js +2 -2
  38. package/management-ui/README.md +109 -245
  39. package/package.json +7 -8
  40. package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +0 -326
  41. package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +0 -337
  42. package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +0 -373
  43. package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +0 -313
  44. package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +0 -269
  45. package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +0 -82
  46. package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +0 -408
  47. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +0 -583
  48. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +0 -314
  49. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +0 -383
  50. package/frigg-cli/__tests__/unit/commands/init.test.js +0 -406
  51. package/frigg-cli/__tests__/unit/commands/provider-dispatch.test.js +0 -383
  52. package/frigg-cli/__tests__/unit/commands/repair.test.js +0 -275
  53. package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +0 -411
  54. package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +0 -405
  55. package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +0 -496
  56. package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +0 -474
  57. package/frigg-cli/__tests__/unit/utils/output.test.js +0 -196
  58. package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +0 -93
  59. package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +0 -93
  60. package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +0 -103
  61. package/frigg-cli/container.js +0 -172
  62. package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +0 -286
  63. package/frigg-cli/domain/entities/ApiModule.js +0 -272
  64. package/frigg-cli/domain/entities/AppDefinition.js +0 -227
  65. package/frigg-cli/domain/entities/Integration.js +0 -198
  66. package/frigg-cli/domain/exceptions/DomainException.js +0 -24
  67. package/frigg-cli/domain/ports/IApiModuleRepository.js +0 -53
  68. package/frigg-cli/domain/ports/IAppDefinitionRepository.js +0 -43
  69. package/frigg-cli/domain/ports/IIntegrationRepository.js +0 -61
  70. package/frigg-cli/domain/services/IntegrationValidator.js +0 -185
  71. package/frigg-cli/domain/value-objects/IntegrationId.js +0 -42
  72. package/frigg-cli/domain/value-objects/IntegrationName.js +0 -60
  73. package/frigg-cli/domain/value-objects/SemanticVersion.js +0 -70
  74. package/frigg-cli/infrastructure/UnitOfWork.js +0 -46
  75. package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +0 -197
  76. package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +0 -224
  77. package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +0 -249
  78. package/frigg-cli/infrastructure/adapters/SchemaValidator.js +0 -92
  79. package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +0 -373
  80. package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +0 -116
  81. package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +0 -277
  82. package/frigg-cli/package-lock.json +0 -16226
  83. package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +0 -376
  84. package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +0 -591
  85. package/frigg-cli/start-command/infrastructure/DockerAdapter.js +0 -306
  86. package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +0 -329
  87. package/frigg-cli/templates/backend/.env.example +0 -62
  88. package/frigg-cli/templates/backend/.eslintrc.json +0 -12
  89. package/frigg-cli/templates/backend/.prettierrc +0 -6
  90. package/frigg-cli/templates/backend/docker-compose.yml +0 -22
  91. package/frigg-cli/templates/backend/index.js +0 -96
  92. package/frigg-cli/templates/backend/infrastructure.js +0 -12
  93. package/frigg-cli/templates/backend/jest.config.js +0 -17
  94. package/frigg-cli/templates/backend/package.json +0 -50
  95. package/frigg-cli/templates/backend/src/api-modules/.gitkeep +0 -10
  96. package/frigg-cli/templates/backend/src/base/.gitkeep +0 -7
  97. package/frigg-cli/templates/backend/src/integrations/.gitkeep +0 -10
  98. package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +0 -65
  99. package/frigg-cli/templates/backend/src/utils/.gitkeep +0 -7
  100. package/frigg-cli/templates/backend/test/setup.js +0 -30
  101. package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
  102. package/frigg-cli/templates/backend/ui-extensions/README.md +0 -77
  103. package/frigg-cli/utils/__tests__/provider-helper.test.js +0 -55
  104. package/frigg-cli/utils/__tests__/repo-detection.test.js +0 -436
  105. package/frigg-cli/utils/output.js +0 -382
  106. package/frigg-cli/utils/provider-helper.js +0 -75
  107. package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +0 -205
  108. package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +0 -104
  109. package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +0 -153
  110. package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +0 -162
  111. package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +0 -152
  112. package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +0 -332
  113. package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +0 -191
  114. package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +0 -146
  115. package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +0 -155
  116. package/frigg-cli/validate-command/adapters/cli/validate-command.js +0 -199
  117. package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +0 -35
  118. package/frigg-cli/validate-command/domain/entities/validation-result.js +0 -74
  119. package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +0 -74
  120. package/frigg-cli/validate-command/domain/value-objects/validation-error.js +0 -68
  121. package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +0 -181
  122. package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +0 -128
  123. package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +0 -113
  124. package/infrastructure/domains/admin-scripts/admin-script-builder.js +0 -200
  125. package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +0 -499
  126. package/infrastructure/domains/admin-scripts/index.js +0 -5
  127. package/infrastructure/jest.config.js +0 -16
@@ -1281,7 +1281,7 @@ npm install @friggframework/frigg-cli@latest
1281
1281
  npm install -g @friggframework/frigg-cli
1282
1282
 
1283
1283
  # Local project dependencies
1284
- frigg init my-app
1284
+ npx create-frigg-app my-app
1285
1285
  # (Will automatically include @friggframework/frigg-cli in package.json)
1286
1286
  ```
1287
1287
 
@@ -207,7 +207,7 @@ describe('CLI Command: build', () => {
207
207
  await buildCommand({ stage: 'dev' });
208
208
 
209
209
  expect(consoleLogSpy).toHaveBeenCalledWith('Building the serverless application...');
210
- expect(consoleLogSpy).toHaveBeenCalledWith('Packaging serverless application...');
210
+ expect(consoleLogSpy).toHaveBeenCalledWith('šŸ“¦ Packaging serverless application...');
211
211
  });
212
212
 
213
213
  it('should construct complete valid serverless command', async () => {
@@ -3,6 +3,8 @@
3
3
  * Tests stack listing, selection, and health check orchestration
4
4
  */
5
5
 
6
+ const { describe, test, expect, jest, beforeEach } = require('@jest/globals');
7
+
6
8
  describe('Doctor Command - Stack Listing and Selection', () => {
7
9
  let mockCloudFormationClient;
8
10
  let mockSelect;
@@ -26,7 +26,7 @@ jest.mock('../../../install-command/validate-package', () => ({
26
26
  validatePackageExists: jest.fn(), // External: npm registry
27
27
  searchAndSelectPackage: jest.fn() // External: interactive selection
28
28
  }));
29
- jest.mock('@friggframework/core/utils', () => ({
29
+ jest.mock('@friggframework/core', () => ({
30
30
  findNearestBackendPackageJson: jest.fn(),
31
31
  validateBackendPath: jest.fn()
32
32
  }));
@@ -43,13 +43,13 @@ const { installPackage } = require('../../../install-command/install-package');
43
43
  const { commitChanges } = require('../../../install-command/commit-changes');
44
44
  const { handleEnvVariables } = require('../../../install-command/environment-variables');
45
45
  const { validatePackageExists, searchAndSelectPackage } = require('../../../install-command/validate-package');
46
- const { findNearestBackendPackageJson, validateBackendPath } = require('@friggframework/core/utils');
46
+ const { findNearestBackendPackageJson, validateBackendPath } = require('@friggframework/core');
47
47
  const { installCommand } = require('../../../install-command');
48
- const output = require('../../../utils/output');
49
48
 
50
49
  describe('CLI Command: install', () => {
51
50
  let processExitSpy;
52
-
51
+ let consoleLogSpy;
52
+ let consoleErrorSpy;
53
53
  const mockBackendPath = '/mock/backend/package.json';
54
54
  const mockBackendDir = '/mock/backend';
55
55
 
@@ -59,14 +59,9 @@ describe('CLI Command: install', () => {
59
59
  // Mock process.exit to prevent actual exit
60
60
  processExitSpy = jest.spyOn(process, 'exit').mockImplementation();
61
61
 
62
- // Mock output module
63
- output.success = jest.fn();
64
- output.error = jest.fn();
65
- output.spinner = jest.fn().mockReturnValue({
66
- start: jest.fn(),
67
- succeed: jest.fn(),
68
- fail: jest.fn()
69
- });
62
+ // Spy on console for logger (don't mock logger - test it!)
63
+ consoleLogSpy = jest.spyOn(console, 'log').mockImplementation();
64
+ consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation();
70
65
 
71
66
  // Setup fs-extra mocks - Let Frigg code run, just mock I/O
72
67
  fs.ensureDirSync = jest.fn();
@@ -103,7 +98,8 @@ describe('CLI Command: install', () => {
103
98
 
104
99
  afterEach(() => {
105
100
  processExitSpy.mockRestore();
106
-
101
+ consoleLogSpy.mockRestore();
102
+ consoleErrorSpy.mockRestore();
107
103
  jest.resetModules(); // Clear module cache after each test
108
104
  });
109
105
 
@@ -209,9 +205,9 @@ describe('CLI Command: install', () => {
209
205
  it('should log info messages during installation', async () => {
210
206
  await installCommand('slack');
211
207
 
212
- // Verify output.spinner was used for installation progress
213
- expect(output.spinner).toHaveBeenCalledWith(
214
- expect.stringContaining('Installing integration for Slack')
208
+ // Verify logger actually logged (we spy on console)
209
+ expect(consoleLogSpy).toHaveBeenCalledWith(
210
+ expect.stringContaining('Successfully installed @friggframework/api-module-slack')
215
211
  );
216
212
  });
217
213
 
@@ -338,8 +334,8 @@ describe('CLI Command: install', () => {
338
334
 
339
335
  await installCommand('slack');
340
336
 
341
- // Verify error logged via output.error
342
- expect(output.error).toHaveBeenCalledWith('An error occurred:', error);
337
+ // Verify error logged via console.error (we spy on it)
338
+ expect(consoleErrorSpy).toHaveBeenCalledWith('An error occurred:', error);
343
339
  expect(processExitSpy).toHaveBeenCalledWith(1);
344
340
  });
345
341
 
@@ -349,7 +345,7 @@ describe('CLI Command: install', () => {
349
345
 
350
346
  await installCommand('slack');
351
347
 
352
- expect(output.error).toHaveBeenCalledWith('An error occurred:', error);
348
+ expect(consoleErrorSpy).toHaveBeenCalledWith('An error occurred:', error);
353
349
  expect(processExitSpy).toHaveBeenCalledWith(1);
354
350
  });
355
351
 
@@ -361,7 +357,7 @@ describe('CLI Command: install', () => {
361
357
 
362
358
  await installCommand('slack');
363
359
 
364
- expect(output.error).toHaveBeenCalledWith('An error occurred:', error);
360
+ expect(consoleErrorSpy).toHaveBeenCalledWith('An error occurred:', error);
365
361
  expect(processExitSpy).toHaveBeenCalledWith(1);
366
362
  });
367
363
 
@@ -374,7 +370,7 @@ describe('CLI Command: install', () => {
374
370
 
375
371
  await installCommand('slack');
376
372
 
377
- expect(output.error).toHaveBeenCalledWith('An error occurred:', expect.any(Error));
373
+ expect(consoleErrorSpy).toHaveBeenCalledWith('An error occurred:', expect.any(Error));
378
374
  expect(processExitSpy).toHaveBeenCalledWith(1);
379
375
  });
380
376
 
@@ -387,7 +383,7 @@ describe('CLI Command: install', () => {
387
383
 
388
384
  await installCommand('slack');
389
385
 
390
- expect(output.error).toHaveBeenCalledWith('An error occurred:', expect.any(Error));
386
+ expect(consoleErrorSpy).toHaveBeenCalledWith('An error occurred:', expect.any(Error));
391
387
  expect(processExitSpy).toHaveBeenCalledWith(1);
392
388
  });
393
389
 
@@ -397,7 +393,7 @@ describe('CLI Command: install', () => {
397
393
 
398
394
  await installCommand('slack');
399
395
 
400
- expect(output.error).toHaveBeenCalledWith('An error occurred:', error);
396
+ expect(consoleErrorSpy).toHaveBeenCalledWith('An error occurred:', error);
401
397
  expect(processExitSpy).toHaveBeenCalledWith(1);
402
398
  });
403
399
  });
@@ -51,8 +51,8 @@ describe('frigg-cli dependencies', () => {
51
51
  expect(packageJson.dependencies.commander).toBeDefined();
52
52
  });
53
53
 
54
- it('should have @friggframework/devtools as a peer dependency', () => {
55
- expect(packageJson.peerDependencies['@friggframework/devtools']).toBeDefined();
54
+ it('should have @friggframework/devtools for infrastructure', () => {
55
+ expect(packageJson.dependencies['@friggframework/devtools']).toBeDefined();
56
56
  });
57
57
  });
58
58
 
@@ -1,15 +1,7 @@
1
1
  const { spawnSync } = require('child_process');
2
2
  const path = require('path');
3
- const fs = require('fs');
4
3
 
5
4
  async function buildCommand(options) {
6
- // Check if the app uses a non-AWS provider
7
- const providerResult = loadProviderIfConfigured();
8
- if (providerResult) {
9
- return buildWithProvider(providerResult, options);
10
- }
11
-
12
- // Default: AWS build via serverless framework
13
5
  console.log('Building the serverless application...');
14
6
 
15
7
  // Suppress AWS SDK warning message about maintenance mode
@@ -18,13 +10,13 @@ async function buildCommand(options) {
18
10
  // Skip AWS discovery for local builds (unless --production flag is set)
19
11
  if (!options.production) {
20
12
  process.env.FRIGG_SKIP_AWS_DISCOVERY = 'true';
21
- console.log('Building in local mode (use --production flag for production builds with AWS discovery)');
13
+ console.log('šŸ  Building in local mode (use --production flag for production builds with AWS discovery)');
22
14
  } else {
23
- console.log('Building in production mode with AWS discovery enabled');
15
+ console.log('šŸš€ Building in production mode with AWS discovery enabled');
24
16
  }
25
17
 
26
18
  // AWS discovery is now handled directly in serverless-template.js
27
- console.log('Packaging serverless application...');
19
+ console.log('šŸ“¦ Packaging serverless application...');
28
20
  const backendPath = path.resolve(process.cwd());
29
21
  const infrastructurePath = 'infrastructure.js';
30
22
  const command = 'osls'; // OSS-Serverless (drop-in replacement for serverless v3)
@@ -59,120 +51,16 @@ async function buildCommand(options) {
59
51
  console.error(`Serverless build failed with code ${result.status}`);
60
52
  process.exit(1);
61
53
  }
62
- }
63
-
64
- /**
65
- * Check if the appDefinition specifies a non-AWS provider and resolve it.
66
- */
67
- function loadProviderIfConfigured() {
68
- try {
69
- const { loadProviderForCli } = require('../utils/provider-helper');
70
- const result = loadProviderForCli();
71
- if (result && result.provider) {
72
- return result;
73
- }
74
- } catch {
75
- // Provider helper not available or appDefinition not found — fall through
76
- }
77
- return null;
78
- }
79
-
80
- /**
81
- * Build using a provider plugin.
82
- * Provider build steps:
83
- * 1. generateConfig() — generate platform-specific config (netlify.toml, etc.)
84
- * 2. getFunctionEntryPoints() — copy function files to the project
85
- */
86
- async function buildWithProvider({ provider, appDefinition, providerName }, options) {
87
- console.log(`Building for ${providerName} provider...`);
88
- const projectDir = path.resolve(process.cwd());
89
-
90
- // 1. Validate
91
- if (typeof provider.validate === 'function') {
92
- const validation = provider.validate(appDefinition);
93
- if (validation.errors?.length > 0) {
94
- console.error(`\nValidation errors for ${providerName}:`);
95
- for (const error of validation.errors) {
96
- console.error(` - ${error}`);
97
- }
98
- process.exit(1);
99
- }
100
- if (validation.warnings?.length > 0) {
101
- for (const warning of validation.warnings) {
102
- console.warn(` Warning: ${warning}`);
103
- }
104
- }
105
- }
106
-
107
- // 2. Generate platform config (e.g., netlify.toml)
108
- if (typeof provider.generateConfig === 'function') {
109
- console.log(`Generating ${providerName} configuration...`);
110
- const config = provider.generateConfig(appDefinition);
111
-
112
- const configFileNames = {
113
- netlify: 'netlify.toml',
114
- };
115
- const configFileName = configFileNames[providerName] || `${providerName}.config`;
116
- const configPath = path.join(projectDir, configFileName);
117
-
118
- fs.writeFileSync(configPath, config, 'utf-8');
119
- console.log(` Written ${configFileName}`);
120
- }
121
54
 
122
- // 3. Copy function entry points
123
- if (typeof provider.getFunctionEntryPoints === 'function') {
124
- console.log('Generating function entry points...');
125
- const entryPoints = provider.getFunctionEntryPoints(appDefinition);
126
- const functionsDir = path.join(projectDir, 'netlify', 'functions');
127
-
128
- fs.mkdirSync(functionsDir, { recursive: true });
129
-
130
- for (const [filename, content] of Object.entries(entryPoints)) {
131
- const filePath = path.join(functionsDir, filename);
132
- fs.writeFileSync(filePath, content, 'utf-8');
133
- if (options.verbose) {
134
- console.log(` Written ${path.relative(projectDir, filePath)}`);
135
- }
136
- }
137
-
138
- console.log(` Generated ${Object.keys(entryPoints).length} function entry points`);
139
- }
140
-
141
- // 4. Copy lib entry points (re-export shims for runtime dependencies)
142
- if (typeof provider.getLibEntryPoints === 'function') {
143
- const libEntryPoints = provider.getLibEntryPoints(appDefinition);
144
- const libDir = path.join(projectDir, 'netlify', 'lib');
145
-
146
- fs.mkdirSync(libDir, { recursive: true });
147
-
148
- for (const [filename, content] of Object.entries(libEntryPoints)) {
149
- const filePath = path.join(libDir, filename);
150
- fs.writeFileSync(filePath, content, 'utf-8');
151
- if (options.verbose) {
152
- console.log(` Written ${path.relative(projectDir, filePath)}`);
153
- }
154
- }
155
-
156
- console.log(` Generated ${Object.keys(libEntryPoints).length} lib entry points`);
157
- }
158
-
159
- // 5. Generate env template (informational)
160
- if (typeof provider.generateEnvTemplate === 'function') {
161
- const envTemplate = provider.generateEnvTemplate(appDefinition);
162
- const missingEnvVars = Object.entries(envTemplate)
163
- .filter(([key]) => !process.env[key])
164
- .map(([key, desc]) => `${key}: ${desc}`);
165
-
166
- if (missingEnvVars.length > 0) {
167
- console.log(`\n Required environment variables not set locally:`);
168
- for (const entry of missingEnvVars) {
169
- console.log(` - ${entry}`);
170
- }
171
- console.log(` Configure these in your ${providerName} dashboard.`);
172
- }
173
- }
55
+ // childProcess.on('error', (error) => {
56
+ // console.error(`Error executing command: ${error.message}`);
57
+ // });
174
58
 
175
- console.log(`\nBuild complete for ${providerName}.`);
59
+ // childProcess.on('close', (code) => {
60
+ // if (code !== 0) {
61
+ // console.log(`Child process exited with code ${code}`);
62
+ // }
63
+ // });
176
64
  }
177
65
 
178
66
  module.exports = { buildCommand };
@@ -268,17 +268,9 @@ async function runPostDeploymentHealthCheck(stackName, options) {
268
268
  }
269
269
 
270
270
  async function deployCommand(options) {
271
- const appDefinition = loadAppDefinition();
272
-
273
- // Check if the app uses a non-AWS provider
274
- const providerResult = loadProviderIfConfigured(appDefinition);
275
- if (providerResult) {
276
- return deployWithProvider(providerResult, options);
277
- }
278
-
279
- // Default: AWS deployment via serverless framework
280
271
  console.log('Deploying the serverless application...');
281
272
 
273
+ const appDefinition = loadAppDefinition();
282
274
  const environment = validateAndBuildEnvironment(appDefinition, options);
283
275
 
284
276
  // Execute deployment
@@ -310,78 +302,4 @@ async function deployCommand(options) {
310
302
  }
311
303
  }
312
304
 
313
- /**
314
- * Check if the appDefinition specifies a non-AWS provider and resolve it.
315
- * Returns null for AWS (default) so the caller falls through to existing behavior.
316
- *
317
- * @param {Object|null} appDefinition
318
- * @returns {{ provider: Object, appDefinition: Object, providerName: string } | null}
319
- */
320
- function loadProviderIfConfigured(appDefinition) {
321
- const providerName = appDefinition?.provider;
322
- if (!providerName || providerName === 'aws') {
323
- return null;
324
- }
325
-
326
- try {
327
- const { resolveProvider } = require('@friggframework/core/providers/resolve-provider');
328
- const provider = resolveProvider(appDefinition);
329
- return { provider, appDefinition, providerName };
330
- } catch (error) {
331
- console.error(`Failed to load provider '${providerName}': ${error.message}`);
332
- process.exit(1);
333
- }
334
- }
335
-
336
- /**
337
- * Deploy using a provider plugin (Netlify, etc.).
338
- * Delegates entirely to the provider's deploy lifecycle:
339
- * 1. validate() — check appDefinition for provider-specific issues
340
- * 2. preflightCheck() — verify prerequisites (CLI tools, credentials)
341
- * 3. deploy() — execute the deployment
342
- */
343
- async function deployWithProvider({ provider, appDefinition, providerName }, options) {
344
- console.log(`Deploying with ${providerName} provider...`);
345
-
346
- // 1. Validate appDefinition for this provider
347
- if (typeof provider.validate === 'function') {
348
- const validation = provider.validate(appDefinition);
349
- if (validation.errors?.length > 0) {
350
- console.error(`\nValidation errors for ${providerName}:`);
351
- for (const error of validation.errors) {
352
- console.error(` - ${error}`);
353
- }
354
- process.exit(1);
355
- }
356
- if (validation.warnings?.length > 0) {
357
- for (const warning of validation.warnings) {
358
- console.warn(` Warning: ${warning}`);
359
- }
360
- }
361
- }
362
-
363
- // 2. Deploy via provider
364
- try {
365
- const result = await provider.deploy(appDefinition, {
366
- stage: options.stage,
367
- prod: options.stage === 'production' || options.stage === 'prod',
368
- dryRun: options.dryRun || false,
369
- });
370
-
371
- console.log(`\nāœ“ Deployment completed successfully!`);
372
- if (result.url) {
373
- console.log(` URL: ${result.url}`);
374
- }
375
- } catch (error) {
376
- console.error(`\nāœ— Deployment failed: ${error.message}`);
377
- if (error.missing) {
378
- console.error(' Missing prerequisites:');
379
- for (const item of error.missing) {
380
- console.error(` - ${item}`);
381
- }
382
- }
383
- process.exit(1);
384
- }
385
- }
386
-
387
305
  module.exports = { deployCommand };
@@ -12,9 +12,8 @@
12
12
  */
13
13
 
14
14
  const path = require('path');
15
- const output = require('../utils/output');
16
15
  const fs = require('fs');
17
- // Using output.select from unified Output class (wraps @inquirer/prompts)
16
+ const { select } = require('@inquirer/prompts');
18
17
  const { CloudFormationClient, ListStacksCommand } = require('@aws-sdk/client-cloudformation');
19
18
 
20
19
  // Domain and Application Layer
@@ -161,9 +160,9 @@ function formatJsonOutput(report) {
161
160
  function writeOutputFile(content, filePath) {
162
161
  try {
163
162
  fs.writeFileSync(filePath, content, 'utf8');
164
- output.success(` Report saved to: ${filePath}`);
163
+ console.log(`\nāœ“ Report saved to: ${filePath}`);
165
164
  } catch (error) {
166
- output.error(` Failed to write output file: ${error.message}`);
165
+ console.error(`\nāœ— Failed to write output file: ${error.message}`);
167
166
  process.exit(1);
168
167
  }
169
168
  }
@@ -205,17 +204,17 @@ async function listStacks(region) {
205
204
  * @returns {Promise<string>} Selected stack name
206
205
  */
207
206
  async function promptForStackSelection(region) {
208
- output.info(`šŸ” Fetching CloudFormation stacks in ${region}...`);
207
+ console.log(`\nšŸ” Fetching CloudFormation stacks in ${region}...`);
209
208
 
210
209
  const stacks = await listStacks(region);
211
210
 
212
211
  if (stacks.length === 0) {
213
- output.error(` No CloudFormation stacks found in ${region}`);
214
- output.log(' Make sure you have stacks deployed and the correct AWS credentials configured.');
212
+ console.error(`\nāœ— No CloudFormation stacks found in ${region}`);
213
+ console.log(' Make sure you have stacks deployed and the correct AWS credentials configured.');
215
214
  process.exit(1);
216
215
  }
217
216
 
218
- output.success(` Found ${stacks.length} stack(s)\n`);
217
+ console.log(`\nāœ“ Found ${stacks.length} stack(s)\n`);
219
218
 
220
219
  // Create choices with stack name and metadata
221
220
  const choices = stacks.map(stack => {
@@ -231,7 +230,7 @@ async function promptForStackSelection(region) {
231
230
  };
232
231
  });
233
232
 
234
- const selectedStack = await output.select({
233
+ const selectedStack = await select({
235
234
  message: 'Select a stack to run health check:',
236
235
  choices,
237
236
  pageSize: 15,
@@ -247,13 +246,6 @@ async function promptForStackSelection(region) {
247
246
  */
248
247
  async function doctorCommand(stackName, options = {}) {
249
248
  try {
250
- // Guard: doctor only works with AWS (CloudFormation stacks)
251
- if (isNonAwsProvider()) {
252
- output.error('The doctor command is only available for AWS deployments.');
253
- output.log('Your appDefinition uses a non-AWS provider.');
254
- process.exit(1);
255
- }
256
-
257
249
  // Extract options with defaults
258
250
  const region = options.region || process.env.AWS_REGION || 'us-east-1';
259
251
  const format = options.format || 'console';
@@ -265,7 +257,7 @@ async function doctorCommand(stackName, options = {}) {
265
257
  }
266
258
 
267
259
  // Show progress to user (always, not just verbose mode)
268
- output.info(`šŸ„ Running health check on stack: ${stackName} (${region})\n`);
260
+ console.log(`\nšŸ„ Running health check on stack: ${stackName} (${region})\n`);
269
261
 
270
262
  // 1. Create stack identifier
271
263
  const stackIdentifier = new StackIdentifier({ stackName, region });
@@ -289,9 +281,9 @@ async function doctorCommand(stackName, options = {}) {
289
281
  // Progress callback to show execution status
290
282
  const progressCallback = (step, message) => {
291
283
  if (verbose) {
292
- output.log(` ${message}`);
284
+ console.log(` ${message}`);
293
285
  } else {
294
- output.log(`${step} ${message}`);
286
+ console.log(`${step} ${message}`);
295
287
  }
296
288
  };
297
289
 
@@ -300,7 +292,7 @@ async function doctorCommand(stackName, options = {}) {
300
292
  onProgress: progressCallback
301
293
  });
302
294
 
303
- output.success(' Health check complete!\n');
295
+ console.log('āœ“ Health check complete!\n');
304
296
 
305
297
  // 5. Format and output results
306
298
  if (format === 'json') {
@@ -309,11 +301,11 @@ async function doctorCommand(stackName, options = {}) {
309
301
  if (options.output) {
310
302
  writeOutputFile(jsonOutput, options.output);
311
303
  } else {
312
- output.log(jsonOutput);
304
+ console.log(jsonOutput);
313
305
  }
314
306
  } else {
315
307
  const consoleOutput = formatConsoleOutput(report, options);
316
- output.log(consoleOutput);
308
+ console.log(consoleOutput);
317
309
 
318
310
  if (options.output) {
319
311
  writeOutputFile(consoleOutput, options.output);
@@ -330,27 +322,14 @@ async function doctorCommand(stackName, options = {}) {
330
322
  process.exit(0);
331
323
  }
332
324
  } catch (error) {
333
- output.error(` Health check failed: ${error.message}`);
325
+ console.error(`\nāœ— Health check failed: ${error.message}`);
334
326
 
335
327
  if (options.verbose && error.stack) {
336
- output.error(`\nStack trace:\n${error.stack}`);
328
+ console.error(`\nStack trace:\n${error.stack}`);
337
329
  }
338
330
 
339
331
  process.exit(1);
340
332
  }
341
333
  }
342
334
 
343
- /**
344
- * Check if the current appDefinition uses a non-AWS provider.
345
- */
346
- function isNonAwsProvider() {
347
- try {
348
- const { loadProviderForCli } = require('../utils/provider-helper');
349
- const result = loadProviderForCli();
350
- return result && result.providerName !== 'aws';
351
- } catch {
352
- return false;
353
- }
354
- }
355
-
356
335
  module.exports = { doctorCommand };
@@ -9,14 +9,7 @@ const { generateIAMCloudFormation, getFeatureSummary } = require('../infrastruct
9
9
  */
10
10
  async function generateIamCommand(options = {}) {
11
11
  try {
12
- // Guard: generate-iam only works with AWS (IAM / CloudFormation)
13
- if (isNonAwsProvider()) {
14
- console.error('The generate-iam command is only available for AWS deployments.');
15
- console.log('Your appDefinition uses a non-AWS provider.');
16
- process.exit(1);
17
- }
18
-
19
- console.log('Finding Frigg application...');
12
+ console.log('šŸ” Finding Frigg application...');
20
13
 
21
14
  // Find the backend package.json
22
15
  const backendPath = findNearestBackendPackageJson();
@@ -122,17 +115,4 @@ async function generateIamCommand(options = {}) {
122
115
  }
123
116
  }
124
117
 
125
- /**
126
- * Check if the current appDefinition uses a non-AWS provider.
127
- */
128
- function isNonAwsProvider() {
129
- try {
130
- const { loadProviderForCli } = require('./utils/provider-helper');
131
- const result = loadProviderForCli();
132
- return result && result.providerName !== 'aws';
133
- } catch {
134
- return false;
135
- }
136
- }
137
-
138
118
  module.exports = { generateIamCommand };
@@ -86,23 +86,15 @@ const { dbSetupCommand } = require('./db-setup-command');
86
86
  const { doctorCommand } = require('./doctor-command');
87
87
  const { repairCommand } = require('./repair-command');
88
88
  const { authCommand } = require('./auth-command');
89
- const { createValidateCommand } = require('./validate-command/adapters/cli/validate-command');
90
89
 
91
90
  const program = new Command();
92
91
 
93
- // Add version command using package.json version
94
- const packageJson = require('./package.json');
95
92
  program
96
- .version(packageJson.version, '-v, --version', 'output the current version');
97
-
98
- program
99
- .command('init <projectName>')
93
+ .command('init [templateName]')
100
94
  .description('Initialize a new Frigg application')
101
- .option('-m, --mode <mode>', 'deployment mode: standalone or embedded')
102
- .option('-f, --force', 'overwrite existing files')
103
- .option('--frontend <value>', 'include demo frontend (true/false)')
104
- .option('-y, --yes', 'accept defaults without prompting')
105
- .option('--verbose', 'enable verbose output')
95
+ .option('-t, --template <template>', 'template to use', 'backend-only')
96
+ .option('-n, --name <name>', 'project name')
97
+ .option('-d, --directory <directory>', 'target directory')
106
98
  .action(initCommand);
107
99
 
108
100
  program
@@ -115,8 +107,6 @@ program
115
107
  .description('Run the backend and optional frontend')
116
108
  .option('-s, --stage <stage>', 'deployment stage', 'dev')
117
109
  .option('-v, --verbose', 'enable verbose output')
118
- .option('--ipc', 'enable IPC mode for Management UI communication')
119
- .option('--no-interactive', 'skip interactive pre-flight prompts')
120
110
  .action(startCommand);
121
111
 
122
112
  program
@@ -179,8 +169,6 @@ program
179
169
  .option('-v, --verbose', 'enable verbose output')
180
170
  .action(repairCommand);
181
171
 
182
- createValidateCommand(program);
183
-
184
172
  // Auth command group for testing API module authentication
185
173
  const authProgram = program
186
174
  .command('auth')
@@ -215,9 +203,6 @@ authProgram
215
203
  .option('-y, --yes', 'Skip confirmation')
216
204
  .action(authCommand.delete);
217
205
 
218
- // Only parse arguments when run directly, not when imported by tests
219
- if (require.main === module) {
220
- program.parse(process.argv);
221
- }
206
+ program.parse(process.argv);
222
207
 
223
- module.exports = { initCommand, installCommand, startCommand, buildCommand, deployCommand, generateIamCommand, uiCommand, dbSetupCommand, doctorCommand, repairCommand, authCommand, createValidateCommand, program };
208
+ module.exports = { initCommand, installCommand, startCommand, buildCommand, deployCommand, generateIamCommand, uiCommand, dbSetupCommand, doctorCommand, repairCommand, authCommand };
@@ -6,14 +6,9 @@ const { installPackage } = require('./install-command/install-package');
6
6
  const { createIntegrationFile } = require('./install-command/integration-file');
7
7
  const { updateBackendJsFile } = require('./install-command/backend-js');
8
8
  const { commitChanges } = require('./install-command/commit-changes');
9
+ const { logInfo, logError } = require('./install-command/logger');
9
10
 
10
- /**
11
- * @group unit
12
- * @group infrastructure
13
- */
14
- // TODO: Fix these tests - they have issues with Commander.js mocking
15
- // The mocks need to be set up before the module is loaded, not inline in tests
16
- describe.skip('CLI Command Tests', () => {
11
+ describe('CLI Command Tests', () => {
17
12
  it('should successfully install an API module when all steps complete without errors', async () => {
18
13
  const mockApiModuleName = 'testModule';
19
14
  const mockPackageName = `@friggframework/api-module-${mockApiModuleName}`;