@friggframework/devtools 2.0.0--canary.522.cbd3d5a.0 → 2.0.0--canary.517.21b69ac.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 (247) hide show
  1. package/.eslintrc.json +3 -0
  2. package/CHANGELOG.md +132 -0
  3. package/frigg-cli/README.md +1 -1
  4. package/frigg-cli/__tests__/unit/commands/doctor.test.js +2 -0
  5. package/frigg-cli/__tests__/unit/commands/install.test.js +17 -21
  6. package/frigg-cli/doctor-command/index.js +16 -17
  7. package/frigg-cli/index.js +6 -21
  8. package/frigg-cli/index.test.js +1 -7
  9. package/frigg-cli/init-command/backend-first-handler.js +42 -124
  10. package/frigg-cli/init-command/index.js +1 -2
  11. package/frigg-cli/init-command/template-handler.js +3 -13
  12. package/frigg-cli/install-command/backend-js.js +3 -3
  13. package/frigg-cli/install-command/environment-variables.js +19 -16
  14. package/frigg-cli/install-command/environment-variables.test.js +13 -12
  15. package/frigg-cli/install-command/index.js +9 -14
  16. package/frigg-cli/install-command/integration-file.js +3 -3
  17. package/frigg-cli/install-command/logger.js +12 -0
  18. package/frigg-cli/install-command/validate-package.js +9 -5
  19. package/frigg-cli/jest.config.js +1 -4
  20. package/frigg-cli/repair-command/index.js +128 -101
  21. package/frigg-cli/start-command/index.js +2 -246
  22. package/frigg-cli/ui-command/index.js +36 -58
  23. package/frigg-cli/utils/repo-detection.js +37 -85
  24. package/infrastructure/docs/iam-policy-templates.md +1 -1
  25. package/infrastructure/domains/networking/vpc-builder.test.js +4 -2
  26. package/infrastructure/domains/networking/vpc-resolver.test.js +1 -1
  27. package/infrastructure/domains/shared/cloudformation-discovery.test.js +7 -4
  28. package/infrastructure/domains/shared/resource-discovery.js +5 -5
  29. package/infrastructure/domains/shared/types/discovery-result.test.js +1 -1
  30. package/infrastructure/domains/shared/utilities/base-definition-factory.js +2 -25
  31. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +2 -2
  32. package/infrastructure/infrastructure-composer.test.js +2 -2
  33. package/layers/prisma/.build-complete +3 -0
  34. package/layers/prisma/nodejs/package.json +8 -0
  35. package/management-ui/.eslintrc.js +22 -0
  36. package/management-ui/README.md +109 -245
  37. package/management-ui/components.json +21 -0
  38. package/management-ui/docs/phase2-integration-guide.md +320 -0
  39. package/management-ui/index.html +13 -0
  40. package/management-ui/package.json +76 -0
  41. package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
  42. package/management-ui/postcss.config.js +6 -0
  43. package/management-ui/server/api/backend.js +256 -0
  44. package/management-ui/server/api/cli.js +315 -0
  45. package/management-ui/server/api/codegen.js +663 -0
  46. package/management-ui/server/api/connections.js +857 -0
  47. package/management-ui/server/api/discovery.js +185 -0
  48. package/management-ui/server/api/environment/index.js +1 -0
  49. package/management-ui/server/api/environment/router.js +378 -0
  50. package/management-ui/server/api/environment.js +328 -0
  51. package/management-ui/server/api/integrations.js +876 -0
  52. package/management-ui/server/api/logs.js +248 -0
  53. package/management-ui/server/api/monitoring.js +282 -0
  54. package/management-ui/server/api/open-ide.js +31 -0
  55. package/management-ui/server/api/project.js +1029 -0
  56. package/management-ui/server/api/users/sessions.js +371 -0
  57. package/management-ui/server/api/users/simulation.js +254 -0
  58. package/management-ui/server/api/users.js +362 -0
  59. package/management-ui/server/api-contract.md +275 -0
  60. package/management-ui/server/index.js +873 -0
  61. package/management-ui/server/middleware/errorHandler.js +93 -0
  62. package/management-ui/server/middleware/security.js +32 -0
  63. package/management-ui/server/processManager.js +296 -0
  64. package/management-ui/server/server.js +346 -0
  65. package/management-ui/server/services/aws-monitor.js +413 -0
  66. package/management-ui/server/services/npm-registry.js +347 -0
  67. package/management-ui/server/services/template-engine.js +538 -0
  68. package/management-ui/server/utils/cliIntegration.js +220 -0
  69. package/management-ui/server/utils/environment/auditLogger.js +471 -0
  70. package/management-ui/server/utils/environment/awsParameterStore.js +275 -0
  71. package/management-ui/server/utils/environment/encryption.js +278 -0
  72. package/management-ui/server/utils/environment/envFileManager.js +286 -0
  73. package/management-ui/server/utils/import-commonjs.js +28 -0
  74. package/management-ui/server/utils/response.js +83 -0
  75. package/management-ui/server/websocket/handler.js +325 -0
  76. package/management-ui/src/App.jsx +25 -0
  77. package/management-ui/src/assets/FriggLogo.svg +1 -0
  78. package/management-ui/src/components/AppRouter.jsx +65 -0
  79. package/management-ui/src/components/Button.jsx +70 -0
  80. package/management-ui/src/components/Card.jsx +97 -0
  81. package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
  82. package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
  83. package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
  84. package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
  85. package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
  86. package/management-ui/src/components/ErrorBoundary.jsx +73 -0
  87. package/management-ui/src/components/IntegrationCard.jsx +481 -0
  88. package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
  89. package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
  90. package/management-ui/src/components/IntegrationStatus.jsx +336 -0
  91. package/management-ui/src/components/Layout.jsx +716 -0
  92. package/management-ui/src/components/LoadingSpinner.jsx +113 -0
  93. package/management-ui/src/components/RepositoryPicker.jsx +248 -0
  94. package/management-ui/src/components/SessionMonitor.jsx +350 -0
  95. package/management-ui/src/components/StatusBadge.jsx +208 -0
  96. package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
  97. package/management-ui/src/components/UserSimulation.jsx +327 -0
  98. package/management-ui/src/components/Welcome.jsx +434 -0
  99. package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
  100. package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
  101. package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
  102. package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
  103. package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
  104. package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
  105. package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
  106. package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
  107. package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
  108. package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
  109. package/management-ui/src/components/codegen/index.js +10 -0
  110. package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
  111. package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
  112. package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
  113. package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
  114. package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
  115. package/management-ui/src/components/connections/index.js +5 -0
  116. package/management-ui/src/components/index.js +21 -0
  117. package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
  118. package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
  119. package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
  120. package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
  121. package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
  122. package/management-ui/src/components/monitoring/index.js +6 -0
  123. package/management-ui/src/components/monitoring/monitoring.css +218 -0
  124. package/management-ui/src/components/theme-provider.jsx +52 -0
  125. package/management-ui/src/components/theme-toggle.jsx +39 -0
  126. package/management-ui/src/components/ui/badge.tsx +36 -0
  127. package/management-ui/src/components/ui/button.test.jsx +56 -0
  128. package/management-ui/src/components/ui/button.tsx +57 -0
  129. package/management-ui/src/components/ui/card.tsx +76 -0
  130. package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
  131. package/management-ui/src/components/ui/select.tsx +157 -0
  132. package/management-ui/src/components/ui/skeleton.jsx +15 -0
  133. package/management-ui/src/hooks/useFrigg.jsx +387 -0
  134. package/management-ui/src/hooks/useSocket.jsx +58 -0
  135. package/management-ui/src/index.css +193 -0
  136. package/management-ui/src/lib/utils.ts +6 -0
  137. package/management-ui/src/main.jsx +10 -0
  138. package/management-ui/src/pages/CodeGeneration.jsx +14 -0
  139. package/management-ui/src/pages/Connections.jsx +252 -0
  140. package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
  141. package/management-ui/src/pages/Dashboard.jsx +311 -0
  142. package/management-ui/src/pages/Environment.jsx +314 -0
  143. package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
  144. package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
  145. package/management-ui/src/pages/IntegrationTest.jsx +742 -0
  146. package/management-ui/src/pages/Integrations.jsx +253 -0
  147. package/management-ui/src/pages/Monitoring.jsx +17 -0
  148. package/management-ui/src/pages/Simulation.jsx +155 -0
  149. package/management-ui/src/pages/Users.jsx +492 -0
  150. package/management-ui/src/services/api.js +41 -0
  151. package/management-ui/src/services/apiModuleService.js +193 -0
  152. package/management-ui/src/services/websocket-handlers.js +120 -0
  153. package/management-ui/src/test/api/project.test.js +273 -0
  154. package/management-ui/src/test/components/Welcome.test.jsx +378 -0
  155. package/management-ui/src/test/mocks/server.js +178 -0
  156. package/management-ui/src/test/setup.js +61 -0
  157. package/management-ui/src/test/utils/test-utils.jsx +134 -0
  158. package/management-ui/src/utils/repository.js +98 -0
  159. package/management-ui/src/utils/repository.test.js +118 -0
  160. package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
  161. package/management-ui/tailwind.config.js +63 -0
  162. package/management-ui/tsconfig.json +37 -0
  163. package/management-ui/tsconfig.node.json +10 -0
  164. package/management-ui/vite.config.js +26 -0
  165. package/management-ui/vitest.config.js +38 -0
  166. package/package.json +7 -17
  167. package/frigg-cli/__tests__/application/use-cases/AddApiModuleToIntegrationUseCase.test.js +0 -326
  168. package/frigg-cli/__tests__/application/use-cases/CreateApiModuleUseCase.test.js +0 -337
  169. package/frigg-cli/__tests__/domain/entities/ApiModule.test.js +0 -373
  170. package/frigg-cli/__tests__/domain/entities/AppDefinition.test.js +0 -313
  171. package/frigg-cli/__tests__/domain/services/IntegrationValidator.test.js +0 -269
  172. package/frigg-cli/__tests__/domain/value-objects/IntegrationName.test.js +0 -82
  173. package/frigg-cli/__tests__/infrastructure/adapters/IntegrationJsUpdater.test.js +0 -408
  174. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemApiModuleRepository.test.js +0 -583
  175. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemAppDefinitionRepository.test.js +0 -314
  176. package/frigg-cli/__tests__/infrastructure/repositories/FileSystemIntegrationRepository.test.js +0 -430
  177. package/frigg-cli/__tests__/unit/commands/init.test.js +0 -406
  178. package/frigg-cli/__tests__/unit/commands/repair.test.js +0 -275
  179. package/frigg-cli/__tests__/unit/start-command/application/RunPreflightChecksUseCase.test.js +0 -411
  180. package/frigg-cli/__tests__/unit/start-command/infrastructure/DatabaseAdapter.test.js +0 -405
  181. package/frigg-cli/__tests__/unit/start-command/infrastructure/DockerAdapter.test.js +0 -496
  182. package/frigg-cli/__tests__/unit/start-command/presentation/InteractivePromptAdapter.test.js +0 -474
  183. package/frigg-cli/__tests__/unit/utils/output.test.js +0 -196
  184. package/frigg-cli/application/use-cases/AddApiModuleToIntegrationUseCase.js +0 -93
  185. package/frigg-cli/application/use-cases/CreateApiModuleUseCase.js +0 -93
  186. package/frigg-cli/application/use-cases/CreateIntegrationUseCase.js +0 -103
  187. package/frigg-cli/container.js +0 -172
  188. package/frigg-cli/docs/OUTPUT_MIGRATION_GUIDE.md +0 -286
  189. package/frigg-cli/domain/entities/ApiModule.js +0 -272
  190. package/frigg-cli/domain/entities/AppDefinition.js +0 -227
  191. package/frigg-cli/domain/entities/Integration.js +0 -198
  192. package/frigg-cli/domain/exceptions/DomainException.js +0 -24
  193. package/frigg-cli/domain/ports/IApiModuleRepository.js +0 -53
  194. package/frigg-cli/domain/ports/IAppDefinitionRepository.js +0 -43
  195. package/frigg-cli/domain/ports/IIntegrationRepository.js +0 -61
  196. package/frigg-cli/domain/services/IntegrationValidator.js +0 -185
  197. package/frigg-cli/domain/value-objects/IntegrationId.js +0 -42
  198. package/frigg-cli/domain/value-objects/IntegrationName.js +0 -60
  199. package/frigg-cli/domain/value-objects/SemanticVersion.js +0 -70
  200. package/frigg-cli/infrastructure/UnitOfWork.js +0 -46
  201. package/frigg-cli/infrastructure/adapters/BackendJsUpdater.js +0 -197
  202. package/frigg-cli/infrastructure/adapters/FileSystemAdapter.js +0 -224
  203. package/frigg-cli/infrastructure/adapters/IntegrationJsUpdater.js +0 -249
  204. package/frigg-cli/infrastructure/adapters/SchemaValidator.js +0 -92
  205. package/frigg-cli/infrastructure/repositories/FileSystemApiModuleRepository.js +0 -373
  206. package/frigg-cli/infrastructure/repositories/FileSystemAppDefinitionRepository.js +0 -116
  207. package/frigg-cli/infrastructure/repositories/FileSystemIntegrationRepository.js +0 -277
  208. package/frigg-cli/package-lock.json +0 -16226
  209. package/frigg-cli/start-command/application/RunPreflightChecksUseCase.js +0 -376
  210. package/frigg-cli/start-command/infrastructure/DatabaseAdapter.js +0 -591
  211. package/frigg-cli/start-command/infrastructure/DockerAdapter.js +0 -306
  212. package/frigg-cli/start-command/presentation/InteractivePromptAdapter.js +0 -329
  213. package/frigg-cli/templates/backend/.env.example +0 -62
  214. package/frigg-cli/templates/backend/.eslintrc.json +0 -12
  215. package/frigg-cli/templates/backend/.prettierrc +0 -6
  216. package/frigg-cli/templates/backend/docker-compose.yml +0 -22
  217. package/frigg-cli/templates/backend/index.js +0 -96
  218. package/frigg-cli/templates/backend/infrastructure.js +0 -12
  219. package/frigg-cli/templates/backend/jest.config.js +0 -17
  220. package/frigg-cli/templates/backend/package.json +0 -50
  221. package/frigg-cli/templates/backend/src/api-modules/.gitkeep +0 -10
  222. package/frigg-cli/templates/backend/src/base/.gitkeep +0 -7
  223. package/frigg-cli/templates/backend/src/integrations/.gitkeep +0 -10
  224. package/frigg-cli/templates/backend/src/integrations/ExampleIntegration.js +0 -65
  225. package/frigg-cli/templates/backend/src/utils/.gitkeep +0 -7
  226. package/frigg-cli/templates/backend/test/setup.js +0 -30
  227. package/frigg-cli/templates/backend/ui-extensions/.gitkeep +0 -0
  228. package/frigg-cli/templates/backend/ui-extensions/README.md +0 -77
  229. package/frigg-cli/utils/__tests__/repo-detection.test.js +0 -436
  230. package/frigg-cli/utils/output.js +0 -382
  231. package/frigg-cli/validate-command/__tests__/adapters/validate-command.test.js +0 -205
  232. package/frigg-cli/validate-command/__tests__/application/validate-app-use-case.test.js +0 -104
  233. package/frigg-cli/validate-command/__tests__/domain/fix-suggestion.test.js +0 -153
  234. package/frigg-cli/validate-command/__tests__/domain/validation-error.test.js +0 -162
  235. package/frigg-cli/validate-command/__tests__/domain/validation-result.test.js +0 -152
  236. package/frigg-cli/validate-command/__tests__/infrastructure/api-module-validator.test.js +0 -332
  237. package/frigg-cli/validate-command/__tests__/infrastructure/app-definition-validator.test.js +0 -191
  238. package/frigg-cli/validate-command/__tests__/infrastructure/integration-class-validator.test.js +0 -146
  239. package/frigg-cli/validate-command/__tests__/infrastructure/template-validation.test.js +0 -155
  240. package/frigg-cli/validate-command/adapters/cli/validate-command.js +0 -199
  241. package/frigg-cli/validate-command/application/use-cases/validate-app-use-case.js +0 -35
  242. package/frigg-cli/validate-command/domain/entities/validation-result.js +0 -74
  243. package/frigg-cli/validate-command/domain/value-objects/fix-suggestion.js +0 -74
  244. package/frigg-cli/validate-command/domain/value-objects/validation-error.js +0 -68
  245. package/frigg-cli/validate-command/infrastructure/validators/api-module-validator.js +0 -181
  246. package/frigg-cli/validate-command/infrastructure/validators/app-definition-validator.js +0 -128
  247. package/frigg-cli/validate-command/infrastructure/validators/integration-class-validator.js +0 -113
