@friggframework/devtools 2.0.0--canary.522.923dfae.0 → 2.0.0--canary.540.c5ef83f.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 (119) hide show
  1. package/frigg-cli/README.md +1 -1
  2. package/frigg-cli/__tests__/unit/commands/doctor.test.js +2 -0
  3. package/frigg-cli/__tests__/unit/commands/install.test.js +19 -23
  4. package/frigg-cli/__tests__/unit/dependencies.test.js +2 -2
  5. package/frigg-cli/doctor-command/index.js +16 -17
  6. package/frigg-cli/index.js +6 -21
  7. package/frigg-cli/index.test.js +2 -7
  8. package/frigg-cli/init-command/backend-first-handler.js +42 -124
  9. package/frigg-cli/init-command/index.js +1 -2
  10. package/frigg-cli/init-command/template-handler.js +3 -13
  11. package/frigg-cli/install-command/backend-js.js +3 -3
  12. package/frigg-cli/install-command/environment-variables.js +19 -16
  13. package/frigg-cli/install-command/environment-variables.test.js +13 -12
  14. package/frigg-cli/install-command/index.js +9 -14
  15. package/frigg-cli/install-command/integration-file.js +3 -3
  16. package/frigg-cli/install-command/logger.js +12 -0
  17. package/frigg-cli/install-command/validate-package.js +9 -5
  18. package/frigg-cli/jest.config.js +1 -4
  19. package/frigg-cli/repair-command/index.js +128 -101
  20. package/frigg-cli/start-command/index.js +2 -246
  21. package/frigg-cli/ui-command/index.js +36 -58
  22. package/frigg-cli/utils/repo-detection.js +37 -85
  23. package/infrastructure/docs/iam-policy-templates.md +1 -1
  24. package/infrastructure/domains/networking/vpc-builder.test.js +4 -2
  25. package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
  26. package/infrastructure/domains/shared/cloudformation-discovery.test.js +7 -4
  27. package/infrastructure/domains/shared/resource-discovery.js +5 -5
  28. package/infrastructure/domains/shared/types/app-definition.js +0 -21
  29. package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
  30. package/infrastructure/domains/shared/utilities/base-definition-factory.js +1 -10
  31. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
  32. package/infrastructure/infrastructure-composer.test.js +2 -2
  33. package/management-ui/README.md +109 -245
  34. package/package.json +7 -8
  35. package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +0 -326
  36. package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +0 -337
  37. package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +0 -373
  38. package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +0 -313
  39. package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +0 -269
  40. package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +0 -82
  41. package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +0 -408
  42. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +0 -583
  43. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +0 -314
  44. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +0 -383
  45. package/frigg-cli/__tests__/unit/commands/init.test.js +0 -406
  46. package/frigg-cli/__tests__/unit/commands/repair.test.js +0 -275
  47. package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +0 -411
  48. package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +0 -405
  49. package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +0 -496
  50. package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +0 -474
  51. package/frigg-cli/__tests__/unit/utils/output.test.js +0 -196
  52. package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +0 -93
  53. package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +0 -93
  54. package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +0 -103
  55. package/frigg-cli/container.js +0 -172
  56. package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +0 -286
  57. package/frigg-cli/domain/entities/ApiModule.js +0 -272
  58. package/frigg-cli/domain/entities/AppDefinition.js +0 -227
  59. package/frigg-cli/domain/entities/Integration.js +0 -198
  60. package/frigg-cli/domain/exceptions/DomainException.js +0 -24
  61. package/frigg-cli/domain/ports/IApiModuleRepository.js +0 -53
  62. package/frigg-cli/domain/ports/IAppDefinitionRepository.js +0 -43
  63. package/frigg-cli/domain/ports/IIntegrationRepository.js +0 -61
  64. package/frigg-cli/domain/services/IntegrationValidator.js +0 -185
  65. package/frigg-cli/domain/value-objects/IntegrationId.js +0 -42
  66. package/frigg-cli/domain/value-objects/IntegrationName.js +0 -60
  67. package/frigg-cli/domain/value-objects/SemanticVersion.js +0 -70
  68. package/frigg-cli/infrastructure/UnitOfWork.js +0 -46
  69. package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +0 -197
  70. package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +0 -224
  71. package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +0 -249
  72. package/frigg-cli/infrastructure/adapters/SchemaValidator.js +0 -92
  73. package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +0 -373
  74. package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +0 -116
  75. package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +0 -277
  76. package/frigg-cli/package-lock.json +0 -16226
  77. package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +0 -376
  78. package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +0 -591
  79. package/frigg-cli/start-command/infrastructure/DockerAdapter.js +0 -306
  80. package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +0 -329
  81. package/frigg-cli/templates/backend/.env.example +0 -62
  82. package/frigg-cli/templates/backend/.eslintrc.json +0 -12
  83. package/frigg-cli/templates/backend/.prettierrc +0 -6
  84. package/frigg-cli/templates/backend/docker-compose.yml +0 -22
  85. package/frigg-cli/templates/backend/index.js +0 -96
  86. package/frigg-cli/templates/backend/infrastructure.js +0 -12
  87. package/frigg-cli/templates/backend/jest.config.js +0 -17
  88. package/frigg-cli/templates/backend/package.json +0 -50
  89. package/frigg-cli/templates/backend/src/api-modules/.gitkeep +0 -10
  90. package/frigg-cli/templates/backend/src/base/.gitkeep +0 -7
  91. package/frigg-cli/templates/backend/src/integrations/.gitkeep +0 -10
  92. package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +0 -65
  93. package/frigg-cli/templates/backend/src/utils/.gitkeep +0 -7
  94. package/frigg-cli/templates/backend/test/setup.js +0 -30
  95. package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
  96. package/frigg-cli/templates/backend/ui-extensions/README.md +0 -77
  97. package/frigg-cli/utils/__tests__/repo-detection.test.js +0 -436
  98. package/frigg-cli/utils/output.js +0 -382
  99. package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +0 -205
  100. package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +0 -104
  101. package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +0 -153
  102. package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +0 -162
  103. package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +0 -152
  104. package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +0 -332
  105. package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +0 -191
  106. package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +0 -146
  107. package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +0 -155
  108. package/frigg-cli/validate-command/adapters/cli/validate-command.js +0 -199
  109. package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +0 -35
  110. package/frigg-cli/validate-command/domain/entities/validation-result.js +0 -74
  111. package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +0 -74
  112. package/frigg-cli/validate-command/domain/value-objects/validation-error.js +0 -68
  113. package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +0 -181
  114. package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +0 -128
  115. package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +0 -113
  116. package/infrastructure/domains/admin-scripts/admin-script-builder.js +0 -200
  117. package/infrastructure/domains/admin-scripts/admin-script-builder.test.js +0 -499
  118. package/infrastructure/domains/admin-scripts/index.js +0 -5
  119. 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
 
