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.
- package/dist/server/config/project-configs.json +236 -0
- package/dist/server/index.js +30 -5
- package/dist/server/logs/deployment.log +12 -0
- package/dist/server/routes/deployApplication.js +174 -27
- package/dist/server/routes/logStreaming.js +174 -0
- package/dist/server/routes/remoteConnections.d.ts +3 -0
- package/dist/server/routes/remoteConnections.js +634 -0
- package/dist/server/services/ProjectSetupService.d.ts +72 -0
- package/dist/server/services/ProjectSetupService.js +327 -0
- package/dist/server/utils/dialog.d.ts +1 -0
- package/dist/server/utils/dialog.js +16 -0
- package/dist/server/utils/encryption.d.ts +12 -0
- package/dist/server/utils/encryption.js +72 -0
- package/dist/server/utils/remote-connection.d.ts +152 -0
- package/dist/server/utils/remote-connection.js +590 -0
- package/dist/server/utils/upload.d.ts +3 -0
- package/dist/server/utils/upload.js +39 -0
- package/package.json +65 -63
- package/src/client/build/asset-manifest.json +3 -3
- package/src/client/build/favicon.ico +2 -0
- package/src/client/build/index.html +1 -1
- package/src/client/build/logo192.svg +7 -0
- package/src/client/build/logo512.svg +7 -0
- package/src/client/build/manifest.json +5 -6
- package/src/client/build/static/js/{main.1d7f99ff.js → main.31323a04.js} +13 -13
- package/src/client/build/static/js/main.31323a04.js.map +1 -0
- package/src/client/build/static/js/main.1d7f99ff.js.map +0 -1
- /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;
|