plazbot-cli 0.4.0 → 0.5.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.
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 +179 -88
  10. package/dist/commands/agent/files.js +155 -73
  11. package/dist/commands/agent/get.js +24 -16
  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 +101 -53
  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 +183 -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 +77 -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 +2 -2
@@ -1,30 +1,30 @@
1
1
  import { Command } from 'commander';
2
- import { addExamples } from '../../utils/help.js';
2
+ import { addExamples, addNotes } from '../../utils/help.js';
3
3
  import { getCommand } from './get.js';
4
4
  import { deleteCommand } from './delete.js';
5
5
  import { createCommand } from './create.js';
6
6
  import { updateCommand } from './update.js';
7
- import { addAgentCommand } from './add-agent.js';
7
+ import { addAgentCommand, removeAgentCommand } from './add-agent.js';
8
8
  import { listCommand } from './list.js';
9
9
  import { addLinkCommand } from './add-link.js';
10
10
  import { clearLinksCommand } from './clear-links.js';
11
11
  export const portalCommands = new Command('portal')
12
- .description('Commands related to portals')
12
+ .description('Manage the public web portal where customers chat with your agents')
13
13
  .addCommand(listCommand)
14
14
  .addCommand(getCommand)
15
- .addCommand(deleteCommand)
16
15
  .addCommand(createCommand)
17
16
  .addCommand(updateCommand)
17
+ .addCommand(deleteCommand)
18
18
  .addCommand(addAgentCommand)
19
+ .addCommand(removeAgentCommand)
19
20
  .addCommand(addLinkCommand)
20
21
  .addCommand(clearLinksCommand);
21
22
  addExamples(portalCommands, [
22
- { description: 'List the portal of the active workspace',
23
- command: 'plazbot portal list' },
24
- { description: 'Create a portal',
25
- command: 'plazbot portal create -n "Help Center" -t "Welcome"' },
26
- { description: 'Attach an agent to a portal',
27
- command: 'plazbot portal add-agent-portal -p prt_AbcDef123 -a agt_AbcDef123' },
28
- { description: 'Add a link to a portal',
29
- command: 'plazbot portal add-link prt_AbcDef123 -t "Docs" -u https://docs.example.com' },
23
+ { description: 'Show the portal of the active workspace', command: 'plazbot portal list' },
24
+ { description: 'Create a portal', command: 'plazbot portal create -n "Help Center" -t "Welcome"' },
25
+ { description: 'Attach an agent to the portal', command: 'plazbot portal add-agent por_AbcDef123 -a age_AbcDef123' },
26
+ { description: 'Add a link to the portal', command: 'plazbot portal add-link por_AbcDef123 -t "Docs" -u https://docs.example.com' },
27
+ ]);
28
+ addNotes(portalCommands, [
29
+ 'Each workspace has at most one portal.',
30
30
  ]);
@@ -1,68 +1,50 @@
1
1
  import { Command } from 'commander';
2
- import { Portal } from 'plazbot';
3
- import { getStoredCredentials } from '../../utils/credentials.js';
4
- import { logger } from '../../utils/logger.js';
5
- import { addExamples } from '../../utils/help.js';
2
+ import { addExamples, addNotes } from '../../utils/help.js';
3
+ import { jsonOption, isJsonMode, printJson, fail, CliError } from '../../utils/output.js';
4
+ import { createSpinner } from '../../utils/ui.js';
5
+ import { createPortalClient, printPortalDetails } from './shared.js';
6
6
  export const listCommand = new Command('list')
7
- .description('Show the portal associated with the workspace')
7
+ .description('Show the portal of the active workspace (one portal per workspace)')
8
+ .addOption(jsonOption())
8
9
  .option('--dev', 'Use development environment', false)
