@friggframework/devtools 2.0.0-next.29 → 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.
- package/frigg-cli/.eslintrc.js +141 -0
- package/frigg-cli/__tests__/jest.config.js +102 -0
- package/frigg-cli/__tests__/unit/commands/build.test.js +483 -0
- package/frigg-cli/__tests__/unit/commands/install.test.js +418 -0
- package/frigg-cli/__tests__/unit/commands/ui.test.js +592 -0
- package/frigg-cli/__tests__/utils/command-tester.js +170 -0
- package/frigg-cli/__tests__/utils/mock-factory.js +270 -0
- package/frigg-cli/__tests__/utils/test-fixtures.js +463 -0
- package/frigg-cli/__tests__/utils/test-setup.js +286 -0
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +312 -0
- package/frigg-cli/generate-command/azure-generator.js +43 -0
- package/frigg-cli/generate-command/gcp-generator.js +47 -0
- package/frigg-cli/generate-command/index.js +332 -0
- package/frigg-cli/generate-command/terraform-generator.js +555 -0
- package/frigg-cli/index.js +19 -1
- package/frigg-cli/init-command/backend-first-handler.js +756 -0
- package/frigg-cli/init-command/index.js +93 -0
- package/frigg-cli/init-command/template-handler.js +143 -0
- package/frigg-cli/package.json +51 -0
- package/frigg-cli/test/init-command.test.js +180 -0
- package/frigg-cli/test/npm-registry.test.js +319 -0
- package/frigg-cli/ui-command/index.js +154 -0
- package/frigg-cli/utils/app-resolver.js +319 -0
- package/frigg-cli/utils/backend-path.js +25 -0
- package/frigg-cli/utils/npm-registry.js +167 -0
- package/frigg-cli/utils/process-manager.js +199 -0
- package/frigg-cli/utils/repo-detection.js +405 -0
- package/infrastructure/serverless-template.js +177 -292
- package/management-ui/.eslintrc.js +22 -0
- package/management-ui/README.md +203 -0
- package/management-ui/components.json +21 -0
- package/management-ui/docs/phase2-integration-guide.md +320 -0
- package/management-ui/{dist/index.html → index.html} +1 -2
- package/management-ui/package-lock.json +16517 -0
- package/management-ui/package.json +76 -0
- package/management-ui/packages/devtools/frigg-cli/ui-command/index.js +302 -0
- package/management-ui/postcss.config.js +6 -0
- package/management-ui/server/api/backend.js +256 -0
- package/management-ui/server/api/cli.js +315 -0
- package/management-ui/server/api/codegen.js +663 -0
- package/management-ui/server/api/connections.js +857 -0
- package/management-ui/server/api/discovery.js +185 -0
- package/management-ui/server/api/environment/index.js +1 -0
- package/management-ui/server/api/environment/router.js +378 -0
- package/management-ui/server/api/environment.js +328 -0
- package/management-ui/server/api/integrations.js +876 -0
- package/management-ui/server/api/logs.js +248 -0
- package/management-ui/server/api/monitoring.js +282 -0
- package/management-ui/server/api/open-ide.js +31 -0
- package/management-ui/server/api/project.js +1029 -0
- package/management-ui/server/api/users/sessions.js +371 -0
- package/management-ui/server/api/users/simulation.js +254 -0
- package/management-ui/server/api/users.js +362 -0
- package/management-ui/server/api-contract.md +275 -0
- package/management-ui/server/index.js +873 -0
- package/management-ui/server/middleware/errorHandler.js +93 -0
- package/management-ui/server/middleware/security.js +32 -0
- package/management-ui/server/processManager.js +296 -0
- package/management-ui/server/server.js +346 -0
- package/management-ui/server/services/aws-monitor.js +413 -0
- package/management-ui/server/services/npm-registry.js +347 -0
- package/management-ui/server/services/template-engine.js +538 -0
- package/management-ui/server/utils/cliIntegration.js +220 -0
- package/management-ui/server/utils/environment/auditLogger.js +471 -0
- package/management-ui/server/utils/environment/awsParameterStore.js +264 -0
- package/management-ui/server/utils/environment/encryption.js +278 -0
- package/management-ui/server/utils/environment/envFileManager.js +286 -0
- package/management-ui/server/utils/import-commonjs.js +28 -0
- package/management-ui/server/utils/response.js +83 -0
- package/management-ui/server/websocket/handler.js +325 -0
- package/management-ui/src/App.jsx +109 -0
- package/management-ui/src/components/AppRouter.jsx +65 -0
- package/management-ui/src/components/Button.jsx +70 -0
- package/management-ui/src/components/Card.jsx +97 -0
- package/management-ui/src/components/EnvironmentCompare.jsx +400 -0
- package/management-ui/src/components/EnvironmentEditor.jsx +372 -0
- package/management-ui/src/components/EnvironmentImportExport.jsx +469 -0
- package/management-ui/src/components/EnvironmentSchema.jsx +491 -0
- package/management-ui/src/components/EnvironmentSecurity.jsx +463 -0
- package/management-ui/src/components/ErrorBoundary.jsx +73 -0
- package/management-ui/src/components/IntegrationCard.jsx +481 -0
- package/management-ui/src/components/IntegrationCardEnhanced.jsx +770 -0
- package/management-ui/src/components/IntegrationExplorer.jsx +379 -0
- package/management-ui/src/components/IntegrationStatus.jsx +336 -0
- package/management-ui/src/components/Layout.jsx +716 -0
- package/management-ui/src/components/LoadingSpinner.jsx +113 -0
- package/management-ui/src/components/RepositoryPicker.jsx +248 -0
- package/management-ui/src/components/SessionMonitor.jsx +350 -0
- package/management-ui/src/components/StatusBadge.jsx +208 -0
- package/management-ui/src/components/UserContextSwitcher.jsx +212 -0
- package/management-ui/src/components/UserSimulation.jsx +327 -0
- package/management-ui/src/components/Welcome.jsx +434 -0
- package/management-ui/src/components/codegen/APIEndpointGenerator.jsx +637 -0
- package/management-ui/src/components/codegen/APIModuleSelector.jsx +227 -0
- package/management-ui/src/components/codegen/CodeGenerationWizard.jsx +247 -0
- package/management-ui/src/components/codegen/CodePreviewEditor.jsx +316 -0
- package/management-ui/src/components/codegen/DynamicModuleForm.jsx +271 -0
- package/management-ui/src/components/codegen/FormBuilder.jsx +737 -0
- package/management-ui/src/components/codegen/IntegrationGenerator.jsx +855 -0
- package/management-ui/src/components/codegen/ProjectScaffoldWizard.jsx +797 -0
- package/management-ui/src/components/codegen/SchemaBuilder.jsx +303 -0
- package/management-ui/src/components/codegen/TemplateSelector.jsx +586 -0
- package/management-ui/src/components/codegen/index.js +10 -0
- package/management-ui/src/components/connections/ConnectionConfigForm.jsx +362 -0
- package/management-ui/src/components/connections/ConnectionHealthMonitor.jsx +182 -0
- package/management-ui/src/components/connections/ConnectionTester.jsx +200 -0
- package/management-ui/src/components/connections/EntityRelationshipMapper.jsx +292 -0
- package/management-ui/src/components/connections/OAuthFlow.jsx +204 -0
- package/management-ui/src/components/connections/index.js +5 -0
- package/management-ui/src/components/index.js +21 -0
- package/management-ui/src/components/monitoring/APIGatewayMetrics.jsx +222 -0
- package/management-ui/src/components/monitoring/LambdaMetrics.jsx +169 -0
- package/management-ui/src/components/monitoring/MetricsChart.jsx +197 -0
- package/management-ui/src/components/monitoring/MonitoringDashboard.jsx +393 -0
- package/management-ui/src/components/monitoring/SQSMetrics.jsx +246 -0
- package/management-ui/src/components/monitoring/index.js +6 -0
- package/management-ui/src/components/monitoring/monitoring.css +218 -0
- package/management-ui/src/components/theme-provider.jsx +52 -0
- package/management-ui/src/components/theme-toggle.jsx +39 -0
- package/management-ui/src/components/ui/badge.tsx +36 -0
- package/management-ui/src/components/ui/button.test.jsx +56 -0
- package/management-ui/src/components/ui/button.tsx +57 -0
- package/management-ui/src/components/ui/card.tsx +76 -0
- package/management-ui/src/components/ui/dropdown-menu.tsx +199 -0
- package/management-ui/src/components/ui/select.tsx +157 -0
- package/management-ui/src/components/ui/skeleton.jsx +15 -0
- package/management-ui/src/hooks/useFrigg.jsx +601 -0
- package/management-ui/src/hooks/useSocket.jsx +58 -0
- package/management-ui/src/index.css +193 -0
- package/management-ui/src/lib/utils.ts +6 -0
- package/management-ui/src/main.jsx +10 -0
- package/management-ui/src/pages/CodeGeneration.jsx +14 -0
- package/management-ui/src/pages/Connections.jsx +252 -0
- package/management-ui/src/pages/ConnectionsEnhanced.jsx +633 -0
- package/management-ui/src/pages/Dashboard.jsx +311 -0
- package/management-ui/src/pages/Environment.jsx +314 -0
- package/management-ui/src/pages/IntegrationConfigure.jsx +669 -0
- package/management-ui/src/pages/IntegrationDiscovery.jsx +567 -0
- package/management-ui/src/pages/IntegrationTest.jsx +742 -0
- package/management-ui/src/pages/Integrations.jsx +253 -0
- package/management-ui/src/pages/Monitoring.jsx +17 -0
- package/management-ui/src/pages/Simulation.jsx +155 -0
- package/management-ui/src/pages/Users.jsx +492 -0
- package/management-ui/src/services/api.js +41 -0
- package/management-ui/src/services/apiModuleService.js +193 -0
- package/management-ui/src/services/websocket-handlers.js +120 -0
- package/management-ui/src/test/api/project.test.js +273 -0
- package/management-ui/src/test/components/Welcome.test.jsx +378 -0
- package/management-ui/src/test/mocks/server.js +178 -0
- package/management-ui/src/test/setup.js +61 -0
- package/management-ui/src/test/utils/test-utils.jsx +134 -0
- package/management-ui/src/utils/repository.js +98 -0
- package/management-ui/src/utils/repository.test.js +118 -0
- package/management-ui/src/workflows/phase2-integration-workflows.js +884 -0
- package/management-ui/tailwind.config.js +63 -0
- package/management-ui/tsconfig.json +37 -0
- package/management-ui/tsconfig.node.json +10 -0
- package/management-ui/vite.config.js +26 -0
- package/management-ui/vitest.config.js +38 -0
- package/package.json +5 -5
- package/management-ui/dist/assets/index-BA21WgFa.js +0 -1221
- package/management-ui/dist/assets/index-CbM64Oba.js +0 -1221
- package/management-ui/dist/assets/index-CkvseXTC.css +0 -1
- /package/management-ui/{dist/assets/FriggLogo-B7Xx8ZW1.svg → src/assets/FriggLogo.svg} +0 -0
|
@@ -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,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;
|