ezpm2gui 1.1.0 → 1.2.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 (28) hide show
  1. package/dist/server/config/project-configs.json +236 -0
  2. package/dist/server/index.js +30 -5
  3. package/dist/server/logs/deployment.log +12 -0
  4. package/dist/server/routes/deployApplication.js +174 -27
  5. package/dist/server/routes/logStreaming.js +174 -0
  6. package/dist/server/routes/remoteConnections.d.ts +3 -0
  7. package/dist/server/routes/remoteConnections.js +634 -0
  8. package/dist/server/services/ProjectSetupService.d.ts +72 -0
  9. package/dist/server/services/ProjectSetupService.js +327 -0
  10. package/dist/server/utils/dialog.d.ts +1 -0
  11. package/dist/server/utils/dialog.js +16 -0
  12. package/dist/server/utils/encryption.d.ts +12 -0
  13. package/dist/server/utils/encryption.js +72 -0
  14. package/dist/server/utils/remote-connection.d.ts +152 -0
  15. package/dist/server/utils/remote-connection.js +590 -0
  16. package/dist/server/utils/upload.d.ts +3 -0
  17. package/dist/server/utils/upload.js +39 -0
  18. package/package.json +65 -63
  19. package/src/client/build/asset-manifest.json +3 -3
  20. package/src/client/build/favicon.ico +2 -0
  21. package/src/client/build/index.html +1 -1
  22. package/src/client/build/logo192.svg +7 -0
  23. package/src/client/build/logo512.svg +7 -0
  24. package/src/client/build/manifest.json +5 -6
  25. package/src/client/build/static/js/{main.1d7f99ff.js → main.31323a04.js} +13 -13
  26. package/src/client/build/static/js/main.31323a04.js.map +1 -0
  27. package/src/client/build/static/js/main.1d7f99ff.js.map +0 -1
  28. /package/src/client/build/static/js/{main.1d7f99ff.js.LICENSE.txt → main.31323a04.js.LICENSE.txt} +0 -0
