@velaro/cli 1.2.0 → 1.4.8

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 (98) hide show
  1. package/README.md +161 -138
  2. package/bin/velaro.js +177 -62
  3. package/lib/api.js +91 -52
  4. package/lib/api.test.js +46 -0
  5. package/lib/banner.js +76 -0
  6. package/lib/commands/activity.js +133 -0
  7. package/lib/commands/acuity.js +66 -0
  8. package/lib/commands/agent.js +204 -50
  9. package/lib/commands/ai-config.js +193 -0
  10. package/lib/commands/ai-models.js +159 -0
  11. package/lib/commands/appointments.js +198 -0
  12. package/lib/commands/article.js +668 -388
  13. package/lib/commands/automation-draft.js +134 -0
  14. package/lib/commands/avatar.js +75 -0
  15. package/lib/commands/bigcommerce.js +50 -0
  16. package/lib/commands/billing-contacts.js +62 -0
  17. package/lib/commands/billing-email-preference.js +64 -0
  18. package/lib/commands/billing-subscription.js +265 -0
  19. package/lib/commands/billing.js +138 -0
  20. package/lib/commands/bot.js +141 -137
  21. package/lib/commands/bundle.js +168 -0
  22. package/lib/commands/calendly.js +62 -0
  23. package/lib/commands/callback.js +125 -0
  24. package/lib/commands/callrail.js +88 -0
  25. package/lib/commands/campaigns.js +44 -0
  26. package/lib/commands/case.js +102 -0
  27. package/lib/commands/check.js +163 -163
  28. package/lib/commands/compliance.js +229 -0
  29. package/lib/commands/conversation-efficiency.js +178 -0
  30. package/lib/commands/copilotstudio.js +114 -0
  31. package/lib/commands/coupon-grant.js +192 -0
  32. package/lib/commands/db.js +101 -0
  33. package/lib/commands/deployment.js +107 -107
  34. package/lib/commands/diagnostics.js +298 -0
  35. package/lib/commands/email-campaign.js +47 -0
  36. package/lib/commands/email-inbox.js +88 -0
  37. package/lib/commands/entitlement.js +176 -0
  38. package/lib/commands/env.js +45 -45
  39. package/lib/commands/feature-discovery.js +40 -0
  40. package/lib/commands/focus.js +278 -0
  41. package/lib/commands/index.js +38 -5
  42. package/lib/commands/ingest.js +31 -31
  43. package/lib/commands/inline-widget-config.js +126 -0
  44. package/lib/commands/integration.js +93 -0
  45. package/lib/commands/kb.js +450 -309
  46. package/lib/commands/login.js +86 -86
  47. package/lib/commands/logs.js +680 -0
  48. package/lib/commands/magento.js +210 -0
  49. package/lib/commands/mcp-key.js +188 -159
  50. package/lib/commands/migrate.js +134 -0
  51. package/lib/commands/migration-status.js +66 -0
  52. package/lib/commands/monday.js +137 -0
  53. package/lib/commands/netsuite.js +87 -0
  54. package/lib/commands/notifications.js +63 -0
  55. package/lib/commands/notion.js +70 -0
  56. package/lib/commands/ops.js +267 -173
  57. package/lib/commands/payment-recovery.js +170 -0
  58. package/lib/commands/pickup.js +172 -0
  59. package/lib/commands/pricing.js +132 -0
  60. package/lib/commands/product.js +55 -0
  61. package/lib/commands/recruiting.js +374 -0
  62. package/lib/commands/report.js +462 -0
  63. package/lib/commands/routing.js +304 -0
  64. package/lib/commands/rule.js +85 -85
  65. package/lib/commands/sharepoint.js +167 -0
  66. package/lib/commands/site-provision.js +68 -0
  67. package/lib/commands/site.js +62 -62
  68. package/lib/commands/sitesync.js +158 -0
  69. package/lib/commands/slack.js +64 -0
  70. package/lib/commands/squarespace.js +108 -0
  71. package/lib/commands/status.js +24 -24
  72. package/lib/commands/subscription.js +43 -0
  73. package/lib/commands/support.js +128 -0
  74. package/lib/commands/survey.js +216 -0
  75. package/lib/commands/team.js +144 -144
  76. package/lib/commands/teams-phone.js +131 -0
  77. package/lib/commands/teams.js +106 -0
  78. package/lib/commands/telephony.js +99 -0
  79. package/lib/commands/update.js +47 -47
  80. package/lib/commands/webflow.js +128 -0
  81. package/lib/commands/whoami.js +25 -22
  82. package/lib/commands/widget-container.js +152 -0
  83. package/lib/commands/woocommerce.js +240 -0
  84. package/lib/commands/workflow.js +233 -98
  85. package/lib/config.js +85 -83
  86. package/lib/kb-screenshot.js +320 -0
  87. package/lib/migrations/amscro.json +72 -0
  88. package/lib/migrations/azenta.json +68 -0
  89. package/lib/migrations/bluefire.json +49 -0
  90. package/lib/migrations/donaldson.json +75 -0
  91. package/lib/oauth.js +149 -135
  92. package/lib/run.js +21 -16
  93. package/lib/sharepoint-auth.js +138 -0
  94. package/lib/subscription.js +41 -39
  95. package/lib/track.js +35 -35
  96. package/lib/update-check.js +64 -64
  97. package/package.json +34 -19
  98. package/scripts/postinstall.js +12 -0