@@ -1,474 +0,0 @@
1
- /**
2
- * InteractivePromptAdapter Tests
3
- * Handles prompts in terminal mode (inquirer) or IPC mode (JSON over stdio)
4
- *
5
- * Tests follow TDD pattern - written BEFORE implementation
6
- */
7
-
8
- // Mock @inquirer/prompts
9
- jest.mock('@inquirer/prompts', () => ({
10
- confirm: jest.fn(),
11
- select: jest.fn(),
12
- input: jest.fn()
13
- }));
14
-
15
- const { confirm, select, input } = require('@inquirer/prompts');
16
-
17
- // Import after mocks
18
- const {
19
- InteractivePromptAdapter,
20
- TerminalPromptAdapter,
21
- IpcPromptAdapter
22
- } = require('../../../../start-command/presentation/InteractivePromptAdapter');
23
-
24
- describe('InteractivePromptAdapter', () => {
25
- describe('factory method - create()', () => {
26
- it('should create TerminalPromptAdapter when mode is terminal', () => {
27
- const adapter = InteractivePromptAdapter.create({ mode: 'terminal' });
28
- expect(adapter).toBeInstanceOf(TerminalPromptAdapter);
29
- });
30
-
31
- it('should create IpcPromptAdapter when mode is ipc', () => {
32
- const adapter = InteractivePromptAdapter.create({ mode: 'ipc' });
33
- expect(adapter).toBeInstanceOf(IpcPromptAdapter);
34
- });
35
-
36
- it('should default to terminal mode when no mode specified', () => {
37
- const adapter = InteractivePromptAdapter.create({});
38
- expect(adapter).toBeInstanceOf(TerminalPromptAdapter);
39
- });
40
-
41
- it('should use ipc mode when FRIGG_IPC env var is true', () => {
42
- const originalEnv = process.env.FRIGG_IPC;
43
- process.env.FRIGG_IPC = 'true';
44
-
45
- const adapter = InteractivePromptAdapter.create({});
46
- expect(adapter).toBeInstanceOf(IpcPromptAdapter);
47
-
48
- process.env.FRIGG_IPC = originalEnv;
49
- });
50
- });
51
- });
52
-
53
- describe('TerminalPromptAdapter', () => {
54
- let adapter;
55
-
56
- beforeEach(() => {
57
- jest.clearAllMocks();
58
- adapter = new TerminalPromptAdapter();
59
- });
60
-
61
- describe('confirm()', () => {
62
- it('should call inquirer confirm with message', async () => {
63
- confirm.mockResolvedValue(true);
64
-
65
- const result = await adapter.confirm({
66
- message: 'Start Docker Desktop?',
67
- default: true
68
- });
69
-
70
- expect(result).toBe(true);
71
- expect(confirm).toHaveBeenCalledWith({
72
- message: 'Start Docker Desktop?',
73
- default: true
74
- });
75
- });
76
-
77
- it('should return false when user declines', async () => {
78
- confirm.mockResolvedValue(false);
79
-
80
- const result = await adapter.confirm({
81
- message: 'Continue?'
82
- });
83
-
84
- expect(result).toBe(false);
85
- });
86
-
87
- it('should use default value when provided', async () => {
88
- confirm.mockResolvedValue(false);
89
-
90
- await adapter.confirm({
91
- message: 'Continue?',
92
- default: false
93
- });
94
-
95
- expect(confirm).toHaveBeenCalledWith(expect.objectContaining({
96
- default: false
97
- }));
98
- });
99
- });
100
-
101
- describe('select()', () => {
102
- it('should call inquirer select with options', async () => {
103
- select.mockResolvedValue('option1');
104
-
105
- const result = await adapter.select({
106
- message: 'Choose an option:',
107
- choices: [
108
- { value: 'option1', name: 'Option 1' },
109
- { value: 'option2', name: 'Option 2' }
110
- ]
111
- });
112
-
113
- expect(result).toBe('option1');
114
- expect(select).toHaveBeenCalledWith(expect.objectContaining({
115
- message: 'Choose an option:'
116
- }));
117
- });
118
-
119
- it('should return selected value', async () => {
120
- select.mockResolvedValue('option2');
121
-
122
- const result = await adapter.select({
123
- message: 'Choose:',
124
- choices: [
125
- { value: 'option1', name: 'Option 1' },
126
- { value: 'option2', name: 'Option 2' }
127
- ]
128
- });
129
-
130
- expect(result).toBe('option2');
131
- });
132
- });
133
-
134
- describe('input()', () => {
135
- it('should call inquirer input with message', async () => {
136
- input.mockResolvedValue('user input');
137
-
138
- const result = await adapter.input({
139
- message: 'Enter value:'
140
- });
141
-
142
- expect(result).toBe('user input');
143
- expect(input).toHaveBeenCalledWith(expect.objectContaining({
144
- message: 'Enter value:'
145
- }));
146
- });
147
-
148
- it('should use default value when provided', async () => {
149
- input.mockResolvedValue('default');
150
-
151
- await adapter.input({
152
- message: 'Enter value:',
153
- default: 'default'
154
- });
155
-
156
- expect(input).toHaveBeenCalledWith(expect.objectContaining({
157
- default: 'default'
158
- }));
159
- });
160
- });
161
-
162
- describe('promptForResolution()', () => {
163
- it('should prompt confirm for start_docker resolution', async () => {
164
- confirm.mockResolvedValue(true);
165
-
166
- const result = await adapter.promptForResolution({
167
- name: 'docker_running',
168
- status: 'failed',
169
- message: 'Docker is not running',
170
- canResolve: true,
171
- resolution: {
172
- type: 'start_docker',
173
- prompt: 'Would you like to start Docker Desktop?'
174
- }
175
- });
176
-
177
- expect(result.shouldResolve).toBe(true);
178
- expect(confirm).toHaveBeenCalledWith(expect.objectContaining({
179
- message: 'Would you like to start Docker Desktop?'
180
- }));
181
- });
182
-
183
- it('should prompt confirm for start_docker_compose resolution', async () => {
184
- confirm.mockResolvedValue(true);
185
-
186
- const result = await adapter.promptForResolution({
187
- name: 'database_reachable',
188
- status: 'failed',
189
- message: 'Database not reachable',
190
- canResolve: true,
191
- resolution: {
192
- type: 'start_docker_compose',
193
- prompt: 'Would you like to run docker-compose up?',
194
- composePath: '/test/docker-compose.yml'
195
- }
196
- });
197
-
198
- expect(result.shouldResolve).toBe(true);
199
- expect(result.composePath).toBe('/test/docker-compose.yml');
200
- });
201
-
202
- it('should return shouldResolve: false when user declines', async () => {
203
- confirm.mockResolvedValue(false);
204
-
205
- const result = await adapter.promptForResolution({
206
- name: 'docker_running',
207
- status: 'failed',
208
- message: 'Docker not running',
209
- canResolve: true,
210
- resolution: {
211
- type: 'start_docker',
212
- prompt: 'Start Docker?'
213
- }
214
- });
215
-
216
- expect(result.shouldResolve).toBe(false);
217
- });
218
-
219
- it('should return shouldResolve: false for non-resolvable checks', async () => {
220
- const result = await adapter.promptForResolution({
221
- name: 'docker_installed',
222
- status: 'failed',
223
- message: 'Docker not installed',
224
- canResolve: false,
225
- resolution: {
226
- type: 'manual',
227
- instructions: 'Install Docker manually'
228
- }
229
- });
230
-
231
- expect(result.shouldResolve).toBe(false);
232
- expect(confirm).not.toHaveBeenCalled();
233
- });
234
- });
235
- });
236
-
237
- describe('IpcPromptAdapter', () => {
238
- let adapter;
239
- let originalStdout;
240
- let mockStdout;
241
-
242
- beforeEach(() => {
243
- jest.clearAllMocks();
244
- adapter = new IpcPromptAdapter();
245
-
246
- // Mock stdout.write
247
- mockStdout = jest.fn();
248
- originalStdout = process.stdout.write;
249
- process.stdout.write = mockStdout;
250
- });
251
-
252
- afterEach(() => {
253
- process.stdout.write = originalStdout;
254
- });
255
-
256
- describe('confirm()', () => {
257
- it('should output JSON prompt request to stdout', async () => {
258
- // Mock requestId generation for predictable test
259
- adapter._generateRequestId = () => 'test-id';
260
-
261
- const resultPromise = adapter.confirm({
262
- message: 'Start Docker?',
263
- default: true
264
- });
265
-
266
- // Resolve immediately for test
267
- adapter._resolvePrompt('test-id', true);
268
-
269
- const result = await resultPromise;
270
-
271
- expect(result).toBe(true);
272
- expect(mockStdout).toHaveBeenCalledWith(expect.stringContaining('frigg_ipc'));
273
- expect(mockStdout).toHaveBeenCalledWith(expect.stringContaining('prompt_request'));
274
- expect(mockStdout).toHaveBeenCalledWith(expect.stringContaining('confirm'));
275
- });
276
-
277
- it('should include requestId in output', async () => {
278
- adapter._generateRequestId = () => 'unique-id-123';
279
- adapter._resolvePrompt = jest.fn();
280
-
281
- // Start the promise but don't await yet
282
- adapter.confirm({ message: 'Test?' });
283
-
284
- // Give time for stdout.write to be called
285
- await new Promise(resolve => setTimeout(resolve, 10));
286
-
287
- const output = mockStdout.mock.calls[0][0];
288
- expect(output).toContain('unique-id-123');
289
- });
290
-
291
- it('should output newline-terminated JSON', async () => {
292
- adapter._generateRequestId = () => 'test-id';
293
-
294
- adapter.confirm({ message: 'Test?' });
295
-
296
- await new Promise(resolve => setTimeout(resolve, 10));
297
-
298
- const output = mockStdout.mock.calls[0][0];
299
- expect(output.endsWith('\n')).toBe(true);
300
- });
301
- });
302
-
303
- describe('_parseIpcMessage()', () => {
304
- it('should parse valid prompt response', () => {
305
- const message = JSON.stringify({
306
- frigg_ipc: 'prompt_response',
307
- requestId: 'test-id',
308
- response: true
309
- });
310
-
311
- const result = adapter._parseIpcMessage(message);
312
-
313
- expect(result.type).toBe('prompt_response');
314
- expect(result.requestId).toBe('test-id');
315
- expect(result.response).toBe(true);
316
- });
317
-
318
- it('should return null for non-IPC messages', () => {
319
- const message = 'regular log message';
320
- const result = adapter._parseIpcMessage(message);
321
-
322
- expect(result).toBeNull();
323
- });
324
-
325
- it('should return null for invalid JSON', () => {
326
- const message = '{ invalid json }';
327
- const result = adapter._parseIpcMessage(message);
328
-
329
- expect(result).toBeNull();
330
- });
331
- });
332
-
333
- describe('_formatIpcOutput()', () => {
334
- it('should format prompt request as JSON', () => {
335
- const output = adapter._formatIpcOutput('prompt_request', {
336
- requestId: 'test-123',
337
- prompt: {
338
- type: 'confirm',
339
- message: 'Continue?',
340
- default: true
341
- }
342
- });
343
-
344
- const parsed = JSON.parse(output.trim());
345
- expect(parsed.frigg_ipc).toBe('prompt_request');
346
- expect(parsed.requestId).toBe('test-123');
347
- expect(parsed.prompt.type).toBe('confirm');
348
- });
349
-
350
- it('should add newline to output', () => {
351
- const output = adapter._formatIpcOutput('prompt_request', {});
352
- expect(output.endsWith('\n')).toBe(true);
353
- });
354
- });
355
-
356
- describe('handleResponse()', () => {
357
- it('should resolve pending prompt with response', async () => {
358
- adapter._generateRequestId = () => 'test-id';
359
-
360
- const resultPromise = adapter.confirm({ message: 'Test?' });
361
-
362
- // Wait for prompt to be registered
363
- await new Promise(resolve => setTimeout(resolve, 10));
364
-
365
- // Handle the response
366
- adapter.handleResponse('test-id', true);
367
-
368
- const result = await resultPromise;
369
- expect(result).toBe(true);
370
- });
371
-
372
- it('should ignore responses for unknown requestIds', () => {
373
- // Should not throw
374
- expect(() => {
375
- adapter.handleResponse('unknown-id', true);
376
- }).not.toThrow();
377
- });
378
- });
379
-
380
- describe('promptForResolution()', () => {
381
- it('should output prompt in IPC format', async () => {
382
- adapter._generateRequestId = () => 'test-id';
383
-
384
- const check = {
385
- name: 'docker_running',
386
- status: 'failed',
387
- message: 'Docker not running',
388
- canResolve: true,
389
- resolution: {
390
- type: 'start_docker',
391
- prompt: 'Start Docker Desktop?'
392
- }
393
- };
394
-
395
- const resultPromise = adapter.promptForResolution(check);
396
-
397
- await new Promise(resolve => setTimeout(resolve, 10));
398
-
399
- const output = mockStdout.mock.calls[0][0];
400
- expect(output).toContain('prompt_request');
401
- expect(output).toContain('Start Docker Desktop?');
402
-
403
- // Resolve to complete the test
404
- adapter.handleResponse('test-id', true);
405
- await resultPromise;
406
- });
407
- });
408
- });
409
-
410
- describe('IPC Protocol Format', () => {
411
- describe('prompt_request format', () => {
412
- it('should match expected IPC protocol for confirm prompts', () => {
413
- const adapter = new IpcPromptAdapter();
414
- const output = adapter._formatIpcOutput('prompt_request', {
415
- requestId: 'prompt-1234',
416
- prompt: {
417
- type: 'confirm',
418
- message: 'Docker is not running. Start Docker Desktop?',
419
- default: true
420
- }
421
- });
422
-
423
- const parsed = JSON.parse(output.trim());
424
-
425
- expect(parsed).toEqual({
426
- frigg_ipc: 'prompt_request',
427
- requestId: 'prompt-1234',
428
- prompt: {
429
- type: 'confirm',
430
- message: 'Docker is not running. Start Docker Desktop?',
431
- default: true
432
- }
433
- });
434
- });
435
-
436
- it('should match expected IPC protocol for select prompts', () => {
437
- const adapter = new IpcPromptAdapter();
438
- const output = adapter._formatIpcOutput('prompt_request', {
439
- requestId: 'prompt-5678',
440
- prompt: {
441
- type: 'select',
442
- message: 'Choose an action:',
443
- choices: [
444
- { value: 'start', name: 'Start services' },
445
- { value: 'skip', name: 'Skip' }
446
- ]
447
- }
448
- });
449
-
450
- const parsed = JSON.parse(output.trim());
451
-
452
- expect(parsed.frigg_ipc).toBe('prompt_request');
453
- expect(parsed.prompt.type).toBe('select');
454
- expect(parsed.prompt.choices).toHaveLength(2);
455
- });
456
- });
457
-
458
- describe('prompt_response format', () => {
459
- it('should parse prompt_response messages correctly', () => {
460
- const adapter = new IpcPromptAdapter();
461
- const response = JSON.stringify({
462
- frigg_ipc: 'prompt_response',
463
- requestId: 'prompt-1234',
464
- response: true
465
- });
466
-
467
- const parsed = adapter._parseIpcMessage(response);
468
-
469
- expect(parsed.type).toBe('prompt_response');
470
- expect(parsed.requestId).toBe('prompt-1234');
471
- expect(parsed.response).toBe(true);
472
- });
473
- });
474
- });
@@ -1,196 +0,0 @@
1
- /**
2
- * Tests for unified Output utility
3
- */
4
-
5
- const output = require('../../../utils/output');
6
-
7
- describe('Output Utility', () => {
8
- // Mock console methods
9
- let originalConsole;
10
-
11
- beforeEach(() => {
12
- originalConsole = { ...console };
13
- console.log = jest.fn();
14
- console.error = jest.fn();
15
- console.warn = jest.fn();
16
- });
17
-
18
- afterEach(() => {
19
- console.log = originalConsole.log;
20
- console.error = originalConsole.error;
21
- console.warn = originalConsole.warn;
22
- });
23
-
24
- describe('success()', () => {
25
- it('should display success message with checkmark', () => {
26
- output.success('Operation completed');
27
- expect(console.log).toHaveBeenCalled();
28
- const args = console.log.mock.calls[0];
29
- expect(args.join(' ')).toContain('Operation completed');
30
- });
31
- });
32
-
33
- describe('error()', () => {
34
- it('should display error message with X mark', () => {
35
- output.error('Operation failed');
36
- expect(console.error).toHaveBeenCalled();
37
- const args = console.error.mock.calls[0];
38
- expect(args.join(' ')).toContain('Operation failed');
39
- });
40
-
41
- it('should display error stack in debug mode', () => {
42
- const originalDebug = process.env.DEBUG;
43
- process.env.DEBUG = 'true';
44
-
45
- const error = new Error('Test error');
46
- output.error('Operation failed', error);
47
-
48
- expect(console.error).toHaveBeenCalledTimes(2);
49
-
50
- process.env.DEBUG = originalDebug;
51
- });
52
- });
53
-
54
- describe('info()', () => {
55
- it('should display info message', () => {
56
- output.info('Information message');
57
- expect(console.log).toHaveBeenCalled();
58
- const args = console.log.mock.calls[0];
59
- expect(args.join(' ')).toContain('Information message');
60
- });
61
- });
62
-
63
- describe('warn()', () => {
64
- it('should display warning message', () => {
65
- output.warn('Warning message');
66
- expect(console.warn).toHaveBeenCalled();
67
- const args = console.warn.mock.calls[0];
68
- expect(args.join(' ')).toContain('Warning message');
69
- });
70
- });
71
-
72
- describe('header()', () => {
73
- it('should display formatted header', () => {
74
- output.header('Test Header');
75
- expect(console.log).toHaveBeenCalledTimes(3); // empty line, title, separator
76
- });
77
- });
78
-
79
- describe('table()', () => {
80
- it('should display table with data', () => {
81
- const data = [
82
- { name: 'Module A', version: '1.0.0', status: 'active' },
83
- { name: 'Module B', version: '2.1.0', status: 'inactive' }
84
- ];
85
-
86
- output.table(data);
87
- expect(console.log).toHaveBeenCalled();
88
- expect(console.log.mock.calls.length).toBeGreaterThan(3); // header + separator + rows
89
- });
90
-
91
- it('should handle empty data', () => {
92
- output.table([]);
93
- expect(console.log).toHaveBeenCalledWith(expect.stringContaining('No data'));
94
- });
95
-
96
- it('should handle specific columns', () => {
97
- const data = [
98
- { name: 'Module A', version: '1.0.0', status: 'active', extra: 'ignored' }
99
- ];
100
-
101
- output.table(data, ['name', 'version']);
102
- expect(console.log).toHaveBeenCalled();
103
- });
104
- });
105
-
106
- describe('keyValue()', () => {
107
- it('should display key-value pairs', () => {
108
- const data = {
109
- 'Module Name': 'test-module',
110
- 'Version': '1.0.0',
111
- 'Status': 'active'
112
- };
113
-
114
- output.keyValue(data);
115
- expect(console.log).toHaveBeenCalledTimes(3);
116
- });
117
- });
118
-
119
- describe('json()', () => {
120
- it('should display formatted JSON', () => {
121
- const data = { name: 'test', version: '1.0.0', active: true };
122
-
123
- output.json(data);
124
- expect(console.log).toHaveBeenCalled();
125
- const output_text = console.log.mock.calls[0][0];
126
- expect(output_text).toContain('name');
127
- expect(output_text).toContain('1.0.0');
128
- });
129
- });
130
-
131
- describe('spinner()', () => {
132
- jest.useFakeTimers();
133
-
134
- it('should create and control spinner', () => {
135
- const spinner = output.spinner('Loading...');
136
-
137
- // Spinner should have control methods
138
- expect(spinner).toHaveProperty('update');
139
- expect(spinner).toHaveProperty('succeed');
140
- expect(spinner).toHaveProperty('fail');
141
- expect(spinner).toHaveProperty('stop');
142
-
143
- spinner.stop();
144
- });
145
-
146
- it('should succeed with message', () => {
147
- const spinner = output.spinner('Loading...');
148
- spinner.succeed('Loaded successfully');
149
-
150
- expect(console.log).toHaveBeenCalled();
151
- });
152
-
153
- it('should fail with message', () => {
154
- const spinner = output.spinner('Loading...');
155
- spinner.fail('Loading failed');
156
-
157
- expect(console.error).toHaveBeenCalled();
158
- });
159
-
160
- jest.useRealTimers();
161
- });
162
-
163
- describe('progress()', () => {
164
- let originalStdout;
165
-
166
- beforeEach(() => {
167
- originalStdout = process.stdout.write;
168
- process.stdout.write = jest.fn();
169
- });
170
-
171
- afterEach(() => {
172
- process.stdout.write = originalStdout;
173
- });
174
-
175
- it('should display progress bar', () => {
176
- output.progress(50, 100, 'Processing...');
177
- expect(process.stdout.write).toHaveBeenCalled();
178
-
179
- const output_text = process.stdout.write.mock.calls[0][0];
180
- expect(output_text).toContain('%');
181
- expect(output_text).toContain('Processing...');
182
- });
183
-
184
- it('should complete progress bar', () => {
185
- output.progress(100, 100);
186
- expect(console.log).toHaveBeenCalled(); // Newline on completion
187
- });
188
- });
189
-
190
- describe('log()', () => {
191
- it('should log raw messages', () => {
192
- output.log('Raw message');
193
- expect(console.log).toHaveBeenCalledWith('Raw message');
194
- });
195
- });
196
- });