@friggframework/devtools 2.0.0-next.4 → 2.0.0-next.41
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/build-command/index.js +54 -0
- package/frigg-cli/deploy-command/index.js +175 -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/generate-iam-command.js +115 -0
- package/frigg-cli/index.js +47 -1
- package/frigg-cli/index.test.js +1 -4
- 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/install-command/index.js +1 -4
- package/frigg-cli/package.json +51 -0
- package/frigg-cli/start-command/index.js +30 -4
- package/frigg-cli/start-command/start-command.test.js +155 -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 +16 -17
- 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/DEPLOYMENT-INSTRUCTIONS.md +268 -0
- package/infrastructure/GENERATE-IAM-DOCS.md +278 -0
- package/infrastructure/IAM-POLICY-TEMPLATES.md +176 -0
- package/infrastructure/README.md +443 -0
- package/infrastructure/WEBSOCKET-CONFIGURATION.md +105 -0
- package/infrastructure/__tests__/fixtures/mock-aws-resources.js +391 -0
- package/infrastructure/__tests__/helpers/test-utils.js +277 -0
- package/infrastructure/aws-discovery.js +1176 -0
- package/infrastructure/aws-discovery.test.js +1220 -0
- package/infrastructure/build-time-discovery.js +206 -0
- package/infrastructure/build-time-discovery.test.js +378 -0
- package/infrastructure/create-frigg-infrastructure.js +3 -5
- package/infrastructure/env-validator.js +77 -0
- package/infrastructure/frigg-deployment-iam-stack.yaml +401 -0
- package/infrastructure/iam-generator.js +836 -0
- package/infrastructure/iam-generator.test.js +172 -0
- package/infrastructure/iam-policy-basic.json +218 -0
- package/infrastructure/iam-policy-full.json +288 -0
- package/infrastructure/integration.test.js +383 -0
- package/infrastructure/run-discovery.js +110 -0
- package/infrastructure/serverless-template.js +1493 -138
- package/infrastructure/serverless-template.test.js +1804 -0
- 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/index.html +13 -0
- 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/assets/FriggLogo.svg +1 -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 +20 -9
- package/infrastructure/app-handler-helpers.js +0 -57
- package/infrastructure/backend-utils.js +0 -90
- package/infrastructure/routers/auth.js +0 -26
- package/infrastructure/routers/integration-defined-routers.js +0 -37
- package/infrastructure/routers/middleware/loadUser.js +0 -15
- package/infrastructure/routers/middleware/requireLoggedInUser.js +0 -12
- package/infrastructure/routers/user.js +0 -41
- package/infrastructure/routers/websocket.js +0 -55
- package/infrastructure/workers/integration-defined-workers.js +0 -24
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import express from 'express'
|
|
2
|
+
import { spawn } from 'child_process'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { createStandardResponse, createErrorResponse, ERROR_CODES, asyncHandler } from '../utils/response.js'
|
|
5
|
+
|
|
6
|
+
const router = express.Router()
|
|
7
|
+
|
|
8
|
+
// Available Frigg CLI commands
|
|
9
|
+
const AVAILABLE_COMMANDS = [
|
|
10
|
+
{
|
|
11
|
+
name: 'init',
|
|
12
|
+
description: 'Initialize a new Frigg project',
|
|
13
|
+
usage: 'frigg init [project-name]',
|
|
14
|
+
options: [
|
|
15
|
+
{ name: '--template', description: 'Template to use (serverless, express)' },
|
|
16
|
+
{ name: '--skip-install', description: 'Skip npm install' },
|
|
17
|
+
{ name: '--force', description: 'Overwrite existing directory' }
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'create',
|
|
22
|
+
description: 'Create a new integration module',
|
|
23
|
+
usage: 'frigg create [integration-name]',
|
|
24
|
+
options: [
|
|
25
|
+
{ name: '--template', description: 'Integration template to use' },
|
|
26
|
+
{ name: '--skip-config', description: 'Skip initial configuration' }
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'install',
|
|
31
|
+
description: 'Install an integration module',
|
|
32
|
+
usage: 'frigg install [module-name]',
|
|
33
|
+
options: [
|
|
34
|
+
{ name: '--version', description: 'Specific version to install' },
|
|
35
|
+
{ name: '--save-dev', description: 'Install as dev dependency' }
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'start',
|
|
40
|
+
description: 'Start the Frigg application',
|
|
41
|
+
usage: 'frigg start',
|
|
42
|
+
options: [
|
|
43
|
+
{ name: '--port', description: 'Port to run on' },
|
|
44
|
+
{ name: '--stage', description: 'Environment stage' },
|
|
45
|
+
{ name: '--verbose', description: 'Verbose logging' }
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'build',
|
|
50
|
+
description: 'Build the Frigg application',
|
|
51
|
+
usage: 'frigg build',
|
|
52
|
+
options: [
|
|
53
|
+
{ name: '--stage', description: 'Build for specific stage' },
|
|
54
|
+
{ name: '--optimize', description: 'Enable optimizations' }
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'deploy',
|
|
59
|
+
description: 'Deploy the Frigg application',
|
|
60
|
+
usage: 'frigg deploy',
|
|
61
|
+
options: [
|
|
62
|
+
{ name: '--stage', description: 'Deploy to specific stage' },
|
|
63
|
+
{ name: '--region', description: 'AWS region' },
|
|
64
|
+
{ name: '--dry-run', description: 'Preview deployment without executing' }
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'ui',
|
|
69
|
+
description: 'Launch the management UI',
|
|
70
|
+
usage: 'frigg ui',
|
|
71
|
+
options: [
|
|
72
|
+
{ name: '--port', description: 'UI port (default: 3001)' },
|
|
73
|
+
{ name: '--open', description: 'Auto-open browser' }
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get available CLI commands
|
|
80
|
+
*/
|
|
81
|
+
router.get('/commands', asyncHandler(async (req, res) => {
|
|
82
|
+
res.json(createStandardResponse({
|
|
83
|
+
commands: AVAILABLE_COMMANDS,
|
|
84
|
+
friggPath: await getFriggPath()
|
|
85
|
+
}))
|
|
86
|
+
}))
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Execute a CLI command
|
|
90
|
+
*/
|
|
91
|
+
router.post('/execute', asyncHandler(async (req, res) => {
|
|
92
|
+
const { command, args = [], options = {} } = req.body
|
|
93
|
+
|
|
94
|
+
if (!command) {
|
|
95
|
+
return res.status(400).json(
|
|
96
|
+
createErrorResponse(ERROR_CODES.INVALID_REQUEST, 'Command is required')
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Validate command
|
|
101
|
+
const validCommand = AVAILABLE_COMMANDS.find(cmd => cmd.name === command)
|
|
102
|
+
if (!validCommand) {
|
|
103
|
+
return res.status(400).json(
|
|
104
|
+
createErrorResponse(ERROR_CODES.CLI_COMMAND_NOT_FOUND, `Unknown command: ${command}`)
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const result = await executeFriggCommand(command, args, options, req.app.get('io'))
|
|
110
|
+
|
|
111
|
+
res.json(createStandardResponse({
|
|
112
|
+
command,
|
|
113
|
+
args,
|
|
114
|
+
options,
|
|
115
|
+
output: result.output,
|
|
116
|
+
exitCode: result.exitCode,
|
|
117
|
+
duration: result.duration
|
|
118
|
+
}))
|
|
119
|
+
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return res.status(500).json(
|
|
122
|
+
createErrorResponse(ERROR_CODES.CLI_COMMAND_FAILED, error.message, {
|
|
123
|
+
command,
|
|
124
|
+
args,
|
|
125
|
+
options
|
|
126
|
+
})
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
}))
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get CLI command history
|
|
133
|
+
*/
|
|
134
|
+
router.get('/history', asyncHandler(async (req, res) => {
|
|
135
|
+
// In a real implementation, this would read from a persistent history
|
|
136
|
+
// For now, return empty array
|
|
137
|
+
res.json(createStandardResponse({
|
|
138
|
+
history: [],
|
|
139
|
+
message: 'Command history not yet implemented'
|
|
140
|
+
}))
|
|
141
|
+
}))
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get Frigg CLI version and info
|
|
145
|
+
*/
|
|
146
|
+
router.get('/info', asyncHandler(async (req, res) => {
|
|
147
|
+
try {
|
|
148
|
+
const result = await executeFriggCommand('--version', [], {}, null)
|
|
149
|
+
|
|
150
|
+
res.json(createStandardResponse({
|
|
151
|
+
version: result.output.trim(),
|
|
152
|
+
path: await getFriggPath(),
|
|
153
|
+
nodeVersion: process.version,
|
|
154
|
+
platform: process.platform
|
|
155
|
+
}))
|
|
156
|
+
|
|
157
|
+
} catch (error) {
|
|
158
|
+
return res.status(500).json(
|
|
159
|
+
createErrorResponse(ERROR_CODES.CLI_COMMAND_FAILED, 'Failed to get CLI info', {
|
|
160
|
+
error: error.message
|
|
161
|
+
})
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
}))
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Execute a Frigg CLI command
|
|
168
|
+
*/
|
|
169
|
+
async function executeFriggCommand(command, args = [], options = {}, io = null) {
|
|
170
|
+
return new Promise((resolve, reject) => {
|
|
171
|
+
const startTime = Date.now()
|
|
172
|
+
|
|
173
|
+
// Build command arguments
|
|
174
|
+
const cmdArgs = [command, ...args]
|
|
175
|
+
|
|
176
|
+
// Add options as flags
|
|
177
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
178
|
+
if (value === true) {
|
|
179
|
+
cmdArgs.push(`--${key}`)
|
|
180
|
+
} else if (value !== false && value !== null && value !== undefined) {
|
|
181
|
+
cmdArgs.push(`--${key}`, value.toString())
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
let output = ''
|
|
186
|
+
let errorOutput = ''
|
|
187
|
+
|
|
188
|
+
// Try to find frigg command
|
|
189
|
+
const friggCommand = process.platform === 'win32' ? 'frigg.cmd' : 'frigg'
|
|
190
|
+
|
|
191
|
+
// Spawn the command
|
|
192
|
+
const childProcess = spawn(friggCommand, cmdArgs, {
|
|
193
|
+
cwd: process.cwd(),
|
|
194
|
+
env: process.env,
|
|
195
|
+
shell: true
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
// Capture stdout
|
|
199
|
+
childProcess.stdout?.on('data', (data) => {
|
|
200
|
+
const chunk = data.toString()
|
|
201
|
+
output += chunk
|
|
202
|
+
|
|
203
|
+
// Broadcast real-time output via WebSocket
|
|
204
|
+
if (io) {
|
|
205
|
+
io.emit('cli:output', {
|
|
206
|
+
type: 'stdout',
|
|
207
|
+
data: chunk,
|
|
208
|
+
command,
|
|
209
|
+
timestamp: new Date().toISOString()
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
// Capture stderr
|
|
215
|
+
childProcess.stderr?.on('data', (data) => {
|
|
216
|
+
const chunk = data.toString()
|
|
217
|
+
errorOutput += chunk
|
|
218
|
+
|
|
219
|
+
// Broadcast real-time output via WebSocket
|
|
220
|
+
if (io) {
|
|
221
|
+
io.emit('cli:output', {
|
|
222
|
+
type: 'stderr',
|
|
223
|
+
data: chunk,
|
|
224
|
+
command,
|
|
225
|
+
timestamp: new Date().toISOString()
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
// Handle process completion
|
|
231
|
+
childProcess.on('close', (code) => {
|
|
232
|
+
const duration = Date.now() - startTime
|
|
233
|
+
|
|
234
|
+
// Broadcast completion via WebSocket
|
|
235
|
+
if (io) {
|
|
236
|
+
io.emit('cli:complete', {
|
|
237
|
+
command,
|
|
238
|
+
args,
|
|
239
|
+
options,
|
|
240
|
+
exitCode: code,
|
|
241
|
+
duration,
|
|
242
|
+
timestamp: new Date().toISOString()
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (code === 0) {
|
|
247
|
+
resolve({
|
|
248
|
+
output: output || errorOutput,
|
|
249
|
+
exitCode: code,
|
|
250
|
+
duration
|
|
251
|
+
})
|
|
252
|
+
} else {
|
|
253
|
+
reject(new Error(`Command failed with exit code ${code}: ${errorOutput || output}`))
|
|
254
|
+
}
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
// Handle process errors
|
|
258
|
+
childProcess.on('error', (error) => {
|
|
259
|
+
const duration = Date.now() - startTime
|
|
260
|
+
|
|
261
|
+
// Broadcast error via WebSocket
|
|
262
|
+
if (io) {
|
|
263
|
+
io.emit('cli:error', {
|
|
264
|
+
command,
|
|
265
|
+
args,
|
|
266
|
+
options,
|
|
267
|
+
error: error.message,
|
|
268
|
+
duration,
|
|
269
|
+
timestamp: new Date().toISOString()
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
reject(error)
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
// Set timeout for long-running commands (5 minutes)
|
|
277
|
+
setTimeout(() => {
|
|
278
|
+
if (!childProcess.killed) {
|
|
279
|
+
childProcess.kill('SIGTERM')
|
|
280
|
+
reject(new Error('Command timed out after 5 minutes'))
|
|
281
|
+
}
|
|
282
|
+
}, 5 * 60 * 1000)
|
|
283
|
+
})
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Get the path to the Frigg CLI
|
|
288
|
+
*/
|
|
289
|
+
async function getFriggPath() {
|
|
290
|
+
return new Promise((resolve) => {
|
|
291
|
+
const which = process.platform === 'win32' ? 'where' : 'which'
|
|
292
|
+
const friggCommand = process.platform === 'win32' ? 'frigg.cmd' : 'frigg'
|
|
293
|
+
|
|
294
|
+
const childProcess = spawn(which, [friggCommand], { shell: true })
|
|
295
|
+
|
|
296
|
+
let output = ''
|
|
297
|
+
childProcess.stdout?.on('data', (data) => {
|
|
298
|
+
output += data.toString()
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
childProcess.on('close', (code) => {
|
|
302
|
+
if (code === 0) {
|
|
303
|
+
resolve(output.trim().split('\n')[0])
|
|
304
|
+
} else {
|
|
305
|
+
resolve('frigg command not found in PATH')
|
|
306
|
+
}
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
childProcess.on('error', () => {
|
|
310
|
+
resolve('frigg command not found')
|
|
311
|
+
})
|
|
312
|
+
})
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export default router
|