plazbot-cli 0.1.3 → 0.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/.claude/settings.local.json +15 -0
- package/CLAUDE.md +92 -0
- package/README.md +1 -1
- package/dist/cli.js +14 -5
- package/dist/commands/agent/ai-config.js +103 -0
- package/dist/commands/agent/chat.js +130 -34
- package/dist/commands/agent/copy.js +37 -0
- package/dist/commands/agent/create.js +80 -17
- package/dist/commands/agent/delete.js +3 -3
- package/dist/commands/agent/enable-widget.js +1 -1
- package/dist/commands/agent/files.js +142 -0
- package/dist/commands/agent/get.js +1 -2
- package/dist/commands/agent/index.js +14 -2
- package/dist/commands/agent/list.js +6 -6
- package/dist/commands/agent/set.js +127 -0
- package/dist/commands/agent/templates.js +803 -0
- package/dist/commands/agent/tools.js +155 -0
- package/dist/commands/agent/wizard.js +369 -0
- package/dist/commands/portal/add-agent.js +4 -4
- package/dist/commands/portal/list.js +5 -4
- package/dist/commands/whatsapp/broadcast.js +97 -0
- package/dist/commands/whatsapp/channels.js +86 -0
- package/dist/commands/whatsapp/chat.js +74 -0
- package/dist/commands/whatsapp/index.js +11 -2
- package/dist/commands/whatsapp/send-template.js +51 -14
- package/dist/commands/whatsapp/send.js +10 -10
- package/dist/commands/whatsapp/widget.js +64 -0
- package/dist/utils/banner.js +87 -0
- package/dist/utils/logger.js +27 -6
- package/dist/utils/ui.js +111 -0
- package/package.json +10 -2
- package/src/cli.ts +13 -5
- package/src/commands/agent/ai-config.ts +108 -0
- package/src/commands/agent/chat.ts +149 -40
- package/src/commands/agent/copy.ts +40 -0
- package/src/commands/agent/create.ts +58 -23
- package/src/commands/agent/delete.ts +3 -3
- package/src/commands/agent/enable-widget.ts +1 -1
- package/src/commands/agent/files.ts +158 -0
- package/src/commands/agent/get.ts +1 -2
- package/src/commands/agent/index.ts +14 -2
- package/src/commands/agent/list.ts +7 -7
- package/src/commands/agent/set.ts +137 -0
- package/src/commands/agent/templates.ts +843 -0
- package/src/commands/agent/tools.ts +161 -0
- package/src/commands/agent/wizard.ts +475 -0
- package/src/commands/portal/add-agent.ts +4 -4
- package/src/commands/portal/list.ts +5 -4
- package/src/commands/whatsapp/broadcast.ts +100 -0
- package/src/commands/whatsapp/channels.ts +98 -0
- package/src/commands/whatsapp/chat.ts +77 -0
- package/src/commands/whatsapp/index.ts +11 -2
- package/src/commands/whatsapp/send-template.ts +57 -19
- package/src/commands/whatsapp/send.ts +15 -14
- package/src/commands/whatsapp/widget.ts +67 -0
- package/src/utils/banner.ts +94 -0
- package/src/utils/logger.ts +26 -7
- package/src/utils/ui.ts +109 -0
- package/dist/commands/message/delete-webhook.js +0 -39
- package/dist/commands/message/index.js +0 -14
- package/dist/commands/message/register-webhook.js +0 -42
- package/dist/commands/message/send-template.js +0 -42
- package/dist/commands/message/send.js +0 -42
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { Message } from 'plazbot';
|
|
3
|
+
import { getStoredCredentials } from '../../utils/credentials';
|
|
4
|
+
import { logger } from '../../utils/logger';
|
|
5
|
+
import { createSpinner, theme, section, progressBar } from '../../utils/ui';
|
|
6
|
+
import fs from 'fs/promises';
|
|
7
|
+
|
|
8
|
+
export const broadcastCommand = new Command('broadcast')
|
|
9
|
+
.description('Envio masivo de mensajes de template WhatsApp')
|
|
10
|
+
.requiredOption('-t, --template <name>', 'Nombre del template')
|
|
11
|
+
.requiredOption('--phones <file>', 'Archivo CSV con numeros de telefono (uno por linea)')
|
|
12
|
+
.option('--var <vars...>', 'Variables del body (formato: name=valor)')
|
|
13
|
+
.option('--delay <ms>', 'Delay entre mensajes en ms', '1000')
|
|
14
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
15
|
+
.action(async (options: any) => {
|
|
16
|
+
try {
|
|
17
|
+
const credentials = await getStoredCredentials();
|
|
18
|
+
|
|
19
|
+
const messageClient = new Message({
|
|
20
|
+
workspaceId: credentials.workspace,
|
|
21
|
+
apiKey: credentials.apiKey,
|
|
22
|
+
zone: credentials.zone,
|
|
23
|
+
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Leer archivo de telefonos
|
|
27
|
+
let phones: string[];
|
|
28
|
+
try {
|
|
29
|
+
const content = await fs.readFile(options.phones, 'utf-8');
|
|
30
|
+
phones = content.split('\n')
|
|
31
|
+
.map(line => line.trim())
|
|
32
|
+
.filter(line => line && !line.startsWith('#'));
|
|
33
|
+
} catch {
|
|
34
|
+
throw new Error(`No se pudo leer el archivo: ${options.phones}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (phones.length === 0) {
|
|
38
|
+
throw new Error('El archivo no contiene numeros de telefono');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Parsear variables
|
|
42
|
+
const variablesBody = parseVariables(options.var);
|
|
43
|
+
|
|
44
|
+
console.log(section('Broadcast WhatsApp'));
|
|
45
|
+
logger.label('Template', options.template);
|
|
46
|
+
logger.label('Destinatarios', String(phones.length));
|
|
47
|
+
logger.label('Delay', `${options.delay}ms`);
|
|
48
|
+
if (variablesBody.length > 0) {
|
|
49
|
+
logger.label('Variables', variablesBody.map(v => `${v.variable}=${v.value}`).join(', '));
|
|
50
|
+
}
|
|
51
|
+
console.log();
|
|
52
|
+
|
|
53
|
+
const delay = parseInt(options.delay) || 1000;
|
|
54
|
+
let sent = 0;
|
|
55
|
+
let failed = 0;
|
|
56
|
+
|
|
57
|
+
for (let i = 0; i < phones.length; i++) {
|
|
58
|
+
const phone = phones[i];
|
|
59
|
+
try {
|
|
60
|
+
const params: any = {
|
|
61
|
+
to: phone,
|
|
62
|
+
template: options.template,
|
|
63
|
+
};
|
|
64
|
+
if (variablesBody.length > 0) params.variablesBody = variablesBody;
|
|
65
|
+
|
|
66
|
+
await messageClient.onConversation(params);
|
|
67
|
+
sent++;
|
|
68
|
+
} catch {
|
|
69
|
+
failed++;
|
|
70
|
+
console.log(theme.error(` ✖ Fallo: ${phone}`));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Progress
|
|
74
|
+
console.log(` ${progressBar(i + 1, phones.length)}`);
|
|
75
|
+
|
|
76
|
+
// Rate limiting
|
|
77
|
+
if (i < phones.length - 1) {
|
|
78
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
console.log(section('Resultado'));
|
|
83
|
+
logger.label('Enviados', theme.success(String(sent)));
|
|
84
|
+
logger.label('Fallidos', failed > 0 ? theme.error(String(failed)) : '0');
|
|
85
|
+
logger.label('Total', String(phones.length));
|
|
86
|
+
|
|
87
|
+
} catch (error: unknown) {
|
|
88
|
+
const message = (error as Error)?.message || 'Error desconocido';
|
|
89
|
+
logger.error(message);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
function parseVariables(vars: string[] | undefined): { variable: string; value: string }[] {
|
|
95
|
+
if (!vars) return [];
|
|
96
|
+
return vars.map(v => {
|
|
97
|
+
const [variable, ...rest] = v.split('=');
|
|
98
|
+
return { variable: variable.trim(), value: rest.join('=').trim() };
|
|
99
|
+
}).filter(v => v.variable && v.value);
|
|
100
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { Agent } from 'plazbot';
|
|
3
|
+
import { getStoredCredentials } from '../../utils/credentials';
|
|
4
|
+
import { logger } from '../../utils/logger';
|
|
5
|
+
import { createSpinner, createTable, theme, section, statusBadge } from '../../utils/ui';
|
|
6
|
+
|
|
7
|
+
export const channelsCommand = new Command('channels')
|
|
8
|
+
.description('Listar agentes con canales de WhatsApp asignados')
|
|
9
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
10
|
+
.action(async (options: any) => {
|
|
11
|
+
try {
|
|
12
|
+
const credentials = await getStoredCredentials();
|
|
13
|
+
const agent = new Agent({
|
|
14
|
+
workspaceId: credentials.workspace,
|
|
15
|
+
apiKey: credentials.apiKey,
|
|
16
|
+
zone: credentials.zone,
|
|
17
|
+
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const spinner = createSpinner('Cargando canales...');
|
|
21
|
+
spinner.start();
|
|
22
|
+
const agents = await agent.getAgents();
|
|
23
|
+
spinner.stop();
|
|
24
|
+
|
|
25
|
+
console.log(section('Canales WhatsApp'));
|
|
26
|
+
|
|
27
|
+
const whatsappAgents = (agents || []).filter((a: any) =>
|
|
28
|
+
a.channels && a.channels.some((c: any) => c.channel === 'whatsapp')
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
if (whatsappAgents.length === 0) {
|
|
32
|
+
console.log(theme.muted('\n No hay agentes con WhatsApp configurado'));
|
|
33
|
+
console.log(theme.muted(' Usa el wizard: plazbot agent create\n'));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const rows = whatsappAgents.map((a: any) => {
|
|
38
|
+
const waChannel = a.channels.find((c: any) => c.channel === 'whatsapp');
|
|
39
|
+
return [
|
|
40
|
+
a.id || a._id,
|
|
41
|
+
a.name,
|
|
42
|
+
waChannel?.key || 'N/A',
|
|
43
|
+
statusBadge(a.enable !== false),
|
|
44
|
+
];
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
console.log(createTable(['Agent ID', 'Nombre', 'Numero WhatsApp', 'Estado'], rows));
|
|
48
|
+
|
|
49
|
+
} catch (error) {
|
|
50
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
51
|
+
logger.error(message);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const assignCommand = new Command('assign')
|
|
57
|
+
.description('Asignar un agente a un numero de WhatsApp')
|
|
58
|
+
.argument('<phone>', 'Numero de WhatsApp')
|
|
59
|
+
.argument('<agentId>', 'ID del agente')
|
|
60
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
61
|
+
.action(async (phone: string, agentId: string, options: any) => {
|
|
62
|
+
try {
|
|
63
|
+
const credentials = await getStoredCredentials();
|
|
64
|
+
const agent = new Agent({
|
|
65
|
+
workspaceId: credentials.workspace,
|
|
66
|
+
apiKey: credentials.apiKey,
|
|
67
|
+
zone: credentials.zone,
|
|
68
|
+
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const spinner = createSpinner('Cargando agente...');
|
|
72
|
+
spinner.start();
|
|
73
|
+
const agentData = await agent.getAgentById({ id: agentId });
|
|
74
|
+
spinner.stop();
|
|
75
|
+
|
|
76
|
+
const channels = agentData.channels || [];
|
|
77
|
+
|
|
78
|
+
// Verificar si ya tiene este canal
|
|
79
|
+
const existing = channels.findIndex((c: any) => c.channel === 'whatsapp' && c.key === phone);
|
|
80
|
+
if (existing >= 0) {
|
|
81
|
+
logger.warning('Este numero ya esta asignado a este agente');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Agregar canal
|
|
86
|
+
channels.push({ channel: 'whatsapp', key: phone, multianswer: false });
|
|
87
|
+
|
|
88
|
+
const updateSpinner = createSpinner('Asignando...');
|
|
89
|
+
updateSpinner.start();
|
|
90
|
+
await agent.updateAgent(agentId, { channels });
|
|
91
|
+
updateSpinner.succeed(`Agente "${agentData.name}" asignado a WhatsApp ${phone}`);
|
|
92
|
+
|
|
93
|
+
} catch (error) {
|
|
94
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
95
|
+
logger.error(message);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { Message } from 'plazbot';
|
|
3
|
+
import { getStoredCredentials } from '../../utils/credentials';
|
|
4
|
+
import { logger } from '../../utils/logger';
|
|
5
|
+
import { createSpinner, theme } from '../../utils/ui';
|
|
6
|
+
import readline from 'readline';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
|
|
9
|
+
export const whatsappChatCommand = new Command('chat')
|
|
10
|
+
.description('Chat interactivo directo por WhatsApp')
|
|
11
|
+
.argument('<phone>', 'Numero de telefono destino (con codigo de pais)')
|
|
12
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
13
|
+
.action(async (phone: string, options: any) => {
|
|
14
|
+
try {
|
|
15
|
+
const credentials = await getStoredCredentials();
|
|
16
|
+
|
|
17
|
+
const messageClient = new Message({
|
|
18
|
+
workspaceId: credentials.workspace,
|
|
19
|
+
apiKey: credentials.apiKey,
|
|
20
|
+
zone: credentials.zone,
|
|
21
|
+
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const rl = readline.createInterface({
|
|
25
|
+
input: process.stdin,
|
|
26
|
+
output: process.stdout,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
console.clear();
|
|
30
|
+
console.log();
|
|
31
|
+
console.log(chalk.hex('#25D366')(' ┌' + '─'.repeat(50) + '┐'));
|
|
32
|
+
console.log(chalk.hex('#25D366')(' │') + chalk.bold(` WhatsApp Chat`).padEnd(60) + chalk.hex('#25D366')('│'));
|
|
33
|
+
console.log(chalk.hex('#25D366')(' │') + chalk.gray(` Destino: ${phone}`).padEnd(60) + chalk.hex('#25D366')('│'));
|
|
34
|
+
console.log(chalk.hex('#25D366')(' │') + chalk.gray(' /exit para salir').padEnd(60) + chalk.hex('#25D366')('│'));
|
|
35
|
+
console.log(chalk.hex('#25D366')(' └' + '─'.repeat(50) + '┘'));
|
|
36
|
+
console.log();
|
|
37
|
+
|
|
38
|
+
const ask = () => {
|
|
39
|
+
rl.question(chalk.hex('#25D366')(' > '), async (message) => {
|
|
40
|
+
if (!message.trim()) {
|
|
41
|
+
ask();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (message.toLowerCase() === '/exit') {
|
|
46
|
+
console.log(chalk.gray('\n Chat terminado.\n'));
|
|
47
|
+
rl.close();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const spinner = createSpinner('Enviando...');
|
|
53
|
+
spinner.start();
|
|
54
|
+
|
|
55
|
+
await messageClient.onWhatsappMessage({
|
|
56
|
+
message,
|
|
57
|
+
to: phone,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
spinner.succeed('Enviado');
|
|
61
|
+
ask();
|
|
62
|
+
} catch (error) {
|
|
63
|
+
const msg = error instanceof Error ? error.message : 'Error';
|
|
64
|
+
console.log(chalk.hex('#EF5350')(` ✖ ${msg}`));
|
|
65
|
+
ask();
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
ask();
|
|
71
|
+
|
|
72
|
+
} catch (error) {
|
|
73
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
74
|
+
logger.error(message);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
@@ -3,10 +3,19 @@ import { sendMessageCommand } from './send';
|
|
|
3
3
|
import { sendTemplateCommand } from './send-template';
|
|
4
4
|
import { registerWebhookCommand } from './register-webhook';
|
|
5
5
|
import { deleteWebhookCommand } from './delete-webhook';
|
|
6
|
+
import { broadcastCommand } from './broadcast';
|
|
7
|
+
import { whatsappChatCommand } from './chat';
|
|
8
|
+
import { widgetCommand } from './widget';
|
|
9
|
+
import { channelsCommand, assignCommand } from './channels';
|
|
6
10
|
|
|
7
11
|
export const whatsappCommands = new Command('whatsapp')
|
|
8
|
-
.description('Comandos
|
|
12
|
+
.description('Comandos de WhatsApp: mensajes, templates, broadcast y mas')
|
|
9
13
|
.addCommand(sendMessageCommand)
|
|
10
14
|
.addCommand(sendTemplateCommand)
|
|
11
15
|
.addCommand(registerWebhookCommand)
|
|
12
|
-
.addCommand(deleteWebhookCommand)
|
|
16
|
+
.addCommand(deleteWebhookCommand)
|
|
17
|
+
.addCommand(broadcastCommand)
|
|
18
|
+
.addCommand(whatsappChatCommand)
|
|
19
|
+
.addCommand(widgetCommand)
|
|
20
|
+
.addCommand(channelsCommand)
|
|
21
|
+
.addCommand(assignCommand);
|
|
@@ -2,16 +2,21 @@ import { Command } from 'commander';
|
|
|
2
2
|
import { Message } from 'plazbot';
|
|
3
3
|
import { getStoredCredentials } from '../../utils/credentials';
|
|
4
4
|
import { logger } from '../../utils/logger';
|
|
5
|
-
import {
|
|
5
|
+
import { createSpinner } from '../../utils/ui';
|
|
6
6
|
|
|
7
7
|
export const sendTemplateCommand = new Command('send-template')
|
|
8
|
-
.description('
|
|
9
|
-
.requiredOption('-p, --phone <number>', '
|
|
10
|
-
.requiredOption('-t, --template <name>', 'Nombre
|
|
8
|
+
.description('Envia un mensaje de template de WhatsApp con variables')
|
|
9
|
+
.requiredOption('-p, --phone <number>', 'Numero de telefono (con codigo de pais)')
|
|
10
|
+
.requiredOption('-t, --template <name>', 'Nombre del template')
|
|
11
|
+
.option('--var <vars...>', 'Variables del body (formato: name=valor)')
|
|
12
|
+
.option('--header-var <vars...>', 'Variables del header (formato: name=valor)')
|
|
13
|
+
.option('--file-url <url>', 'URL del archivo adjunto')
|
|
14
|
+
.option('--file-name <name>', 'Nombre del archivo adjunto')
|
|
11
15
|
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
12
|
-
.action(async (options:
|
|
16
|
+
.action(async (options: any) => {
|
|
13
17
|
try {
|
|
14
18
|
const credentials = await getStoredCredentials();
|
|
19
|
+
|
|
15
20
|
const messageClient = new Message({
|
|
16
21
|
workspaceId: credentials.workspace,
|
|
17
22
|
apiKey: credentials.apiKey,
|
|
@@ -19,26 +24,59 @@ export const sendTemplateCommand = new Command('send-template')
|
|
|
19
24
|
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
20
25
|
});
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
// Parsear variables
|
|
28
|
+
const variablesBody = parseVariables(options.var);
|
|
29
|
+
const variablesHeader = parseVariables(options.headerVar);
|
|
30
|
+
|
|
31
|
+
// Archivo adjunto
|
|
32
|
+
const file = options.fileUrl ? {
|
|
33
|
+
fileUrl: options.fileUrl,
|
|
34
|
+
fileName: options.fileName || 'archivo',
|
|
35
|
+
} : undefined;
|
|
36
|
+
|
|
37
|
+
logger.title('Enviando template WhatsApp');
|
|
38
|
+
logger.label('Destino', options.phone);
|
|
39
|
+
logger.label('Template', options.template);
|
|
40
|
+
if (variablesBody.length > 0) {
|
|
41
|
+
logger.label('Variables body', variablesBody.map(v => `${v.variable}=${v.value}`).join(', '));
|
|
42
|
+
}
|
|
43
|
+
if (variablesHeader.length > 0) {
|
|
44
|
+
logger.label('Variables header', variablesHeader.map(v => `${v.variable}=${v.value}`).join(', '));
|
|
45
|
+
}
|
|
46
|
+
if (file) {
|
|
47
|
+
logger.label('Archivo', file.fileUrl);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const spinner = createSpinner('Enviando...');
|
|
51
|
+
spinner.start();
|
|
52
|
+
|
|
53
|
+
const params: any = {
|
|
27
54
|
to: options.phone,
|
|
28
|
-
template: options.template
|
|
29
|
-
}
|
|
55
|
+
template: options.template,
|
|
56
|
+
};
|
|
57
|
+
if (variablesBody.length > 0) params.variablesBody = variablesBody;
|
|
58
|
+
if (variablesHeader.length > 0) params.variablesHeader = variablesHeader;
|
|
59
|
+
if (file) params.file = file;
|
|
60
|
+
|
|
61
|
+
const response = await messageClient.onConversation(params);
|
|
62
|
+
|
|
63
|
+
spinner.succeed('Template enviado exitosamente');
|
|
30
64
|
|
|
31
|
-
logger.success('Plantilla enviada exitosamente');
|
|
32
|
-
logger.info('\n📋 Detalles:');
|
|
33
|
-
logger.info(JSON.stringify(response, null, 2));
|
|
34
|
-
|
|
35
65
|
if (options.dev) {
|
|
36
|
-
logger.warning('
|
|
66
|
+
logger.warning('Ambiente: desarrollo');
|
|
37
67
|
}
|
|
38
68
|
|
|
39
69
|
} catch (error: unknown) {
|
|
40
|
-
const message = error
|
|
70
|
+
const message = (error as Error)?.message || 'Error desconocido al enviar el template';
|
|
41
71
|
logger.error(message);
|
|
42
72
|
process.exit(1);
|
|
43
73
|
}
|
|
44
|
-
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
function parseVariables(vars: string[] | undefined): { variable: string; value: string }[] {
|
|
77
|
+
if (!vars) return [];
|
|
78
|
+
return vars.map(v => {
|
|
79
|
+
const [variable, ...rest] = v.split('=');
|
|
80
|
+
return { variable: variable.trim(), value: rest.join('=').trim() };
|
|
81
|
+
}).filter(v => v.variable && v.value);
|
|
82
|
+
}
|
|
@@ -3,17 +3,17 @@ import { Message } from 'plazbot';
|
|
|
3
3
|
import { getStoredCredentials } from '../../utils/credentials';
|
|
4
4
|
import { logger } from '../../utils/logger';
|
|
5
5
|
import { DirectMessageCommandOptions } from '../../types/message';
|
|
6
|
+
import { createSpinner } from '../../utils/ui';
|
|
6
7
|
|
|
7
8
|
export const sendMessageCommand = new Command('send-message')
|
|
8
|
-
.description('
|
|
9
|
-
.requiredOption('-t, --to <phone>', '
|
|
9
|
+
.description('Envia un mensaje directo de WhatsApp')
|
|
10
|
+
.requiredOption('-t, --to <phone>', 'Numero de telefono (con codigo de pais, ej: 51912345678)')
|
|
10
11
|
.requiredOption('-m, --message <text>', 'Mensaje a enviar')
|
|
11
12
|
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
12
13
|
.action(async (options: DirectMessageCommandOptions) => {
|
|
13
14
|
try {
|
|
14
|
-
// Obtener credenciales guardadas
|
|
15
15
|
const credentials = await getStoredCredentials();
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
const messageClient = new Message({
|
|
18
18
|
workspaceId: credentials.workspace,
|
|
19
19
|
apiKey: credentials.apiKey,
|
|
@@ -21,21 +21,22 @@ export const sendMessageCommand = new Command('send-message')
|
|
|
21
21
|
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
22
22
|
});
|
|
23
23
|
|
|
24
|
-
logger.
|
|
25
|
-
logger.
|
|
26
|
-
logger.
|
|
27
|
-
|
|
24
|
+
logger.title('Enviando mensaje WhatsApp');
|
|
25
|
+
logger.label('Destino', options.to);
|
|
26
|
+
logger.label('Mensaje', options.message);
|
|
27
|
+
|
|
28
|
+
const spinner = createSpinner('Enviando...');
|
|
29
|
+
spinner.start();
|
|
30
|
+
|
|
28
31
|
const response = await messageClient.onWhatsappMessage({
|
|
29
32
|
message: options.message,
|
|
30
33
|
to: options.to
|
|
31
34
|
});
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
logger.info(JSON.stringify(response, null, 2));
|
|
36
|
-
|
|
36
|
+
spinner.succeed('Mensaje enviado exitosamente');
|
|
37
|
+
|
|
37
38
|
if (options.dev) {
|
|
38
|
-
logger.warning('
|
|
39
|
+
logger.warning('Ambiente: desarrollo');
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
} catch (error: unknown) {
|
|
@@ -43,4 +44,4 @@ export const sendMessageCommand = new Command('send-message')
|
|
|
43
44
|
logger.error(message);
|
|
44
45
|
process.exit(1);
|
|
45
46
|
}
|
|
46
|
-
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { Agent } from 'plazbot';
|
|
3
|
+
import { getStoredCredentials } from '../../utils/credentials';
|
|
4
|
+
import { logger } from '../../utils/logger';
|
|
5
|
+
import { createSpinner } from '../../utils/ui';
|
|
6
|
+
|
|
7
|
+
const widgetGroup = new Command('widget')
|
|
8
|
+
.description('Gestionar widget de WhatsApp');
|
|
9
|
+
|
|
10
|
+
widgetGroup.command('enable')
|
|
11
|
+
.description('Activar widget de WhatsApp en un agente')
|
|
12
|
+
.argument('<agentId>', 'ID del agente')
|
|
13
|
+
.requiredOption('-u, --url <url>', 'URL de WhatsApp (ej: https://wa.me/51912345678)')
|
|
14
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
15
|
+
.action(async (agentId: string, options: any) => {
|
|
16
|
+
try {
|
|
17
|
+
const credentials = await getStoredCredentials();
|
|
18
|
+
const agent = new Agent({
|
|
19
|
+
workspaceId: credentials.workspace,
|
|
20
|
+
apiKey: credentials.apiKey,
|
|
21
|
+
zone: credentials.zone,
|
|
22
|
+
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const spinner = createSpinner('Activando widget WhatsApp...');
|
|
26
|
+
spinner.start();
|
|
27
|
+
await agent.updateAgent(agentId, {
|
|
28
|
+
enableWhatsappWidget: true,
|
|
29
|
+
urlWhatsappWidget: options.url,
|
|
30
|
+
});
|
|
31
|
+
spinner.succeed('Widget WhatsApp activado');
|
|
32
|
+
logger.label('URL', options.url);
|
|
33
|
+
|
|
34
|
+
} catch (error) {
|
|
35
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
36
|
+
logger.error(message);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
widgetGroup.command('disable')
|
|
42
|
+
.description('Desactivar widget de WhatsApp de un agente')
|
|
43
|
+
.argument('<agentId>', 'ID del agente')
|
|
44
|
+
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
45
|
+
.action(async (agentId: string, options: any) => {
|
|
46
|
+
try {
|
|
47
|
+
const credentials = await getStoredCredentials();
|
|
48
|
+
const agent = new Agent({
|
|
49
|
+
workspaceId: credentials.workspace,
|
|
50
|
+
apiKey: credentials.apiKey,
|
|
51
|
+
zone: credentials.zone,
|
|
52
|
+
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const spinner = createSpinner('Desactivando widget WhatsApp...');
|
|
56
|
+
spinner.start();
|
|
57
|
+
await agent.updateAgent(agentId, { enableWhatsappWidget: false });
|
|
58
|
+
spinner.succeed('Widget WhatsApp desactivado');
|
|
59
|
+
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const message = error instanceof Error ? error.message : 'Error desconocido';
|
|
62
|
+
logger.error(message);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
export const widgetCommand = widgetGroup;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { getStoredCredentials } from './credentials';
|
|
3
|
+
|
|
4
|
+
const VERSION = '0.2.0';
|
|
5
|
+
|
|
6
|
+
// ASCII art del logo Plazbot (burbujas de chat)
|
|
7
|
+
const logo = [
|
|
8
|
+
' ╭──────────╮ ',
|
|
9
|
+
' │ ● ● ● │ ',
|
|
10
|
+
' ╰────┬─────╯ ',
|
|
11
|
+
' ╭─────┴────────╮ ',
|
|
12
|
+
' │ ╭─╮ ╭─╮ │ ',
|
|
13
|
+
' │ ╰─╯ ╰─╯ │ ',
|
|
14
|
+
' │ ╰────╯ │ ',
|
|
15
|
+
' ╰───────────────╯ ',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const coloredLogo = logo.map(line =>
|
|
19
|
+
chalk.hex('#2E8B57')(line)
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export async function showBanner(): Promise<void> {
|
|
23
|
+
const width = 70;
|
|
24
|
+
|
|
25
|
+
// Intentar cargar credenciales
|
|
26
|
+
let credentials: { email?: string; workspace?: string; zone?: string } | null = null;
|
|
27
|
+
try {
|
|
28
|
+
credentials = await getStoredCredentials();
|
|
29
|
+
} catch {
|
|
30
|
+
// No hay credenciales guardadas
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log();
|
|
34
|
+
console.log(chalk.hex('#4CAF50')('─'.repeat(width)));
|
|
35
|
+
console.log();
|
|
36
|
+
|
|
37
|
+
// Layout de 2 columnas
|
|
38
|
+
const leftWidth = 30;
|
|
39
|
+
const rightStart = leftWidth + 4;
|
|
40
|
+
|
|
41
|
+
// Línea del título
|
|
42
|
+
const title = chalk.bold.hex('#4CAF50')(` Plazbot CLI v${VERSION}`);
|
|
43
|
+
|
|
44
|
+
// Info columna derecha
|
|
45
|
+
const rightColumn: string[] = [];
|
|
46
|
+
|
|
47
|
+
if (credentials) {
|
|
48
|
+
rightColumn.push(chalk.bold.hex('#4CAF50')('Workspace conectado'));
|
|
49
|
+
rightColumn.push(chalk.gray(` ${credentials.workspace || 'N/A'}`));
|
|
50
|
+
rightColumn.push(chalk.gray(` ${credentials.email || ''}`));
|
|
51
|
+
rightColumn.push(chalk.gray(` Zona: ${credentials.zone || 'N/A'}`));
|
|
52
|
+
rightColumn.push('');
|
|
53
|
+
rightColumn.push(chalk.hex('#4CAF50')('─'.repeat(35)));
|
|
54
|
+
rightColumn.push('');
|
|
55
|
+
rightColumn.push(chalk.bold.hex('#4CAF50')('Comandos rapidos'));
|
|
56
|
+
rightColumn.push(chalk.white(' plazbot agent list'));
|
|
57
|
+
rightColumn.push(chalk.white(' plazbot agent create'));
|
|
58
|
+
rightColumn.push(chalk.white(' plazbot agent chat -a <id>'));
|
|
59
|
+
rightColumn.push(chalk.white(' plazbot whatsapp send-message'));
|
|
60
|
+
} else {
|
|
61
|
+
rightColumn.push(chalk.bold.hex('#FFA726')('No conectado'));
|
|
62
|
+
rightColumn.push('');
|
|
63
|
+
rightColumn.push(chalk.bold.hex('#4CAF50')('Para comenzar'));
|
|
64
|
+
rightColumn.push(chalk.white(' plazbot init -e <email> -k <key> -w <workspace> -z <zone>'));
|
|
65
|
+
rightColumn.push('');
|
|
66
|
+
rightColumn.push(chalk.hex('#4CAF50')('─'.repeat(35)));
|
|
67
|
+
rightColumn.push('');
|
|
68
|
+
rightColumn.push(chalk.bold.hex('#4CAF50')('Documentacion'));
|
|
69
|
+
rightColumn.push(chalk.gray(' https://docs.plazbot.com'));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Imprimir título
|
|
73
|
+
console.log(title);
|
|
74
|
+
console.log();
|
|
75
|
+
|
|
76
|
+
// Imprimir logo + info lado a lado
|
|
77
|
+
const maxLines = Math.max(coloredLogo.length, rightColumn.length);
|
|
78
|
+
for (let i = 0; i < maxLines; i++) {
|
|
79
|
+
const left = i < coloredLogo.length ? coloredLogo[i] : ' '.repeat(leftWidth);
|
|
80
|
+
const right = i < rightColumn.length ? rightColumn[i] : '';
|
|
81
|
+
// Pad left column
|
|
82
|
+
const paddedLeft = left.replace(/\x1b\[[0-9;]*m/g, '');
|
|
83
|
+
const padding = ' '.repeat(Math.max(0, leftWidth - paddedLeft.length));
|
|
84
|
+
console.log(`${left}${padding} ${right}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log();
|
|
88
|
+
console.log(chalk.hex('#4CAF50')('─'.repeat(width)));
|
|
89
|
+
console.log();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function showMiniHeader(command: string): void {
|
|
93
|
+
console.log(chalk.hex('#4CAF50')(`\n Plazbot`) + chalk.gray(` > ${command}\n`));
|
|
94
|
+
}
|
package/src/utils/logger.ts
CHANGED
|
@@ -1,21 +1,40 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
|
|
1
3
|
export const logger = {
|
|
2
4
|
info: (message: string) => {
|
|
3
|
-
console.log(message);
|
|
5
|
+
console.log(chalk.white(message));
|
|
4
6
|
},
|
|
5
7
|
success: (message: string) => {
|
|
6
|
-
console.log(`\n
|
|
8
|
+
console.log(chalk.hex('#66BB6A')(`\n ✔ ${message}`));
|
|
7
9
|
},
|
|
8
10
|
warning: (message: string) => {
|
|
9
|
-
console.log(`\n
|
|
11
|
+
console.log(chalk.hex('#FFA726')(`\n ⚠ ${message}`));
|
|
10
12
|
},
|
|
11
13
|
error: (error: Error | string) => {
|
|
12
14
|
const message = error instanceof Error ? error.message : error;
|
|
13
|
-
console.error(`\n
|
|
15
|
+
console.error(chalk.hex('#EF5350')(`\n ✖ Error: ${message}`));
|
|
14
16
|
},
|
|
15
17
|
divider: (length: number = 50) => {
|
|
16
|
-
console.log('─'.repeat(length));
|
|
18
|
+
console.log(chalk.gray('─'.repeat(length)));
|
|
17
19
|
},
|
|
18
20
|
doubleDivider: (length: number = 50) => {
|
|
19
|
-
console.log('═'.repeat(length));
|
|
21
|
+
console.log(chalk.gray('═'.repeat(length)));
|
|
22
|
+
},
|
|
23
|
+
label: (key: string, value: string) => {
|
|
24
|
+
console.log(` ${chalk.gray(key + ':')} ${chalk.white(value)}`);
|
|
25
|
+
},
|
|
26
|
+
title: (text: string) => {
|
|
27
|
+
console.log(chalk.bold.hex('#4CAF50')(`\n ${text}`));
|
|
28
|
+
console.log(chalk.gray(' ' + '─'.repeat(40)));
|
|
29
|
+
},
|
|
30
|
+
dim: (message: string) => {
|
|
31
|
+
console.log(chalk.gray(` ${message}`));
|
|
32
|
+
},
|
|
33
|
+
json: (data: any) => {
|
|
34
|
+
const formatted = JSON.stringify(data, null, 2)
|
|
35
|
+
.split('\n')
|
|
36
|
+
.map(line => ' ' + line)
|
|
37
|
+
.join('\n');
|
|
38
|
+
console.log(chalk.gray(formatted));
|
|
20
39
|
}
|
|
21
|
-
};
|
|
40
|
+
};
|