@friggframework/devtools 2.0.0-next.3 → 2.0.0-next.30

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 (199) hide show
  1. package/frigg-cli/.eslintrc.js +141 -0
  2. package/frigg-cli/__tests__/jest.config.js +102 -0
  3. package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
  4. package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
  5. package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
  6. package/frigg-cli/__tests__/utils/command-tester.js +170 -0
  7. package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
  8. package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
  9. package/frigg-cli/__tests__/utils/test-setup.js +286 -0
  10. package/frigg-cli/build-command/index.js +54 -0
  11. package/frigg-cli/deploy-command/index.js +36 -0
  12. package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
  13. package/frigg-cli/generate-command/azure-generator.js +43 -0
  14. package/frigg-cli/generate-command/gcp-generator.js +47 -0
  15. package/frigg-cli/generate-command/index.js +332 -0
  16. package/frigg-cli/generate-command/terraform-generator.js +555 -0
  17. package/frigg-cli/generate-iam-command.js +115 -0
  18. package/frigg-cli/index.js +47 -1
  19. package/frigg-cli/index.test.js +1 -4
  20. package/frigg-cli/init-command/backend-first-handler.js +756 -0
  21. package/frigg-cli/init-command/index.js +93 -0
  22. package/frigg-cli/init-command/template-handler.js +143 -0
  23. package/frigg-cli/install-command/index.js +1 -4
  24. package/frigg-cli/package.json +51 -0
  25. package/frigg-cli/start-command/index.js +24 -4
  26. package/frigg-cli/test/init-command.test.js +180 -0
  27. package/frigg-cli/test/npm-registry.test.js +319 -0
  28. package/frigg-cli/ui-command/index.js +154 -0
  29. package/frigg-cli/utils/app-resolver.js +319 -0
  30. package/frigg-cli/utils/backend-path.js +16 -17
  31. package/frigg-cli/utils/npm-registry.js +167 -0
  32. package/frigg-cli/utils/process-manager.js +199 -0
  33. package/frigg-cli/utils/repo-detection.js +405 -0
  34. package/infrastructure/AWS-DISCOVERY-TROUBLESHOOTING.md +245 -0
  35. package/infrastructure/AWS-IAM-CREDENTIAL-NEEDS.md +596 -0
  36. package/infrastructure/DEPLOYMENT-INSTRUCTIONS.md +268 -0
  37. package/infrastructure/GENERATE-IAM-DOCS.md +253 -0
  38. package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
  39. package/infrastructure/README-TESTING.md +332 -0
  40. package/infrastructure/README.md +421 -0
  41. package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
  42. package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
  43. package/infrastructure/__tests__/helpers/test-utils.js +277 -0
  44. package/infrastructure/aws-discovery.js +568 -0
  45. package/infrastructure/aws-discovery.test.js +373 -0
  46. package/infrastructure/build-time-discovery.js +206 -0
  47. package/infrastructure/build-time-discovery.test.js +375 -0
  48. package/infrastructure/create-frigg-infrastructure.js +3 -5
  49. package/infrastructure/frigg-deployment-iam-stack.yaml +379 -0
  50. package/infrastructure/iam-generator.js +687 -0
  51. package/infrastructure/iam-generator.test.js +169 -0
  52. package/infrastructure/iam-policy-basic.json +212 -0
  53. package/infrastructure/iam-policy-full.json +282 -0
  54. package/infrastructure/integration.test.js +383 -0
  55. package/infrastructure/run-discovery.js +110 -0
  56. package/infrastructure/serverless-template.js +923 -113
  57. package/infrastructure/serverless-template.test.js +541 -0
  58. package/management-ui/.eslintrc.js +22 -0
  59. package/management-ui/README.md +203 -0
  60. package/management-ui/components.json +21 -0
  61. package/management-ui/docs/phase2-integration-guide.md +320 -0
  62. package/management-ui/index.html +13 -0
  63. package/management-ui/package-lock.json +16517 -0
  64. package/management-ui/package.json +76 -0
  65. package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
  66. package/management-ui/postcss.config.js +6 -0
  67. package/management-ui/server/api/backend.js +256 -0
  68. package/management-ui/server/api/cli.js +315 -0
  69. package/management-ui/server/api/codegen.js +663 -0
  70. package/management-ui/server/api/connections.js +857 -0
  71. package/management-ui/server/api/discovery.js +185 -0
  72. package/management-ui/server/api/environment/index.js +1 -0
  73. package/management-ui/server/api/environment/router.js +378 -0
  74. package/management-ui/server/api/environment.js +328 -0
  75. package/management-ui/server/api/integrations.js +876 -0
  76. package/management-ui/server/api/logs.js +248 -0
  77. package/management-ui/server/api/monitoring.js +282 -0
  78. package/management-ui/server/api/open-ide.js +31 -0
  79. package/management-ui/server/api/project.js +1029 -0
  80. package/management-ui/server/api/users/sessions.js +371 -0
  81. package/management-ui/server/api/users/simulation.js +254 -0
  82. package/management-ui/server/api/users.js +362 -0
  83. package/management-ui/server/api-contract.md +275 -0
  84. package/management-ui/server/index.js +873 -0
  85. package/management-ui/server/middleware/errorHandler.js +93 -0
  86. package/management-ui/server/middleware/security.js +32 -0
  87. package/management-ui/server/processManager.js +296 -0
  88. package/management-ui/server/server.js +346 -0
  89. package/management-ui/server/services/aws-monitor.js +413 -0
  90. package/management-ui/server/services/npm-registry.js +347 -0
  91. package/management-ui/server/services/template-engine.js +538 -0
  92. package/management-ui/server/utils/cliIntegration.js +220 -0
  93. package/management-ui/server/utils/environment/auditLogger.js +471 -0
  94. package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
  95. package/management-ui/server/utils/environment/encryption.js +278 -0
  96. package/management-ui/server/utils/environment/envFileManager.js +286 -0
  97. package/management-ui/server/utils/import-commonjs.js +28 -0
  98. package/management-ui/server/utils/response.js +83 -0
  99. package/management-ui/server/websocket/handler.js +325 -0
  100. package/management-ui/src/App.jsx +109 -0
  101. package/management-ui/src/assets/FriggLogo.svg +1 -0
  102. package/management-ui/src/components/AppRouter.jsx +65 -0
  103. package/management-ui/src/components/Button.jsx +70 -0
  104. package/management-ui/src/components/Card.jsx +97 -0
  105. package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
  106. package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
  107. package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
  108. package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
  109. package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
  110. package/management-ui/src/components/ErrorBoundary.jsx +73 -0
  111. package/management-ui/src/components/IntegrationCard.jsx +481 -0
  112. package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
  113. package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
  114. package/management-ui/src/components/IntegrationStatus.jsx +336 -0
  115. package/management-ui/src/components/Layout.jsx +716 -0
  116. package/management-ui/src/components/LoadingSpinner.jsx +113 -0
  117. package/management-ui/src/components/RepositoryPicker.jsx +248 -0
  118. package/management-ui/src/components/SessionMonitor.jsx +350 -0
  119. package/management-ui/src/components/StatusBadge.jsx +208 -0
  120. package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
  121. package/management-ui/src/components/UserSimulation.jsx +327 -0
  122. package/management-ui/src/components/Welcome.jsx +434 -0
  123. package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
  124. package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
  125. package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
  126. package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
  127. package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
  128. package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
  129. package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
  130. package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
  131. package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
  132. package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
  133. package/management-ui/src/components/codegen/index.js +10 -0
  134. package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
  135. package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
  136. package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
  137. package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
  138. package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
  139. package/management-ui/src/components/connections/index.js +5 -0
  140. package/management-ui/src/components/index.js +21 -0
  141. package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
  142. package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
  143. package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
  144. package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
  145. package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
  146. package/management-ui/src/components/monitoring/index.js +6 -0
  147. package/management-ui/src/components/monitoring/monitoring.css +218 -0
  148. package/management-ui/src/components/theme-provider.jsx +52 -0
  149. package/management-ui/src/components/theme-toggle.jsx +39 -0
  150. package/management-ui/src/components/ui/badge.tsx +36 -0
  151. package/management-ui/src/components/ui/button.test.jsx +56 -0
  152. package/management-ui/src/components/ui/button.tsx +57 -0
  153. package/management-ui/src/components/ui/card.tsx +76 -0
  154. package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
  155. package/management-ui/src/components/ui/select.tsx +157 -0
  156. package/management-ui/src/components/ui/skeleton.jsx +15 -0
  157. package/management-ui/src/hooks/useFrigg.jsx +601 -0
  158. package/management-ui/src/hooks/useSocket.jsx +58 -0
  159. package/management-ui/src/index.css +193 -0
  160. package/management-ui/src/lib/utils.ts +6 -0
  161. package/management-ui/src/main.jsx +10 -0
  162. package/management-ui/src/pages/CodeGeneration.jsx +14 -0
  163. package/management-ui/src/pages/Connections.jsx +252 -0
  164. package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
  165. package/management-ui/src/pages/Dashboard.jsx +311 -0
  166. package/management-ui/src/pages/Environment.jsx +314 -0
  167. package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
  168. package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
  169. package/management-ui/src/pages/IntegrationTest.jsx +742 -0
  170. package/management-ui/src/pages/Integrations.jsx +253 -0
  171. package/management-ui/src/pages/Monitoring.jsx +17 -0
  172. package/management-ui/src/pages/Simulation.jsx +155 -0
  173. package/management-ui/src/pages/Users.jsx +492 -0
  174. package/management-ui/src/services/api.js +41 -0
  175. package/management-ui/src/services/apiModuleService.js +193 -0
  176. package/management-ui/src/services/websocket-handlers.js +120 -0
  177. package/management-ui/src/test/api/project.test.js +273 -0
  178. package/management-ui/src/test/components/Welcome.test.jsx +378 -0
  179. package/management-ui/src/test/mocks/server.js +178 -0
  180. package/management-ui/src/test/setup.js +61 -0
  181. package/management-ui/src/test/utils/test-utils.jsx +134 -0
  182. package/management-ui/src/utils/repository.js +98 -0
  183. package/management-ui/src/utils/repository.test.js +118 -0
  184. package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
  185. package/management-ui/tailwind.config.js +63 -0
  186. package/management-ui/tsconfig.json +37 -0
  187. package/management-ui/tsconfig.node.json +10 -0
  188. package/management-ui/vite.config.js +26 -0
  189. package/management-ui/vitest.config.js +38 -0
  190. package/package.json +16 -9
  191. package/infrastructure/app-handler-helpers.js +0 -57
  192. package/infrastructure/backend-utils.js +0 -90
  193. package/infrastructure/routers/auth.js +0 -26
  194. package/infrastructure/routers/integration-defined-routers.js +0 -37
  195. package/infrastructure/routers/middleware/loadUser.js +0 -15
  196. package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
  197. package/infrastructure/routers/user.js +0 -41
  198. package/infrastructure/routers/websocket.js +0 -55
  199. package/infrastructure/workers/integration-defined-workers.js +0 -24
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@friggframework/management-ui",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "dev:server": "concurrently \"npm run server\" \"npm run dev\"",
9
+ "build": "vite build",
10
+ "preview": "vite preview",
11
+ "server": "node server/server.js",
12
+ "server:old": "node server/index.js",
13
+ "server:dev": "nodemon server/server.js",
14
+ "test": "vitest",
15
+ "test:ui": "vitest --ui",
16
+ "test:watch": "vitest --watch",
17
+ "test:coverage": "vitest --coverage",
18
+ "lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
19
+ "lint:fix": "eslint src --ext js,jsx --fix",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "dependencies": {
23
+ "@aws-sdk/client-api-gateway": "^3.478.0",
24
+ "@aws-sdk/client-cloudwatch": "^3.478.0",
25
+ "@aws-sdk/client-lambda": "^3.478.0",
26
+ "@aws-sdk/client-sqs": "^3.478.0",
27
+ "@friggframework/ui": "^2.0.0-next.0",
28
+ "@friggframework/ui-react": "file:../../ui/react",
29
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
30
+ "@radix-ui/react-select": "^2.2.5",
31
+ "@radix-ui/react-slot": "^1.2.3",
32
+ "axios": "^1.6.7",
33
+ "class-variance-authority": "^0.7.1",
34
+ "clsx": "^2.1.1",
35
+ "cors": "^2.8.5",
36
+ "express": "^4.18.2",
37
+ "framer-motion": "^12.20.1",
38
+ "fs-extra": "^11.2.0",
39
+ "handlebars": "^4.7.8",
40
+ "lucide-react": "^0.473.0",
41
+ "node-cache": "^5.1.2",
42
+ "node-fetch": "^3.3.2",
43
+ "react": "^18.3.1",
44
+ "react-dom": "^18.3.1",
45
+ "react-router-dom": "^6.22.0",
46
+ "semver": "^7.5.4",
47
+ "socket.io": "^4.7.4",
48
+ "socket.io-client": "^4.7.4",
49
+ "tailwind-merge": "^2.6.0",
50
+ "tailwindcss-animate": "^1.0.7"
51
+ },
52
+ "devDependencies": {
53
+ "@types/react": "^18.3.3",
54
+ "@types/react-dom": "^18.3.0",
55
+ "@vitejs/plugin-react": "^4.3.1",
56
+ "autoprefixer": "^10.4.20",
57
+ "concurrently": "^8.2.2",
58
+ "eslint": "^8.57.0",
59
+ "eslint-plugin-react": "^7.34.3",
60
+ "eslint-plugin-react-hooks": "^4.6.2",
61
+ "eslint-plugin-react-refresh": "^0.4.7",
62
+ "nodemon": "^3.0.3",
63
+ "postcss": "^8.4.41",
64
+ "tailwindcss": "^3.4.10",
65
+ "typescript": "^5.2.2",
66
+ "vite": "^5.3.4",
67
+ "vitest": "^1.6.0",
68
+ "@vitest/ui": "^1.6.0",
69
+ "@vitest/coverage-v8": "^1.6.0",
70
+ "@testing-library/react": "^14.3.1",
71
+ "@testing-library/jest-dom": "^6.4.6",
72
+ "@testing-library/user-event": "^14.5.2",
73
+ "jsdom": "^24.1.0",
74
+ "msw": "^2.3.1"
75
+ }
76
+ }
@@ -0,0 +1,302 @@
1
+ <<<<<<< HEAD
2
+ <<<<<<< HEAD
3
+ const open = require('open');
4
+ const chalk = require('chalk');
5
+ const path = require('path');
6
+ const ProcessManager = require('../utils/process-manager');
7
+ const {
8
+ getCurrentRepositoryInfo,
9
+ discoverFriggRepositories,
10
+ promptRepositorySelection,
11
+ formatRepositoryInfo
12
+ } = require('../utils/repo-detection');
13
+
14
+ async function uiCommand(options) {
15
+ const { port = 3001, open: shouldOpen = true, repo: specifiedRepo } = options;
16
+
17
+ let targetRepo = null;
18
+ let workingDirectory = process.cwd();
19
+
20
+ // If a specific repo path is provided, use it
21
+ if (specifiedRepo) {
22
+ const repoPath = path.resolve(specifiedRepo);
23
+ console.log(chalk.blue(`Using specified repository: ${repoPath}`));
24
+ workingDirectory = repoPath;
25
+ targetRepo = { path: repoPath, name: path.basename(repoPath) };
26
+ } else {
27
+ // Check if we're already in a Frigg repository
28
+ console.log(chalk.blue('Detecting Frigg repository...'));
29
+ const currentRepo = await getCurrentRepositoryInfo();
30
+
31
+ if (currentRepo) {
32
+ console.log(chalk.green(`✓ Found Frigg repository: ${formatRepositoryInfo(currentRepo)}`));
33
+ if (currentRepo.currentSubPath) {
34
+ console.log(chalk.gray(` Currently in subdirectory: ${currentRepo.currentSubPath}`));
35
+ }
36
+ targetRepo = currentRepo;
37
+ workingDirectory = currentRepo.path;
38
+ } else {
39
+ // Discover Frigg repositories
40
+ console.log(chalk.yellow('Current directory is not a Frigg repository.'));
41
+ console.log(chalk.blue('Searching for Frigg repositories...'));
42
+
43
+ const discoveredRepos = await discoverFriggRepositories();
44
+ targetRepo = await promptRepositorySelection(discoveredRepos);
45
+
46
+ if (!targetRepo) {
47
+ console.log(chalk.red('No Frigg repository selected. Exiting.'));
48
+ process.exit(1);
49
+ }
50
+
51
+ workingDirectory = targetRepo.path;
52
+ }
53
+ }
54
+
55
+ console.log(chalk.blue('🚀 Starting Frigg Management UI...'));
56
+
57
+ const processManager = new ProcessManager();
58
+
59
+ try {
60
+ const managementUiPath = path.join(__dirname, '../../management-ui');
61
+
62
+ // Check if we're in development mode (no dist folder)
63
+ const distPath = path.join(managementUiPath, 'dist');
64
+ const fs = require('fs');
65
+ const isDevelopment = !fs.existsSync(distPath);
66
+
67
+ if (isDevelopment) {
68
+ const env = {
69
+ ...process.env,
70
+ VITE_API_URL: `http://localhost:${port}`,
71
+ PORT: port,
72
+ PROJECT_ROOT: workingDirectory,
73
+ REPOSITORY_INFO: JSON.stringify(targetRepo)
74
+ };
75
+
76
+ // Start backend server
77
+ processManager.spawnProcess(
78
+ 'backend',
79
+ 'npm',
80
+ ['run', 'server'],
81
+ { cwd: managementUiPath, env }
82
+ );
83
+
84
+ // Start frontend dev server
85
+ processManager.spawnProcess(
86
+ 'frontend',
87
+ 'npm',
88
+ ['run', 'dev'],
89
+ { cwd: managementUiPath, env }
90
+ );
91
+
92
+ // Wait for servers to start
93
+ await new Promise(resolve => setTimeout(resolve, 2000));
94
+
95
+ // Display clean status
96
+ processManager.printStatus(
97
+ 'http://localhost:5173',
98
+ `http://localhost:${port}`,
99
+ targetRepo.name
100
+ );
101
+
102
+ // Open browser if requested
103
+ if (shouldOpen) {
104
+ setTimeout(() => {
105
+ open('http://localhost:5173');
106
+ }, 1000);
107
+ }
108
+
109
+ } else {
110
+ // Production mode - just start the backend server
111
+ const { FriggManagementServer } = await import('../../management-ui/server/index.js');
112
+
113
+ const server = new FriggManagementServer({
114
+ port,
115
+ projectRoot: workingDirectory,
116
+ repositoryInfo: targetRepo
117
+ });
118
+ await server.start();
119
+
120
+ processManager.printStatus(
121
+ `http://localhost:${port}`,
122
+ `http://localhost:${port}/api`,
123
+ targetRepo.name
124
+ );
125
+
126
+ if (shouldOpen) {
127
+ setTimeout(() => {
128
+ open(`http://localhost:${port}`);
129
+ }, 1000);
130
+ }
131
+ }
132
+
133
+ // Keep the process running
134
+ process.stdin.resume();
135
+
136
+ } catch (error) {
137
+ console.error(chalk.red('Failed to start Management UI:'), error.message);
138
+ if (error.code === 'EADDRINUSE') {
139
+ console.log(chalk.yellow(`Port ${port} is already in use. Try using a different port with --port <number>`));
140
+ }
141
+ =======
142
+ const { FriggManagementServer } = require('../../management-ui/server');
143
+ =======
144
+ >>>>>>> f153939e (refactor: clean up CLI help display and remove unused dependencies)
145
+ const open = require('open');
146
+ const chalk = require('chalk');
147
+ const path = require('path');
148
+ const ProcessManager = require('../utils/process-manager');
149
+ const {
150
+ getCurrentRepositoryInfo,
151
+ discoverFriggRepositories,
152
+ promptRepositorySelection,
153
+ formatRepositoryInfo
154
+ } = require('../utils/repo-detection');
155
+
156
+ async function uiCommand(options) {
157
+ const { port = 3001, open: shouldOpen = true, repo: specifiedRepo, dev = false } = options;
158
+
159
+ let targetRepo = null;
160
+ let workingDirectory = process.cwd();
161
+
162
+ // If a specific repo path is provided, use it
163
+ if (specifiedRepo) {
164
+ const repoPath = path.resolve(specifiedRepo);
165
+ console.log(chalk.blue(`Using specified repository: ${repoPath}`));
166
+ workingDirectory = repoPath;
167
+ targetRepo = { path: repoPath, name: path.basename(repoPath) };
168
+ } else {
169
+ // Check if we're already in a Frigg repository
170
+ console.log(chalk.blue('Detecting Frigg repository...'));
171
+ const currentRepo = await getCurrentRepositoryInfo();
172
+
173
+ if (currentRepo) {
174
+ console.log(chalk.green(`✓ Found Frigg repository: ${formatRepositoryInfo(currentRepo)}`));
175
+ if (currentRepo.currentSubPath) {
176
+ console.log(chalk.gray(` Currently in subdirectory: ${currentRepo.currentSubPath}`));
177
+ }
178
+ targetRepo = currentRepo;
179
+ workingDirectory = currentRepo.path;
180
+ } else {
181
+ // Discover Frigg repositories
182
+ console.log(chalk.yellow('Current directory is not a Frigg repository.'));
183
+ console.log(chalk.blue('Searching for Frigg repositories...'));
184
+
185
+ const discoveredRepos = await discoverFriggRepositories();
186
+
187
+ if (discoveredRepos.length === 0) {
188
+ console.log(chalk.red('No Frigg repositories found. Please create one first.'));
189
+ process.exit(1);
190
+ }
191
+
192
+ // For UI command, we'll let the UI handle repository selection
193
+ // Set a placeholder and pass the discovered repos via environment
194
+ targetRepo = {
195
+ name: 'Multiple Repositories Available',
196
+ path: process.cwd(),
197
+ isMultiRepo: true,
198
+ availableRepos: discoveredRepos
199
+ };
200
+ workingDirectory = process.cwd();
201
+
202
+ console.log(chalk.blue(`Found ${discoveredRepos.length} Frigg repositories. You'll be able to select one in the UI.`));
203
+ }
204
+ }
205
+
206
+ console.log(chalk.blue('🚀 Starting Frigg Management UI...'));
207
+
208
+ const processManager = new ProcessManager();
209
+
210
+ try {
211
+ const managementUiPath = path.join(__dirname, '../../management-ui');
212
+
213
+ // Check if we're in development mode
214
+ // For CLI usage, we prefer development mode unless explicitly set to production
215
+ const fs = require('fs');
216
+ const isDevelopment = dev || process.env.NODE_ENV !== 'production';
217
+
218
+ if (isDevelopment) {
219
+ const env = {
220
+ ...process.env,
221
+ VITE_API_URL: `http://localhost:${port}`,
222
+ PORT: port,
223
+ PROJECT_ROOT: workingDirectory,
224
+ REPOSITORY_INFO: JSON.stringify(targetRepo),
225
+ AVAILABLE_REPOSITORIES: targetRepo.isMultiRepo ? JSON.stringify(targetRepo.availableRepos) : null
226
+ };
227
+
228
+ // Start backend server
229
+ processManager.spawnProcess(
230
+ 'backend',
231
+ 'npm',
232
+ ['run', 'server'],
233
+ { cwd: managementUiPath, env }
234
+ );
235
+
236
+ // Start frontend dev server
237
+ processManager.spawnProcess(
238
+ 'frontend',
239
+ 'npm',
240
+ ['run', 'dev'],
241
+ { cwd: managementUiPath, env }
242
+ );
243
+
244
+ // Wait for servers to start
245
+ await new Promise(resolve => setTimeout(resolve, 2000));
246
+
247
+ // Display clean status
248
+ processManager.printStatus(
249
+ 'http://localhost:5173',
250
+ `http://localhost:${port}`,
251
+ targetRepo.name
252
+ );
253
+
254
+ // Open browser if requested
255
+ if (shouldOpen) {
256
+ setTimeout(() => {
257
+ open('http://localhost:5173');
258
+ }, 1000);
259
+ }
260
+
261
+ } else {
262
+ // Production mode - just start the backend server
263
+ const { FriggManagementServer } = await import('../../management-ui/server/index.js');
264
+
265
+ const server = new FriggManagementServer({
266
+ port,
267
+ projectRoot: workingDirectory,
268
+ repositoryInfo: targetRepo,
269
+ availableRepositories: targetRepo.isMultiRepo ? targetRepo.availableRepos : null
270
+ });
271
+ await server.start();
272
+
273
+ processManager.printStatus(
274
+ `http://localhost:${port}`,
275
+ `http://localhost:${port}/api`,
276
+ targetRepo.name
277
+ );
278
+
279
+ if (shouldOpen) {
280
+ setTimeout(() => {
281
+ open(`http://localhost:${port}`);
282
+ }, 1000);
283
+ }
284
+ }
285
+
286
+ // Keep the process running
287
+ process.stdin.resume();
288
+
289
+ } catch (error) {
290
+ console.error(chalk.red('Failed to start Management UI:'), error.message);
291
+ <<<<<<< HEAD
292
+ >>>>>>> 652520a5 (Claude Flow RFC related development)
293
+ =======
294
+ if (error.code === 'EADDRINUSE') {
295
+ console.log(chalk.yellow(`Port ${port} is already in use. Try using a different port with --port <number>`));
296
+ }
297
+ >>>>>>> f153939e (refactor: clean up CLI help display and remove unused dependencies)
298
+ process.exit(1);
299
+ }
300
+ }
301
+
302
+ module.exports = { uiCommand };
@@ -0,0 +1,6 @@
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ }
@@ -0,0 +1,256 @@
1
+ import express from 'express';
2
+ import { spawn } from 'child_process';
3
+ import path from 'path';
4
+ import fs from 'fs-extra';
5
+ import { wsHandler } from '../websocket/handler.js';
6
+
7
+ const router = express.Router();
8
+
9
+ // Track backend process
10
+ let backendProcess = null;
11
+ let backendStatus = 'stopped';
12
+ let backendLogs = [];
13
+ const MAX_LOGS = 1000;
14
+
15
+ // Helper function to find the backend directory
16
+ async function findBackendDirectory() {
17
+ const cwd = process.cwd();
18
+ const possiblePaths = [
19
+ path.join(cwd, 'backend'),
20
+ path.join(cwd, '../../../backend'),
21
+ path.join(cwd, '../../backend'),
22
+ path.join(process.env.HOME || '', 'frigg', 'backend')
23
+ ];
24
+
25
+ for (const backendPath of possiblePaths) {
26
+ if (await fs.pathExists(backendPath)) {
27
+ return backendPath;
28
+ }
29
+ }
30
+
31
+ throw new Error('Backend directory not found');
32
+ }
33
+
34
+ // Get backend status
35
+ router.get('/status', (req, res) => {
36
+ res.json({
37
+ status: backendStatus,
38
+ pid: backendProcess ? backendProcess.pid : null,
39
+ uptime: backendProcess ? process.uptime() : 0,
40
+ logs: backendLogs.slice(-100) // Return last 100 logs
41
+ });
42
+ });
43
+
44
+ // Start backend
45
+ router.post('/start', async (req, res) => {
46
+ if (backendProcess && backendStatus === 'running') {
47
+ return res.status(400).json({
48
+ error: 'Backend is already running'
49
+ });
50
+ }
51
+
52
+ try {
53
+ const backendPath = await findBackendDirectory();
54
+ const { stage = 'dev', verbose = false } = req.body;
55
+
56
+ // Clear previous logs
57
+ backendLogs = [];
58
+ backendStatus = 'starting';
59
+
60
+ // Broadcast status update
61
+ wsHandler.broadcast('backend-status', {
62
+ status: 'starting',
63
+ message: 'Starting Frigg backend...'
64
+ });
65
+
66
+ // Start the backend process
67
+ const args = ['run', 'start'];
68
+ if (stage !== 'dev') {
69
+ args.push('--stage', stage);
70
+ }
71
+ if (verbose) {
72
+ args.push('--verbose');
73
+ }
74
+
75
+ backendProcess = spawn('npm', args, {
76
+ cwd: backendPath,
77
+ env: { ...process.env, NODE_ENV: stage === 'production' ? 'production' : 'development' },
78
+ shell: true
79
+ });
80
+
81
+ // Handle stdout
82
+ backendProcess.stdout.on('data', (data) => {
83
+ const log = {
84
+ type: 'stdout',
85
+ message: data.toString(),
86
+ timestamp: new Date().toISOString()
87
+ };
88
+ backendLogs.push(log);
89
+ if (backendLogs.length > MAX_LOGS) {
90
+ backendLogs.shift();
91
+ }
92
+ wsHandler.broadcast('backend-log', log);
93
+ });
94
+
95
+ // Handle stderr
96
+ backendProcess.stderr.on('data', (data) => {
97
+ const log = {
98
+ type: 'stderr',
99
+ message: data.toString(),
100
+ timestamp: new Date().toISOString()
101
+ };
102
+ backendLogs.push(log);
103
+ if (backendLogs.length > MAX_LOGS) {
104
+ backendLogs.shift();
105
+ }
106
+ wsHandler.broadcast('backend-log', log);
107
+ });
108
+
109
+ // Handle process exit
110
+ backendProcess.on('exit', (code, signal) => {
111
+ backendStatus = 'stopped';
112
+ backendProcess = null;
113
+
114
+ const message = {
115
+ status: 'stopped',
116
+ code,
117
+ signal,
118
+ message: `Backend process exited with code ${code}`
119
+ };
120
+
121
+ wsHandler.broadcast('backend-status', message);
122
+ });
123
+
124
+ // Wait a bit to ensure process started
125
+ await new Promise(resolve => setTimeout(resolve, 2000));
126
+
127
+ if (backendProcess && !backendProcess.killed) {
128
+ backendStatus = 'running';
129
+ wsHandler.broadcast('backend-status', {
130
+ status: 'running',
131
+ message: 'Backend started successfully'
132
+ });
133
+
134
+ res.json({
135
+ status: 'success',
136
+ message: 'Backend started',
137
+ pid: backendProcess.pid
138
+ });
139
+ } else {
140
+ throw new Error('Failed to start backend process');
141
+ }
142
+
143
+ } catch (error) {
144
+ backendStatus = 'stopped';
145
+ res.status(500).json({
146
+ error: error.message,
147
+ details: 'Failed to start backend'
148
+ });
149
+ }
150
+ });
151
+
152
+ // Stop backend
153
+ router.post('/stop', (req, res) => {
154
+ if (!backendProcess || backendStatus !== 'running') {
155
+ return res.status(400).json({
156
+ error: 'Backend is not running'
157
+ });
158
+ }
159
+
160
+ try {
161
+ backendStatus = 'stopping';
162
+ wsHandler.broadcast('backend-status', {
163
+ status: 'stopping',
164
+ message: 'Stopping Frigg backend...'
165
+ });
166
+
167
+ // Kill the process group
168
+ if (process.platform === 'win32') {
169
+ spawn('taskkill', ['/pid', backendProcess.pid, '/T', '/F']);
170
+ } else {
171
+ process.kill(-backendProcess.pid, 'SIGTERM');
172
+ }
173
+
174
+ // Give it time to shut down gracefully
175
+ setTimeout(() => {
176
+ if (backendProcess && !backendProcess.killed) {
177
+ backendProcess.kill('SIGKILL');
178
+ }
179
+ }, 5000);
180
+
181
+ res.json({
182
+ status: 'success',
183
+ message: 'Backend stopping'
184
+ });
185
+
186
+ } catch (error) {
187
+ res.status(500).json({
188
+ error: error.message,
189
+ details: 'Failed to stop backend'
190
+ });
191
+ }
192
+ });
193
+
194
+ // Restart backend
195
+ router.post('/restart', async (req, res) => {
196
+ try {
197
+ // Stop if running
198
+ if (backendProcess && backendStatus === 'running') {
199
+ await new Promise((resolve) => {
200
+ backendProcess.on('exit', resolve);
201
+
202
+ if (process.platform === 'win32') {
203
+ spawn('taskkill', ['/pid', backendProcess.pid, '/T', '/F']);
204
+ } else {
205
+ process.kill(-backendProcess.pid, 'SIGTERM');
206
+ }
207
+ });
208
+ }
209
+
210
+ // Wait a moment
211
+ await new Promise(resolve => setTimeout(resolve, 1000));
212
+
213
+ // Start again
214
+ const response = await fetch('http://localhost:3001/api/backend/start', {
215
+ method: 'POST',
216
+ headers: { 'Content-Type': 'application/json' },
217
+ body: JSON.stringify(req.body)
218
+ });
219
+
220
+ const result = await response.json();
221
+ res.json(result);
222
+
223
+ } catch (error) {
224
+ res.status(500).json({
225
+ error: error.message,
226
+ details: 'Failed to restart backend'
227
+ });
228
+ }
229
+ });
230
+
231
+ // Get logs
232
+ router.get('/logs', (req, res) => {
233
+ const { limit = 100, type } = req.query;
234
+
235
+ let logs = backendLogs;
236
+
237
+ if (type && ['stdout', 'stderr'].includes(type)) {
238
+ logs = logs.filter(log => log.type === type);
239
+ }
240
+
241
+ res.json({
242
+ logs: logs.slice(-parseInt(limit)),
243
+ total: logs.length
244
+ });
245
+ });
246
+
247
+ // Clear logs
248
+ router.delete('/logs', (req, res) => {
249
+ backendLogs = [];
250
+ res.json({
251
+ status: 'success',
252
+ message: 'Logs cleared'
253
+ });
254
+ });
255
+
256
+ export default router;