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.
- package/README.md +67 -111
- package/dist/cli.js +26 -11
- package/dist/commands/agent/ai-config.js +264 -63
- package/dist/commands/agent/chat.js +16 -11
- package/dist/commands/agent/copy.js +49 -13
- package/dist/commands/agent/create.js +62 -17
- package/dist/commands/agent/delete.js +50 -39
- package/dist/commands/agent/enable-widget.js +47 -27
- package/dist/commands/agent/export.js +180 -91
- package/dist/commands/agent/files.js +155 -73
- package/dist/commands/agent/get.js +25 -19
- package/dist/commands/agent/index.js +12 -10
- package/dist/commands/agent/list.js +20 -11
- package/dist/commands/agent/monitor.js +103 -57
- package/dist/commands/agent/on-message.js +55 -32
- package/dist/commands/agent/set.js +230 -82
- package/dist/commands/agent/templates.js +259 -156
- package/dist/commands/agent/tools.js +356 -123
- package/dist/commands/agent/update.js +69 -28
- package/dist/commands/agent/validate.js +72 -40
- package/dist/commands/agent/wizard.js +240 -329
- package/dist/commands/auth/browser-login.js +37 -31
- package/dist/commands/auth/login.js +49 -45
- package/dist/commands/auth/logout.js +20 -11
- package/dist/commands/auth/status.js +36 -12
- package/dist/commands/auth/workspace.js +61 -27
- package/dist/commands/portal/add-agent.js +106 -45
- package/dist/commands/portal/add-link.js +25 -28
- package/dist/commands/portal/clear-links.js +39 -19
- package/dist/commands/portal/create.js +66 -37
- package/dist/commands/portal/delete.js +40 -45
- package/dist/commands/portal/get.js +21 -54
- package/dist/commands/portal/index.js +12 -12
- package/dist/commands/portal/list.js +34 -52
- package/dist/commands/portal/shared.js +92 -0
- package/dist/commands/portal/update.js +100 -70
- package/dist/commands/whatsapp/broadcast.js +169 -77
- package/dist/commands/whatsapp/channels.js +167 -65
- package/dist/commands/whatsapp/chat.js +45 -46
- package/dist/commands/whatsapp/connect-flow.js +16 -15
- package/dist/commands/whatsapp/connect.js +36 -21
- package/dist/commands/whatsapp/delete-webhook.js +42 -25
- package/dist/commands/whatsapp/index.js +15 -16
- package/dist/commands/whatsapp/register-webhook.js +43 -26
- package/dist/commands/whatsapp/send-template.js +62 -61
- package/dist/commands/whatsapp/send.js +46 -33
- package/dist/commands/whatsapp/setup.js +62 -52
- package/dist/commands/whatsapp/shared.js +75 -0
- package/dist/commands/whatsapp/widget.js +82 -45
- package/dist/commands/workers/deploy.js +80 -58
- package/dist/commands/workers/index.js +8 -8
- package/dist/commands/workers/list.js +42 -20
- package/dist/commands/workers/logs.js +139 -36
- package/dist/commands/workers/remove.js +45 -47
- package/dist/commands/workers/secret.js +159 -83
- package/dist/commands/workers/test.js +108 -60
- package/dist/schemas/agent.config.schema.json +159 -8
- package/dist/studio/api/sseClient.js +1 -1
- package/dist/studio/api/studioApi.js +8 -0
- package/dist/studio/components/App.js +12 -0
- package/dist/studio/components/Footer.js +1 -1
- package/dist/studio/index.js +74 -14
- package/dist/studio/runOneShot.js +62 -23
- package/dist/studio/runRepl.js +5 -5
- package/dist/studio/slash/handlers.js +11 -8
- package/dist/studio/state/store.js +1 -1
- package/dist/utils/agent-errors.js +14 -11
- package/dist/utils/agent-patch.js +60 -0
- package/dist/utils/banner.js +9 -5
- package/dist/utils/confirm.js +31 -0
- package/dist/utils/credentials.js +13 -3
- package/dist/utils/logger.js +13 -10
- package/dist/utils/output.js +78 -0
- package/dist/utils/phone.js +22 -0
- package/dist/utils/ui.js +14 -11
- package/package.json +3 -3
|
@@ -1,55 +1,116 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Command, Option } from 'commander';
|
|
2
|
+
import { Agent } from 'plazbot';
|
|
3
|
+
import { addExamples, addNotes } from '../../utils/help.js';
|
|
4
|
+
import { jsonOption, isJsonMode, printJson, fail, CliError } from '../../utils/output.js';
|
|
5
|
+
import { addYesOption, confirmAction } from '../../utils/confirm.js';
|
|
6
|
+
import { createSpinner } from '../../utils/ui.js';
|
|
4
7
|
import { logger } from '../../utils/logger.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
import { createPortalClient, resolvePortalId } from './shared.js';
|
|
9
|
+
function resolveAgentId(options) {
|
|
10
|
+
const id = (options.agent || options.agentId || '').trim();
|
|
11
|
+
if (!id) {
|
|
12
|
+
throw new CliError('Agent ID is required.', 'missing_agent_id', "Pass it with -a, --agent <agentId>. Find it with 'plazbot agent list'.");
|
|
13
|
+
}
|
|
14
|
+
return id;
|
|
15
|
+
}
|
|
16
|
+
/** Loads the agent name (the SDK returns { success, agent }). */
|
|
17
|
+
async function fetchAgentName(client, agentId, dev) {
|
|
18
|
+
const agent = new Agent({
|
|
19
|
+
workspaceId: client.credentials.workspace,
|
|
20
|
+
apiKey: client.credentials.apiKey,
|
|
21
|
+
zone: client.credentials.zone,
|
|
22
|
+
...(dev && { customUrl: 'http://localhost:5090' }),
|
|
23
|
+
});
|
|
24
|
+
const response = await agent.getAgentById({ id: agentId });
|
|
25
|
+
const data = response?.agent || response?.data || response;
|
|
26
|
+
return data?.name;
|
|
27
|
+
}
|
|
28
|
+
const portalIdOption = () => new Option('-p, --portal-id <portalId>', 'Portal ID (legacy, use the positional argument)').hideHelp();
|
|
29
|
+
export const addAgentCommand = new Command('add-agent')
|
|
30
|
+
.alias('add-agent-portal')
|
|
31
|
+
.description('Attach an existing agent to a portal')
|
|
32
|
+
.argument('[portalId]', 'Portal ID (see plazbot portal list)')
|
|
33
|
+
.option('-a, --agent <agentId>', 'ID of the agent to attach (see plazbot agent list)')
|
|
34
|
+
.addOption(portalIdOption())
|
|
35
|
+
.addOption(new Option('--agent-id <agentId>', 'Alias of --agent').hideHelp())
|
|
36
|
+
.addOption(jsonOption())
|
|
10
37
|
.option('--dev', 'Use development environment', false)
|
|
11
|
-
.action(async (options) => {
|
|
38
|
+
.action(async (portalIdArg, options) => {
|
|
12
39
|
try {
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
logger.label('Portal ID', portalDetails.portal?.id || options.portalId);
|
|
34
|
-
logger.label('Portal Name', portalDetails.portal?.name || 'N/A');
|
|
35
|
-
logger.label('Agent ID', agentDetails.id);
|
|
36
|
-
logger.label('Agent Name', agentDetails.name);
|
|
37
|
-
await portal.addAgentToPortal({
|
|
38
|
-
portalId: options.portalId,
|
|
39
|
-
id: options.agentId
|
|
40
|
-
});
|
|
41
|
-
logger.success('Agent added to the portal successfully');
|
|
42
|
-
if (options.dev) {
|
|
43
|
-
logger.warning('Environment: development');
|
|
40
|
+
const portalId = resolvePortalId(portalIdArg, options.portalId);
|
|
41
|
+
const agentId = resolveAgentId(options);
|
|
42
|
+
const client = await createPortalClient(options.dev);
|
|
43
|
+
const spinner = createSpinner('Attaching agent...').start();
|
|
44
|
+
const [portalRes, agentName] = await Promise.all([
|
|
45
|
+
client.portal.getPortal(portalId),
|
|
46
|
+
fetchAgentName(client, agentId, options.dev),
|
|
47
|
+
]);
|
|
48
|
+
const portalName = portalRes?.portal?.name || portalId;
|
|
49
|
+
if (portalRes?.portal?.agents?.some(a => a.id === agentId)) {
|
|
50
|
+
spinner.info(`Agent "${agentName || agentId}" is already attached to portal "${portalName}"`);
|
|
51
|
+
if (isJsonMode())
|
|
52
|
+
printJson({ portalId, agentId, added: false, alreadyAttached: true });
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
await client.portal.addAgentToPortal({ portalId, id: agentId });
|
|
56
|
+
spinner.succeed(`Agent "${agentName || agentId}" attached to portal "${portalName}"`);
|
|
57
|
+
if (isJsonMode()) {
|
|
58
|
+
printJson({ portalId, agentId, agentName: agentName ?? null, added: true });
|
|
59
|
+
return;
|
|
44
60
|
}
|
|
61
|
+
console.log();
|
|
45
62
|
}
|
|
46
63
|
catch (error) {
|
|
47
|
-
|
|
48
|
-
logger.error(message);
|
|
49
|
-
process.exit(1);
|
|
64
|
+
fail(error);
|
|
50
65
|
}
|
|
51
66
|
});
|
|
52
67
|
addExamples(addAgentCommand, [
|
|
53
|
-
{ description: 'Attach an
|
|
54
|
-
|
|
68
|
+
{ description: 'Attach an agent to a portal', command: 'plazbot portal add-agent por_AbcDef123 -a age_AbcDef123' },
|
|
69
|
+
{ description: 'Attach and get the result as JSON', command: 'plazbot portal add-agent por_AbcDef123 -a age_AbcDef123 --json' },
|
|
70
|
+
]);
|
|
71
|
+
addNotes(addAgentCommand, [
|
|
72
|
+
'The agent must already exist in the active workspace (plazbot agent list).',
|
|
73
|
+
'Old form still works: plazbot portal add-agent-portal -p <portalId> -a <agentId>.',
|
|
74
|
+
]);
|
|
75
|
+
export const removeAgentCommand = new Command('remove-agent')
|
|
76
|
+
.description('Detach an agent from a portal (the agent itself is not deleted)')
|
|
77
|
+
.argument('[portalId]', 'Portal ID (see plazbot portal list)')
|
|
78
|
+
.option('-a, --agent <agentId>', 'ID of the agent to detach')
|
|
79
|
+
.addOption(portalIdOption())
|
|
80
|
+
.addOption(new Option('--agent-id <agentId>', 'Alias of --agent').hideHelp())
|
|
81
|
+
.addOption(jsonOption())
|
|
82
|
+
.option('--dev', 'Use development environment', false);
|
|
83
|
+
addYesOption(removeAgentCommand);
|
|
84
|
+
removeAgentCommand.action(async (portalIdArg, options) => {
|
|
85
|
+
try {
|
|
86
|
+
const portalId = resolvePortalId(portalIdArg, options.portalId);
|
|
87
|
+
const agentId = resolveAgentId(options);
|
|
88
|
+
const client = await createPortalClient(options.dev);
|
|
89
|
+
const spinner = createSpinner('Loading portal...').start();
|
|
90
|
+
const portalRes = (await client.portal.getPortal(portalId));
|
|
91
|
+
spinner.stop();
|
|
92
|
+
const portalName = portalRes?.portal?.name || portalId;
|
|
93
|
+
const attached = portalRes?.portal?.agents?.find(a => a.id === agentId);
|
|
94
|
+
if (portalRes?.portal?.agents && !attached) {
|
|
95
|
+
throw new CliError(`Agent ${agentId} is not attached to portal "${portalName}".`, 'agent_not_attached', `See the attached agents with 'plazbot portal get ${portalId}'.`);
|
|
96
|
+
}
|
|
97
|
+
const agentLabel = attached?.name || agentId;
|
|
98
|
+
const ok = await confirmAction(`Detach agent "${agentLabel}" from portal "${portalName}"?`, options);
|
|
99
|
+
if (!ok) {
|
|
100
|
+
logger.dim('Aborted.');
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
const removing = createSpinner('Detaching agent...').start();
|
|
104
|
+
await client.portal.removeAgentFromPortal({ portalId, id: agentId });
|
|
105
|
+
removing.succeed(`Agent "${agentLabel}" detached from portal "${portalName}"`);
|
|
106
|
+
if (isJsonMode())
|
|
107
|
+
printJson({ portalId, agentId, removed: true });
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
fail(error);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
addExamples(removeAgentCommand, [
|
|
114
|
+
{ description: 'Detach an agent from a portal (asks for confirmation)', command: 'plazbot portal remove-agent por_AbcDef123 -a age_AbcDef123' },
|
|
115
|
+
{ description: 'Detach without confirmation (scripts and CI)', command: 'plazbot portal remove-agent por_AbcDef123 -a age_AbcDef123 --yes' },
|
|
55
116
|
]);
|
|
@@ -1,38 +1,35 @@
|
|
|
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
2
|
import { addExamples } 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, resolvePortalId, validateHttpUrl } from './shared.js';
|
|
6
6
|
export const addLinkCommand = new Command('add-link')
|
|
7
|
-
.description('Add a link to the portal')
|
|
8
|
-
.argument('<portalId>', 'Portal ID')
|
|
9
|
-
.requiredOption('-t, --title <title>', 'Link
|
|
10
|
-
.requiredOption('-u, --url <url>', 'Link URL')
|
|
11
|
-
.
|
|
12
|
-
.
|
|
7
|
+
.description('Add a link to the portal navigation')
|
|
8
|
+
.argument('<portalId>', 'Portal ID (see plazbot portal list)')
|
|
9
|
+
.requiredOption('-t, --title <title>', 'Link text')
|
|
10
|
+
.requiredOption('-u, --url <url>', 'Link URL (http:// or https://)')
|
|
11
|
+
.addOption(jsonOption())
|
|
12
|
+
.option('--dev', 'Use development environment', false)
|
|
13
|
+
.action(async (portalIdArg, options) => {
|
|
13
14
|
try {
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
await portal.addLinkToPortal({
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
url:
|
|
25
|
-
});
|
|
26
|
-
logger.success('Link added successfully');
|
|
15
|
+
const portalId = resolvePortalId(portalIdArg);
|
|
16
|
+
const title = options.title.trim();
|
|
17
|
+
if (!title)
|
|
18
|
+
throw new CliError('Link title cannot be empty.', 'missing_title', 'Pass it with -t, --title <title>.');
|
|
19
|
+
const url = validateHttpUrl(options.url, '--url');
|
|
20
|
+
const { portal } = await createPortalClient(options.dev);
|
|
21
|
+
const spinner = createSpinner('Adding link...').start();
|
|
22
|
+
await portal.addLinkToPortal({ portalId, value: title, url });
|
|
23
|
+
spinner.succeed(`Link "${title}" added`);
|
|
24
|
+
if (isJsonMode())
|
|
25
|
+
printJson({ portalId, title, url, added: true });
|
|
27
26
|
}
|
|
28
27
|
catch (error) {
|
|
29
|
-
|
|
30
|
-
process.exit(1);
|
|
28
|
+
fail(error);
|
|
31
29
|
}
|
|
32
30
|
});
|
|
33
31
|
addExamples(addLinkCommand, [
|
|
34
|
-
{ description: 'Add a documentation link
|
|
35
|
-
|
|
36
|
-
{ description: 'Add a
|
|
37
|
-
command: 'plazbot portal add-link prt_AbcDef123 -t "Contact us" -u https://example.com/contact' },
|
|
32
|
+
{ description: 'Add a documentation link', command: 'plazbot portal add-link por_AbcDef123 -t "Docs" -u https://docs.example.com' },
|
|
33
|
+
{ description: 'Add a contact link', command: 'plazbot portal add-link por_AbcDef123 -t "Contact us" -u https://example.com/contact' },
|
|
34
|
+
{ description: 'Add a link and get the result as JSON', command: 'plazbot portal add-link por_AbcDef123 -t "Pricing" -u https://example.com/pricing --json' },
|
|
38
35
|
]);
|
|
@@ -1,30 +1,50 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { addExamples, addNotes } from '../../utils/help.js';
|
|
3
|
+
import { jsonOption, isJsonMode, printJson, fail } from '../../utils/output.js';
|
|
4
|
+
import { addYesOption, confirmAction } from '../../utils/confirm.js';
|
|
5
|
+
import { createSpinner } from '../../utils/ui.js';
|
|
4
6
|
import { logger } from '../../utils/logger.js';
|
|
5
|
-
import {
|
|
7
|
+
import { createPortalClient, resolvePortalId } from './shared.js';
|
|
6
8
|
export const clearLinksCommand = new Command('clear-links')
|
|
7
|
-
.description('Remove
|
|
8
|
-
.argument('<portalId>', 'Portal ID')
|
|
9
|
-
.
|
|
10
|
-
.
|
|
9
|
+
.description('Remove every link from a portal')
|
|
10
|
+
.argument('<portalId>', 'Portal ID (see plazbot portal list)')
|
|
11
|
+
.addOption(jsonOption())
|
|
12
|
+
.option('--dev', 'Use development environment', false);
|
|
13
|
+
addYesOption(clearLinksCommand);
|
|
14
|
+
clearLinksCommand.action(async (portalIdArg, options) => {
|
|
11
15
|
try {
|
|
12
|
-
const
|
|
13
|
-
const portal =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const portalId = resolvePortalId(portalIdArg);
|
|
17
|
+
const { portal } = await createPortalClient(options.dev);
|
|
18
|
+
const spinner = createSpinner('Loading portal...').start();
|
|
19
|
+
const response = (await portal.getPortal(portalId));
|
|
20
|
+
spinner.stop();
|
|
21
|
+
const name = response?.portal?.name || portalId;
|
|
22
|
+
const links = response?.portal?.links || [];
|
|
23
|
+
if (links.length === 0) {
|
|
24
|
+
logger.dim(`Portal "${name}" has no links. Nothing to remove.`);
|
|
25
|
+
if (isJsonMode())
|
|
26
|
+
printJson({ portalId, cleared: true, removed: 0 });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const ok = await confirmAction(`Remove all ${links.length} link(s) from portal "${name}"?`, options);
|
|
30
|
+
if (!ok) {
|
|
31
|
+
logger.dim('Aborted.');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const clearing = createSpinner('Removing links...').start();
|
|
19
35
|
await portal.clearLinks(portalId);
|
|
20
|
-
|
|
36
|
+
clearing.succeed(`Removed ${links.length} link(s) from portal "${name}"`);
|
|
37
|
+
if (isJsonMode())
|
|
38
|
+
printJson({ portalId, cleared: true, removed: links.length });
|
|
21
39
|
}
|
|
22
40
|
catch (error) {
|
|
23
|
-
|
|
24
|
-
process.exit(1);
|
|
41
|
+
fail(error);
|
|
25
42
|
}
|
|
26
43
|
});
|
|
27
44
|
addExamples(clearLinksCommand, [
|
|
28
|
-
{ description: 'Remove every link
|
|
29
|
-
|
|
45
|
+
{ description: 'Remove every link (asks for confirmation)', command: 'plazbot portal clear-links por_AbcDef123' },
|
|
46
|
+
{ description: 'Remove every link without confirmation', command: 'plazbot portal clear-links por_AbcDef123 --yes' },
|
|
47
|
+
]);
|
|
48
|
+
addNotes(clearLinksCommand, [
|
|
49
|
+
'There is no command to remove a single link: clear them and add back the ones you want with add-link.',
|
|
30
50
|
]);
|
|
@@ -1,51 +1,80 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { addExamples, addNotes } from '../../utils/help.js';
|
|
4
|
+
import { jsonOption, isJsonMode, printJson, fail, CliError } from '../../utils/output.js';
|
|
5
|
+
import { createSpinner } from '../../utils/ui.js';
|
|
4
6
|
import { logger } from '../../utils/logger.js';
|
|
5
|
-
import {
|
|
7
|
+
import { createPortalClient, validateAccess, validateLogo } from './shared.js';
|
|
6
8
|
export const createCommand = new Command('create')
|
|
7
|
-
.description('Create
|
|
9
|
+
.description('Create the portal of the active workspace')
|
|
8
10
|
.requiredOption('-n, --name <name>', 'Portal name')
|
|
9
|
-
.requiredOption('-t, --title <title>', '
|
|
11
|
+
.requiredOption('-t, --title <title>', 'Welcome title shown on the portal')
|
|
12
|
+
.option('-s, --subtitle <subtitle>', 'Subtitle shown under the title')
|
|
13
|
+
.option('-l, --logo <url>', 'Logo URL (.png or .jpg)')
|
|
14
|
+
.option('-d, --logo-dark <url>', 'Dark-mode logo URL (.png or .jpg)')
|
|
15
|
+
.option('-a, --access <type>', 'Access type: direct (open) or form (asks for contact details first)', 'direct')
|
|
16
|
+
.addOption(jsonOption())
|
|
10
17
|
.option('--dev', 'Use development environment', false)
|
|
11
18
|
.action(async (options) => {
|
|
12
19
|
try {
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
logger.warning('\nEnvironment: development');
|
|
20
|
+
const name = options.name.trim();
|
|
21
|
+
const title = options.title.trim();
|
|
22
|
+
if (!name)
|
|
23
|
+
throw new CliError('Portal name is required.', 'missing_name', 'Pass it with -n, --name <name>.');
|
|
24
|
+
if (!title)
|
|
25
|
+
throw new CliError('Portal title is required.', 'missing_title', 'Pass it with -t, --title <title>.');
|
|
26
|
+
const access = validateAccess(options.access || 'direct');
|
|
27
|
+
const logo = options.logo ? validateLogo(options.logo, '--logo') : undefined;
|
|
28
|
+
const logodark = options.logoDark ? validateLogo(options.logoDark, '--logo-dark') : undefined;
|
|
29
|
+
const { portal, credentials } = await createPortalClient(options.dev);
|
|
30
|
+
const spinner = createSpinner('Creating portal...').start();
|
|
31
|
+
let created;
|
|
32
|
+
try {
|
|
33
|
+
created = await portal.addPortal({
|
|
34
|
+
name,
|
|
35
|
+
title,
|
|
36
|
+
zone: credentials.zone,
|
|
37
|
+
subtitle: options.subtitle?.trim() || '',
|
|
38
|
+
...(logo && { logo }),
|
|
39
|
+
...(logodark && { logodark }),
|
|
40
|
+
access,
|
|
41
|
+
disabled: false,
|
|
42
|
+
brandOff: false,
|
|
43
|
+
});
|
|
38
44
|
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
spinner.stop();
|
|
47
|
+
if (error instanceof Error && /only one portal/i.test(error.message)) {
|
|
48
|
+
throw new CliError('This workspace already has a portal (only one is allowed).', 'portal_exists', "See it with 'plazbot portal list' or change it with 'plazbot portal update <portalId>'.");
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
spinner.succeed(`Portal "${name}" created`);
|
|
53
|
+
if (isJsonMode()) {
|
|
54
|
+
printJson({ id: created.id, url: created.url });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
logger.label('ID', created.id);
|
|
58
|
+
logger.label('URL', created.url);
|
|
59
|
+
console.log();
|
|
60
|
+
logger.dim(`Next: ${chalk.cyan(`plazbot portal add-agent ${created.id} -a <agentId>`)}`);
|
|
61
|
+
console.log();
|
|
39
62
|
}
|
|
40
63
|
catch (error) {
|
|
41
|
-
|
|
42
|
-
logger.error(message);
|
|
43
|
-
process.exit(1);
|
|
64
|
+
fail(error);
|
|
44
65
|
}
|
|
45
66
|
});
|
|
46
67
|
addExamples(createCommand, [
|
|
47
|
-
{ description: 'Create a portal with name and welcome title',
|
|
48
|
-
command: 'plazbot portal create -n "
|
|
49
|
-
{ description: 'Create
|
|
50
|
-
command: 'plazbot portal create -n "
|
|
68
|
+
{ description: 'Create a portal with a name and welcome title',
|
|
69
|
+
command: 'plazbot portal create -n "Help Center" -t "How can we help you?"' },
|
|
70
|
+
{ description: 'Create a portal with subtitle and logos',
|
|
71
|
+
command: 'plazbot portal create -n "Help Center" -t "Welcome" -s "Ask our AI agents" -l https://files.example.com/logo.png -d https://files.example.com/logo-dark.png' },
|
|
72
|
+
{ description: 'Ask visitors for their details before chatting',
|
|
73
|
+
command: 'plazbot portal create -n "Support" -t "Welcome" -a form' },
|
|
74
|
+
{ description: 'Create and capture the ID for scripts',
|
|
75
|
+
command: "plazbot portal create -n \"Help Center\" -t \"Welcome\" --json | jq -r '.id'" },
|
|
76
|
+
]);
|
|
77
|
+
addNotes(createCommand, [
|
|
78
|
+
'Only one portal per workspace is allowed.',
|
|
79
|
+
'Logos must be .png or .jpg, given as an https:// URL or a path starting with "/".',
|
|
51
80
|
]);
|
|
@@ -1,58 +1,53 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { addExamples, addNotes } from '../../utils/help.js';
|
|
3
|
+
import { jsonOption, isJsonMode, printJson, fail } from '../../utils/output.js';
|
|
4
|
+
import { addYesOption, confirmAction } from '../../utils/confirm.js';
|
|
5
|
+
import { createSpinner } from '../../utils/ui.js';
|
|
4
6
|
import { logger } from '../../utils/logger.js';
|
|
5
|
-
import {
|
|
6
|
-
import inquirer from 'inquirer';
|
|
7
|
+
import { createPortalClient, resolvePortalId } from './shared.js';
|
|
7
8
|
export const deleteCommand = new Command('delete')
|
|
8
9
|
.description('Delete a portal')
|
|
9
|
-
.argument('<portalId>', 'Portal ID')
|
|
10
|
-
.
|
|
11
|
-
.option('--dev', 'Use development environment', false)
|
|
12
|
-
|
|
10
|
+
.argument('<portalId>', 'Portal ID (see plazbot portal list)')
|
|
11
|
+
.addOption(jsonOption())
|
|
12
|
+
.option('--dev', 'Use development environment', false);
|
|
13
|
+
addYesOption(deleteCommand);
|
|
14
|
+
deleteCommand.action(async (portalIdArg, options) => {
|
|
13
15
|
try {
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!options.force) {
|
|
29
|
-
const { confirm } = await inquirer.prompt([{
|
|
30
|
-
type: 'confirm',
|
|
31
|
-
name: 'confirm',
|
|
32
|
-
message: 'Are you sure you want to delete this portal?',
|
|
33
|
-
default: false
|
|
34
|
-
}]);
|
|
35
|
-
if (!confirm) {
|
|
36
|
-
logger.info('Operation cancelled.');
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
16
|
+
const portalId = resolvePortalId(portalIdArg);
|
|
17
|
+
const { portal } = await createPortalClient(options.dev);
|
|
18
|
+
const spinner = createSpinner('Loading portal...').start();
|
|
19
|
+
const response = (await portal.getPortal(portalId));
|
|
20
|
+
spinner.stop();
|
|
21
|
+
const details = response.portal;
|
|
22
|
+
const name = details?.name || portalId;
|
|
23
|
+
if (!isJsonMode()) {
|
|
24
|
+
logger.title('Portal to delete');
|
|
25
|
+
logger.label('ID', details?.id || portalId);
|
|
26
|
+
logger.label('Name', name);
|
|
27
|
+
if (details?.url)
|
|
28
|
+
logger.label('URL', details.url);
|
|
29
|
+
console.log();
|
|
39
30
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
logger.warning('\nEnvironment: development');
|
|
31
|
+
const ok = await confirmAction(`Delete portal "${name}"? Its public URL will stop working.`, options);
|
|
32
|
+
if (!ok) {
|
|
33
|
+
logger.dim('Aborted.');
|
|
34
|
+
process.exit(1);
|
|
45
35
|
}
|
|
36
|
+
const deleting = createSpinner('Deleting portal...').start();
|
|
37
|
+
await portal.deletePortal(portalId);
|
|
38
|
+
deleting.succeed(`Portal "${name}" deleted`);
|
|
39
|
+
if (isJsonMode())
|
|
40
|
+
printJson({ id: portalId, deleted: true });
|
|
46
41
|
}
|
|
47
42
|
catch (error) {
|
|
48
|
-
|
|
49
|
-
logger.error(message);
|
|
50
|
-
process.exit(1);
|
|
43
|
+
fail(error);
|
|
51
44
|
}
|
|
52
45
|
});
|
|
53
46
|
addExamples(deleteCommand, [
|
|
54
|
-
{ description: 'Delete a portal
|
|
55
|
-
|
|
56
|
-
{ description: 'Delete
|
|
57
|
-
|
|
47
|
+
{ description: 'Delete a portal (asks for confirmation)', command: 'plazbot portal delete por_AbcDef123' },
|
|
48
|
+
{ description: 'Delete without confirmation (scripts and CI)', command: 'plazbot portal delete por_AbcDef123 --yes' },
|
|
49
|
+
{ description: 'Delete and get the result as JSON', command: 'plazbot portal delete por_AbcDef123 --yes --json' },
|
|
50
|
+
]);
|
|
51
|
+
addNotes(deleteCommand, [
|
|
52
|
+
'This cannot be undone. Agents attached to the portal are not deleted.',
|
|
58
53
|
]);
|
|
@@ -1,66 +1,33 @@
|
|
|
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
2
|
import { addExamples } from '../../utils/help.js';
|
|
3
|
+
import { jsonOption, isJsonMode, printJson, fail } from '../../utils/output.js';
|
|
4
|
+
import { createSpinner } from '../../utils/ui.js';
|
|
5
|
+
import { createPortalClient, printPortalDetails, resolvePortalId } from './shared.js';
|
|
6
6
|
export const getCommand = new Command('get')
|
|
7
|
-
.description('Show
|
|
8
|
-
.argument('<portalId>', 'Portal ID')
|
|
7
|
+
.description('Show the details of a portal (settings, links and agents)')
|
|
8
|
+
.argument('<portalId>', 'Portal ID (see plazbot portal list)')
|
|
9
|
+
.addOption(jsonOption())
|
|
9
10
|
.option('--dev', 'Use development environment', false)
|
|
10
|
-
.action(async (
|
|
11
|
+
.action(async (portalIdArg, options) => {
|
|
11
12
|
try {
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const response = await portal.getPortal(portalId);
|
|
21
|
-
const portalDetails = response.portal;
|
|
22
|
-
logger.title('Portal details');
|
|
23
|
-
logger.label('ID', portalDetails.id);
|
|
24
|
-
logger.label('Name', portalDetails.name);
|
|
25
|
-
logger.label('URL', portalDetails.url);
|
|
26
|
-
logger.label('Access', portalDetails.access);
|
|
27
|
-
logger.label('Status', portalDetails.disabled ? 'Disabled' : 'Enabled');
|
|
28
|
-
if (portalDetails.title) {
|
|
29
|
-
logger.label('Title', portalDetails.title);
|
|
30
|
-
}
|
|
31
|
-
if (portalDetails.subtitle) {
|
|
32
|
-
logger.label('Subtitle', portalDetails.subtitle);
|
|
33
|
-
}
|
|
34
|
-
if (portalDetails.logo) {
|
|
35
|
-
logger.title('Assets');
|
|
36
|
-
logger.label('Logo', portalDetails.logo);
|
|
37
|
-
if (portalDetails.logodark) {
|
|
38
|
-
logger.label('Logo (dark mode)', portalDetails.logodark);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
if (portalDetails.links && portalDetails.links.length > 0) {
|
|
42
|
-
logger.title('Links');
|
|
43
|
-
portalDetails.links.forEach((link) => {
|
|
44
|
-
logger.label(link.value, link.url);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
if (portalDetails.agents && portalDetails.agents.length > 0) {
|
|
48
|
-
logger.title('Associated agents');
|
|
49
|
-
portalDetails.agents.forEach((agent) => {
|
|
50
|
-
logger.label(agent.name, agent.id);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
if (options.dev) {
|
|
54
|
-
logger.warning('\nEnvironment: development');
|
|
13
|
+
const portalId = resolvePortalId(portalIdArg);
|
|
14
|
+
const { portal } = await createPortalClient(options.dev);
|
|
15
|
+
const spinner = createSpinner('Loading portal...').start();
|
|
16
|
+
const response = (await portal.getPortal(portalId));
|
|
17
|
+
spinner.stop();
|
|
18
|
+
if (isJsonMode()) {
|
|
19
|
+
printJson(response.portal);
|
|
20
|
+
return;
|
|
55
21
|
}
|
|
22
|
+
printPortalDetails(response.portal, 'Portal details');
|
|
23
|
+
console.log();
|
|
56
24
|
}
|
|
57
25
|
catch (error) {
|
|
58
|
-
|
|
59
|
-
logger.error(message);
|
|
60
|
-
process.exit(1);
|
|
26
|
+
fail(error);
|
|
61
27
|
}
|
|
62
28
|
});
|
|
63
29
|
addExamples(getCommand, [
|
|
64
|
-
{ description: 'Show details
|
|
65
|
-
|
|
30
|
+
{ description: 'Show the details of a portal', command: 'plazbot portal get por_AbcDef123' },
|
|
31
|
+
{ description: 'Get the portal as JSON', command: 'plazbot portal get por_AbcDef123 --json' },
|
|
32
|
+
{ description: 'List the agents attached to the portal', command: "plazbot portal get por_AbcDef123 --json | jq '.agents'" },
|
|
66
33
|
]);
|