plazbot-cli 0.4.1 → 0.5.1

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 (76) hide show
  1. package/README.md +67 -111
  2. package/dist/cli.js +26 -11
  3. package/dist/commands/agent/ai-config.js +264 -63
  4. package/dist/commands/agent/chat.js +16 -11
  5. package/dist/commands/agent/copy.js +49 -13
  6. package/dist/commands/agent/create.js +62 -17
  7. package/dist/commands/agent/delete.js +50 -39
  8. package/dist/commands/agent/enable-widget.js +47 -27
  9. package/dist/commands/agent/export.js +180 -91
  10. package/dist/commands/agent/files.js +155 -73
  11. package/dist/commands/agent/get.js +25 -19
  12. package/dist/commands/agent/index.js +12 -10
  13. package/dist/commands/agent/list.js +20 -11
  14. package/dist/commands/agent/monitor.js +103 -57
  15. package/dist/commands/agent/on-message.js +55 -32
  16. package/dist/commands/agent/set.js +230 -82
  17. package/dist/commands/agent/templates.js +259 -156
  18. package/dist/commands/agent/tools.js +356 -123
  19. package/dist/commands/agent/update.js +69 -28
  20. package/dist/commands/agent/validate.js +72 -40
  21. package/dist/commands/agent/wizard.js +240 -329
  22. package/dist/commands/auth/browser-login.js +37 -31
  23. package/dist/commands/auth/login.js +49 -45
  24. package/dist/commands/auth/logout.js +20 -11
  25. package/dist/commands/auth/status.js +36 -12
  26. package/dist/commands/auth/workspace.js +61 -27
  27. package/dist/commands/portal/add-agent.js +106 -45
  28. package/dist/commands/portal/add-link.js +25 -28
  29. package/dist/commands/portal/clear-links.js +39 -19
  30. package/dist/commands/portal/create.js +66 -37
  31. package/dist/commands/portal/delete.js +40 -45
  32. package/dist/commands/portal/get.js +21 -54
  33. package/dist/commands/portal/index.js +12 -12
  34. package/dist/commands/portal/list.js +34 -52
  35. package/dist/commands/portal/shared.js +92 -0
  36. package/dist/commands/portal/update.js +100 -70
  37. package/dist/commands/whatsapp/broadcast.js +169 -77
  38. package/dist/commands/whatsapp/channels.js +167 -65
  39. package/dist/commands/whatsapp/chat.js +45 -46
  40. package/dist/commands/whatsapp/connect-flow.js +16 -15
  41. package/dist/commands/whatsapp/connect.js +36 -21
  42. package/dist/commands/whatsapp/delete-webhook.js +42 -25
  43. package/dist/commands/whatsapp/index.js +15 -16
  44. package/dist/commands/whatsapp/register-webhook.js +43 -26
  45. package/dist/commands/whatsapp/send-template.js +62 -61
  46. package/dist/commands/whatsapp/send.js +46 -33
  47. package/dist/commands/whatsapp/setup.js +62 -52
  48. package/dist/commands/whatsapp/shared.js +75 -0
  49. package/dist/commands/whatsapp/widget.js +82 -45
  50. package/dist/commands/workers/deploy.js +80 -58
  51. package/dist/commands/workers/index.js +8 -8
  52. package/dist/commands/workers/list.js +42 -20
  53. package/dist/commands/workers/logs.js +139 -36
  54. package/dist/commands/workers/remove.js +45 -47
  55. package/dist/commands/workers/secret.js +159 -83
  56. package/dist/commands/workers/test.js +108 -60
  57. package/dist/schemas/agent.config.schema.json +159 -8
  58. package/dist/studio/api/sseClient.js +1 -1
  59. package/dist/studio/api/studioApi.js +8 -0
  60. package/dist/studio/components/App.js +12 -0
  61. package/dist/studio/components/Footer.js +1 -1
  62. package/dist/studio/index.js +74 -14
  63. package/dist/studio/runOneShot.js +62 -23
  64. package/dist/studio/runRepl.js +5 -5
  65. package/dist/studio/slash/handlers.js +11 -8
  66. package/dist/studio/state/store.js +1 -1
  67. package/dist/utils/agent-errors.js +14 -11
  68. package/dist/utils/agent-patch.js +60 -0
  69. package/dist/utils/banner.js +9 -5
  70. package/dist/utils/confirm.js +31 -0
  71. package/dist/utils/credentials.js +13 -3
  72. package/dist/utils/logger.js +13 -10
  73. package/dist/utils/output.js +78 -0
  74. package/dist/utils/phone.js +22 -0
  75. package/dist/utils/ui.js +14 -11
  76. package/package.json +3 -3
