plazbot-cli 0.1.2 → 0.1.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.
Files changed (51) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/CLAUDE.md +92 -0
  3. package/README.md +102 -0
  4. package/dist/cli.js +14 -5
  5. package/dist/commands/agent/ai-config.js +107 -0
  6. package/dist/commands/agent/chat.js +130 -34
  7. package/dist/commands/agent/copy.js +37 -0
  8. package/dist/commands/agent/create.js +80 -17
  9. package/dist/commands/agent/files.js +142 -0
  10. package/dist/commands/agent/index.js +14 -2
  11. package/dist/commands/agent/set.js +127 -0
  12. package/dist/commands/agent/templates.js +240 -0
  13. package/dist/commands/agent/tools.js +161 -0
  14. package/dist/commands/agent/wizard.js +369 -0
  15. package/dist/commands/whatsapp/broadcast.js +97 -0
  16. package/dist/commands/whatsapp/channels.js +86 -0
  17. package/dist/commands/whatsapp/chat.js +74 -0
  18. package/dist/commands/whatsapp/index.js +11 -2
  19. package/dist/commands/whatsapp/send-template.js +51 -14
  20. package/dist/commands/whatsapp/send.js +10 -10
  21. package/dist/commands/whatsapp/widget.js +64 -0
  22. package/dist/utils/banner.js +87 -0
  23. package/dist/utils/logger.js +27 -6
  24. package/dist/utils/ui.js +111 -0
  25. package/package.json +10 -2
  26. package/src/cli.ts +13 -5
  27. package/src/commands/agent/ai-config.ts +112 -0
  28. package/src/commands/agent/chat.ts +149 -40
  29. package/src/commands/agent/copy.ts +40 -0
  30. package/src/commands/agent/create.ts +58 -23
  31. package/src/commands/agent/files.ts +158 -0
  32. package/src/commands/agent/index.ts +14 -2
  33. package/src/commands/agent/set.ts +137 -0
  34. package/src/commands/agent/templates.ts +249 -0
  35. package/src/commands/agent/tools.ts +167 -0
  36. package/src/commands/agent/wizard.ts +475 -0
  37. package/src/commands/whatsapp/broadcast.ts +100 -0
  38. package/src/commands/whatsapp/channels.ts +98 -0
  39. package/src/commands/whatsapp/chat.ts +77 -0
  40. package/src/commands/whatsapp/index.ts +11 -2
  41. package/src/commands/whatsapp/send-template.ts +57 -19
  42. package/src/commands/whatsapp/send.ts +15 -14
  43. package/src/commands/whatsapp/widget.ts +67 -0
  44. package/src/utils/banner.ts +94 -0
  45. package/src/utils/logger.ts +26 -7
  46. package/src/utils/ui.ts +109 -0
  47. package/dist/commands/message/delete-webhook.js +0 -39
  48. package/dist/commands/message/index.js +0 -14
  49. package/dist/commands/message/register-webhook.js +0 -42
  50. package/dist/commands/message/send-template.js +0 -42
  51. 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 relacionados con mensajes de WhatsApp')
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 { TemplateCommandOptions } from '../../types/message';
5
+ import { createSpinner } from '../../utils/ui';
6
6
 
7
7
  export const sendTemplateCommand = new Command('send-template')
8
- .description('Envía una plantilla de WhatsApp')
9
- .requiredOption('-p, --phone <number>', 'Número de teléfono del destinatario (con código de país, ej: 51912345678)')
10
- .requiredOption('-t, --template <name>', 'Nombre de la plantilla a enviar')
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: TemplateCommandOptions) => {
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
- logger.info('\n📱 Enviando plantilla de WhatsApp...');
23
- logger.info(`A: ${options.phone}`);
24
- logger.info(`Plantilla: ${options.template}`);
25
-
26
- const response = await messageClient.onConversation({
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('\nAmbiente: desarrollo');
66
+ logger.warning('Ambiente: desarrollo');
37
67
  }
38
68
 
39
69
  } catch (error: unknown) {
40
- const message = error instanceof Error ? error.message : 'Error desconocido al enviar la plantilla';
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('Envía un mensaje de WhatsApp')
9
- .requiredOption('-t, --to <phone>', 'Número de teléfono del destinatario (con código de país, ej: 51912345678)')
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.info('\n📱 Enviando mensaje de WhatsApp...');
25
- logger.info(`A: ${options.to}`);
26
- logger.info(`Mensaje: ${options.message}`);
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
- logger.success('Mensaje enviado exitosamente');
34
- logger.info('\n📋 Detalles:');
35
- logger.info(JSON.stringify(response, null, 2));
36
-
36
+ spinner.succeed('Mensaje enviado exitosamente');
37
+
37
38
  if (options.dev) {
38
- logger.warning('\nAmbiente: desarrollo');
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
+ }
@@ -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 ${message}`);
8
+ console.log(chalk.hex('#66BB6A')(`\n ${message}`));
7
9
  },
8
10
  warning: (message: string) => {
9
- console.log(`\n⚠️ ${message}`);
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 Error: ${message}`);
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
+ };