@deinossrl/dgp-agent 1.4.11 → 1.4.13

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 (2) hide show
  1. package/index.mjs +154 -42
  2. package/package.json +1 -1
package/index.mjs CHANGED
@@ -23,7 +23,7 @@
23
23
  * DGP_MACHINE_ID ID personalizado de la máquina
24
24
  */
25
25
 
26
- import { execSync, spawn } from 'child_process';
26
+ import { execSync, spawn, spawnSync } from 'child_process';
27
27
  import { hostname, homedir } from 'os';
28
28
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
29
29
  import { join, dirname } from 'path';
@@ -203,7 +203,7 @@ async function fetchPlatformConfig() {
203
203
  let platformConfig = null;
204
204
 
205
205
  // Versión y modo del agente
206
- const AGENT_VERSION = '1.4.11';
206
+ const AGENT_VERSION = '1.4.13';
207
207
  let AGENT_MODE = 'status'; // 'status' | 'deploy' | 'ai'
208
208
 
209
209
  // Configuración (prioridad: env vars > archivo config > platform config > defaults)
@@ -395,6 +395,51 @@ function getRepoContext() {
395
395
  return context;
396
396
  }
397
397
 
398
+ /**
399
+ * Procesa un comando git con ayuda de IA para entender mejor la intención
400
+ */
401
+ async function processGitCommandWithAI(command, params) {
402
+ logAI(`Procesando comando con IA: ${command}`);
403
+
404
+ const context = getRepoContext();
405
+
406
+ const systemPrompt = `Eres un experto en Git y DevOps. Tu trabajo es analizar comandos git y mejorarlos si es necesario.
407
+
408
+ IMPORTANTE:
409
+ - Si el comando es claro, simplemente ejecuta lo solicitado
410
+ - Si hay ambigüedad, usa tu inteligencia para resolver
411
+ - Genera mensajes de commit descriptivos si el mensaje es vago
412
+ - Responde SOLO con JSON válido
413
+
414
+ Formato de respuesta:
415
+ {
416
+ "analysis": "qué vas a hacer y por qué",
417
+ "improved_message": "mensaje mejorado (solo para commits)",
418
+ "additional_commands": ["comandos adicionales si son necesarios"],
419
+ "skip": false
420
+ }`;
421
+
422
+ const prompt = `Contexto del repositorio:
423
+ ${JSON.stringify(context, null, 2)}
424
+
425
+ Comando recibido: ${command}
426
+ Parámetros: ${JSON.stringify(params)}
427
+
428
+ Analiza y mejora este comando si es necesario.`;
429
+
430
+ try {
431
+ const response = await callClaude(prompt, systemPrompt);
432
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
433
+ if (jsonMatch) {
434
+ return JSON.parse(jsonMatch[0]);
435
+ }
436
+ return null;
437
+ } catch (e) {
438
+ logError(`Error procesando con IA: ${e.message}`);
439
+ return null;
440
+ }
441
+ }
442
+
398
443
  /**
399
444
  * Ejecuta una tarea usando IA
400
445
  */
@@ -594,9 +639,9 @@ async function runAIMode() {
594
639
  logError('Tarea AI fallida');
595
640
  }
596
641
  } else {
597
- // Comandos git (git_commit_push, git_pull, git_fetch, etc)
642
+ // Comandos git (git_commit_push, git_pull, git_fetch, etc) - con IA activa
598
643
  logInfo(`📥 Comando recibido: ${command.command}`);
599
- await executeCommand(command);
644
+ await executeCommand(command, true); // useAI = true en modo AI
600
645
  }
601
646
 
602
647
  isProcessing = false;
@@ -666,6 +711,9 @@ function shell(command, options = {}) {
666
711
  }
667
712
  }
668
713
 
714
+ // Alias para compatibilidad
715
+ const shellSync = shell;
716
+
669
717
  /**
670
718
  * Ejecuta un comando shell de forma asíncrona con output en tiempo real
671
719
  */