@@ -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
 
@@ -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,
@@ -258,7 +257,7 @@ async function doctorCommand(stackName, options = {}) {
258
257
  }
259
258
 
260
259
  // Show progress to user (always, not just verbose mode)
261
- output.info(`šŸ„ Running health check on stack: ${stackName} (${region})\n`);
260
+ console.log(`\nšŸ„ Running health check on stack: ${stackName} (${region})\n`);
262
261
 
263
262
  // 1. Create stack identifier
264
263
  const stackIdentifier = new StackIdentifier({ stackName, region });
@@ -282,9 +281,9 @@ async function doctorCommand(stackName, options = {}) {
282
281
  // Progress callback to show execution status
283
282
  const progressCallback = (step, message) => {
284
283
  if (verbose) {
285
- output.log(` ${message}`);
284
+ console.log(` ${message}`);
286
285
  } else {
287
- output.log(`${step} ${message}`);
286
+ console.log(`${step} ${message}`);
288
287
  }
289
288
  };
290
289
 
@@ -293,7 +292,7 @@ async function doctorCommand(stackName, options = {}) {
293
292
  onProgress: progressCallback
294
293
  });
295
294
 
296
- output.success(' Health check complete!\n');
295
+ console.log('āœ“ Health check complete!\n');
297
296
 
