@deinossrl/dgp-agent 1.0.0 → 1.1.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/index.mjs +333 -22
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* DGP Agent - Agente local para Despliegue-GPT
|
|
4
|
-
* @
|
|
4
|
+
* @deinossrl/dgp-agent
|
|
5
5
|
*
|
|
6
6
|
* Este agente corre en la máquina del desarrollador y:
|
|
7
7
|
* 1. Reporta el estado del repositorio git a la plataforma TenMinute IA
|
|
8
|
-
* 2.
|
|
8
|
+
* 2. Ejecuta comandos de deploy enviados desde la plataforma
|
|
9
9
|
*
|
|
10
10
|
* Instalación:
|
|
11
|
-
* npm install -g @
|
|
11
|
+
* npm install -g @deinossrl/dgp-agent
|
|
12
12
|
*
|
|
13
13
|
* Uso:
|
|
14
14
|
* dgp-agent # Inicia el agente (reporta cada 30s)
|
|
15
15
|
* dgp-agent status # Muestra estado una vez
|
|
16
|
+
* dgp-agent deploy # Modo deploy (escucha comandos)
|
|
16
17
|
* dgp-agent help # Muestra ayuda
|
|
17
18
|
*
|
|
18
19
|
* Variables de entorno:
|
|
@@ -22,13 +23,16 @@
|
|
|
22
23
|
* DGP_MACHINE_ID ID personalizado de la máquina
|
|
23
24
|
*/
|
|
24
25
|
|
|
25
|
-
import { execSync } from 'child_process';
|
|
26
|
+
import { execSync, spawn } from 'child_process';
|
|
26
27
|
import { hostname } from 'os';
|
|
27
28
|
|
|
28
29
|
// Configuración
|
|
29
30
|
const CONFIG = {
|
|
30
31
|
apiUrl: process.env.DGP_API_URL || 'https://asivayhbrqennwiwttds.supabase.co/functions/v1/dgp-agent-status',
|
|
32
|
+
commandsUrl: process.env.DGP_COMMANDS_URL || 'https://asivayhbrqennwiwttds.supabase.co/rest/v1/dgp_agent_commands',
|
|
33
|
+
supabaseKey: process.env.DGP_SUPABASE_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFzaXZheWhicnFlbm53aXd0dGRzIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NjczMDAwOTcsImV4cCI6MjA4Mjg3NjA5N30.s3a7dR-dPkEXI7B2lUTUXU69923hhuX6meheNeo5EKA',
|
|
31
34
|
interval: parseInt(process.env.DGP_INTERVAL || '30', 10),
|
|
35
|
+
commandPollInterval: parseInt(process.env.DGP_COMMAND_POLL_INTERVAL || '10', 10),
|
|
32
36
|
machineId: process.env.DGP_MACHINE_ID || `${hostname()}-${process.env.USERNAME || process.env.USER || 'dev'}`,
|
|
33
37
|
authToken: process.env.DGP_AUTH_TOKEN || null,
|
|
34
38
|
};
|
|
@@ -42,6 +46,7 @@ const colors = {
|
|
|
42
46
|
red: '\x1b[31m',
|
|
43
47
|
gray: '\x1b[90m',
|
|
44
48
|
cyan: '\x1b[36m',
|
|
49
|
+
magenta: '\x1b[35m',
|
|
45
50
|
bold: '\x1b[1m',
|
|
46
51
|
};
|
|
47
52
|
|
|
@@ -62,6 +67,10 @@ function logInfo(message) {
|
|
|
62
67
|
log(message, 'blue');
|
|
63
68
|
}
|
|
64
69
|
|
|
70
|
+
function logCommand(message) {
|
|
71
|
+
log(message, 'magenta');
|
|
72
|
+
}
|
|
73
|
+
|
|
65
74
|
/**
|
|
66
75
|
* Ejecuta un comando git y retorna el resultado
|
|
67
76
|
*/
|
|
@@ -76,6 +85,64 @@ function git(command) {
|
|
|
76
85
|
}
|
|
77
86
|
}
|
|
78
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Ejecuta un comando shell y retorna el resultado
|
|
90
|
+
*/
|
|
91
|
+
function shell(command, options = {}) {
|
|
92
|
+
try {
|
|
93
|
+
return execSync(command, {
|
|
94
|
+
encoding: 'utf-8',
|
|
95
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
96
|
+
...options,
|
|
97
|
+
}).trim();
|
|
98
|
+
} catch (error) {
|
|
99
|
+
throw new Error(`Command failed: ${command}\n${error.message}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Ejecuta un comando shell de forma asíncrona con output en tiempo real
|
|
105
|
+
*/
|
|
106
|
+
function shellAsync(command, options = {}) {
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
const isWindows = process.platform === 'win32';
|
|
109
|
+
const shellCmd = isWindows ? 'cmd' : '/bin/sh';
|
|
110
|
+
const shellArgs = isWindows ? ['/c', command] : ['-c', command];
|
|
111
|
+
|
|
112
|
+
const proc = spawn(shellCmd, shellArgs, {
|
|
113
|
+
...options,
|
|
114
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
let stdout = '';
|
|
118
|
+
let stderr = '';
|
|
119
|
+
|
|
120
|
+
proc.stdout.on('data', (data) => {
|
|
121
|
+
const str = data.toString();
|
|
122
|
+
stdout += str;
|
|
123
|
+
process.stdout.write(colors.gray + str + colors.reset);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
proc.stderr.on('data', (data) => {
|
|
127
|
+
const str = data.toString();
|
|
128
|
+
stderr += str;
|
|
129
|
+
process.stderr.write(colors.yellow + str + colors.reset);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
proc.on('close', (code) => {
|
|
133
|
+
if (code === 0) {
|
|
134
|
+
resolve({ stdout, stderr, code });
|
|
135
|
+
} else {
|
|
136
|
+
reject(new Error(`Command exited with code ${code}\n${stderr}`));
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
proc.on('error', (error) => {
|
|
141
|
+
reject(error);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
79
146
|
/**
|
|
80
147
|
* Verifica si estamos en un repositorio git
|
|
81
148
|
*/
|
|
@@ -194,6 +261,195 @@ async function reportStatus(status) {
|
|
|
194
261
|
return await response.json();
|
|
195
262
|
}
|
|
196
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Obtiene comandos pendientes de la plataforma
|
|
266
|
+
*/
|
|
267
|
+
async function getPendingCommands() {
|
|
268
|
+
const url = `${CONFIG.commandsUrl}?status=eq.pending&select=*&order=created_at.asc&limit=1`;
|
|
269
|
+
|
|
270
|
+
const response = await fetch(url, {
|
|
271
|
+
headers: {
|
|
272
|
+
'apikey': CONFIG.supabaseKey,
|
|
273
|
+
'Authorization': `Bearer ${CONFIG.supabaseKey}`,
|
|
274
|
+
},
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
if (!response.ok) {
|
|
278
|
+
throw new Error(`Failed to get commands: HTTP ${response.status}`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return await response.json();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Actualiza el estado de un comando
|
|
286
|
+
*/
|
|
287
|
+
async function updateCommandStatus(commandId, status, result = {}, errorMessage = null) {
|
|
288
|
+
const payload = {
|
|
289
|
+
status,
|
|
290
|
+
result,
|
|
291
|
+
error_message: errorMessage,
|
|
292
|
+
...(status === 'running' ? { picked_up_at: new Date().toISOString() } : {}),
|
|
293
|
+
...(status === 'success' || status === 'failed' ? { completed_at: new Date().toISOString() } : {}),
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const url = `${CONFIG.commandsUrl}?id=eq.${commandId}`;
|
|
297
|
+
|
|
298
|
+
const response = await fetch(url, {
|
|
299
|
+
method: 'PATCH',
|
|
300
|
+
headers: {
|
|
301
|
+
'apikey': CONFIG.supabaseKey,
|
|
302
|
+
'Authorization': `Bearer ${CONFIG.supabaseKey}`,
|
|
303
|
+
'Content-Type': 'application/json',
|
|
304
|
+
'Prefer': 'return=minimal',
|
|
305
|
+
},
|
|
306
|
+
body: JSON.stringify(payload),
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
if (!response.ok) {
|
|
310
|
+
throw new Error(`Failed to update command: HTTP ${response.status}`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Ejecuta un comando de deploy
|
|
316
|
+
*/
|
|
317
|
+
async function executeDeploy(command) {
|
|
318
|
+
const { id, environment, branch, server_host, ssh_user, deploy_url } = command;
|
|
319
|
+
|
|
320
|
+
logCommand(`=== Executing Deploy Command ===`);
|
|
321
|
+
logInfo(`Environment: ${environment}`);
|
|
322
|
+
logInfo(`Branch: ${branch}`);
|
|
323
|
+
logInfo(`Server: ${ssh_user}@${server_host}`);
|
|
324
|
+
|
|
325
|
+
const steps = [];
|
|
326
|
+
let currentStep = '';
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
// Mark as running
|
|
330
|
+
await updateCommandStatus(id, 'running');
|
|
331
|
+
|
|
332
|
+
// Step 1: Git fetch and checkout
|
|
333
|
+
currentStep = 'git_checkout';
|
|
334
|
+
logCommand(`[1/5] Checkout branch ${branch}...`);
|
|
335
|
+
steps.push({ step: currentStep, status: 'running' });
|
|
336
|
+
|
|
337
|
+
await shellAsync(`git fetch origin`);
|
|
338
|
+
await shellAsync(`git checkout ${branch}`);
|
|
339
|
+
await shellAsync(`git pull origin ${branch}`);
|
|
340
|
+
|
|
341
|
+
steps[steps.length - 1].status = 'success';
|
|
342
|
+
logSuccess(`Branch ${branch} updated`);
|
|
343
|
+
|
|
344
|
+
// Step 2: Install dependencies
|
|
345
|
+
currentStep = 'npm_install';
|
|
346
|
+
logCommand(`[2/5] Installing dependencies...`);
|
|
347
|
+
steps.push({ step: currentStep, status: 'running' });
|
|
348
|
+
|
|
349
|
+
await shellAsync(`npm ci`);
|
|
350
|
+
|
|
351
|
+
steps[steps.length - 1].status = 'success';
|
|
352
|
+
logSuccess(`Dependencies installed`);
|
|
353
|
+
|
|
354
|
+
// Step 3: Build
|
|
355
|
+
currentStep = 'npm_build';
|
|
356
|
+
logCommand(`[3/5] Building application...`);
|
|
357
|
+
steps.push({ step: currentStep, status: 'running' });
|
|
358
|
+
|
|
359
|
+
await shellAsync(`npm run build`);
|
|
360
|
+
|
|
361
|
+
steps[steps.length - 1].status = 'success';
|
|
362
|
+
logSuccess(`Build completed`);
|
|
363
|
+
|
|
364
|
+
// Step 4: Deploy via rsync
|
|
365
|
+
currentStep = 'rsync_deploy';
|
|
366
|
+
logCommand(`[4/5] Deploying to server...`);
|
|
367
|
+
steps.push({ step: currentStep, status: 'running' });
|
|
368
|
+
|
|
369
|
+
const deployFolder = environment === 'production'
|
|
370
|
+
? '/var/www/tenminuteia-prod/'
|
|
371
|
+
: '/var/www/tenminuteia-staging/';
|
|
372
|
+
|
|
373
|
+
// Rsync the dist folder
|
|
374
|
+
await shellAsync(`rsync -avz --delete dist/ ${ssh_user}@${server_host}:${deployFolder}`);
|
|
375
|
+
|
|
376
|
+
steps[steps.length - 1].status = 'success';
|
|
377
|
+
logSuccess(`Files deployed to ${server_host}:${deployFolder}`);
|
|
378
|
+
|
|
379
|
+
// Step 5: Reload nginx
|
|
380
|
+
currentStep = 'reload_nginx';
|
|
381
|
+
logCommand(`[5/5] Reloading Nginx...`);
|
|
382
|
+
steps.push({ step: currentStep, status: 'running' });
|
|
383
|
+
|
|
384
|
+
await shellAsync(`ssh ${ssh_user}@${server_host} "sudo nginx -t && sudo systemctl reload nginx"`);
|
|
385
|
+
|
|
386
|
+
steps[steps.length - 1].status = 'success';
|
|
387
|
+
logSuccess(`Nginx reloaded`);
|
|
388
|
+
|
|
389
|
+
// Healthcheck (optional)
|
|
390
|
+
if (deploy_url) {
|
|
391
|
+
logCommand(`Verifying deployment at ${deploy_url}...`);
|
|
392
|
+
try {
|
|
393
|
+
const healthResponse = await fetch(deploy_url);
|
|
394
|
+
if (healthResponse.ok) {
|
|
395
|
+
logSuccess(`Healthcheck passed`);
|
|
396
|
+
} else {
|
|
397
|
+
log(`Healthcheck returned ${healthResponse.status}`, 'yellow');
|
|
398
|
+
}
|
|
399
|
+
} catch (e) {
|
|
400
|
+
log(`Healthcheck failed: ${e.message}`, 'yellow');
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Mark as success
|
|
405
|
+
await updateCommandStatus(id, 'success', { steps, deploy_url });
|
|
406
|
+
|
|
407
|
+
console.log('');
|
|
408
|
+
logSuccess(`=== Deploy to ${environment} completed successfully! ===`);
|
|
409
|
+
console.log('');
|
|
410
|
+
|
|
411
|
+
return { success: true };
|
|
412
|
+
|
|
413
|
+
} catch (error) {
|
|
414
|
+
logError(`Deploy failed at step: ${currentStep}`);
|
|
415
|
+
logError(error.message);
|
|
416
|
+
|
|
417
|
+
steps[steps.length - 1].status = 'failed';
|
|
418
|
+
steps[steps.length - 1].error = error.message;
|
|
419
|
+
|
|
420
|
+
await updateCommandStatus(id, 'failed', { steps }, error.message);
|
|
421
|
+
|
|
422
|
+
return { success: false, error: error.message };
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Ejecuta un comando recibido
|
|
428
|
+
*/
|
|
429
|
+
async function executeCommand(command) {
|
|
430
|
+
logCommand(`Received command: ${command.command}`);
|
|
431
|
+
|
|
432
|
+
switch (command.command) {
|
|
433
|
+
case 'deploy':
|
|
434
|
+
return await executeDeploy(command);
|
|
435
|
+
|
|
436
|
+
case 'status':
|
|
437
|
+
const status = getRepoStatus();
|
|
438
|
+
await updateCommandStatus(command.id, 'success', { status });
|
|
439
|
+
return { success: true, status };
|
|
440
|
+
|
|
441
|
+
case 'rollback':
|
|
442
|
+
logError('Rollback not implemented yet');
|
|
443
|
+
await updateCommandStatus(command.id, 'failed', {}, 'Rollback not implemented');
|
|
444
|
+
return { success: false };
|
|
445
|
+
|
|
446
|
+
default:
|
|
447
|
+
logError(`Unknown command: ${command.command}`);
|
|
448
|
+
await updateCommandStatus(command.id, 'failed', {}, `Unknown command: ${command.command}`);
|
|
449
|
+
return { success: false };
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
197
453
|
/**
|
|
198
454
|
* Muestra el estado en consola
|
|
199
455
|
*/
|
|
@@ -223,11 +479,11 @@ function printStatus(status) {
|
|
|
223
479
|
/**
|
|
224
480
|
* Loop principal del agente
|
|
225
481
|
*/
|
|
226
|
-
async function runAgent() {
|
|
482
|
+
async function runAgent(deployMode = false) {
|
|
227
483
|
console.log('');
|
|
228
484
|
console.log(`${colors.green}╔═══════════════════════════════════════════════════════╗${colors.reset}`);
|
|
229
485
|
console.log(`${colors.green}║ DGP Agent - Despliegue-GPT Local Agent ║${colors.reset}`);
|
|
230
|
-
console.log(`${colors.green}║ @
|
|
486
|
+
console.log(`${colors.green}║ @deinossrl/dgp-agent v1.1.0 ║${colors.reset}`);
|
|
231
487
|
console.log(`${colors.green}╚═══════════════════════════════════════════════════════╝${colors.reset}`);
|
|
232
488
|
console.log('');
|
|
233
489
|
|
|
@@ -240,6 +496,11 @@ async function runAgent() {
|
|
|
240
496
|
logInfo(`Report interval: ${CONFIG.interval}s`);
|
|
241
497
|
logInfo(`API URL: ${CONFIG.apiUrl}`);
|
|
242
498
|
|
|
499
|
+
if (deployMode) {
|
|
500
|
+
logInfo(`Deploy mode: ACTIVE`);
|
|
501
|
+
logInfo(`Command poll interval: ${CONFIG.commandPollInterval}s`);
|
|
502
|
+
}
|
|
503
|
+
|
|
243
504
|
if (!CONFIG.authToken) {
|
|
244
505
|
log('INFO: No auth token. Reporting anonymously.', 'yellow');
|
|
245
506
|
log('Set DGP_AUTH_TOKEN to associate with your user.', 'gray');
|
|
@@ -249,7 +510,8 @@ async function runAgent() {
|
|
|
249
510
|
logInfo('Press Ctrl+C to stop');
|
|
250
511
|
console.log('');
|
|
251
512
|
|
|
252
|
-
|
|
513
|
+
// Status reporting cycle
|
|
514
|
+
const runStatusCycle = async () => {
|
|
253
515
|
try {
|
|
254
516
|
const status = getRepoStatus();
|
|
255
517
|
printStatus(status);
|
|
@@ -262,8 +524,36 @@ async function runAgent() {
|
|
|
262
524
|
}
|
|
263
525
|
};
|
|
264
526
|
|
|
265
|
-
|
|
266
|
-
|
|
527
|
+
// Command polling cycle (only in deploy mode)
|
|
528
|
+
const runCommandCycle = async () => {
|
|
529
|
+
try {
|
|
530
|
+
const commands = await getPendingCommands();
|
|
531
|
+
if (commands.length > 0) {
|
|
532
|
+
const command = commands[0];
|
|
533
|
+
logCommand(`Found pending command: ${command.id}`);
|
|
534
|
+
await executeCommand(command);
|
|
535
|
+
}
|
|
536
|
+
} catch (error) {
|
|
537
|
+
// Silent fail for command polling - don't spam logs
|
|
538
|
+
if (error.message.includes('42P01')) {
|
|
539
|
+
// Table doesn't exist yet - ignore
|
|
540
|
+
} else {
|
|
541
|
+
logError(`Command poll failed: ${error.message}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
// Initial run
|
|
547
|
+
await runStatusCycle();
|
|
548
|
+
if (deployMode) {
|
|
549
|
+
await runCommandCycle();
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Set intervals
|
|
553
|
+
setInterval(runStatusCycle, CONFIG.interval * 1000);
|
|
554
|
+
if (deployMode) {
|
|
555
|
+
setInterval(runCommandCycle, CONFIG.commandPollInterval * 1000);
|
|
556
|
+
}
|
|
267
557
|
}
|
|
268
558
|
|
|
269
559
|
/**
|
|
@@ -309,37 +599,53 @@ async function showStatus() {
|
|
|
309
599
|
function showHelp() {
|
|
310
600
|
console.log(`
|
|
311
601
|
${colors.bold}${colors.cyan}DGP Agent - Despliegue-GPT Local Agent${colors.reset}
|
|
312
|
-
${colors.gray}@
|
|
602
|
+
${colors.gray}@deinossrl/dgp-agent v1.1.0${colors.reset}
|
|
313
603
|
|
|
314
604
|
${colors.bold}DESCRIPCIÓN${colors.reset}
|
|
315
605
|
Agente local que reporta el estado de tu repositorio Git
|
|
316
|
-
a la plataforma TenMinute IA (Despliegue-GPT)
|
|
606
|
+
a la plataforma TenMinute IA (Despliegue-GPT) y puede
|
|
607
|
+
ejecutar comandos de deploy remotos.
|
|
317
608
|
|
|
318
609
|
${colors.bold}INSTALACIÓN${colors.reset}
|
|
319
|
-
${colors.green}npm install -g @
|
|
610
|
+
${colors.green}npm install -g @deinossrl/dgp-agent${colors.reset}
|
|
320
611
|
|
|
321
612
|
${colors.bold}USO${colors.reset}
|
|
322
|
-
${colors.cyan}dgp-agent${colors.reset} Inicia el agente (reporta
|
|
613
|
+
${colors.cyan}dgp-agent${colors.reset} Inicia el agente (solo reporta estado)
|
|
614
|
+
${colors.cyan}dgp-agent deploy${colors.reset} Modo deploy (reporta + escucha comandos)
|
|
323
615
|
${colors.cyan}dgp-agent status${colors.reset} Muestra el estado actual una vez
|
|
324
616
|
${colors.cyan}dgp-agent help${colors.reset} Muestra esta ayuda
|
|
325
617
|
|
|
618
|
+
${colors.bold}MODOS DE OPERACIÓN${colors.reset}
|
|
619
|
+
${colors.yellow}Default${colors.reset} Solo reporta estado del repo cada 30s
|
|
620
|
+
${colors.yellow}Deploy${colors.reset} Reporta estado + escucha comandos de la plataforma
|
|
621
|
+
Puede ejecutar: build, deploy via rsync, reload nginx
|
|
622
|
+
|
|
326
623
|
${colors.bold}VARIABLES DE ENTORNO${colors.reset}
|
|
327
|
-
${colors.yellow}DGP_AUTH_TOKEN${colors.reset}
|
|
328
|
-
|
|
329
|
-
${colors.yellow}
|
|
330
|
-
${colors.yellow}
|
|
331
|
-
${colors.yellow}DGP_MACHINE_ID${colors.reset}
|
|
624
|
+
${colors.yellow}DGP_AUTH_TOKEN${colors.reset} Token JWT para asociar a tu usuario
|
|
625
|
+
${colors.yellow}DGP_API_URL${colors.reset} URL del endpoint API
|
|
626
|
+
${colors.yellow}DGP_INTERVAL${colors.reset} Intervalo de reporte en segundos (default: 30)
|
|
627
|
+
${colors.yellow}DGP_COMMAND_POLL_INTERVAL${colors.reset} Intervalo de polling comandos (default: 10)
|
|
628
|
+
${colors.yellow}DGP_MACHINE_ID${colors.reset} ID personalizado de la máquina
|
|
332
629
|
|
|
333
630
|
${colors.bold}EJEMPLOS${colors.reset}
|
|
334
|
-
# Iniciar agente básico
|
|
631
|
+
# Iniciar agente básico (solo reporta)
|
|
335
632
|
${colors.gray}$ dgp-agent${colors.reset}
|
|
336
633
|
|
|
634
|
+
# Iniciar en modo deploy (puede ejecutar deploys)
|
|
635
|
+
${colors.gray}$ dgp-agent deploy${colors.reset}
|
|
636
|
+
|
|
337
637
|
# Con token de autenticación
|
|
338
|
-
${colors.gray}$ DGP_AUTH_TOKEN=eyJ... dgp-agent${colors.reset}
|
|
638
|
+
${colors.gray}$ DGP_AUTH_TOKEN=eyJ... dgp-agent deploy${colors.reset}
|
|
339
639
|
|
|
340
640
|
# Intervalo personalizado (60 segundos)
|
|
341
641
|
${colors.gray}$ DGP_INTERVAL=60 dgp-agent${colors.reset}
|
|
342
642
|
|
|
643
|
+
${colors.bold}REQUISITOS PARA DEPLOY${colors.reset}
|
|
644
|
+
- SSH key configurada para acceso al servidor
|
|
645
|
+
- Node.js y npm en el PATH
|
|
646
|
+
- rsync instalado (Linux/Mac) o equivalente (Windows)
|
|
647
|
+
- Permisos sudo para reload nginx (vía sudoers sin password)
|
|
648
|
+
|
|
343
649
|
${colors.bold}MÁS INFO${colors.reset}
|
|
344
650
|
https://github.com/DEINOS-SRL/tenminuteia
|
|
345
651
|
`);
|
|
@@ -350,6 +656,11 @@ const args = process.argv.slice(2);
|
|
|
350
656
|
const command = args[0];
|
|
351
657
|
|
|
352
658
|
switch (command) {
|
|
659
|
+
case 'deploy':
|
|
660
|
+
case '-d':
|
|
661
|
+
case '--deploy':
|
|
662
|
+
runAgent(true); // Deploy mode
|
|
663
|
+
break;
|
|
353
664
|
case 'status':
|
|
354
665
|
case '-s':
|
|
355
666
|
case '--status':
|
|
@@ -363,8 +674,8 @@ switch (command) {
|
|
|
363
674
|
case 'version':
|
|
364
675
|
case '-v':
|
|
365
676
|
case '--version':
|
|
366
|
-
console.log('@
|
|
677
|
+
console.log('@deinossrl/dgp-agent v1.1.0');
|
|
367
678
|
break;
|
|
368
679
|
default:
|
|
369
|
-
runAgent();
|
|
680
|
+
runAgent(false); // Status-only mode
|
|
370
681
|
}
|