@@ -994,9 +1042,11 @@ async function executeDeploy(command) {
994
1042
 
995
1043
  /**
996
1044
  * Ejecuta un comando recibido
1045
+ * @param {Object} command - El comando a ejecutar
1046
+ * @param {boolean} useAI - Si es true, usa IA para mejorar la ejecución
997
1047
  */
998
- async function executeCommand(command) {
999
- logCommand(`Received command: ${command.command}`);
1048
+ async function executeCommand(command, useAI = false) {
1049
+ logCommand(`Received command: ${command.command}${useAI ? ' (con IA)' : ''}`);
1000
1050
 
1001
1051
  switch (command.command) {
1002
1052
  case 'deploy':
@@ -1008,7 +1058,7 @@ async function executeCommand(command) {
1008
1058
  return { success: true, status };
1009
1059
 
1010
1060
  case 'git_commit_push':
1011
- return await executeGitCommitPush(command);
1061
+ return await executeGitCommitPush(command, useAI);
1012
1062
 
1013
1063
  case 'rollback':
1014
1064
  logError('Rollback not implemented yet');
@@ -1016,6 +1066,15 @@ async function executeCommand(command) {
1016
1066
  return { success: false };
1017
1067
 
1018
1068
  default:
1069
+ // Si es un comando desconocido pero tenemos IA, intentar procesarlo
1070
+ if (useAI && CONFIG.anthropicApiKey) {
1071
+ logAI(`Intentando procesar comando desconocido con IA: ${command.command}`);
1072
+ const result = await executeAITask(`Ejecutar: ${command.command} con params: ${JSON.stringify(command.params || {})}`);
1073
+ if (result.success) {
1074
+ await updateCommandStatus(command.id, 'completed', result);
1075
+ return result;
1076
+ }
1077
+ }
1019
1078
  logError(`Unknown command: ${command.command}`);
1020
1079
  await updateCommandStatus(command.id, 'failed', {}, `Unknown command: ${command.command}`);
1021
1080
  return { success: false };
@@ -1023,10 +1082,10 @@ async function executeCommand(command) {
1023
1082
  }
1024
1083
 
1025
1084
  /**
1026
- * Ejecuta git add, commit y push
1085
+ * Ejecuta git add, commit y push (con mejoras de IA si está disponible)
1027
1086
  */
1028
- async function executeGitCommitPush(command) {
1029
- const { message, add_all } = command.params || {};
1087
+ async function executeGitCommitPush(command, useAI = false) {
1088
+ let { message, add_all } = command.params || {};
1030
1089
 
1031
1090
  if (!message) {
1032
1091
  await updateCommandStatus(command.id, 'failed', {}, 'Commit message is required');
@@ -1037,6 +1096,20 @@ async function executeGitCommitPush(command) {
1037
1096
  // Marcar como running
1038
1097
  await updateCommandStatus(command.id, 'running', {});
1039
1098
 
1099
+ // Si tenemos API key y useAI está activo, mejorar el mensaje con IA
1100
+ let aiAnalysis = null;
1101
+ if (useAI && CONFIG.anthropicApiKey) {
1102
+ logAI('Analizando commit con IA...');
1103
+ aiAnalysis = await processGitCommandWithAI('git_commit_push', { message, add_all });
1104
+ if (aiAnalysis) {
1105
+ logAI(`Análisis: ${aiAnalysis.analysis}`);
1106
+ if (aiAnalysis.improved_message && aiAnalysis.improved_message !== message) {
1107
+ logAI(`Mensaje mejorado: ${aiAnalysis.improved_message}`);
1108
+ message = aiAnalysis.improved_message;
1109
+ }
1110
+ }
1111
+ }
1112
+
1040
1113
  logInfo('Executing git commit + push...');
1041
1114
 
1042
1115
  // git add
@@ -1045,21 +1118,21 @@ async function executeGitCommitPush(command) {
1045
1118
  await shellAsync('git add .');
1046
1119
  }
1047
1120
 
1048
- // git commit - escapar mensaje según el SO
1049
- const isWindows = process.platform === 'win32';
1050
- let commitCmd;
1051
- if (isWindows) {
1052
- // En Windows cmd /c, escapar comillas con \"
1053
- const safeMessage = message.replace(/"/g, '\\"');
1054
- commitCmd = `git commit -m "${safeMessage}"`;
1121
+ // git commit - usar spawnSync para evitar problemas de comillas en shell
1122
+ logCommand(`git commit -m "${message}"`);
1123
+ const commitProc = spawnSync('git', ['commit', '-m', message], { encoding: 'utf-8' });
1124
+ if (commitProc.status !== 0) {
1125
+ const errorMsg = commitProc.stderr || commitProc.stdout || 'Unknown error';
1126
+ // Verificar si es "nothing to commit"
1127
+ if (errorMsg.includes('nothing to commit') || (commitProc.stdout && commitProc.stdout.includes('nothing to commit'))) {
1128
+ logInfo('Nothing to commit, skipping...');
1129
+ } else {
1130
+ throw new Error(`Git commit failed: ${errorMsg}`);
1131
+ }
1055
1132
  } else {
1056
- // En Unix, usar comillas simples es más seguro
1057
- const safeMessage = message.replace(/'/g, "'\\''");
1058
- commitCmd = `git commit -m '${safeMessage}'`;
1133
+ logSuccess('Commit created');
1134
+ if (commitProc.stdout) console.log(colors.gray + commitProc.stdout + colors.reset);
1059
1135
  }
1060
- logCommand(`git commit -m "${message}"`);
1061
- const commitResult = await shellAsync(commitCmd);
1062
- logSuccess('Commit created');
1063
1136
 
1064
1137
  // git push
1065
1138
  const branch = shellSync('git branch --show-current').trim();
@@ -1068,8 +1141,9 @@ async function executeGitCommitPush(command) {
1068
1141
  logSuccess('Push completed');
1069
1142
 
1070
1143
  await updateCommandStatus(command.id, 'completed', {
1071
- commit: commitResult,
1072
- branch: branch
1144
+ message: message,
1145
+ branch: branch,
1146
+ ai_analysis: aiAnalysis?.analysis || null
1073
1147
  });
1074
1148
 
1075
1149
  return { success: true };
@@ -1157,36 +1231,74 @@ async function runAgent(deployMode = false) {
1157
1231
  }
1158
1232
  };
1159
1233
 
1160
- // Command polling cycle (only in deploy mode)
1234
+ // Command polling cycle - SIEMPRE escucha comandos (Web PC)
1235
+ let isProcessingCommand = false;
1161
1236
  const runCommandCycle = async () => {
1237
+ if (isProcessingCommand) return;
1238
+
1162
1239
  try {
1163
- const commands = await getPendingCommands();
1164
- if (commands.length > 0) {
1165
- const command = commands[0];
1166
- logCommand(`Found pending command: ${command.id}`);
1167
- await executeCommand(command);
1240
+ // Buscar comandos pendientes para ESTE machine_id
1241
+ const url = `${CONFIG.commandsUrl}?machine_id=eq.${CONFIG.machineId}&status=eq.pending&select=*&order=created_at.asc&limit=1`;
1242
+ const response = await fetch(url, {
1243
+ headers: {
1244
+ 'apikey': CONFIG.supabaseKey,
1245
+ 'Authorization': `Bearer ${CONFIG.supabaseKey}`,
1246
+ },
1247
+ });
1248
+
1249
+ if (!response.ok) return;
1250
+
1251
+ const commands = await response.json();
1252
+ if (commands.length === 0) return;
1253
+
1254
+ const command = commands[0];
1255
+ isProcessingCommand = true;
1256
+
1257
+ logCommand(`📥 Comando recibido: ${command.command}`);
1258
+
1259
+ // Verificar si tenemos IA disponible
1260
+ const useAI = !!CONFIG.anthropicApiKey;
1261
+
1262
+ if (command.command === 'ai_task' && useAI) {
1263
+ // Tarea AI - ejecutar con Claude
1264
+ await updateCommandStatus(command.id, 'running', {});
1265
+ const result = await executeAITask(command.params?.task || '');
1266
+
1267
+ if (result.success) {
1268
+ await updateCommandStatus(command.id, 'completed', {
1269
+ output: result.results?.map(r => r.output).join('\n'),
1270
+ commands_executed: result.results?.length || 0,
1271
+ });
1272
+ logSuccess('Tarea completada');
1273
+ } else {
1274
+ await updateCommandStatus(command.id, 'failed', {}, result.error || 'Task failed');
1275
+ logError('Tarea fallida');
1276
+ }
1277
+ } else {
1278
+ // Comandos git y otros
1279
+ await executeCommand(command, useAI);
1168
1280
  }
1281
+
1282
+ isProcessingCommand = false;
1283
+
1169
1284
  } catch (error) {
1285
+ isProcessingCommand = false;
1170
1286
  // Silent fail for command polling - don't spam logs
1171
- if (error.message.includes('42P01')) {
1172
- // Table doesn't exist yet - ignore
1173
- } else {
1174
- logError(`Command poll failed: ${error.message}`);
1287
+ if (!error.message?.includes('42P01')) {
1288
+ // Solo loggear si no es error de tabla inexistente
1175
1289
  }
1176
1290
  }
1177
1291
  };
1178
1292
 
1179
1293
  // Initial run
1180
1294
  await runStatusCycle();
1181
- if (deployMode) {
1182
- await runCommandCycle();
1183
- }
1295
+ await runCommandCycle();
1184
1296
 
1185
- // Set intervals
1297
+ // Set intervals - SIEMPRE escucha comandos
1186
1298
  setInterval(runStatusCycle, CONFIG.interval * 1000);
1187
- if (deployMode) {
1188
- setInterval(runCommandCycle, CONFIG.commandPollInterval * 1000);
1189
- }
1299
+ setInterval(runCommandCycle, CONFIG.commandPollInterval * 1000);
1300
+
1301
+ logInfo(`Escuchando comandos de la web (cada ${CONFIG.commandPollInterval}s)...`);
1190
1302
  }
1191
1303
 
1192
1304
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deinossrl/dgp-agent",
3
- "version": "1.4.11",
3
+ "version": "1.4.13",
4
4
  "description": "Agente local para Despliegue-GPT - Reporta el estado del repositorio Git a la plataforma TenMinute IA",
5
5
  "main": "index.mjs",
6
6
  "bin": {