@deinossrl/dgp-agent 1.2.7 β 1.3.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 +298 -4
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -35,6 +35,9 @@ const CONFIG = {
|
|
|
35
35
|
commandPollInterval: parseInt(process.env.DGP_COMMAND_POLL_INTERVAL || '10', 10),
|
|
36
36
|
machineId: process.env.DGP_MACHINE_ID || `${hostname()}-${process.env.USERNAME || process.env.USER || 'dev'}`,
|
|
37
37
|
authToken: process.env.DGP_AUTH_TOKEN || null,
|
|
38
|
+
// Claude AI config
|
|
39
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY || null,
|
|
40
|
+
aiModel: process.env.DGP_AI_MODEL || 'claude-sonnet-4-20250514',
|
|
38
41
|
};
|
|
39
42
|
|
|
40
43
|
// Colores para la consola
|
|
@@ -71,6 +74,290 @@ function logCommand(message) {
|
|
|
71
74
|
log(message, 'magenta');
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
function logAI(message) {
|
|
78
|
+
log(`π€ ${message}`, 'cyan');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ============================================
|
|
82
|
+
// CLAUDE AI INTEGRATION
|
|
83
|
+
// ============================================
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Llama a la API de Claude
|
|
87
|
+
*/
|
|
88
|
+
async function callClaude(prompt, systemPrompt = null) {
|
|
89
|
+
if (!CONFIG.anthropicApiKey) {
|
|
90
|
+
throw new Error('ANTHROPIC_API_KEY not configured. Set it as environment variable.');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const messages = [{ role: 'user', content: prompt }];
|
|
94
|
+
|
|
95
|
+
const body = {
|
|
96
|
+
model: CONFIG.aiModel,
|
|
97
|
+
max_tokens: 4096,
|
|
98
|
+
messages,
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
if (systemPrompt) {
|
|
102
|
+
body.system = systemPrompt;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: {
|
|
108
|
+
'Content-Type': 'application/json',
|
|
109
|
+
'x-api-key': CONFIG.anthropicApiKey,
|
|
110
|
+
'anthropic-version': '2023-06-01',
|
|
111
|
+
},
|
|
112
|
+
body: JSON.stringify(body),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
const text = await response.text();
|
|
117
|
+
throw new Error(`Claude API error: ${response.status} - ${text}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const data = await response.json();
|
|
121
|
+
return data.content[0].text;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Analiza el repositorio y genera contexto para IA
|
|
126
|
+
*/
|
|
127
|
+
function getRepoContext() {
|
|
128
|
+
const context = {
|
|
129
|
+
cwd: process.cwd(),
|
|
130
|
+
machineId: CONFIG.machineId,
|
|
131
|
+
git: {},
|
|
132
|
+
project: {},
|
|
133
|
+
files: [],
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Info de git
|
|
137
|
+
try {
|
|
138
|
+
context.git.branch = shellSync('git branch --show-current').trim();
|
|
139
|
+
context.git.remoteUrl = shellSync('git config --get remote.origin.url').trim();
|
|
140
|
+
context.git.lastCommit = shellSync('git log -1 --oneline').trim();
|
|
141
|
+
context.git.status = shellSync('git status --short').trim();
|
|
142
|
+
} catch (e) {
|
|
143
|
+
context.git.error = e.message;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Detectar tipo de proyecto
|
|
147
|
+
try {
|
|
148
|
+
const files = shellSync('ls -la').split('\n').slice(1);
|
|
149
|
+
context.files = files.map(f => f.split(/\s+/).pop()).filter(Boolean);
|
|
150
|
+
|
|
151
|
+
if (context.files.includes('package.json')) {
|
|
152
|
+
context.project.type = 'node';
|
|
153
|
+
try {
|
|
154
|
+
const pkg = JSON.parse(shellSync('cat package.json'));
|
|
155
|
+
context.project.name = pkg.name;
|
|
156
|
+
context.project.scripts = Object.keys(pkg.scripts || {});
|
|
157
|
+
context.project.dependencies = Object.keys(pkg.dependencies || {});
|
|
158
|
+
context.project.devDependencies = Object.keys(pkg.devDependencies || {});
|
|
159
|
+
} catch (e) {}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (context.files.includes('requirements.txt') || context.files.includes('setup.py')) {
|
|
163
|
+
context.project.type = 'python';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (context.files.includes('Cargo.toml')) {
|
|
167
|
+
context.project.type = 'rust';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (context.files.includes('go.mod')) {
|
|
171
|
+
context.project.type = 'go';
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Detectar frameworks
|
|
175
|
+
if (context.project.dependencies) {
|
|
176
|
+
if (context.project.dependencies.includes('react')) context.project.framework = 'react';
|
|
177
|
+
if (context.project.dependencies.includes('vue')) context.project.framework = 'vue';
|
|
178
|
+
if (context.project.dependencies.includes('next')) context.project.framework = 'nextjs';
|
|
179
|
+
if (context.project.dependencies.includes('vite')) context.project.bundler = 'vite';
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Detectar CI/CD
|
|
183
|
+
if (context.files.includes('.github')) {
|
|
184
|
+
context.project.ci = 'github-actions';
|
|
185
|
+
}
|
|
186
|
+
if (context.files.includes('.gitlab-ci.yml')) {
|
|
187
|
+
context.project.ci = 'gitlab-ci';
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
} catch (e) {
|
|
191
|
+
context.filesError = e.message;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return context;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Ejecuta una tarea usando IA
|
|
199
|
+
*/
|
|
200
|
+
async function executeAITask(task) {
|
|
201
|
+
logAI(`Analizando tarea: "${task}"`);
|
|
202
|
+
|
|
203
|
+
const context = getRepoContext();
|
|
204
|
+
|
|
205
|
+
const systemPrompt = `Eres un agente DevOps inteligente que ejecuta tareas en repositorios.
|
|
206
|
+
Tu trabajo es analizar la tarea solicitada y devolver los comandos shell que se deben ejecutar.
|
|
207
|
+
|
|
208
|
+
IMPORTANTE:
|
|
209
|
+
- Solo devuelve comandos que sean seguros de ejecutar
|
|
210
|
+
- No hagas cambios destructivos sin confirmaciΓ³n
|
|
211
|
+
- Usa el contexto del proyecto para elegir los comandos correctos
|
|
212
|
+
- Responde SOLO con JSON vΓ‘lido, sin explicaciones adicionales
|
|
213
|
+
|
|
214
|
+
Formato de respuesta:
|
|
215
|
+
{
|
|
216
|
+
"analysis": "breve explicaciΓ³n de lo que vas a hacer",
|
|
217
|
+
"commands": ["comando1", "comando2"],
|
|
218
|
+
"requires_confirmation": true/false,
|
|
219
|
+
"warning": "mensaje de advertencia si aplica"
|
|
220
|
+
}`;
|
|
221
|
+
|
|
222
|
+
const prompt = `Contexto del repositorio:
|
|
223
|
+
${JSON.stringify(context, null, 2)}
|
|
224
|
+
|
|
225
|
+
Tarea a ejecutar: ${task}
|
|
226
|
+
|
|
227
|
+
Devuelve los comandos necesarios en formato JSON.`;
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const response = await callClaude(prompt, systemPrompt);
|
|
231
|
+
|
|
232
|
+
// Parsear respuesta JSON
|
|
233
|
+
let result;
|
|
234
|
+
try {
|
|
235
|
+
// Extraer JSON de la respuesta (puede venir con markdown)
|
|
236
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
237
|
+
if (jsonMatch) {
|
|
238
|
+
result = JSON.parse(jsonMatch[0]);
|
|
239
|
+
} else {
|
|
240
|
+
throw new Error('No JSON found in response');
|
|
241
|
+
}
|
|
242
|
+
} catch (e) {
|
|
243
|
+
logError(`Failed to parse AI response: ${e.message}`);
|
|
244
|
+
console.log('Raw response:', response);
|
|
245
|
+
return { success: false, error: 'Invalid AI response' };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
logAI(`AnΓ‘lisis: ${result.analysis}`);
|
|
249
|
+
|
|
250
|
+
if (result.warning) {
|
|
251
|
+
log(`β οΈ ${result.warning}`, 'yellow');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (result.requires_confirmation) {
|
|
255
|
+
log('Esta operaciΓ³n requiere confirmaciΓ³n. Usa --force para ejecutar sin confirmar.', 'yellow');
|
|
256
|
+
console.log('\nComandos a ejecutar:');
|
|
257
|
+
result.commands.forEach((cmd, i) => console.log(` ${i + 1}. ${cmd}`));
|
|
258
|
+
return { success: true, requiresConfirmation: true, commands: result.commands };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Ejecutar comandos
|
|
262
|
+
logAI('Ejecutando comandos...');
|
|
263
|
+
const results = [];
|
|
264
|
+
|
|
265
|
+
for (const cmd of result.commands) {
|
|
266
|
+
logCommand(`$ ${cmd}`);
|
|
267
|
+
try {
|
|
268
|
+
const output = await shellAsync(cmd);
|
|
269
|
+
logSuccess('β Completado');
|
|
270
|
+
if (output.trim()) {
|
|
271
|
+
console.log(colors.gray + output + colors.reset);
|
|
272
|
+
}
|
|
273
|
+
results.push({ cmd, success: true, output });
|
|
274
|
+
} catch (e) {
|
|
275
|
+
logError(`β FallΓ³: ${e.message}`);
|
|
276
|
+
results.push({ cmd, success: false, error: e.message });
|
|
277
|
+
break; // Detener en el primer error
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return { success: true, results };
|
|
282
|
+
|
|
283
|
+
} catch (e) {
|
|
284
|
+
logError(`AI task failed: ${e.message}`);
|
|
285
|
+
return { success: false, error: e.message };
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Modo interactivo con IA
|
|
291
|
+
*/
|
|
292
|
+
async function runAIMode() {
|
|
293
|
+
console.log('');
|
|
294
|
+
console.log(`${colors.cyan}βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${colors.reset}`);
|
|
295
|
+
console.log(`${colors.cyan}β DGP Agent - AI Mode π€ β${colors.reset}`);
|
|
296
|
+
console.log(`${colors.cyan}β Powered by Claude β${colors.reset}`);
|
|
297
|
+
console.log(`${colors.cyan}βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${colors.reset}`);
|
|
298
|
+
console.log('');
|
|
299
|
+
|
|
300
|
+
if (!CONFIG.anthropicApiKey) {
|
|
301
|
+
logError('ANTHROPIC_API_KEY not set.');
|
|
302
|
+
log('Set your API key: export ANTHROPIC_API_KEY=sk-ant-...', 'yellow');
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Analizar repo
|
|
307
|
+
logAI('Analizando repositorio...');
|
|
308
|
+
const context = getRepoContext();
|
|
309
|
+
|
|
310
|
+
console.log('');
|
|
311
|
+
console.log(`${colors.bold}Proyecto detectado:${colors.reset}`);
|
|
312
|
+
console.log(` Tipo: ${context.project.type || 'desconocido'}`);
|
|
313
|
+
console.log(` Framework: ${context.project.framework || 'ninguno'}`);
|
|
314
|
+
console.log(` Bundler: ${context.project.bundler || 'ninguno'}`);
|
|
315
|
+
console.log(` CI/CD: ${context.project.ci || 'no detectado'}`);
|
|
316
|
+
console.log(` Branch: ${context.git.branch}`);
|
|
317
|
+
console.log(` Scripts: ${context.project.scripts?.join(', ') || 'ninguno'}`);
|
|
318
|
+
console.log('');
|
|
319
|
+
|
|
320
|
+
// Obtener tarea de los argumentos
|
|
321
|
+
const taskArgs = process.argv.slice(3).join(' ');
|
|
322
|
+
|
|
323
|
+
if (taskArgs) {
|
|
324
|
+
// Ejecutar tarea pasada como argumento
|
|
325
|
+
await executeAITask(taskArgs);
|
|
326
|
+
} else {
|
|
327
|
+
// Modo interactivo
|
|
328
|
+
const readline = await import('readline');
|
|
329
|
+
const rl = readline.createInterface({
|
|
330
|
+
input: process.stdin,
|
|
331
|
+
output: process.stdout,
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const askQuestion = () => {
|
|
335
|
+
rl.question(`${colors.cyan}π€ ΒΏQuΓ© querΓ©s hacer? ${colors.reset}`, async (answer) => {
|
|
336
|
+
if (answer.toLowerCase() === 'exit' || answer.toLowerCase() === 'salir') {
|
|
337
|
+
console.log('Β‘Hasta luego!');
|
|
338
|
+
rl.close();
|
|
339
|
+
process.exit(0);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (answer.trim()) {
|
|
343
|
+
await executeAITask(answer);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
console.log('');
|
|
347
|
+
askQuestion();
|
|
348
|
+
});
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
log('EscribΓ "exit" o "salir" para terminar', 'gray');
|
|
352
|
+
console.log('');
|
|
353
|
+
askQuestion();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ============================================
|
|
358
|
+
// GIT FUNCTIONS
|
|
359
|
+
// ============================================
|
|
360
|
+
|
|
74
361
|
/**
|
|
75
362
|
* Ejecuta un comando git y retorna el resultado
|
|
76
363
|
*/
|
|
@@ -236,7 +523,7 @@ async function reportStatus(status) {
|
|
|
236
523
|
const payload = {
|
|
237
524
|
machine_id: CONFIG.machineId,
|
|
238
525
|
timestamp: new Date().toISOString(),
|
|
239
|
-
agent_version: '1.
|
|
526
|
+
agent_version: '1.3.0',
|
|
240
527
|
status,
|
|
241
528
|
};
|
|
242
529
|
|
|
@@ -535,7 +822,7 @@ async function runAgent(deployMode = false) {
|
|
|
535
822
|
console.log('');
|
|
536
823
|
console.log(`${colors.green}βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${colors.reset}`);
|
|
537
824
|
console.log(`${colors.green}β DGP Agent - Despliegue-GPT Local Agent β${colors.reset}`);
|
|
538
|
-
console.log(`${colors.green}β @deinossrl/dgp-agent v1.
|
|
825
|
+
console.log(`${colors.green}β @deinossrl/dgp-agent v1.3.0 β${colors.reset}`);
|
|
539
826
|
console.log(`${colors.green}βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ${colors.reset}`);
|
|
540
827
|
console.log('');
|
|
541
828
|
|
|
@@ -651,7 +938,7 @@ async function showStatus() {
|
|
|
651
938
|
function showHelp() {
|
|
652
939
|
console.log(`
|
|
653
940
|
${colors.bold}${colors.cyan}DGP Agent - Despliegue-GPT Local Agent${colors.reset}
|
|
654
|
-
${colors.gray}@deinossrl/dgp-agent v1.
|
|
941
|
+
${colors.gray}@deinossrl/dgp-agent v1.3.0${colors.reset}
|
|
655
942
|
|
|
656
943
|
${colors.bold}DESCRIPCIΓN${colors.reset}
|
|
657
944
|
Agente local que reporta el estado de tu repositorio Git
|
|
@@ -665,6 +952,8 @@ ${colors.bold}USO${colors.reset}
|
|
|
665
952
|
${colors.cyan}dgp-agent${colors.reset} Inicia el agente (solo reporta estado)
|
|
666
953
|
${colors.cyan}dgp-agent deploy${colors.reset} Modo deploy (reporta + escucha comandos)
|
|
667
954
|
${colors.cyan}dgp-agent status${colors.reset} Muestra el estado actual una vez
|
|
955
|
+
${colors.cyan}dgp-agent ai${colors.reset} Modo IA interactivo (requiere ANTHROPIC_API_KEY)
|
|
956
|
+
${colors.cyan}dgp-agent ai "tarea"${colors.reset} Ejecuta una tarea con IA
|
|
668
957
|
${colors.cyan}dgp-agent help${colors.reset} Muestra esta ayuda
|
|
669
958
|
|
|
670
959
|
${colors.bold}MODOS DE OPERACIΓN${colors.reset}
|
|
@@ -699,6 +988,7 @@ ${colors.bold}REQUISITOS PARA DEPLOY${colors.reset}
|
|
|
699
988
|
- Permisos sudo para reload nginx (vΓa sudoers sin password)
|
|
700
989
|
|
|
701
990
|
${colors.bold}CHANGELOG${colors.reset}
|
|
991
|
+
${colors.cyan}v1.3.0${colors.reset} - AI Mode: ejecuta tareas con lenguaje natural
|
|
702
992
|
${colors.cyan}v1.2.7${colors.reset} - Fix: update via Edge Function (401 fix)
|
|
703
993
|
${colors.cyan}v1.2.6${colors.reset} - Comando git_commit_push desde la UI
|
|
704
994
|
${colors.cyan}v1.2.5${colors.reset} - SincronizaciΓ³n de versiones y changelog
|
|
@@ -735,7 +1025,11 @@ switch (command) {
|
|
|
735
1025
|
case 'version':
|
|
736
1026
|
case '-v':
|
|
737
1027
|
case '--version':
|
|
738
|
-
console.log('@deinossrl/dgp-agent v1.
|
|
1028
|
+
console.log('@deinossrl/dgp-agent v1.3.0');
|
|
1029
|
+
break;
|
|
1030
|
+
case 'ai':
|
|
1031
|
+
case '--ai':
|
|
1032
|
+
runAIMode();
|
|
739
1033
|
break;
|
|
740
1034
|
default:
|
|
741
1035
|
runAgent(false); // Status-only mode
|