plazbot-cli 0.2.2 → 0.2.4
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/commands/agent/chat.js +1 -1
- package/dist/commands/agent/delete.js +1 -1
- package/dist/commands/agent/enable-widget.js +7 -11
- package/dist/commands/agent/get.js +1 -1
- package/dist/commands/agent/index.js +3 -1
- package/dist/commands/agent/list.js +1 -1
- package/dist/commands/agent/monitor.js +293 -0
- package/dist/commands/agent/on-message.js +10 -12
- package/dist/commands/agent/update.js +1 -1
- package/dist/commands/auth/login.js +13 -12
- package/dist/commands/portal/add-agent.js +5 -10
- package/dist/commands/portal/add-link.js +3 -2
- package/dist/commands/portal/clear-links.js +3 -2
- package/dist/commands/portal/create.js +3 -7
- package/dist/commands/portal/delete.js +5 -6
- package/dist/commands/portal/get.js +15 -17
- package/dist/commands/portal/list.js +15 -17
- package/dist/commands/portal/update.js +5 -6
- package/dist/commands/whatsapp/delete-webhook.js +3 -3
- package/dist/commands/whatsapp/register-webhook.js +4 -4
- package/dist/utils/logger.js +3 -3
- package/package.json +2 -1
- package/src/commands/agent/chat.ts +1 -1
- package/src/commands/agent/delete.ts +1 -1
- package/src/commands/agent/enable-widget.ts +8 -12
- package/src/commands/agent/get.ts +1 -1
- package/src/commands/agent/index.ts +3 -1
- package/src/commands/agent/list.ts +1 -1
- package/src/commands/agent/monitor.ts +346 -0
- package/src/commands/agent/on-message.ts +11 -13
- package/src/commands/agent/update.ts +1 -1
- package/src/commands/auth/login.ts +13 -12
- package/src/commands/portal/add-agent.ts +5 -11
- package/src/commands/portal/add-link.ts +2 -2
- package/src/commands/portal/clear-links.ts +3 -2
- package/src/commands/portal/create.ts +3 -8
- package/src/commands/portal/delete.ts +5 -6
- package/src/commands/portal/get.ts +16 -20
- package/src/commands/portal/list.ts +16 -19
- package/src/commands/portal/update.ts +5 -6
- package/src/commands/whatsapp/delete-webhook.ts +3 -3
- package/src/commands/whatsapp/register-webhook.ts +4 -4
- package/src/utils/logger.ts +3 -3
|
@@ -19,39 +19,37 @@ exports.getCommand = new commander_1.Command('get')
|
|
|
19
19
|
zone: credentials.zone,
|
|
20
20
|
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
21
21
|
});
|
|
22
|
-
logger_1.logger.info('\n🔄 Obteniendo detalles del portal...');
|
|
23
22
|
const response = await portal.getPortal(portalId);
|
|
24
23
|
const portalDetails = response.portal;
|
|
25
|
-
logger_1.logger.
|
|
26
|
-
logger_1.logger.
|
|
27
|
-
logger_1.logger.
|
|
28
|
-
logger_1.logger.
|
|
29
|
-
logger_1.logger.
|
|
30
|
-
logger_1.logger.
|
|
31
|
-
logger_1.logger.info(`Estado: ${portalDetails.disabled ? 'Deshabilitado' : 'Habilitado'}`);
|
|
24
|
+
logger_1.logger.title('Detalles del portal');
|
|
25
|
+
logger_1.logger.label('ID', portalDetails.id);
|
|
26
|
+
logger_1.logger.label('Nombre', portalDetails.name);
|
|
27
|
+
logger_1.logger.label('URL', portalDetails.url);
|
|
28
|
+
logger_1.logger.label('Acceso', portalDetails.access);
|
|
29
|
+
logger_1.logger.label('Estado', portalDetails.disabled ? 'Deshabilitado' : 'Habilitado');
|
|
32
30
|
if (portalDetails.title) {
|
|
33
|
-
logger_1.logger.
|
|
31
|
+
logger_1.logger.label('Titulo', portalDetails.title);
|
|
34
32
|
}
|
|
35
33
|
if (portalDetails.subtitle) {
|
|
36
|
-
logger_1.logger.
|
|
34
|
+
logger_1.logger.label('Subtitulo', portalDetails.subtitle);
|
|
37
35
|
}
|
|
38
36
|
if (portalDetails.logo) {
|
|
39
|
-
logger_1.logger.
|
|
40
|
-
logger_1.logger.
|
|
37
|
+
logger_1.logger.title('Recursos');
|
|
38
|
+
logger_1.logger.label('Logo', portalDetails.logo);
|
|
41
39
|
if (portalDetails.logodark) {
|
|
42
|
-
logger_1.logger.
|
|
40
|
+
logger_1.logger.label('Logo (modo oscuro)', portalDetails.logodark);
|
|
43
41
|
}
|
|
44
42
|
}
|
|
45
43
|
if (portalDetails.links && portalDetails.links.length > 0) {
|
|
46
|
-
logger_1.logger.
|
|
44
|
+
logger_1.logger.title('Enlaces');
|
|
47
45
|
portalDetails.links.forEach((link) => {
|
|
48
|
-
logger_1.logger.
|
|
46
|
+
logger_1.logger.label(link.value, link.url);
|
|
49
47
|
});
|
|
50
48
|
}
|
|
51
49
|
if (portalDetails.agents && portalDetails.agents.length > 0) {
|
|
52
|
-
logger_1.logger.
|
|
50
|
+
logger_1.logger.title('Agentes asociados');
|
|
53
51
|
portalDetails.agents.forEach((agent) => {
|
|
54
|
-
logger_1.logger.
|
|
52
|
+
logger_1.logger.label(agent.name, agent.id);
|
|
55
53
|
});
|
|
56
54
|
}
|
|
57
55
|
if (options.dev) {
|
|
@@ -18,40 +18,38 @@ exports.listCommand = new commander_1.Command('list')
|
|
|
18
18
|
zone: credentials.zone,
|
|
19
19
|
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
20
20
|
});
|
|
21
|
-
logger_1.logger.info('\n🔍 Buscando portal del workspace...');
|
|
22
21
|
const response = await portal.getExistsPortal();
|
|
23
22
|
const portalDetails = response.portal;
|
|
24
|
-
logger_1.logger.
|
|
25
|
-
logger_1.logger.
|
|
26
|
-
logger_1.logger.
|
|
27
|
-
logger_1.logger.
|
|
28
|
-
logger_1.logger.
|
|
29
|
-
logger_1.logger.
|
|
30
|
-
logger_1.logger.info(`Estado: ${portalDetails.disabled ? 'Deshabilitado' : 'Habilitado'}`);
|
|
23
|
+
logger_1.logger.title('Portal encontrado');
|
|
24
|
+
logger_1.logger.label('ID', portalDetails.id);
|
|
25
|
+
logger_1.logger.label('Nombre', portalDetails.name);
|
|
26
|
+
logger_1.logger.label('URL', portalDetails.url);
|
|
27
|
+
logger_1.logger.label('Acceso', portalDetails.access || 'N/A');
|
|
28
|
+
logger_1.logger.label('Estado', portalDetails.disabled ? 'Deshabilitado' : 'Habilitado');
|
|
31
29
|
if (portalDetails.title) {
|
|
32
|
-
logger_1.logger.
|
|
30
|
+
logger_1.logger.label('Titulo', portalDetails.title);
|
|
33
31
|
}
|
|
34
32
|
if (portalDetails.subtitle) {
|
|
35
|
-
logger_1.logger.
|
|
33
|
+
logger_1.logger.label('Subtitulo', portalDetails.subtitle);
|
|
36
34
|
}
|
|
37
35
|
if (portalDetails.logo) {
|
|
38
|
-
logger_1.logger.
|
|
39
|
-
logger_1.logger.
|
|
36
|
+
logger_1.logger.title('Recursos');
|
|
37
|
+
logger_1.logger.label('Logo', portalDetails.logo);
|
|
40
38
|
if (portalDetails.logodark) {
|
|
41
|
-
logger_1.logger.
|
|
39
|
+
logger_1.logger.label('Logo (modo oscuro)', portalDetails.logodark);
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
const portalAny = portalDetails;
|
|
45
43
|
if (portalAny.links && portalAny.links.length > 0) {
|
|
46
|
-
logger_1.logger.
|
|
44
|
+
logger_1.logger.title('Enlaces');
|
|
47
45
|
portalAny.links.forEach((link) => {
|
|
48
|
-
logger_1.logger.
|
|
46
|
+
logger_1.logger.label(link.value, link.url);
|
|
49
47
|
});
|
|
50
48
|
}
|
|
51
49
|
if (portalAny.agents && portalAny.agents.length > 0) {
|
|
52
|
-
logger_1.logger.
|
|
50
|
+
logger_1.logger.title('Agentes asociados');
|
|
53
51
|
portalAny.agents.forEach((agent) => {
|
|
54
|
-
logger_1.logger.
|
|
52
|
+
logger_1.logger.label(agent.name, agent.id);
|
|
55
53
|
});
|
|
56
54
|
}
|
|
57
55
|
if (options.dev) {
|
|
@@ -29,9 +29,8 @@ exports.updateCommand = new commander_1.Command('update')
|
|
|
29
29
|
});
|
|
30
30
|
// Obtener detalles actuales del portal
|
|
31
31
|
const currentPortal = await portal.getPortal(portalId);
|
|
32
|
-
logger_1.logger.
|
|
33
|
-
logger_1.logger.
|
|
34
|
-
logger_1.logger.info(JSON.stringify(currentPortal.portal, null, 2));
|
|
32
|
+
logger_1.logger.title('Portal actual');
|
|
33
|
+
logger_1.logger.json(currentPortal.portal);
|
|
35
34
|
// Construir objeto de actualización solo con los campos proporcionados
|
|
36
35
|
const updateData = { id: portalId };
|
|
37
36
|
if (options.name)
|
|
@@ -62,11 +61,11 @@ exports.updateCommand = new commander_1.Command('update')
|
|
|
62
61
|
}
|
|
63
62
|
updateData.brandOff = options.brandOff === 'true';
|
|
64
63
|
}
|
|
65
|
-
logger_1.logger.
|
|
66
|
-
logger_1.logger.
|
|
64
|
+
logger_1.logger.title('Cambios a aplicar');
|
|
65
|
+
logger_1.logger.json(updateData);
|
|
67
66
|
const result = await portal.updatePortal(updateData);
|
|
68
67
|
logger_1.logger.success('Portal actualizado exitosamente');
|
|
69
|
-
logger_1.logger.
|
|
68
|
+
logger_1.logger.label('Mensaje', result.message);
|
|
70
69
|
if (options.dev) {
|
|
71
70
|
logger_1.logger.warning('\nAmbiente: desarrollo');
|
|
72
71
|
}
|
|
@@ -18,15 +18,15 @@ exports.deleteWebhookCommand = new commander_1.Command('delete-webhook')
|
|
|
18
18
|
zone: credentials.zone,
|
|
19
19
|
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
20
20
|
});
|
|
21
|
-
logger_1.logger.
|
|
22
|
-
logger_1.logger.
|
|
21
|
+
logger_1.logger.title('Eliminando webhook de WhatsApp');
|
|
22
|
+
logger_1.logger.label('Numero', options.number);
|
|
23
23
|
await messageClient.deleteWebhook({
|
|
24
24
|
number: options.number
|
|
25
25
|
});
|
|
26
26
|
logger_1.logger.success('Webhook eliminado exitosamente');
|
|
27
27
|
}
|
|
28
28
|
catch (error) {
|
|
29
|
-
logger_1.logger.error(
|
|
29
|
+
logger_1.logger.error(error.message);
|
|
30
30
|
process.exit(1);
|
|
31
31
|
}
|
|
32
32
|
});
|
|
@@ -19,9 +19,9 @@ exports.registerWebhookCommand = new commander_1.Command('register-webhook')
|
|
|
19
19
|
zone: credentials.zone,
|
|
20
20
|
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
21
21
|
});
|
|
22
|
-
logger_1.logger.
|
|
23
|
-
logger_1.logger.
|
|
24
|
-
logger_1.logger.
|
|
22
|
+
logger_1.logger.title('Registrando webhook de WhatsApp');
|
|
23
|
+
logger_1.logger.label('Numero', options.number);
|
|
24
|
+
logger_1.logger.label('URL', options.url);
|
|
25
25
|
await messageClient.registerWebhook({
|
|
26
26
|
number: options.number,
|
|
27
27
|
webhookUrl: options.url
|
|
@@ -29,7 +29,7 @@ exports.registerWebhookCommand = new commander_1.Command('register-webhook')
|
|
|
29
29
|
logger_1.logger.success('Webhook registrado exitosamente');
|
|
30
30
|
}
|
|
31
31
|
catch (error) {
|
|
32
|
-
logger_1.logger.error(
|
|
32
|
+
logger_1.logger.error(error.message);
|
|
33
33
|
process.exit(1);
|
|
34
34
|
}
|
|
35
35
|
});
|
package/dist/utils/logger.js
CHANGED
|
@@ -10,14 +10,14 @@ exports.logger = {
|
|
|
10
10
|
console.log(chalk_1.default.white(message));
|
|
11
11
|
},
|
|
12
12
|
success: (message) => {
|
|
13
|
-
console.log(chalk_1.default.hex('#66BB6A')(`\n
|
|
13
|
+
console.log(chalk_1.default.hex('#66BB6A')(`\n ${message}`));
|
|
14
14
|
},
|
|
15
15
|
warning: (message) => {
|
|
16
|
-
console.log(chalk_1.default.hex('#FFA726')(`\n
|
|
16
|
+
console.log(chalk_1.default.hex('#FFA726')(`\n ${message}`));
|
|
17
17
|
},
|
|
18
18
|
error: (error) => {
|
|
19
19
|
const message = error instanceof Error ? error.message : error;
|
|
20
|
-
console.error(chalk_1.default.hex('#EF5350')(`\n
|
|
20
|
+
console.error(chalk_1.default.hex('#EF5350')(`\n Error: ${message}`));
|
|
21
21
|
},
|
|
22
22
|
divider: (length = 50) => {
|
|
23
23
|
console.log(chalk_1.default.gray('─'.repeat(length)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plazbot-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "CLI para Plazbot SDK",
|
|
5
5
|
"main": "dist/cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"author": "Kristian Garcia <kristian@plazbot.com>",
|
|
32
32
|
"license": "MIT",
|
|
33
33
|
"dependencies": {
|
|
34
|
+
"@microsoft/signalr": "^10.0.0",
|
|
34
35
|
"@types/inquirer": "^9.0.8",
|
|
35
36
|
"axios": "^1.6.0",
|
|
36
37
|
"boxen": "^5.1.2",
|
|
@@ -138,7 +138,7 @@ export const chatCommand = new Command('chat')
|
|
|
138
138
|
// Mostrar tool calls si hay
|
|
139
139
|
if (response.actionsExecuted && response.actionsExecuted.length > 0) {
|
|
140
140
|
response.actionsExecuted.forEach((action: any) => {
|
|
141
|
-
console.log(chalk.hex('#FFA726')(`
|
|
141
|
+
console.log(chalk.hex('#FFA726')(` Tool: ${action.name || action.intent || 'action'}`));
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
144
|
|
|
@@ -38,7 +38,7 @@ export const deleteCommand = new Command('delete')
|
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
// Preguntar por confirmación
|
|
41
|
-
rl.question('\
|
|
41
|
+
rl.question('\nEstas seguro que deseas eliminar este agente? (y/N): ', async (answer) => {
|
|
42
42
|
if (answer.toLowerCase() === 'y') {
|
|
43
43
|
await agent.deleteAgent({
|
|
44
44
|
id: agentId
|
|
@@ -24,10 +24,8 @@ export const enableCommand = new Command('enable-widget')
|
|
|
24
24
|
// Obtener estado actual del agente
|
|
25
25
|
const agentDetails = await agent.getAgentById({ id: agentId });
|
|
26
26
|
|
|
27
|
-
logger.
|
|
28
|
-
logger.
|
|
29
|
-
logger.info(`Agente: ${agentDetails.name}`);
|
|
30
|
-
logger.divider();
|
|
27
|
+
logger.title('Estado actual del widget');
|
|
28
|
+
logger.label('Agente', agentDetails.name);
|
|
31
29
|
|
|
32
30
|
// Cambiar estado
|
|
33
31
|
const newState = !options.disable; // Si --disable está presente, newState será false
|
|
@@ -38,15 +36,13 @@ export const enableCommand = new Command('enable-widget')
|
|
|
38
36
|
|
|
39
37
|
logger.success(`Widget ${newState ? 'habilitado' : 'deshabilitado'} exitosamente`);
|
|
40
38
|
|
|
41
|
-
logger.
|
|
42
|
-
logger.
|
|
43
|
-
logger.
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
logger.title('Respuesta del servidor');
|
|
40
|
+
logger.label('Estado', result.success ? 'Exitoso' : 'Fallido');
|
|
41
|
+
logger.label('Mensaje', result.message);
|
|
42
|
+
|
|
46
43
|
if (newState && result.script) {
|
|
47
|
-
logger.
|
|
48
|
-
logger.
|
|
49
|
-
logger.info('Coloca este script debajo de la etiqueta <HEAD> en tu sitio web:');
|
|
44
|
+
logger.title('Instrucciones de instalacion');
|
|
45
|
+
logger.dim('Coloca este script debajo de la etiqueta <HEAD> en tu sitio web:');
|
|
50
46
|
logger.info('\n' + result.script);
|
|
51
47
|
}
|
|
52
48
|
|
|
@@ -33,7 +33,7 @@ export const getCommand = new Command('get')
|
|
|
33
33
|
logger.info(`ID: ${agentData.id}`);
|
|
34
34
|
logger.info(`Nombre: ${agentData.name}`);
|
|
35
35
|
logger.info(`Descripción: ${agentData.description}`);
|
|
36
|
-
logger.info(`Estado: ${agentData.enable ? '
|
|
36
|
+
logger.info(`Estado: ${agentData.enable ? 'Activo' : 'Inactivo'}`);
|
|
37
37
|
logger.info(`Zona: ${agentData.zone}`);
|
|
38
38
|
logger.info(`Buffer: ${agentData.buffer}`);
|
|
39
39
|
logger.info(`Color: ${agentData.color}`);
|
|
@@ -13,6 +13,7 @@ import { templatesCommand } from './templates';
|
|
|
13
13
|
import { copyCommand } from './copy';
|
|
14
14
|
import { filesCommand } from './files';
|
|
15
15
|
import { setCommand } from './set';
|
|
16
|
+
import { monitorCommand } from './monitor';
|
|
16
17
|
|
|
17
18
|
export const agentCommands = new Command('agent')
|
|
18
19
|
.description('Comandos relacionados con agentes de IA')
|
|
@@ -29,4 +30,5 @@ export const agentCommands = new Command('agent')
|
|
|
29
30
|
.addCommand(templatesCommand)
|
|
30
31
|
.addCommand(copyCommand)
|
|
31
32
|
.addCommand(filesCommand)
|
|
32
|
-
.addCommand(setCommand)
|
|
33
|
+
.addCommand(setCommand)
|
|
34
|
+
.addCommand(monitorCommand);
|
|
@@ -34,7 +34,7 @@ export const listCommand = new Command('list')
|
|
|
34
34
|
agents.forEach((a: any, index: number) => {
|
|
35
35
|
logger.info(`${index + 1}. ID: ${a.id}`);
|
|
36
36
|
logger.info(` Nombre: ${a.name}`);
|
|
37
|
-
logger.info(` Estado: ${a.enable ? '
|
|
37
|
+
logger.info(` Estado: ${a.enable ? 'Activo' : 'Inactivo'}`);
|
|
38
38
|
logger.info(` Descripción: ${a.description}`);
|
|
39
39
|
logger.info(` Creado: ${a.createdAt ? new Date(a.createdAt).toLocaleString() : 'N/A'}`);
|
|
40
40
|
logger.divider();
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { Agent } from 'plazbot';
|
|
3
|
+
import { getStoredCredentials } from '../../utils/credentials';
|
|
4
|
+
import { logger } from '../../utils/logger';
|
|
5
|
+
import { theme } from '../../utils/ui';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import readline from 'readline';
|
|
8
|
+
import { HubConnectionBuilder, HttpTransportType, HubConnectionState } from '@microsoft/signalr';
|
|
9
|
+
|
|
10
|
+
// Colores por tipo de evento (mismos del MonitorTab frontend)
|
|
11
|
+
const EVENT_COLORS: Record<string, { color: string; label: string }> = {
|
|
12
|
+
msg_in: { color: '#22d3ee', label: 'msg_in' },
|
|
13
|
+
msg_out: { color: '#4ade80', label: 'msg_out' },
|
|
14
|
+
tool_call: { color: '#c084fc', label: 'tool_call' },
|
|
15
|
+
api_req: { color: '#fbbf24', label: 'api_req' },
|
|
16
|
+
api_res: { color: '#fbbf24', label: 'api_res' },
|
|
17
|
+
action: { color: '#f97316', label: 'action' },
|
|
18
|
+
rag: { color: '#60a5fa', label: 'rag' },
|
|
19
|
+
tokens: { color: '#94a3b8', label: 'tokens' },
|
|
20
|
+
error: { color: '#ef4444', label: 'error' },
|
|
21
|
+
model: { color: '#a78bfa', label: 'model' },
|
|
22
|
+
intent: { color: '#a78bfa', label: 'intent' },
|
|
23
|
+
bot_off: { color: '#f97316', label: 'bot_off' },
|
|
24
|
+
session_field: { color: '#a78bfa', label: 'session_field' },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const DEFAULT_EVENT_COLOR = { color: '#94a3b8', label: 'unknown' };
|
|
28
|
+
|
|
29
|
+
interface AgentLogEvent {
|
|
30
|
+
timestamp: string;
|
|
31
|
+
workspace_id: string;
|
|
32
|
+
agent_id: string;
|
|
33
|
+
contact_id: string;
|
|
34
|
+
contact_name: string;
|
|
35
|
+
session_id: string;
|
|
36
|
+
event_type: string;
|
|
37
|
+
event_title: string;
|
|
38
|
+
event_data: string;
|
|
39
|
+
duration_ms: number;
|
|
40
|
+
level: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getBaseUrl(zone: string, dev: boolean): string {
|
|
44
|
+
if (dev) return 'http://localhost:5090';
|
|
45
|
+
return zone === 'EU' ? 'https://apieu.plazbot.com' : 'https://api.plazbot.com';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function formatTimestamp(ts: string): string {
|
|
49
|
+
try {
|
|
50
|
+
const d = new Date(ts);
|
|
51
|
+
return d.toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
|
|
52
|
+
} catch {
|
|
53
|
+
return ts.substring(11, 19);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function truncate(text: string, maxLen: number): string {
|
|
58
|
+
if (!text) return '';
|
|
59
|
+
return text.length > maxLen ? text.substring(0, maxLen - 3) + '...' : text;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function shortSession(sessionId: string): string {
|
|
63
|
+
if (!sessionId) return '';
|
|
64
|
+
return sessionId.substring(0, 6);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function renderLogLine(
|
|
68
|
+
log: AgentLogEvent,
|
|
69
|
+
opts: { showSession: boolean; jsonMode: boolean },
|
|
70
|
+
lastSessionId: string
|
|
71
|
+
): string {
|
|
72
|
+
// Modo JSON crudo
|
|
73
|
+
if (opts.jsonMode) {
|
|
74
|
+
return JSON.stringify(log);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const config = EVENT_COLORS[log.event_type] || DEFAULT_EVENT_COLOR;
|
|
78
|
+
const colorFn = chalk.hex(config.color);
|
|
79
|
+
const grayFn = chalk.hex('#71717a');
|
|
80
|
+
const dimFn = chalk.hex('#52525b');
|
|
81
|
+
|
|
82
|
+
let lines: string[] = [];
|
|
83
|
+
|
|
84
|
+
// Separador de sesion
|
|
85
|
+
if (lastSessionId && log.session_id && log.session_id !== lastSessionId) {
|
|
86
|
+
lines.push(dimFn(' ' + '─'.repeat(16) + ' nueva sesion ' + '─'.repeat(16)));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Linea principal
|
|
90
|
+
const timestamp = grayFn(formatTimestamp(log.timestamp));
|
|
91
|
+
const dot = colorFn('●');
|
|
92
|
+
const eventType = colorFn(config.label.padEnd(14));
|
|
93
|
+
const title = chalk.white(truncate(log.event_title, 80));
|
|
94
|
+
const duration = log.duration_ms > 0 ? dimFn(` ${log.duration_ms}ms`) : '';
|
|
95
|
+
const session = opts.showSession && log.session_id
|
|
96
|
+
? dimFn(` [${shortSession(log.session_id)}]`)
|
|
97
|
+
: '';
|
|
98
|
+
|
|
99
|
+
lines.push(` ${timestamp} ${dot} ${eventType} ${title}${duration}${session}`);
|
|
100
|
+
|
|
101
|
+
// Linea de contacto para mensajes
|
|
102
|
+
if (log.contact_name && (log.event_type === 'msg_in' || log.event_type === 'msg_out')) {
|
|
103
|
+
lines.push(dimFn(' | contacto: ') + dimFn(log.contact_name));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return lines.join('\n');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function printHeader(agentName: string) {
|
|
110
|
+
console.log();
|
|
111
|
+
console.log(chalk.hex('#4CAF50')(' ┌' + '─'.repeat(62) + '┐'));
|
|
112
|
+
console.log(
|
|
113
|
+
chalk.hex('#4CAF50')(' │') +
|
|
114
|
+
chalk.bold(` Monitor`) +
|
|
115
|
+
chalk.hex('#4ade80')(' ● En vivo') +
|
|
116
|
+
' '.repeat(38) +
|
|
117
|
+
chalk.hex('#4CAF50')('│')
|
|
118
|
+
);
|
|
119
|
+
console.log(
|
|
120
|
+
chalk.hex('#4CAF50')(' │') +
|
|
121
|
+
chalk.gray(` Agente: ${truncate(agentName, 44)}`) +
|
|
122
|
+
' '.repeat(Math.max(0, 49 - agentName.length)) +
|
|
123
|
+
chalk.hex('#4CAF50')('│')
|
|
124
|
+
);
|
|
125
|
+
console.log(
|
|
126
|
+
chalk.hex('#4CAF50')(' │') +
|
|
127
|
+
chalk.gray(' Ctrl+C salir | /filter <tipo> | /clear | /help') +
|
|
128
|
+
' '.repeat(12) +
|
|
129
|
+
chalk.hex('#4CAF50')('│')
|
|
130
|
+
);
|
|
131
|
+
console.log(chalk.hex('#4CAF50')(' └' + '─'.repeat(62) + '┘'));
|
|
132
|
+
console.log();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const COMMANDS_HELP = `
|
|
136
|
+
${chalk.bold('Comandos disponibles:')}
|
|
137
|
+
${chalk.hex('#4CAF50')('/filter <tipo>')} Toggle filtro por tipo (ej: msg_in, error, tool_call)
|
|
138
|
+
${chalk.hex('#4CAF50')('/filters')} Mostrar filtros activos
|
|
139
|
+
${chalk.hex('#4CAF50')('/clear')} Limpiar pantalla
|
|
140
|
+
${chalk.hex('#4CAF50')('/json')} Toggle modo JSON expandido
|
|
141
|
+
${chalk.hex('#4CAF50')('/help')} Mostrar estos comandos
|
|
142
|
+
|
|
143
|
+
${chalk.bold('Tipos de evento:')}
|
|
144
|
+
${Object.entries(EVENT_COLORS).map(([key, val]) =>
|
|
145
|
+
` ${chalk.hex(val.color)('●')} ${key}`
|
|
146
|
+
).join('\n')}
|
|
147
|
+
`;
|
|
148
|
+
|
|
149
|
+
export const monitorCommand = new Command('monitor')
|
|
150
|
+
.description('Monitor en tiempo real de un agente (logs via SignalR)')
|
|
151
|
+
.requiredOption('-a, --agent-id <id>', 'ID del agente')
|
|
152
|
+
.option('-f, --filter <types>', 'Filtrar por tipos separados por coma (ej: msg_in,msg_out)')
|
|
153
|
+
.option('--no-session', 'Ocultar session ID')
|
|
154
|
+
.option('--json', 'Modo JSON crudo (para piping)', false)
|
|
155
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
156
|
+
.action(async (options: {
|
|
157
|
+
agentId: string;
|
|
158
|
+
filter?: string;
|
|
159
|
+
session: boolean;
|
|
160
|
+
json: boolean;
|
|
161
|
+
dev: boolean;
|
|
162
|
+
}) => {
|
|
163
|
+
try {
|
|
164
|
+
const credentials = await getStoredCredentials();
|
|
165
|
+
const baseUrl = getBaseUrl(credentials.zone, options.dev);
|
|
166
|
+
|
|
167
|
+
// Filtros iniciales
|
|
168
|
+
const activeFilters: Set<string> = new Set(
|
|
169
|
+
options.filter ? options.filter.split(',').map(f => f.trim()) : []
|
|
170
|
+
);
|
|
171
|
+
let jsonMode = options.json;
|
|
172
|
+
let lastSessionId = '';
|
|
173
|
+
|
|
174
|
+
// Cargar info del agente
|
|
175
|
+
let agentName = 'Agente';
|
|
176
|
+
try {
|
|
177
|
+
process.stdout.write(chalk.gray(' Conectando con agente...'));
|
|
178
|
+
const agent = new Agent({
|
|
179
|
+
workspaceId: credentials.workspace,
|
|
180
|
+
apiKey: credentials.apiKey,
|
|
181
|
+
zone: credentials.zone,
|
|
182
|
+
...(options.dev && { customUrl: 'http://localhost:5090' }),
|
|
183
|
+
});
|
|
184
|
+
const info: any = await agent.getAgentById({ id: options.agentId });
|
|
185
|
+
if (info?.name) agentName = info.name;
|
|
186
|
+
process.stdout.write('\r' + ' '.repeat(40) + '\r');
|
|
187
|
+
} catch {
|
|
188
|
+
process.stdout.write('\r' + ' '.repeat(40) + '\r');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Dibujar header
|
|
192
|
+
if (!jsonMode) {
|
|
193
|
+
console.clear();
|
|
194
|
+
printHeader(agentName);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Conectar a SignalR
|
|
198
|
+
const hubUrl = `${baseUrl}/agentMonitorHub`;
|
|
199
|
+
const connection = new HubConnectionBuilder()
|
|
200
|
+
.withUrl(hubUrl, {
|
|
201
|
+
skipNegotiation: true,
|
|
202
|
+
transport: HttpTransportType.WebSockets,
|
|
203
|
+
})
|
|
204
|
+
.withAutomaticReconnect([0, 2000, 5000, 10000, 30000])
|
|
205
|
+
.build();
|
|
206
|
+
|
|
207
|
+
// Evento de log
|
|
208
|
+
connection.on('agent_log', (log: AgentLogEvent) => {
|
|
209
|
+
// Aplicar filtros
|
|
210
|
+
if (activeFilters.size > 0 && !activeFilters.has(log.event_type)) return;
|
|
211
|
+
|
|
212
|
+
const line = renderLogLine(log, {
|
|
213
|
+
showSession: options.session,
|
|
214
|
+
jsonMode,
|
|
215
|
+
}, lastSessionId);
|
|
216
|
+
|
|
217
|
+
console.log(line);
|
|
218
|
+
lastSessionId = log.session_id || lastSessionId;
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Eventos de conexion
|
|
222
|
+
connection.onreconnecting(() => {
|
|
223
|
+
if (!jsonMode) {
|
|
224
|
+
console.log(chalk.hex('#FFA726')(' ⟳ Reconectando...'));
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
connection.onreconnected(() => {
|
|
229
|
+
if (!jsonMode) {
|
|
230
|
+
console.log(chalk.hex('#4ade80')(' ● Reconectado'));
|
|
231
|
+
}
|
|
232
|
+
connection.invoke('JoinAgentMonitor', options.agentId).catch(() => {});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
connection.onclose(() => {
|
|
236
|
+
if (!jsonMode) {
|
|
237
|
+
console.log(chalk.hex('#ef4444')(' ● Desconectado'));
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Iniciar conexion
|
|
242
|
+
try {
|
|
243
|
+
await connection.start();
|
|
244
|
+
await connection.invoke('JoinAgentMonitor', options.agentId);
|
|
245
|
+
if (!jsonMode) {
|
|
246
|
+
console.log(chalk.hex('#4ade80')(' ● Conectado al monitor en tiempo real'));
|
|
247
|
+
console.log();
|
|
248
|
+
}
|
|
249
|
+
} catch (err) {
|
|
250
|
+
logger.error(`No se pudo conectar al monitor: ${err instanceof Error ? err.message : err}`);
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// readline para comandos interactivos
|
|
255
|
+
const rl = readline.createInterface({
|
|
256
|
+
input: process.stdin,
|
|
257
|
+
output: process.stdout,
|
|
258
|
+
prompt: '',
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// No mostrar prompt para no interferir con el stream
|
|
262
|
+
rl.on('line', (input: string) => {
|
|
263
|
+
const cmd = input.trim().toLowerCase();
|
|
264
|
+
|
|
265
|
+
if (cmd === '/help') {
|
|
266
|
+
console.log(COMMANDS_HELP);
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (cmd === '/clear') {
|
|
271
|
+
console.clear();
|
|
272
|
+
printHeader(agentName);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (cmd === '/json') {
|
|
277
|
+
jsonMode = !jsonMode;
|
|
278
|
+
console.log(chalk.gray(` Modo JSON: ${jsonMode ? 'activado' : 'desactivado'}`));
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (cmd === '/filters') {
|
|
283
|
+
if (activeFilters.size === 0) {
|
|
284
|
+
console.log(chalk.gray(' Sin filtros activos (mostrando todos)'));
|
|
285
|
+
} else {
|
|
286
|
+
console.log(chalk.gray(' Filtros activos: ') + chalk.white([...activeFilters].join(', ')));
|
|
287
|
+
}
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (cmd.startsWith('/filter ')) {
|
|
292
|
+
const filterType = cmd.substring(8).trim();
|
|
293
|
+
if (!filterType) {
|
|
294
|
+
console.log(chalk.gray(' Uso: /filter <tipo>'));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (activeFilters.has(filterType)) {
|
|
298
|
+
activeFilters.delete(filterType);
|
|
299
|
+
console.log(chalk.gray(` Filtro removido: ${filterType}`));
|
|
300
|
+
} else {
|
|
301
|
+
activeFilters.add(filterType);
|
|
302
|
+
const config = EVENT_COLORS[filterType];
|
|
303
|
+
if (config) {
|
|
304
|
+
console.log(chalk.hex(config.color)(` ● Filtro agregado: ${filterType}`));
|
|
305
|
+
} else {
|
|
306
|
+
console.log(chalk.gray(` Filtro agregado: ${filterType} (tipo desconocido)`));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (activeFilters.size > 0) {
|
|
310
|
+
console.log(chalk.gray(' Activos: ') + chalk.white([...activeFilters].join(', ')));
|
|
311
|
+
} else {
|
|
312
|
+
console.log(chalk.gray(' Sin filtros (mostrando todos)'));
|
|
313
|
+
}
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Cierre limpio
|
|
319
|
+
const cleanup = async () => {
|
|
320
|
+
if (!jsonMode) {
|
|
321
|
+
console.log(chalk.gray('\n Cerrando monitor...'));
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
if (connection.state === HubConnectionState.Connected) {
|
|
325
|
+
await connection.invoke('LeaveAgentMonitor', options.agentId);
|
|
326
|
+
}
|
|
327
|
+
await connection.stop();
|
|
328
|
+
} catch {
|
|
329
|
+
// Ignorar errores al cerrar
|
|
330
|
+
}
|
|
331
|
+
rl.close();
|
|
332
|
+
if (!jsonMode) {
|
|
333
|
+
console.log(chalk.gray(' Monitor cerrado.\n'));
|
|
334
|
+
}
|
|
335
|
+
process.exit(0);
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
process.on('SIGINT', cleanup);
|
|
339
|
+
process.on('SIGTERM', cleanup);
|
|
340
|
+
|
|
341
|
+
} catch (error) {
|
|
342
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
343
|
+
logger.error(message);
|
|
344
|
+
process.exit(1);
|
|
345
|
+
}
|
|
346
|
+
});
|