@@ -1,31 +1,31 @@
1
- import { getCredentials, post } from '../api.js';
2
- import { runCommand } from '../run.js';
3
-
4
- export const ingestCommand = {
5
- command: 'ingest',
6
- describe: 'Trigger knowledge base ingestion for a completed scraper job',
7
- builder: (y) =>
8
- y.option('job-id', {
9
- describe: 'Scraper job ID to ingest',
10
- type: 'string',
11
- demandOption: true,
12
- }),
13
-
14
- handler: runCommand(async (argv) => {
15
- // Single credential resolution — avoids double readConfig() from calling readConfig()
16
- // here and again inside post() → getCredentials().
17
- const creds = await getCredentials();
18
-
19
- console.log(`Triggering ingestion for job ${argv['job-id']} on site ${creds.siteId}...`);
20
-
21
- const result = await post('/AzureIndexes/IngestJobDirect', {
22
- siteId: creds.siteId,
23
- jobId: argv['job-id'],
24
- });
25
-
26
- console.log('Ingestion started.');
27
- console.log(` Job ID: ${result.jobId}`);
28
- console.log(` Index: ${result.physicalIndex}`);
29
- console.log('\nEmbedding runs in the background. Check logs for completion.');
30
- }),
31
- };
1
+ import { getCredentials, post } from '../api.js';
2
+ import { runCommand } from '../run.js';
3
+
4
+ export const ingestCommand = {
5
+ command: 'ingest',
6
+ describe: 'Trigger knowledge base ingestion for a completed scraper job',
7
+ builder: (y) =>
8
+ y.option('job-id', {
9
+ describe: 'Scraper job ID to ingest',
10
+ type: 'string',
11
+ demandOption: true,
12
+ }),
13
+
14
+ handler: runCommand(async (argv) => {
15
+ // Single credential resolution — avoids double readConfig() from calling readConfig()
16
+ // here and again inside post() → getCredentials().
17
+ const creds = await getCredentials();
18
+
19
+ console.log(`Triggering ingestion for job ${argv['job-id']} on site ${creds.siteId}...`);
20
+
21
+ const result = await post('/AzureIndexes/IngestJobDirect', {
22
+ siteId: creds.siteId,
23
+ jobId: argv['job-id'],
24
+ });
25
+
26
+ console.log('Ingestion started.');
27
+ console.log(` Job ID: ${result.jobId}`);
28
+ console.log(` Index: ${result.physicalIndex}`);
29
+ console.log('\nEmbedding runs in the background. Check logs for completion.');
30
+ }),
31
+ };
@@ -0,0 +1,126 @@
1
+ import { get, post, del, request } from '../api.js';
2
+ import { runCommand } from '../run.js';
3
+
4
+ const RESET = '\x1b[0m';
5
+ const GRN = '\x1b[32m';
6
+ const YEL = '\x1b[33m';
7
+ const CYN = '\x1b[36m';
8
+
9
+ function formatConfig(c) {
10
+ const enabled = c.enabled ? `${GRN}enabled${RESET}` : `${YEL}disabled${RESET}`;
11
+ return ` #${c.id} | ${CYN}${c.integration}${RESET} / ${c.recordType} | ${enabled}`;
12
+ }
13
+
14
+ // -- list ---------------------------------------------------------------------
15
+
16
+ const listCommand = {
17
+ command: 'list',
18
+ describe: 'List Inline Data Widget configs for this site',
19
+ builder: (y) => y,
20
+ handler: runCommand(async () => {
21
+ const data = await get('/InlineWidgetConfig');
22
+ const configs = Array.isArray(data) ? data : [];
23
+ if (!configs.length) {
24
+ console.log('\nNo Inline Data Widget configs. All integrations use text narration (default behavior).\n');
25
+ return;
26
+ }
27
+ console.log(`\nInline Data Widget Configs (${configs.length})\n`);
28
+ for (const c of configs) console.log(formatConfig(c));
29
+ console.log('');
30
+ }),
31
+ };
32
+
33
+ // -- eligible ---------------------------------------------------------------------
34
+
35
+ const eligibleCommand = {
36
+ command: 'eligible',
37
+ describe: 'List (integration, recordType) combinations eligible for Inline Data Widgets on this site',
38
+ builder: (y) => y,
39
+ handler: runCommand(async () => {
40
+ const data = await get('/InlineWidgetConfig/eligible');
41
+ const pairs = Array.isArray(data) ? data : [];
42
+ if (!pairs.length) {
43
+ console.log('\nNo eligible integration/record-type combinations for this site yet.\n');
44
+ return;
45
+ }
46
+ console.log(`\nEligible for Inline Data Widgets (${pairs.length})\n`);
47
+ for (const p of pairs) console.log(` ${CYN}${p.integration}${RESET} / ${p.recordType}`);
48
+ console.log('');
49
+ }),
50
+ };
51
+
52
+ // -- create ---------------------------------------------------------------------
53
+
54
+ const createCommand = {
55
+ command: 'create',
56
+ describe: 'Create an Inline Data Widget config (opts a record type into inline card rendering)',
57
+ builder: (y) =>
58
+ y
59
+ .option('integration', { type: 'string', describe: 'Integration slug, e.g. NetSuite', demandOption: true })
60
+ .option('record-type', { type: 'string', describe: 'Record type, e.g. Order', demandOption: true })
61
+ .option('disabled', { type: 'boolean', describe: 'Create disabled instead of the default enabled', default: false }),
62
+ handler: runCommand(async (argv) => {
63
+ const c = await post('/InlineWidgetConfig', {
64
+ integration: argv.integration,
65
+ recordType: argv.recordType,
66
+ enabled: !argv.disabled,
67
+ });
68
+ console.log(`\nCreated Inline Data Widget config #${c.id} (${c.integration}/${c.recordType}, ${c.enabled ? 'enabled' : 'disabled'})\n`);
69
+ }),
70
+ };
71
+
72
+ // -- update ---------------------------------------------------------------------
73
+
74
+ const updateCommand = {
75
+ command: 'update <id>',
76
+ describe: 'Update an existing Inline Data Widget config',
77
+ builder: (y) =>
78
+ y
79
+ .positional('id', { type: 'number', describe: 'Config ID' })
80
+ .option('enable', { type: 'boolean', describe: 'Enable the config' })
81
+ .option('disable', { type: 'boolean', describe: 'Disable the config' }),
82
+ handler: runCommand(async (argv) => {
83
+ const body = {};
84
+ if (argv.enable) body.enabled = true;
85
+ if (argv.disable) body.enabled = false;
86
+
87
+ if (!Object.keys(body).length) {
88
+ console.error('No fields to update. Pass --enable or --disable.');
89
+ process.exitCode = 1;
90
+ return;
91
+ }
92
+
93
+ const c = await request('PUT', `/InlineWidgetConfig/${argv.id}`, body);
94
+ console.log(`\nUpdated Inline Data Widget config #${c.id}\n`);
95
+ console.log(formatConfig(c));
96
+ console.log('');
97
+ }),
98
+ };
99
+
100
+ // -- delete ---------------------------------------------------------------------
101
+
102
+ const deleteCommand = {
103
+ command: 'delete <id>',
104
+ describe: 'Delete an Inline Data Widget config (reverts that record type to text narration)',
105
+ builder: (y) => y.positional('id', { type: 'number', describe: 'Config ID' }),
106
+ handler: runCommand(async (argv) => {
107
+ await del(`/InlineWidgetConfig/${argv.id}`);
108
+ console.log(`\nConfig #${argv.id} deleted.\n`);
109
+ }),
110
+ };
111
+
112
+ // -- root command ---------------------------------------------------------------
113
+
114
+ export const inlineWidgetConfigCommand = {
115
+ command: 'inline-widget-config <subcommand>',
116
+ describe: 'Manage per-site Inline Data Widgets config (inline chat card vs. text narration for integration record lookups)',
117
+ builder: (yargs) =>
118
+ yargs
119
+ .command(listCommand)
120
+ .command(eligibleCommand)
121
+ .command(createCommand)
122
+ .command(updateCommand)
123
+ .command(deleteCommand)
124
+ .demandCommand(1, 'Specify a subcommand: list, eligible, create, update, delete'),
125
+ handler: () => {},
126
+ };
@@ -0,0 +1,93 @@
1
+ import { messagingRequest } from '../api.js';
2
+
3
+ const RESET = '\x1b[0m';
4
+ const DIM = '\x1b[2m';
5
+ const RED = '\x1b[31m';
6
+ const YEL = '\x1b[33m';
7
+ const GRN = '\x1b[32m';
8
+ const CYN = '\x1b[36m';
9
+
10
+ function colourise(status) {
11
+ if (status === 'Healthy') return `${GRN}Healthy${RESET}`;
12
+ if (status === 'Degraded') return `${YEL}Degraded${RESET}`;
13
+ if (status === 'Failed') return `${RED}Failed${RESET}`;
14
+ if (status === 'NotConfigured') return `${DIM}NotConfigured${RESET}`;
15
+ return status ?? '?';
16
+ }
17
+
18
+ function formatRow(item) {
19
+ const ts = item.checkedAt ? new Date(item.checkedAt).toISOString().replace('T', ' ').slice(0, 19) : '-';
20
+ const ms = item.latencyMs != null ? `${item.latencyMs}ms` : '-';
21
+ const slug = (item.slug ?? '?').padEnd(14);
22
+ return ` ${CYN}${slug}${RESET} ${colourise(item.status).padEnd(20)} ${ms.padStart(7)} ${DIM}${ts}${RESET} ${item.detail ?? ''}`;
23
+ }
24
+
25
+ async function healthHandler(argv) {
26
+ const slug = argv.slug ? encodeURIComponent(argv.slug) : null;
27
+
28
+ if (argv.run) {
29
+ if (!slug) {
30
+ console.error('Error: --run requires a slug. Example: velaro integration health --slug WhatsApp --run');
31
+ process.exitCode = 1;
32
+ return;
33
+ }
34
+ const result = await messagingRequest('POST', `/Integration/Health/${slug}/run`);
35
+ console.log(`\nManual probe — ${argv.slug}\n`);
36
+ console.log(formatRow(result));
37
+ console.log('');
38
+ return;
39
+ }
40
+
41
+ if (argv.reset) {
42
+ if (!slug) {
43
+ console.error('Error: --reset requires a slug. Example: velaro integration health --slug WhatsApp --reset');
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+ const result = await messagingRequest('POST', `/Integration/Health/${slug}/reset-circuit`);
48
+ console.log(`\nCircuit reset — ${argv.slug}\n`);
49
+ console.log(formatRow(result));
50
+ console.log('');
51
+ return;
52
+ }
53
+
54
+ const path = slug ? `/Integration/Health/${slug}` : '/Integration/Health';
55
+ const data = await messagingRequest('GET', path);
56
+
57
+ if (slug) {
58
+ if (!data) {
59
+ console.log(`\nNo recorded probe for ${argv.slug}. Try: velaro integration health --slug ${argv.slug} --run\n`);
60
+ return;
61
+ }
62
+ console.log(`\nIntegration health — ${argv.slug}\n`);
63
+ console.log(formatRow(data));
64
+ console.log('');
65
+ return;
66
+ }
67
+
68
+ const items = Array.isArray(data) ? data : [];
69
+ if (items.length === 0) {
70
+ console.log('\nNo integration health results recorded yet. The scheduler runs every 15 minutes.\n');
71
+ return;
72
+ }
73
+ console.log(`\n${items.length} integration health result(s)\n`);
74
+ for (const item of items) console.log(formatRow(item));
75
+ console.log('');
76
+ }
77
+
78
+ export const integrationCommand = {
79
+ command: 'integration <subcommand>',
80
+ describe: 'Integration health probes (synthetic monitoring)',
81
+ builder: y => y
82
+ .command({
83
+ command: 'health',
84
+ describe: 'List or run integration health probes',
85
+ builder: yy => yy
86
+ .option('slug', { describe: 'Integration slug (WhatsApp, NetSuite, ...). Omit to list all.', type: 'string' })
87
+ .option('run', { describe: 'Trigger the probe now (requires --slug)', type: 'boolean', default: false })
88
+ .option('reset', { describe: 'Reset circuit breaker for (slug, site) — Velaro admin only (requires --slug)', type: 'boolean', default: false }),
89
+ handler: healthHandler,
90
+ })
91
+ .demandCommand(1, 'Specify a subcommand. Try: velaro integration health'),
92
+ handler: () => {},
93
+ };