@@ -0,0 +1,634 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const remote_connection_1 = require("../utils/remote-connection");
8
+ const router = express_1.default.Router();
9
+ /**
10
+ * Connect to an existing remote server
11
+ * POST /api/remote/:connectionId/connect
12
+ */
13
+ router.post('/:connectionId/connect', async (req, res) => {
14
+ try {
15
+ const { connectionId } = req.params;
16
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
17
+ if (!connection) {
18
+ return res.status(404).json({
19
+ success: false,
20
+ error: 'Connection not found'
21
+ });
22
+ }
23
+ // Connect to the remote server
24
+ await connection.connect();
25
+ // Check if PM2 is installed
26
+ const isPM2Installed = await connection.checkPM2Installation();
27
+ res.json({
28
+ success: true,
29
+ isPM2Installed
30
+ });
31
+ }
32
+ catch (error) {
33
+ console.error('Connection error:', error);
34
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
35
+ res.status(500).json({
36
+ success: false,
37
+ error: `Failed to connect: ${errorMessage}`
38
+ });
39
+ }
40
+ });
41
+ /**
42
+ * Disconnect from a remote server
43
+ * POST /api/remote/:connectionId/disconnect
44
+ */
45
+ router.post('/:connectionId/disconnect', async (req, res) => {
46
+ try {
47
+ const { connectionId } = req.params;
48
+ const success = await remote_connection_1.remoteConnectionManager.closeConnection(connectionId);
49
+ res.json({
50
+ success
51
+ });
52
+ }
53
+ catch (error) {
54
+ res.status(500).json({
55
+ success: false,
56
+ error: `Failed to disconnect: ${error.message}`
57
+ });
58
+ }
59
+ });
60
+ /**
61
+ * Create a new remote server connection (legacy route)
62
+ * POST /api/remote/connect
63
+ */
64
+ router.post('/connect', async (req, res) => {
65
+ try {
66
+ const connectionConfig = req.body;
67
+ // Validate required fields
68
+ if (!connectionConfig.host || !connectionConfig.username) {
69
+ return res.status(400).json({
70
+ success: false,
71
+ error: 'Missing required connection parameters'
72
+ });
73
+ }
74
+ // Ensure port is set
75
+ if (!connectionConfig.port) {
76
+ connectionConfig.port = 22;
77
+ }
78
+ // Validate authentication method
79
+ if (!connectionConfig.password && !connectionConfig.privateKey) {
80
+ return res.status(400).json({
81
+ success: false,
82
+ error: 'No authentication method provided (password or privateKey)'
83
+ });
84
+ }
85
+ // Create the connection
86
+ const connectionId = remote_connection_1.remoteConnectionManager.createConnection(connectionConfig);
87
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
88
+ if (!connection) {
89
+ return res.status(500).json({
90
+ success: false,
91
+ error: 'Failed to create connection'
92
+ });
93
+ }
94
+ // Test the connection
95
+ try {
96
+ await connection.connect();
97
+ // Check if PM2 is installed
98
+ const isPM2Installed = await connection.checkPM2Installation();
99
+ res.json({
100
+ success: true,
101
+ connectionId,
102
+ isPM2Installed,
103
+ name: connectionConfig.name || connectionConfig.host
104
+ });
105
+ }
106
+ catch (error) {
107
+ res.status(400).json({
108
+ success: false,
109
+ error: `Connection failed: ${error.message}`
110
+ });
111
+ }
112
+ }
113
+ catch (error) {
114
+ res.status(500).json({
115
+ success: false,
116
+ error: `Server error: ${error.message}`
117
+ });
118
+ }
119
+ });
120
+ /**
121
+ * Disconnect from a remote server
122
+ * POST /api/remote/disconnect
123
+ */
124
+ router.post('/disconnect', async (req, res) => {
125
+ try {
126
+ const { connectionId } = req.body;
127
+ if (!connectionId) {
128
+ return res.status(400).json({
129
+ success: false,
130
+ error: 'Missing connectionId parameter'
131
+ });
132
+ }
133
+ const success = await remote_connection_1.remoteConnectionManager.closeConnection(connectionId);
134
+ res.json({
135
+ success
136
+ });
137
+ }
138
+ catch (error) {
139
+ res.status(500).json({
140
+ success: false,
141
+ error: `Server error: ${error.message}`
142
+ });
143
+ }
144
+ });
145
+ /**
146
+ * Get PM2 process list from remote server
147
+ * GET /api/remote/pm2/list
148
+ */
149
+ router.get('/pm2/list/:connectionId', async (req, res) => {
150
+ try {
151
+ const { connectionId } = req.params;
152
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
153
+ if (!connection) {
154
+ return res.status(404).json({
155
+ success: false,
156
+ error: 'Connection not found'
157
+ });
158
+ }
159
+ try {
160
+ const processes = await connection.getPM2Processes();
161
+ res.json(processes);
162
+ }
163
+ catch (error) {
164
+ res.status(400).json({
165
+ success: false,
166
+ error: `Failed to get PM2 list: ${error.message}`
167
+ });
168
+ }
169
+ }
170
+ catch (error) {
171
+ res.status(500).json({
172
+ success: false,
173
+ error: `Server error: ${error.message}`
174
+ });
175
+ }
176
+ });
177
+ /**
178
+ * Get detailed information about a PM2 process on remote server
179
+ * GET /api/remote/pm2/info/:connectionId/:processId
180
+ */
181
+ router.get('/pm2/info/:connectionId/:processId', async (req, res) => {
182
+ try {
183
+ const { connectionId, processId } = req.params;
184
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
185
+ if (!connection) {
186
+ return res.status(404).json({
187
+ success: false,
188
+ error: 'Connection not found'
189
+ });
190
+ }
191
+ try {
192
+ // Find process in the list of processes
193
+ const processes = await connection.getPM2Processes();
194
+ const process = processes.find(p => p.pm_id.toString() === processId);
195
+ if (!process) {
196
+ return res.status(404).json({
197
+ success: false,
198
+ error: 'Process not found'
199
+ });
200
+ }
201
+ res.json({
202
+ success: true,
203
+ processInfo: process
204
+ });
205
+ }
206
+ catch (error) {
207
+ res.status(400).json({
208
+ success: false,
209
+ error: `Failed to get process info: ${error.message}`
210
+ });
211
+ }
212
+ }
213
+ catch (error) {
214
+ res.status(500).json({
215
+ success: false,
216
+ error: `Server error: ${error.message}`
217
+ });
218
+ }
219
+ });
220
+ /**
221
+ * Perform process actions (start, stop, restart, delete) on remote server
222
+ * POST /api/remote/pm2/action/:connectionId/:action
223
+ */
224
+ router.post('/pm2/action/:connectionId/:action', async (req, res) => {
225
+ try {
226
+ const { connectionId, action } = req.params;
227
+ const { processId, options } = req.body;
228
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
229
+ if (!connection) {
230
+ return res.status(404).json({
231
+ success: false,
232
+ error: 'Connection not found'
233
+ });
234
+ }
235
+ let result;
236
+ try {
237
+ switch (action) {
238
+ case 'start':
239
+ result = await connection.startPM2Process(options || processId);
240
+ break;
241
+ case 'stop':
242
+ result = await connection.stopPM2Process(processId);
243
+ break;
244
+ case 'restart':
245
+ result = await connection.restartPM2Process(processId);
246
+ break;
247
+ case 'delete':
248
+ result = await connection.deletePM2Process(processId);
249
+ break;
250
+ default:
251
+ return res.status(400).json({
252
+ success: false,
253
+ error: `Unknown action: ${action}`
254
+ });
255
+ }
256
+ res.json({
257
+ success: true,
258
+ result
259
+ });
260
+ }
261
+ catch (error) {
262
+ res.status(400).json({
263
+ success: false,
264
+ error: `Action failed: ${error.message}`
265
+ });
266
+ }
267
+ }
268
+ catch (error) {
269
+ res.status(500).json({
270
+ success: false,
271
+ error: `Server error: ${error.message}`
272
+ });
273
+ }
274
+ });
275
+ /**
276
+ * Get PM2 processes from remote server
277
+ * GET /api/remote/:connectionId/processes
278
+ */
279
+ router.get('/:connectionId/processes', async (req, res) => {
280
+ try {
281
+ const { connectionId } = req.params;
282
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
283
+ if (!connection) {
284
+ return res.status(404).json({
285
+ success: false,
286
+ error: 'Connection not found'
287
+ });
288
+ }
289
+ try {
290
+ const processes = await connection.getPM2Processes();
291
+ res.json(processes);
292
+ }
293
+ catch (error) {
294
+ res.status(400).json({
295
+ success: false,
296
+ error: `Failed to get processes: ${error.message}`
297
+ });
298
+ }
299
+ }
300
+ catch (error) {
301
+ res.status(500).json({
302
+ success: false,
303
+ error: `Server error: ${error.message}`
304
+ });
305
+ }
306
+ });
307
+ /**
308
+ * Perform an action on a PM2 process
309
+ * POST /api/remote/:connectionId/processes/:processName/:action
310
+ */
311
+ router.post('/:connectionId/processes/:processName/:action', async (req, res) => {
312
+ try {
313
+ const { connectionId, processName, action } = req.params;
314
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
315
+ if (!connection) {
316
+ return res.status(404).json({
317
+ success: false,
318
+ error: 'Connection not found'
319
+ });
320
+ }
321
+ try {
322
+ let result;
323
+ switch (action) {
324
+ case 'start':
325
+ result = await connection.startPM2Process(processName);
326
+ break;
327
+ case 'stop':
328
+ result = await connection.stopPM2Process(processName);
329
+ break;
330
+ case 'restart':
331
+ result = await connection.restartPM2Process(processName);
332
+ break;
333
+ case 'delete':
334
+ result = await connection.deletePM2Process(processName);
335
+ break;
336
+ default:
337
+ return res.status(400).json({
338
+ success: false,
339
+ error: `Invalid action: ${action}`
340
+ });
341
+ }
342
+ res.json({
343
+ success: true,
344
+ result
345
+ });
346
+ }
347
+ catch (error) {
348
+ res.status(400).json({
349
+ success: false,
350
+ error: `Failed to ${action} process: ${error.message}`
351
+ });
352
+ }
353
+ }
354
+ catch (error) {
355
+ res.status(500).json({
356
+ success: false,
357
+ error: `Server error: ${error.message}`
358
+ });
359
+ }
360
+ });
361
+ /**
362
+ * Get system information from a remote server
363
+ * GET /api/remote/:connectionId/system-info
364
+ */
365
+ router.get('/:connectionId/system-info', async (req, res) => {
366
+ try {
367
+ const { connectionId } = req.params;
368
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
369
+ if (!connection) {
370
+ return res.status(404).json({
371
+ success: false,
372
+ error: 'Connection not found'
373
+ });
374
+ }
375
+ try {
376
+ const systemInfo = await connection.getSystemInfo();
377
+ res.json(systemInfo);
378
+ }
379
+ catch (error) {
380
+ res.status(400).json({
381
+ success: false,
382
+ error: `Failed to get system info: ${error.message}`
383
+ });
384
+ }
385
+ }
386
+ catch (error) {
387
+ res.status(500).json({
388
+ success: false,
389
+ error: `Server error: ${error.message}`
390
+ });
391
+ }
392
+ });
393
+ /**
394
+ * Get logs for a PM2 process on remote server
395
+ * GET /api/remote/pm2/logs/:connectionId/:processId
396
+ */
397
+ router.get('/pm2/logs/:connectionId/:processId', async (req, res) => {
398
+ try {
399
+ const { connectionId, processId } = req.params;
400
+ const lines = req.query.lines ? parseInt(req.query.lines) : 100;
401
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
402
+ if (!connection) {
403
+ return res.status(404).json({
404
+ success: false,
405
+ error: 'Connection not found'
406
+ });
407
+ }
408
+ try {
409
+ const result = await connection.getPM2Logs(processId, lines);
410
+ res.json({
411
+ success: true,
412
+ logs: result.stdout
413
+ });
414
+ }
415
+ catch (error) {
416
+ res.status(400).json({
417
+ success: false,
418
+ error: `Failed to get logs: ${error.message}`
419
+ });
420
+ }
421
+ }
422
+ catch (error) {
423
+ res.status(500).json({
424
+ success: false,
425
+ error: `Server error: ${error.message}`
426
+ });
427
+ }
428
+ });
429
+ /**
430
+ * Get system information from the remote server
431
+ * GET /api/remote/system/:connectionId
432
+ */
433
+ router.get('/system/:connectionId', async (req, res) => {
434
+ try {
435
+ const { connectionId } = req.params;
436
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
437
+ if (!connection) {
438
+ return res.status(404).json({
439
+ success: false,
440
+ error: 'Connection not found'
441
+ });
442
+ }
443
+ try {
444
+ const systemInfo = await connection.getSystemInfo();
445
+ res.json({
446
+ success: true,
447
+ systemInfo
448
+ });
449
+ }
450
+ catch (error) {
451
+ res.status(400).json({
452
+ success: false,
453
+ error: `Failed to get system info: ${error.message}`
454
+ });
455
+ }
456
+ }
457
+ catch (error) {
458
+ res.status(500).json({
459
+ success: false,
460
+ error: `Server error: ${error.message}`
461
+ });
462
+ }
463
+ });
464
+ /**
465
+ * Get logs from a remote PM2 process
466
+ * GET /api/remote/:connectionId/logs/:processId
467
+ */
468
+ router.get('/:connectionId/logs/:processId', async (req, res) => {
469
+ var _a, _b;
470
+ try {
471
+ const { connectionId, processId } = req.params;
472
+ const connection = remote_connection_1.remoteConnectionManager.getConnection(connectionId);
473
+ if (!connection) {
474
+ return res.status(404).json({
475
+ success: false,
476
+ error: 'Connection not found'
477
+ });
478
+ }
479
+ if (!connection.isConnected()) {
480
+ return res.status(400).json({
481
+ success: false,
482
+ error: 'Connection not established'
483
+ });
484
+ } // Get log paths from PM2 process info
485
+ const processInfoResult = await connection.executeCommand(`pm2 show ${processId} --json`);
486
+ if (processInfoResult.code !== 0) {
487
+ return res.status(500).json({
488
+ success: false,
489
+ error: 'Failed to get process info'
490
+ });
491
+ }
492
+ let processInfo;
493
+ try {
494
+ processInfo = JSON.parse(processInfoResult.stdout);
495
+ if (!Array.isArray(processInfo) || processInfo.length === 0) {
496
+ return res.status(404).json({
497
+ success: false,
498
+ error: 'Process not found'
499
+ });
500
+ }
501
+ processInfo = processInfo[0];
502
+ }
503
+ catch (parseError) {
504
+ return res.status(500).json({
505
+ success: false,
506
+ error: 'Failed to parse process info'
507
+ });
508
+ }
509
+ const outLogPath = (_a = processInfo.pm2_env) === null || _a === void 0 ? void 0 : _a.pm_out_log_path;
510
+ const errLogPath = (_b = processInfo.pm2_env) === null || _b === void 0 ? void 0 : _b.pm_err_log_path;
511
+ const logs = {
512
+ stdout: [],
513
+ stderr: []
514
+ }; // Fetch stdout logs
515
+ if (outLogPath) {
516
+ let outResult = await connection.executeCommand(`tail -n 100 "${outLogPath}" 2>/dev/null || echo ""`);
517
+ // If failed, try with sudo
518
+ if (outResult.code !== 0 || !outResult.stdout.trim()) {
519
+ console.log(`Failed to read ${outLogPath}, trying with sudo`);
520
+ outResult = await connection.executeCommand(`sudo tail -n 100 "${outLogPath}" 2>/dev/null || echo ""`);
521
+ }
522
+ if (outResult.code === 0 && outResult.stdout.trim()) {
523
+ logs.stdout = outResult.stdout.trim().split('\n').filter(line => line.trim());
524
+ }
525
+ }
526
+ // Fetch stderr logs
527
+ if (errLogPath) {
528
+ let errResult = await connection.executeCommand(`tail -n 100 "${errLogPath}" 2>/dev/null || echo ""`);
529
+ // If failed, try with sudo
530
+ if (errResult.code !== 0 || !errResult.stdout.trim()) {
531
+ console.log(`Failed to read ${errLogPath}, trying with sudo`);
532
+ errResult = await connection.executeCommand(`sudo tail -n 100 "${errLogPath}" 2>/dev/null || echo ""`);
533
+ }
534
+ if (errResult.code === 0 && errResult.stdout.trim()) {
535
+ logs.stderr = errResult.stdout.trim().split('\n').filter(line => line.trim());
536
+ }
537
+ }
538
+ res.json({
539
+ success: true,
540
+ ...logs
541
+ });
542
+ }
543
+ catch (error) {
544
+ console.error('Error fetching remote logs:', error);
545
+ res.status(500).json({
546
+ success: false,
547
+ error: `Server error: ${error instanceof Error ? error.message : 'Unknown error'}`
548
+ });
549
+ }
550
+ });
551
+ /**
552
+ * Get list of all remote connections with their status
553
+ * GET /api/remote/connections
554
+ */
555
+ router.get('/connections', async (req, res) => {
556
+ try {
557
+ const connections = remote_connection_1.remoteConnectionManager.getAllConnections();
558
+ const connectionsList = Array.from(connections.entries()).map(([id, conn]) => ({
559
+ id,
560
+ name: conn.name || `${conn.username}@${conn.host}`,
561
+ host: conn.host,
562
+ port: conn.port,
563
+ username: conn.username,
564
+ isConnected: conn.isConnected(),
565
+ isPM2Installed: conn.isPM2Installed
566
+ }));
567
+ res.json(connectionsList);
568
+ }
569
+ catch (error) {
570
+ console.error('Error getting connections:', error);
571
+ res.status(500).json({
572
+ success: false,
573
+ error: `Server error: ${error instanceof Error ? error.message : 'Unknown error'}`
574
+ });
575
+ }
576
+ });
577
+ /**
578
+ * Add a new remote connection configuration
579
+ * POST /api/remote/connections
580
+ */
581
+ router.post('/connections', (req, res) => {
582
+ try {
583
+ const connectionConfig = req.body;
584
+ if (!connectionConfig.name || !connectionConfig.host || !connectionConfig.username) {
585
+ return res.status(400).json({
586
+ success: false,
587
+ error: 'Missing required connection parameters: name, host, or username'
588
+ });
589
+ }
590
+ // Ensure port is set
591
+ if (!connectionConfig.port) {
592
+ connectionConfig.port = 22;
593
+ }
594
+ // Create the connection
595
+ const connectionId = remote_connection_1.remoteConnectionManager.createConnection(connectionConfig);
596
+ res.status(201).json({
597
+ success: true,
598
+ connectionId,
599
+ message: 'Connection configuration saved'
600
+ });
601
+ }
602
+ catch (error) {
603
+ res.status(500).json({
604
+ success: false,
605
+ error: `Server error: ${error.message}`
606
+ });
607
+ }
608
+ });
609
+ /**
610
+ * Delete a connection configuration
611
+ * DELETE /api/remote/connections/:connectionId
612
+ */
613
+ router.delete('/connections/:connectionId', async (req, res) => {
614
+ try {
615
+ const { connectionId } = req.params;
616
+ // Disconnect if connected
617
+ await remote_connection_1.remoteConnectionManager.closeConnection(connectionId);
618
+ // Delete the connection from the manager
619
+ const success = remote_connection_1.remoteConnectionManager.deleteConnection(connectionId);
620
+ if (success) {
621
+ res.json({ success: true, message: 'Connection deleted' });
622
+ }
623
+ else {
624
+ res.status(404).json({ success: false, error: 'Connection not found' });
625
+ }
626
+ }
627
+ catch (error) {
628
+ res.status(500).json({
629
+ success: false,
630
+ error: `Server error: ${error.message}`
631
+ });
632
+ }
633
+ });
634
+ exports.default = router;
@@ -0,0 +1,72 @@
1
+ export interface ProjectConfig {
2
+ name: string;
3
+ detection: {
4
+ files: string[];
5
+ extensions: string[];
6
+ };
7
+ setup: {
8
+ steps: SetupStep[];
9
+ environment: Record<string, string>;
10
+ };
11
+ validation: {
12
+ checks: ValidationCheck[];
13
+ };
14
+ defaultConfig: {
15
+ interpreter: string;
16
+ execMode: 'fork' | 'cluster';
17
+ supportsCluster: boolean;
18
+ interpreterPath?: string;
19
+ startScript?: string;
20
+ startCommand?: string;
21
+ };
22
+ }
23
+ export interface SetupStep {
24
+ name: string;
25
+ command: string;
26
+ description: string;
27
+ required: boolean;
28
+ conditional?: string;
29
+ platform?: 'win32' | 'unix';
30
+ workingDirectory?: string;
31
+ useVenv?: boolean;
32
+ timeout?: number;
33
+ }
34
+ export interface ValidationCheck {
35
+ name: string;
36
+ file?: string;
37
+ directory?: string;
38
+ pattern?: string;
39
+ optional?: boolean;
40
+ }
41
+ export interface SetupResult {
42
+ success: boolean;
43
+ steps: StepResult[];
44
+ errors: string[];
45
+ warnings: string[];
46
+ environment: Record<string, string>;
47
+ interpreterPath?: string;
48
+ }
49
+ export interface StepResult {
50
+ name: string;
51
+ success: boolean;
52
+ output: string;
53
+ error?: string;
54
+ skipped?: boolean;
55
+ duration: number;
56
+ }
57
+ export declare class ProjectSetupService {
58
+ private configs;
59
+ private logFile;
60
+ constructor();
61
+ private loadConfigs;
62
+ private ensureLogDirectory;
63
+ private log;
64
+ detectProjectType(projectPath: string): string | null;
65
+ setupProject(projectPath: string, projectType: string): Promise<SetupResult>;
66
+ private shouldSkipStep;
67
+ private executeStep;
68
+ private validateSetup;
69
+ getProjectConfig(projectType: string): ProjectConfig | null;
70
+ getSupportedProjectTypes(): string[];
71
+ }
72
+ export declare const projectSetupService: ProjectSetupService;