298
297
  // 5. Format and output results
299
298
  if (format === 'json') {
@@ -302,11 +301,11 @@ async function doctorCommand(stackName, options = {}) {
302
301
  if (options.output) {
303
302
  writeOutputFile(jsonOutput, options.output);
304
303
  } else {
305
- output.log(jsonOutput);
304
+ console.log(jsonOutput);
306
305
  }
307
306
  } else {
308
307
  const consoleOutput = formatConsoleOutput(report, options);
309
- output.log(consoleOutput);
308
+ console.log(consoleOutput);
310
309
 
311
310
  if (options.output) {
312
311
  writeOutputFile(consoleOutput, options.output);
@@ -323,10 +322,10 @@ async function doctorCommand(stackName, options = {}) {
323
322
  process.exit(0);
324
323
  }
325
324
  } catch (error) {
326
- output.error(` Health check failed: ${error.message}`);
325
+ console.error(`\nāœ— Health check failed: ${error.message}`);
327
326
 
328
327
  if (options.verbose && error.stack) {
329
- output.error(`\nStack trace:\n${error.stack}`);
328
+ console.error(`\nStack trace:\n${error.stack}`);
330
329
  }
331
330
 
332
331
  process.exit(1);
@@ -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}`;
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs-extra');
2
2
  const path = require('path');
3
3
  const chalk = require('chalk');
4
- const { select, confirm, checkbox } = require('@inquirer/prompts');
4
+ const { select, confirm, multiselect } = require('@inquirer/prompts');
5
5
  const { execSync } = require('child_process');
6
6
  const spawn = require('cross-spawn');
7
7
  const npmRegistry = require('../utils/npm-registry');
@@ -35,15 +35,15 @@ class BackendFirstHandler {
35
35
  await this.createProject(deploymentMode, config);
36
36
 
37
37
  console.log(chalk.green('\nāœ… Frigg application created successfully!'));
38
-
39
- // If user needs custom API module, prompt to create it (skip in --yes mode)
40
- if (config.needsCustomApiModule && !this.options.yes) {
38
+
39
+ // If user needs custom API module, prompt to create it
40
+ if (config.needsCustomApiModule) {
41
41
  console.log(chalk.cyan('\nšŸ”§ Now let\'s create your custom API module...'));
42
42
  const createModule = await confirm({
43
43
  message: 'Would you like to create your custom API module now?',
44
44
  default: true
45
45
  });
46
-
46
+
47
47
  if (createModule) {
48
48
  console.log(chalk.gray('\n Run this command after setup:'));
49
49
  console.log(chalk.cyan(` cd ${path.relative(process.cwd(), this.targetPath)}`));
@@ -62,11 +62,6 @@ class BackendFirstHandler {
62
62
  return this.options.mode;
63
63
  }
64
64
 
65
- // If --yes flag is set, use default
66
- if (this.options.yes) {
67
- return 'standalone';
68
- }
69
-
70
65
  const mode = await select({
71
66
  message: 'How will you deploy this Frigg application?',
72
67
  choices: [
@@ -93,21 +88,6 @@ class BackendFirstHandler {
93
88
  async getProjectConfiguration(deploymentMode) {
94
89
  const config = { deploymentMode };
95
90
 
96
- // If --yes flag is set, use all defaults
97
- if (this.options.yes) {
98
- return {
99
- deploymentMode,
100
- appPurpose: 'exploring',
101
- needsCustomApiModule: false,
102
- includeIntegrations: false,
103
- starterIntegrations: [],
104
- includeDemoFrontend: false,
105
- serverlessProvider: deploymentMode === 'standalone' ? 'aws' : undefined,
106
- installDependencies: true,
107
- initializeGit: true,
108
- };
109
- }
110
-
111
91
  // Ask about the purpose of this Frigg application
112
92
  config.appPurpose = await select({
113
93
  message: 'What are you building with Frigg?',
@@ -178,7 +158,7 @@ class BackendFirstHandler {
178
158
  }
179
159
  });
180
160
 
181
- config.starterIntegrations = await checkbox({
161
+ config.starterIntegrations = await multiselect({
182
162
  message: 'Select API modules to integrate (space to select, enter to confirm):',
183
163
  choices,
184
164
  instructions: '\n Press <space> to select, <a> to toggle all, <enter> to confirm\n',
@@ -286,115 +266,63 @@ class BackendFirstHandler {
286
266
 
287
267
  /**
288
268
  * Create standalone Frigg service
289
- *
290
- * Structure:
291
- * my-app/
292
- * ā”œā”€ā”€ package.json # Root - delegates to backend with "cd backend &&"
293
- * ā”œā”€ā”€ backend/ # Actual Frigg app with its own package.json & node_modules
294
- * │ ā”œā”€ā”€ index.js
295
- * │ ā”œā”€ā”€ infrastructure.js
296
- * │ ā”œā”€ā”€ package.json
297
- * │ └── src/
298
- * └── ui-extensions/ # Platform-specific UI extensions
299
- * └── README.md
300
269
  */
301
270
  async createStandaloneProject(config) {
302
- const backendPath = path.join(this.targetPath, 'backend');
303
- const uiExtensionsPath = path.join(this.targetPath, 'ui-extensions');
304
-
305
- // Copy backend template to backend/ subdirectory
271
+ // Copy backend template
306
272
  const backendTemplate = path.join(this.templatesDir, 'backend');
307
- await fs.copy(backendTemplate, backendPath);
308
-
309
- // Read template package.json
310
- const templatePackageJsonPath = path.join(backendPath, 'package.json');
311
- let templatePackageJson = {};
312
- if (await fs.pathExists(templatePackageJsonPath)) {
313
- templatePackageJson = await fs.readJSON(templatePackageJsonPath);
314
- }
273
+ await fs.copy(backendTemplate, this.targetPath);
315
274
 
316
- // Create backend package.json with all dependencies
317
- const backendPackageJson = {
318
- name: `${this.appName}-backend`,
275
+ // Create package.json for standalone mode
276
+ const packageJson = {
277
+ name: this.appName,
319
278
  version: '0.1.0',
320
279
  private: true,
321
- prettier: templatePackageJson.prettier || '@friggframework/prettier-config',
322
280
  scripts: {
323
- ...templatePackageJson.scripts,
324
281
  "backend-start": "node infrastructure.js start",
325
282
  "start": "npm run backend-start",
326
283
  "build": "node infrastructure.js package",
327
284
  "deploy": "node infrastructure.js deploy",
285
+ "test": "jest"
328
286
  },
329
287
  dependencies: {
330
- ...templatePackageJson.dependencies,
331
- "@friggframework/core": "2.0.0-next.58"
332
- },
333
- devDependencies: {
334
- ...templatePackageJson.devDependencies
335
- }
336
- };
337
-
338
- // Add selected integrations as dependencies to backend
339
- if (config.starterIntegrations && config.starterIntegrations.length > 0) {
340
- for (const integration of config.starterIntegrations) {
341
- backendPackageJson.dependencies[`@friggframework/api-module-${integration}`] = '^2.0.0';
342
- }
343
- }
344
-
345
- await fs.writeJSON(templatePackageJsonPath, backendPackageJson, { spaces: 2 });
346
-
347
- // Create root package.json that delegates to backend
348
- const rootPackageJson = {
349
- name: this.appName,
350
- version: '0.1.0',
351
- private: true,
352
- scripts: {
353
- "start": "cd backend && npm run frigg:start",
354
- "docker:start": "cd backend && npm run docker:start",
355
- "docker:stop": "cd backend && npm run docker:stop",
356
- "test": "cd backend && npm test",
357
- "build": "cd backend && npm run build",
358
- "deploy": "cd backend && npm run deploy",
359
- "lint": "cd backend && npm run lint",
360
- "format": "cd backend && npm run format"
288
+ "@friggframework/core": "^2.0.0"
361
289
  }
362
290
  };
363
291
 
364
292
  // Add demo frontend if requested
365
293
  if (config.includeDemoFrontend) {
366
- rootPackageJson.scripts['dev'] = 'concurrently "cd backend && npm run backend-start" "cd frontend && npm run dev"';
367
- rootPackageJson.scripts['frontend:dev'] = 'cd frontend && npm run dev';
368
- rootPackageJson.devDependencies = { concurrently: '^8.2.2' };
369
-
294
+ packageJson.workspaces = ['backend', 'frontend'];
295
+ packageJson.scripts['dev'] = 'concurrently "npm run backend-start" "npm run frontend:dev"';
296
+ packageJson.scripts['frontend:dev'] = 'cd frontend && npm run dev';
297
+
370
298
  await this.createDemoFrontend(config);
371
299
  }
372
300
 
301
+ // Add selected integrations as dependencies
302
+ if (config.starterIntegrations && config.starterIntegrations.length > 0) {
303
+ for (const integration of config.starterIntegrations) {
304
+ packageJson.dependencies[`@friggframework/api-module-${integration}`] = '^2.0.0';
305
+ }
306
+ }
307
+
373
308
  await fs.writeJSON(
374
309
  path.join(this.targetPath, 'package.json'),
375
- rootPackageJson,
310
+ packageJson,
376
311
  { spaces: 2 }
377
312
  );
378
313
 
379
- // Create ui-extensions directory with README
380
- await fs.ensureDir(uiExtensionsPath);
381
- const uiExtensionsReadme = path.join(this.templatesDir, 'backend', 'ui-extensions', 'README.md');
382
- if (await fs.pathExists(uiExtensionsReadme)) {
383
- await fs.copy(uiExtensionsReadme, path.join(uiExtensionsPath, 'README.md'));
384
- }
385
-
386
314
  // Update index.js with selected integrations
387
315
  if (config.starterIntegrations && config.starterIntegrations.length > 0) {
388
- await this.updateAppDefinition(config.starterIntegrations, backendPath);
316
+ await this.updateAppDefinition(config.starterIntegrations);
389
317
  }
390
318
 
391
319
  // Validate generated app definition against schema
392
- const appDefPath = path.join(backendPath, 'index.js');
320
+ const appDefPath = path.join(this.targetPath, 'index.js');
393
321
  await this.validateGeneratedAppDefinition(appDefPath);
394
322
 
395
323
  // Update serverless.yml based on provider
396
324
  if (config.serverlessProvider === 'aws') {
397
- await this.configureAWSServerless(backendPath);
325
+ await this.configureAWSServerless();
398
326
  }
399
327
  }
400
328
 
@@ -578,9 +506,9 @@ To integrate Frigg into your production application:
578
506
  /**
579
507
  * Configure AWS serverless
580
508
  */
581
- async configureAWSServerless(targetDir = this.targetPath) {
509
+ async configureAWSServerless() {
582
510
  // Update serverless.yml for AWS
583
- const serverlessPath = path.join(targetDir, 'serverless.yml');
511
+ const serverlessPath = path.join(this.targetPath, 'serverless.yml');
584
512
  if (await fs.pathExists(serverlessPath)) {
585
513
  // Keep existing AWS configuration
586
514
  console.log(chalk.gray('AWS Lambda configuration ready'));
@@ -605,25 +533,23 @@ To integrate Frigg into your production application:
605
533
  }
606
534
 
607
535
  /**
608
- * Install dependencies in the backend directory
536
+ * Install dependencies
609
537
  */
610
538
  async installDependencies(config) {
611
- console.log(chalk.blue('\nšŸ“¦ Installing dependencies in backend...'));
612
-
539
+ console.log(chalk.blue('\nšŸ“¦ Installing dependencies...'));
540
+
613
541
  const useYarn = this.isUsingYarn();
614
542
  const command = useYarn ? 'yarn' : 'npm';
615
543
  const args = useYarn ? [] : ['install'];
616
544
 
617
- // Install in backend directory where package.json with dependencies lives
618
- const backendPath = path.join(this.targetPath, 'backend');
619
545
  const proc = spawn.sync(command, args, {
620
- cwd: backendPath,
546
+ cwd: this.targetPath,
621
547
  stdio: 'inherit'
622
548
  });
623
549
 
624
550
  if (proc.status !== 0) {
625
551
  console.log(chalk.yellow('\nāš ļø Dependency installation failed'));
626
- console.log(chalk.gray(`You can install manually with: cd backend && ${command} install`));
552
+ console.log(chalk.gray(`You can install manually with: ${command} install`));
627
553
  }
628
554
  }
629
555
 
@@ -651,7 +577,7 @@ To integrate Frigg into your production application:
651
577
  * Select from default integrations when npm is unavailable
652
578
  */
653
579
  async selectDefaultIntegrations() {
654
- return await checkbox({
580
+ return await multiselect({
655
581
  message: 'Select starter integrations (space to select, enter to confirm):',
656
582
  choices: [
657
583
  { name: 'Salesforce - CRM integration', value: 'salesforce' },
@@ -670,8 +596,8 @@ To integrate Frigg into your production application:
670
596
  /**
671
597
  * Update index.js with selected integrations
672
598
  */
673
- async updateAppDefinition(integrations, targetDir = this.targetPath) {
674
- const appDefPath = path.join(targetDir, 'index.js');
599
+ async updateAppDefinition(integrations) {
600
+ const appDefPath = path.join(this.targetPath, 'index.js');
675
601
  if (await fs.pathExists(appDefPath)) {
676
602
  let content = await fs.readFile(appDefPath, 'utf8');
677
603
 
@@ -794,18 +720,14 @@ To integrate Frigg into your production application:
794
720
  console.log(chalk.cyan(` cd ${cdPath}\n`));
795
721
 
796
722
  if (deploymentMode === 'standalone') {
797
- console.log(`2. Install backend dependencies:`);
798
- console.log(chalk.cyan(` cd backend && npm install\n`));
799
-
800
- console.log(`3. Start the development server:`);
723
+ console.log(`2. Start the development server:`);
801
724
  console.log(chalk.cyan(` npm start\n`));
802
- console.log(chalk.gray(` (or from backend: npm run frigg:start)\n`));
803
725
 
804
- console.log(`4. Open the Frigg UI for development:`);
726
+ console.log(`3. Open the Frigg UI for development:`);
805
727
  console.log(chalk.cyan(` frigg ui\n`));
806
728
 
807
729
  if (config.serverlessProvider === 'aws') {
808
- console.log(`5. Deploy to AWS Lambda:`);
730
+ console.log(`4. Deploy to AWS Lambda:`);
809
731
  console.log(chalk.cyan(` npm run deploy\n`));
810
732
  }
811
733
  } else {
@@ -825,12 +747,8 @@ To integrate Frigg into your production application:
825
747
  console.log(chalk.gray(' See frontend/README.md for integration guidance.'));
826
748
  }
827
749
 
828
- console.log(chalk.gray('\nšŸ“ Project Structure:'));
829
- console.log(chalk.gray(' backend/ - Frigg app (run npm install here)'));
830
- console.log(chalk.gray(' ui-extensions/ - Platform-specific UI extensions'));
831
-
832
750
  console.log(chalk.green('\nšŸŽ‰ Happy integrating with Frigg!\n'));
833
- console.log(chalk.gray('Documentation: https://docs.friggframework.org'));
751
+ console.log(chalk.gray('Documentation: https://docs.frigg.dev'));
834
752
  console.log(chalk.gray('Support: https://github.com/friggframework/frigg/issues'));
835
753
  }
836
754
  }
@@ -68,8 +68,7 @@ async function initCommand(projectName, options) {
68
68
  force,
69
69
  verbose,
70
70
  mode: options.mode,
71
- frontend: options.frontend,
72
- yes: options.yes
71
+ frontend: options.frontend
73
72
  });
74
73
 
75
74
  await handler.initialize();