@@ -2,16 +2,22 @@ import { Command } from 'commander';
2
2
  import { Agent } from 'plazbot';
3
3
  import { getStoredCredentials } from '../../utils/credentials.js';
4
4
  import { logger } from '../../utils/logger.js';
5
- import { addExamples } from '../../utils/help.js';
5
+ import { addExamples, addNotes } from '../../utils/help.js';
6
6
  import { createSpinner } from '../../utils/ui.js';
7
+ import { jsonOption, isJsonMode, printJson, fail, CliError } from '../../utils/output.js';
8
+ import { requireInteractive } from '../../utils/confirm.js';
7
9
  import { runAgentWizard } from './wizard.js';
8
10
  import fs from 'fs/promises';
9
11
  export const createCommand = new Command('create')
10
12
  .description('Create a new AI agent (interactive wizard or JSON file)')
11
- .argument('[configPath]', 'Path to the JSON config file (optional)')
13
+ .argument('[configPath]', 'Path to a JSON config file; omit it to launch the interactive wizard')
14
+ .addOption(jsonOption('Print the created agent as JSON ({"id","name"})'))
12
15
  .option('--dev', 'Use development environment', false)
13
16
  .action(async (configPath, options) => {
14
17
  try {
18
+ if (!configPath) {
19
+ requireInteractive('The agent wizard', 'Pass a JSON file instead: plazbot agent create ./agent.json');
20
+ }
15
21
  const credentials = await getStoredCredentials();
16
22
  const agent = new Agent({
17
23
  workspaceId: credentials.workspace,
@@ -22,16 +28,28 @@ export const createCommand = new Command('create')
22
28
  let agentConfig;
23
29
  if (configPath) {
24
30
  // Modo archivo: leer JSON
31
+ let fileContent;
32
+ try {
33
+ fileContent = await fs.readFile(configPath, 'utf-8');
34
+ }
35
+ catch (error) {
36
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
37
+ throw new CliError(`Could not read the config file: ${errorMessage}`, 'file_not_readable');
38
+ }
25
39
  try {
26
- const fileContent = await fs.readFile(configPath, 'utf-8');
27
40
  agentConfig = JSON.parse(fileContent);
28
41
  }
29
42
  catch (error) {
30
43
  const errorMessage = error instanceof Error ? error.message : 'Unknown error';
31
- throw new Error(`Failed to read config file: ${errorMessage}`);
44
+ throw new CliError(`The config file is not valid JSON: ${errorMessage}`, 'invalid_json', `Check it with: plazbot agent validate ${configPath}`);
45
+ }
46
+ if (!agentConfig || typeof agentConfig !== 'object' || Array.isArray(agentConfig)) {
47
+ throw new CliError('The config file must contain a JSON object.', 'invalid_config');
48
+ }
49
+ if (!isJsonMode()) {
50
+ logger.title('Creating agent from file');
51
+ logger.json(agentConfig);
32
52
  }
33
- logger.title('Creating agent from file');
34
- logger.json(agentConfig);
35
53
  }
36
54
  else {
37
55
  // Modo wizard interactivo
@@ -44,17 +62,39 @@ export const createCommand = new Command('create')
44
62
  default: true,
45
63
  }]);
46
64
  if (!confirm) {
47
- logger.warning('Creation cancelled');
48
- return;
65
+ logger.dim('Aborted.');
66
+ process.exit(1);
49
67
  }
50
68
  }
51
69
  const spinner = createSpinner('Creating agent...');
52
70
  spinner.start();
53
- const result = await agent.addAgent(agentConfig);
71
+ let result;
72
+ try {
73
+ result = await agent.addAgent(agentConfig);
74
+ }
75
+ catch (err) {
76
+ spinner.fail('Could not create the agent');
77
+ throw err;
78
+ }
79
+ if (result?.success === false) {
80
+ spinner.fail('Could not create the agent');
81
+ const errors = (Array.isArray(result?.errors) ? result.errors : [])
82
+ .map((err) => (typeof err === 'string' ? err : JSON.stringify(err)));
83
+ const base = result.message || 'The API rejected the agent configuration.';
84
+ const message = errors.length
85
+ ? `${base.replace(/\.?$/, ':')}\n${errors.map((e, i) => ` ${i + 1}. ${e}`).join('\n')}`
86
+ : base;
87
+ throw new CliError(message, 'create_failed', `Check the file with: plazbot agent validate ${configPath || '<file.json>'}`);
88
+ }
54
89
  spinner.succeed('Agent created successfully');
90
+ const newId = result?.agentId || result?.id;
91
+ if (isJsonMode()) {
92
+ printJson({ id: newId ?? null, name: agentConfig.name ?? null });
93
+ process.exit(0);
94
+ }
55
95
  logger.title('Agent details');
56
- if (result.agentId) {
57
- logger.label('ID', result.agentId);
96
+ if (newId) {
97
+ logger.label('ID', newId);
58
98
  }
59
99
  if (agentConfig.name) {
60
100
  logger.label('Name', agentConfig.name);
@@ -66,17 +106,18 @@ export const createCommand = new Command('create')
66
106
  });
67
107
  }
68
108
  console.log();
69
- logger.dim('Next step: plazbot agent chat -a ' + (result.agentId || '<agentId>'));
109
+ logger.dim('Next steps:');
110
+ logger.dim(` plazbot agent chat ${newId || '<agentId>'} # test it in the terminal`);
111
+ logger.dim(` plazbot agent get ${newId || '<agentId>'} # review the configuration`);
70
112
  console.log();
71
113
  if (options.dev) {
72
114
  logger.warning('Environment: development');
73
115
  }
116
+ // El wizard deja handles abiertos (inquirer); salir explicitamente
74
117
  process.exit(0);
75
118
  }