9
10
  .action(async (options) => {
10
11
  try {
11
- // Obtener credenciales guardadas
12
- const credentials = await getStoredCredentials();
13
- const portal = new Portal({
14
- workspaceId: credentials.workspace,
15
- apiKey: credentials.apiKey,
16
- zone: credentials.zone,
17
- ...(options.dev && { customUrl: "http://localhost:5090" })
18
- });
19
- const response = await portal.getExistsPortal();
20
- const portalDetails = response.portal;
21
- logger.title('Portal found');
22
- logger.label('ID', portalDetails.id);
23
- logger.label('Name', portalDetails.name);
24
- logger.label('URL', portalDetails.url);
25
- logger.label('Access', portalDetails.access || 'N/A');
26
- logger.label('Status', portalDetails.disabled ? 'Disabled' : 'Enabled');
27
- if (portalDetails.title) {
28
- logger.label('Title', portalDetails.title);
12
+ const { portal } = await createPortalClient(options.dev);
13
+ const spinner = createSpinner('Loading portal...').start();
14
+ let details;
15
+ try {
16
+ const response = await portal.getExistsPortal();
17
+ details = response?.portal || undefined;
29
18
  }
30
- if (portalDetails.subtitle) {
31
- logger.label('Subtitle', portalDetails.subtitle);
32
- }
33
- if (portalDetails.logo) {
34
- logger.title('Assets');
35
- logger.label('Logo', portalDetails.logo);
36
- if (portalDetails.logodark) {
37
- logger.label('Logo (dark mode)', portalDetails.logodark);
19
+ catch (error) {
20
+ const message = error instanceof Error ? error.message : '';
21
+ if (!/not found/i.test(message)) {
22
+ spinner.stop();
23
+ throw error;
38
24
  }
39
25
  }
40
- const portalAny = portalDetails;
41
- if (portalAny.links && portalAny.links.length > 0) {
42
- logger.title('Links');
43
- portalAny.links.forEach((link) => {
44
- logger.label(link.value, link.url);
45
- });
46
- }
47
- if (portalAny.agents && portalAny.agents.length > 0) {
48
- logger.title('Associated agents');
49
- portalAny.agents.forEach((agent) => {
50
- logger.label(agent.name, agent.id);
51
- });
26
+ spinner.stop();
27
+ if (!details) {
28
+ if (isJsonMode())
29
+ printJson(null);
30
+ throw new CliError('This workspace has no portal yet.', 'portal_not_found', 'Create one with: plazbot portal create -n "Help Center" -t "Welcome"');
52
31
  }
53
- if (options.dev) {
54
- logger.warning('\nEnvironment: development');
32
+ if (isJsonMode()) {
33
+ printJson(details);
34
+ return;
55
35
  }
36
+ printPortalDetails(details, 'Workspace portal');
37
+ console.log();
56
38
  }
57
39
  catch (error) {
58
- const message = error instanceof Error ? error.message : 'Unknown error while listing the portal';
59
- logger.error(message);
60
- process.exit(1);
40
+ fail(error);
61
41
  }
62
42
  });
63
43
  addExamples(listCommand, [
64
- { description: 'Show the portal of the active workspace',
65
- command: 'plazbot portal list' },
66
- { description: 'Use the development backend',
67
- command: 'plazbot portal list --dev' },
44
+ { description: 'Show the portal of the active workspace', command: 'plazbot portal list' },
45
+ { description: 'Get the portal as JSON (null when there is none)', command: 'plazbot portal list --json' },
46
+ { description: 'Extract only the portal ID', command: "plazbot portal list --json | jq -r '.id'" },
47
+ ]);
48
+ addNotes(listCommand, [
49
+ 'A workspace can have a single portal. Exits with code 1 when there is none.',
68
50
  ]);
@@ -0,0 +1,92 @@
1
+ // Helpers shared by the `plazbot portal` subcommands.
2
+ import { Portal } from 'plazbot';
3
+ import { getStoredCredentials } from '../../utils/credentials.js';
4
+ import { logger } from '../../utils/logger.js';
5
+ import { CliError } from '../../utils/output.js';
6
+ /** Builds an SDK Portal client from the active session. */
7
+ export async function createPortalClient(dev) {
8
+ const credentials = await getStoredCredentials();
9
+ const portal = new Portal({
10
+ workspaceId: credentials.workspace,
11
+ apiKey: credentials.apiKey,
12
+ zone: credentials.zone,
13
+ ...(dev && { customUrl: 'http://localhost:5090' }),
14
+ });
15
+ return { portal, credentials };
16
+ }
17
+ /** Resolves the portal ID from the positional argument or a legacy option. */
18
+ export function resolvePortalId(positional, legacy) {
19
+ const id = (positional || legacy || '').trim();
20
+ if (!id) {
21
+ throw new CliError('Portal ID is required.', 'missing_portal_id', "Pass it as the first argument. Find it with 'plazbot portal list'.");
22
+ }
23
+ return id;
24
+ }
25
+ /** The SDK only accepts PNG/JPG logos given as an absolute URL or a path starting with "/". */
26
+ export function validateLogo(value, flag) {
27
+ const url = value.trim();
28
+ if (!/^(https?:\/\/|\/)/i.test(url) || !/\.(png|jpg)$/i.test(url)) {
29
+ throw new CliError(`Invalid logo for ${flag}: "${value}".`, 'invalid_logo', 'Use a .png or .jpg URL (https://...) or a path starting with "/".');
30
+ }
31
+ return url;
32
+ }
33
+ export function validateAccess(value) {
34
+ const access = value.trim().toLowerCase();
35
+ if (access !== 'direct' && access !== 'form') {
36
+ throw new CliError(`Invalid access type "${value}".`, 'invalid_access', 'Use "direct" or "form".');
37
+ }
38
+ return access;
39
+ }
40
+ export function validateHttpUrl(value, flag) {
41
+ const url = value.trim();
42
+ let parsed;
43
+ try {
44
+ parsed = new URL(url);
45
+ }
46
+ catch {
47
+ throw new CliError(`Invalid URL for ${flag}: "${value}".`, 'invalid_url', 'Use a full URL starting with http:// or https://.');
48
+ }
49
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
50
+ throw new CliError(`Invalid URL for ${flag}: "${value}".`, 'invalid_url', 'Only http:// and https:// URLs are allowed.');
51
+ }
52
+ return url;
53
+ }
54
+ /** Parses a `true|false` flag value (also accepts yes/no, on/off, 1/0). */
55
+ export function parseBoolFlag(value, flag) {
56
+ const v = value.trim().toLowerCase();
57
+ if (['true', 'yes', 'on', '1'].includes(v))
58
+ return true;
59
+ if (['false', 'no', 'off', '0'].includes(v))
60
+ return false;
61
+ throw new CliError(`Invalid value for ${flag}: "${value}".`, 'invalid_boolean', `Use ${flag} true or ${flag} false.`);
62
+ }
63
+ /** Pretty-prints a portal (human mode). */
64
+ export function printPortalDetails(details, title = 'Portal') {
65
+ logger.title(title);
66
+ logger.label('ID', details.id);
67
+ logger.label('Name', details.name);
68
+ logger.label('URL', details.url);
69
+ logger.label('Access', details.access || 'direct');
70
+ logger.label('Status', details.disabled ? 'Disabled' : 'Enabled');
71
+ if (details.title)
72
+ logger.label('Title', details.title);
73
+ if (details.subtitle)
74
+ logger.label('Subtitle', details.subtitle);
75
+ if (typeof details.brandOff === 'boolean')
76
+ logger.label('Plazbot brand', details.brandOff ? 'Hidden' : 'Visible');
77
+ if (details.logo || details.logodark) {
78
+ logger.title('Assets');
79
+ if (details.logo)
80
+ logger.label('Logo', details.logo);
81
+ if (details.logodark)
82
+ logger.label('Logo (dark mode)', details.logodark);
83
+ }
84
+ if (details.links && details.links.length > 0) {
85
+ logger.title('Links');
86
+ details.links.forEach((link) => logger.label(link.value, link.url));
87
+ }
88
+ if (details.agents && details.agents.length > 0) {
89
+ logger.title('Agents');
90
+ details.agents.forEach((agent) => logger.label(agent.name, agent.id));
91
+ }
92
+ }
@@ -1,86 +1,116 @@
1
- import { Command } from 'commander';
2
- import { Portal } from 'plazbot';
3
- import { getStoredCredentials } from '../../utils/credentials.js';
1
+ import { Command, Option } from 'commander';
2
+ import { addExamples, addNotes } from '../../utils/help.js';
3
+ import { jsonOption, isJsonMode, printJson, fail, CliError } from '../../utils/output.js';
4
+ import { createSpinner } from '../../utils/ui.js';
4
5
  import { logger } from '../../utils/logger.js';
5
- import { addExamples } from '../../utils/help.js';
6
+ import { createPortalClient, parseBoolFlag, resolvePortalId, validateAccess, validateLogo } from './shared.js';
6
7
  export const updateCommand = new Command('update')
7
- .description('Update an existing portal')
8
- .argument('<portalId>', 'ID of the portal to update')
8
+ .description('Update a portal (only the fields you pass are changed)')
9
+ .argument('<portalId>', 'Portal ID (see plazbot portal list)')
9
10
  .option('-n, --name <name>', 'New portal name')
10
- .option('-t, --title <title>', 'New portal title')
11
- .option('-s, --subtitle <subtitle>', 'New portal subtitle')
12
- .option('-l, --logo <url>', 'New logo URL')
13
- .option('-d, --logo-dark <url>', 'New dark-mode logo URL')
14
- .option('-a, --access <type>', 'Access type (direct or form)')
15
- .option('--disabled <value>', 'Disabled state (true or false)')
16
- .option('--brand-off <value>', 'Brand-off state (true or false)')
11
+ .option('-t, --title <title>', 'New welcome title')
12
+ .option('-s, --subtitle <subtitle>', 'New subtitle')
13
+ .option('-l, --logo <url>', 'New logo URL (.png or .jpg)')
14
+ .option('-d, --logo-dark <url>', 'New dark-mode logo URL (.png or .jpg)')
15
+ .option('-a, --access <type>', 'Access type: direct or form')
16
+ .option('--disabled <true|false>', 'Disable (true) or enable (false) the portal')
17
+ .option('--brand-off <true|false>', 'Hide (true) or show (false) the Plazbot brand')
18
+ .addOption(new Option('--enable', 'Shortcut for --disabled false').conflicts(['disabled', 'disable']))
19
+ .addOption(new Option('--disable', 'Shortcut for --disabled true').conflicts(['disabled', 'enable']))
20
+ .addOption(jsonOption())
17
21
  .option('--dev', 'Use development environment', false)
18
- .action(async (portalId, options) => {
22
+ .action(async (portalIdArg, options) => {
19
23
  try {
20
- // Obtener credenciales guardadas
21
- const credentials = await getStoredCredentials();
22
- const portal = new Portal({
23
- workspaceId: credentials.workspace,
24
- apiKey: credentials.apiKey,
25
- zone: credentials.zone,
26
- ...(options.dev && { customUrl: "http://localhost:5090" })
27
- });
28
- // Obtener detalles actuales del portal
29
- const currentPortal = await portal.getPortal(portalId);
30
- logger.title('Current portal');
31
- logger.json(currentPortal.portal);
32
- // Construir objeto de actualización solo con los campos proporcionados
33
- const updateData = { id: portalId };
34
- if (options.name)
35
- updateData.name = options.name;
36
- if (options.title)
37
- updateData.title = options.title;
38
- if (options.subtitle)
39
- updateData.subtitle = options.subtitle;
40
- if (options.logo)
41
- updateData.logo = options.logo;
42
- if (options.logoDark)
43
- updateData.logodark = options.logoDark;
44
- if (options.access) {
45
- if (options.access !== 'direct' && options.access !== 'form') {
46
- throw new Error('Access type must be "direct" or "form"');
47
- }
48
- updateData.access = options.access;
24
+ const portalId = resolvePortalId(portalIdArg);
25
+ // Validate everything before calling the API.
26
+ const changes = {};
27
+ if (options.name !== undefined) {
28
+ if (!options.name.trim())
29
+ throw new CliError('Portal name cannot be empty.', 'invalid_name');
30
+ changes.name = options.name.trim();
49
31
  }
50
- if (options.disabled) {
51
- if (options.disabled !== 'true' && options.disabled !== 'false') {
52
- throw new Error('The disabled value must be "true" or "false"');
53
- }
54
- updateData.disabled = options.disabled === 'true';
32
+ if (options.title !== undefined) {
33
+ if (!options.title.trim())
34
+ throw new CliError('Portal title cannot be empty.', 'invalid_title');
35
+ changes.title = options.title.trim();
55
36
  }
56
- if (options.brandOff) {
57
- if (options.brandOff !== 'true' && options.brandOff !== 'false') {
58
- throw new Error('The brand-off value must be "true" or "false"');
37
+ if (options.subtitle !== undefined) {
38
+ if (!options.subtitle.trim()) {
39
+ throw new CliError('Subtitle cannot be empty.', 'invalid_subtitle', 'The API ignores empty values, so a subtitle cannot be cleared from the CLI.');
59
40
  }
60
- updateData.brandOff = options.brandOff === 'true';
41
+ changes.subtitle = options.subtitle.trim();
61
42
  }
62
- logger.title('Changes to apply');
63
- logger.json(updateData);
64
- const result = await portal.updatePortal(updateData);
65
- logger.success('Portal updated successfully');
66
- logger.label('Message', result.message);
67
- if (options.dev) {
68
- logger.warning('\nEnvironment: development');
43
+ if (options.logo !== undefined)
44
+ changes.logo = validateLogo(options.logo, '--logo');
45
+ if (options.logoDark !== undefined)
46
+ changes.logodark = validateLogo(options.logoDark, '--logo-dark');
47
+ if (options.access !== undefined)
48
+ changes.access = validateAccess(options.access);
49
+ if (options.disabled !== undefined)
50
+ changes.disabled = parseBoolFlag(options.disabled, '--disabled');
51
+ if (options.enable)
52
+ changes.disabled = false;
53
+ if (options.disable)
54
+ changes.disabled = true;
55
+ if (options.brandOff !== undefined)
56
+ changes.brandOff = parseBoolFlag(options.brandOff, '--brand-off');
57
+ if (Object.keys(changes).length === 0) {
58
+ throw new CliError('Nothing to update.', 'nothing_to_update', 'Pass at least one option, e.g. -n "New name", -t "New title" or --disable.');
69
59
  }
60
+ const { portal } = await createPortalClient(options.dev);
61
+ const spinner = createSpinner('Updating portal...').start();
62
+ const response = (await portal.getPortal(portalId));
63
+ const current = response.portal || {};
64
+ // The API (and SDK) reset access=direct, theme=light, disabled=false and brandOff=false
65
+ // when they are missing from the request, so the current values are always sent.
66
+ const updateData = { id: portalId };
67
+ if (current.access)
68
+ updateData.access = current.access;
69
+ if (current.theme)
70
+ updateData.theme = current.theme;
71
+ if (typeof current.disabled === 'boolean')
72
+ updateData.disabled = current.disabled;
73
+ if (typeof current.brandOff === 'boolean')
74
+ updateData.brandOff = current.brandOff;
75
+ Object.assign(updateData, changes);
76
+ await portal.updatePortal(updateData);
77
+ spinner.succeed(`Portal "${changes.name || current.name || portalId}" updated`);
78
+ if (isJsonMode()) {
79
+ printJson({ id: portalId, updated: true, changes });
80
+ return;
81
+ }
82
+ const fieldLabels = {
83
+ name: 'Name', title: 'Title', subtitle: 'Subtitle', logo: 'Logo', logodark: 'Logo (dark mode)',
84
+ access: 'Access', disabled: 'Status', brandOff: 'Plazbot brand',
85
+ };
86
+ const show = (key, value) => {
87
+ if (value === undefined || value === null || value === '')
88
+ return '(empty)';
89
+ if (key === 'disabled')
90
+ return value ? 'Disabled' : 'Enabled';
91
+ if (key === 'brandOff')
92
+ return value ? 'Hidden' : 'Visible';
93
+ return String(value);
94
+ };
95
+ logger.title('Changes');
96
+ for (const [key, value] of Object.entries(changes)) {
97
+ const before = show(key, current[key]);
98
+ const after = show(key, value);
99
+ logger.label(fieldLabels[key] || key, before === after ? after : `${before} → ${after}`);
100
+ }
101
+ console.log();
70
102
  }
71
103
  catch (error) {
72
- const message = error instanceof Error ? error.message : 'Unknown error while updating the portal';
73
- logger.error(message);
74
- process.exit(1);
104
+ fail(error);
75
105
  }
76
106
  });
77
107
  addExamples(updateCommand, [
78
- { description: 'Rename a portal',
79
- command: 'plazbot portal update prt_AbcDef123 -n "Support Center"' },
80
- { description: 'Switch access to form mode and update title',
81
- command: 'plazbot portal update prt_AbcDef123 -a form -t "Sign in to continue"' },
82
- { description: 'Disable a portal',
83
- command: 'plazbot portal update prt_AbcDef123 --disabled true' },
84
- { description: 'Hide the Plazbot brand and update the logo',
85
- command: 'plazbot portal update prt_AbcDef123 --brand-off true -l https://files.example.com/logo.png' },
108
+ { description: 'Rename a portal', command: 'plazbot portal update por_AbcDef123 -n "Support Center"' },
109
+ { description: 'Ask for contact details and change the title', command: 'plazbot portal update por_AbcDef123 -a form -t "Sign in to continue"' },
110
+ { description: 'Disable a portal', command: 'plazbot portal update por_AbcDef123 --disable' },
111
+ { description: 'Hide the Plazbot brand and change the logo', command: 'plazbot portal update por_AbcDef123 --brand-off true -l https://files.example.com/logo.png' },
112
+ ]);
113
+ addNotes(updateCommand, [
114
+ 'Fields you do not pass keep their current value (access, status and brand included).',
115
+ '--disabled and --brand-off take true or false (yes/no and on/off also work).',
86
116
  ]);