76
119
  catch (error) {
77
- const message = error instanceof Error ? error.message : 'Unknown error while creating the agent';
78
- logger.error(message);
79
- process.exit(1);
120
+ fail(error);
80
121
  }
81
122
  });
82
123
  addExamples(createCommand, [
@@ -84,6 +125,10 @@ addExamples(createCommand, [
84
125
  command: 'plazbot agent create' },
85
126
  { description: 'Create directly from a JSON configuration file',
86
127
  command: 'plazbot agent create ./agent.json' },
87
- { description: 'Create against a local backend (dev mode)',
88
- command: 'plazbot agent create ./agent.json --dev' },
128
+ { description: 'Create from a file and capture the new ID (scripts)',
129
+ command: "plazbot agent create ./agent.json --json | jq -r '.id'" },
130
+ ]);
131
+ addNotes(createCommand, [
132
+ 'The wizard needs an interactive terminal. In CI or scripts, pass a JSON file.',
133
+ 'Validate a file before creating it: plazbot agent validate ./agent.json',
89
134
  ]);
@@ -2,15 +2,18 @@ import { Command } from 'commander';
2
2
  import { Agent } from 'plazbot';
3
3
  import { getStoredCredentials } from '../../utils/credentials.js';
4
4
  import { logger } from '../../utils/logger.js';
5
- import { addExamples } from '../../utils/help.js';
6
- import readline from 'readline';
5
+ import { addExamples, addNotes } from '../../utils/help.js';
6
+ import { createSpinner } from '../../utils/ui.js';
7
+ import { jsonOption, isJsonMode, printJson, fail } from '../../utils/output.js';
8
+ import { addYesOption, confirmAction } from '../../utils/confirm.js';
7
9
  export const deleteCommand = new Command('delete')
8
10
  .description('Delete an existing agent')
9
11
  .argument('<agentId>', 'Agent ID to delete')
10
- .option('--dev', 'Use development environment', false)
11
- .action(async (agentId, options) => {
12
+ .addOption(jsonOption('Print the result as JSON ({"id","deleted"})'))
13
+ .option('--dev', 'Use development environment', false);
14
+ addYesOption(deleteCommand);
15
+ deleteCommand.action(async (agentId, options) => {
12
16
  try {
13
- // Obtener credenciales guardadas
14
17
  const credentials = await getStoredCredentials();
15
18
  const agent = new Agent({
16
19
  workspaceId: credentials.workspace,
@@ -18,44 +21,52 @@ export const deleteCommand = new Command('delete')
18
21
  zone: credentials.zone,
19
22
  ...(options.dev && { customUrl: "http://localhost:5090" })
20
23
  });
21
- // Obtener detalles del agente para mostrar información
24
+ // Cargar el agente: valida que exista y permite mostrar su nombre en la confirmacion
22
25
  const response = await agent.getAgentById({ id: agentId });
23
- const agentDetails = response.agent || response.data || response;
24
- logger.warning('\nYou are about to delete the following agent:');
25
- logger.divider();
26
- logger.info(`ID: ${agentDetails.id || agentId}`);
27
- logger.info(`Name: ${agentDetails.name || '—'}`);
28
- logger.info(`Description: ${agentDetails.description || '—'}`);
29
- logger.divider();
30
- // Crear interfaz para confirmación
31
- const rl = readline.createInterface({
32
- input: process.stdin,
33
- output: process.stdout
34
- });
35
- // Preguntar por confirmación
36
- rl.question('\nAre you sure you want to delete this agent? (y/N): ', async (answer) => {
37
- if (answer.toLowerCase() === 'y') {
38
- await agent.deleteAgent({
39
- id: agentId
40
- });
41
- logger.success('Agent deleted successfully');
42
- if (options.dev) {
43
- logger.warning('Environment: development');
44
- }
45
- }
46
- else {
47
- logger.error('Operation cancelled');
48
- }
49
- rl.close();
50
- });
26
+ const agentDetails = response?.agent || response?.data || response || {};
27
+ const name = agentDetails.name;
28
+ if (!isJsonMode() && !options.yes && !options.confirm && !options.force) {
29
+ logger.warning('You are about to delete the following agent:');
30
+ logger.label('ID', agentDetails.id || agentId);
31
+ logger.label('Name', name || '—');
32
+ logger.label('Description', agentDetails.description || '—');
33
+ console.log();
34
+ }
35
+ const ok = await confirmAction(name ? `Delete agent "${name}" (${agentId})? This cannot be undone.` : `Delete agent ${agentId}? This cannot be undone.`, options);
36
+ if (!ok) {
37
+ logger.dim('Aborted.');
38
+ process.exit(1);
39
+ }
40
+ const spinner = createSpinner('Deleting agent...');
41
+ spinner.start();
42
+ try {
43
+ await agent.deleteAgent({ id: agentId });
44
+ }
45
+ catch (err) {
46
+ spinner.fail('Could not delete the agent');
47
+ throw err;
48
+ }
49
+ spinner.succeed(name ? `Agent "${name}" deleted` : 'Agent deleted');
50
+ if (isJsonMode()) {
51
+ printJson({ id: agentId, ...(name && { name }), deleted: true });
52
+ return;
53
+ }
54
+ if (options.dev) {
55
+ logger.warning('Environment: development');
56
+ }
51
57
  }
52
58
  catch (error) {
53
- const message = error instanceof Error ? error.message : 'Unknown error while deleting the agent';
54
- logger.error(message);
55
- process.exit(1);
59
+ fail(error);
56
60
  }
57
61
  });
58
62
  addExamples(deleteCommand, [
59
- { description: 'Delete an agent (asks for y/N confirmation)',
60
- command: 'plazbot agent delete agt_AbcDef123' },
63
+ { description: 'Delete an agent (asks for confirmation)',
64
+ command: 'plazbot agent delete age_AbcDef123' },
65
+ { description: 'Delete without prompting (scripts and CI)',
66
+ command: 'plazbot agent delete age_AbcDef123 --yes' },
67
+ { description: 'Delete and get a JSON result',
68
+ command: 'plazbot agent delete age_AbcDef123 --yes --json' },
69
+ ]);
70
+ addNotes(deleteCommand, [
71
+ 'Deleting an agent cannot be undone. Export it first if you may need it again: plazbot agent export <agentId> -o agent.json',
61
72
  ]);
@@ -2,15 +2,17 @@ import { Command } from 'commander';
2
2
  import { Agent } from 'plazbot';
3
3
  import { getStoredCredentials } from '../../utils/credentials.js';
4
4
  import { logger } from '../../utils/logger.js';
5
- import { addExamples } from '../../utils/help.js';
5
+ import { addExamples, addNotes } from '../../utils/help.js';
6
+ import { createSpinner } from '../../utils/ui.js';
7
+ import { jsonOption, isJsonMode, printJson, fail, CliError } from '../../utils/output.js';
6
8
  export const enableCommand = new Command('enable-widget')
7
- .description('Enable or disable an agent widget')
9
+ .description('Enable or disable the web chat widget of an agent')
8
10
  .argument('<agentId>', 'Agent ID')
9
11
  .option('-d, --disable', 'Disable the widget instead of enabling it')
12
+ .addOption(jsonOption('Print the result as JSON ({"id","widgetEnabled","script"})'))
10
13
  .option('--dev', 'Use development environment', false)
11
14
  .action(async (agentId, options) => {
12
15
  try {
13
- // Obtener credenciales guardadas
14
16
  const credentials = await getStoredCredentials();
15
17
  const agent = new Agent({
16
18
  workspaceId: credentials.workspace,
@@ -18,39 +20,57 @@ export const enableCommand = new Command('enable-widget')
18
20
  zone: credentials.zone,
19
21
  ...(options.dev && { customUrl: "http://localhost:5090" })
20
22
  });
21
- // Obtener estado actual del agente
22
- const _res = await agent.getAgentById({ id: agentId });
23
- const agentDetails = _res.agent || _res.data || _res;
24
- logger.title('Current widget status');
25
- logger.label('Agent', agentDetails.name);
26
- // Cambiar estado
27
- const newState = !options.disable; // Si --disable está presente, newState será false
28
- const result = await agent.enableWidget({
29
- id: agentId,
30
- enable: newState
31
- });
32
- logger.success(`Widget ${newState ? 'enabled' : 'disabled'} successfully`);
33
- logger.title('Server response');
34
- logger.label('Status', result.success ? 'Success' : 'Failed');
35
- logger.label('Message', result.message);
36
- if (newState && result.script) {
37
- logger.title('Installation instructions');
38
- logger.dim('Place this script under the <HEAD> tag of your website:');
39
- logger.info('\n' + result.script);
23
+ const newState = !options.disable;
24
+ const spinner = createSpinner(`${newState ? 'Enabling' : 'Disabling'} widget...`);
25
+ spinner.start();
26
+ let agentDetails;
27
+ let result;
28
+ try {
29
+ // Valida que el agente exista antes de cambiar el widget
30
+ const res = await agent.getAgentById({ id: agentId });
31
+ agentDetails = res?.agent || res?.data || res || {};
32
+ result = await agent.enableWidget({ id: agentId, enable: newState });
33
+ }
34
+ catch (err) {
35
+ spinner.fail(`Could not ${newState ? 'enable' : 'disable'} the widget`);
36
+ throw err;
37
+ }
38
+ if (result?.success === false) {
39
+ spinner.fail(`Could not ${newState ? 'enable' : 'disable'} the widget`);
40
+ throw new CliError(result.message || 'The API rejected the request.', 'widget_failed');
41
+ }
42
+ spinner.succeed(`Widget ${newState ? 'enabled' : 'disabled'}${agentDetails?.name ? ` for "${agentDetails.name}"` : ''}`);
43
+ if (isJsonMode()) {
44
+ printJson({
45
+ id: agentId,
46
+ widgetEnabled: newState,
47
+ ...(newState && result?.script && { script: result.script }),
48
+ });
49
+ return;
50
+ }
51
+ if (result?.message)
52
+ logger.dim(result.message);
53
+ if (newState && result?.script) {
54
+ logger.title('Installation');
55
+ logger.dim('Paste this script inside the <head> tag of your website:');
56
+ logger.info('\n' + result.script + '\n');
40
57
  }
41
58
  if (options.dev) {
42
59
  logger.warning('Environment: development');
43
60
  }
44
61
  }
45
62
  catch (error) {
46
- const message = error instanceof Error ? error.message : 'Unknown error while updating the widget';
47
- logger.error(message);
48
- process.exit(1);
63
+ fail(error);
49
64
  }
50
65
  });
51
66
  addExamples(enableCommand, [
52
67
  { description: 'Enable the widget and print the <script> snippet',
53
- command: 'plazbot agent enable-widget agt_AbcDef123' },
68
+ command: 'plazbot agent enable-widget age_AbcDef123' },
54
69
  { description: 'Disable an existing widget',
55
- command: 'plazbot agent enable-widget agt_AbcDef123 --disable' },
70
+ command: 'plazbot agent enable-widget age_AbcDef123 --disable' },
71
+ { description: 'Save the install snippet to a file',
72
+ command: "plazbot agent enable-widget age_AbcDef123 --json | jq -r '.script' > widget.html" },
73
+ ]);
74
+ addNotes(enableCommand, [
75
+ 'Copied agents (copy, cross-copy) start with the widget disabled.',
56
76
  ]);