@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.
- package/README.md +161 -138
- package/bin/velaro.js +177 -62
- package/lib/api.js +91 -52
- package/lib/api.test.js +46 -0
- package/lib/banner.js +76 -0
- package/lib/commands/activity.js +133 -0
- package/lib/commands/acuity.js +66 -0
- package/lib/commands/agent.js +204 -50
- package/lib/commands/ai-config.js +193 -0
- package/lib/commands/ai-models.js +159 -0
- package/lib/commands/appointments.js +198 -0
- package/lib/commands/article.js +668 -388
- package/lib/commands/automation-draft.js +134 -0
- package/lib/commands/avatar.js +75 -0
- package/lib/commands/bigcommerce.js +50 -0
- package/lib/commands/billing-contacts.js +62 -0
- package/lib/commands/billing-email-preference.js +64 -0
- package/lib/commands/billing-subscription.js +265 -0
- package/lib/commands/billing.js +138 -0
- package/lib/commands/bot.js +141 -137
- package/lib/commands/bundle.js +168 -0
- package/lib/commands/calendly.js +62 -0
- package/lib/commands/callback.js +125 -0
- package/lib/commands/callrail.js +88 -0
- package/lib/commands/campaigns.js +44 -0
- package/lib/commands/case.js +102 -0
- package/lib/commands/check.js +163 -163
- package/lib/commands/compliance.js +229 -0
- package/lib/commands/conversation-efficiency.js +178 -0
- package/lib/commands/copilotstudio.js +114 -0
- package/lib/commands/coupon-grant.js +192 -0
- package/lib/commands/db.js +101 -0
- package/lib/commands/deployment.js +107 -107
- package/lib/commands/diagnostics.js +298 -0
- package/lib/commands/email-campaign.js +47 -0
- package/lib/commands/email-inbox.js +88 -0
- package/lib/commands/entitlement.js +176 -0
- package/lib/commands/env.js +45 -45
- package/lib/commands/feature-discovery.js +40 -0
- package/lib/commands/focus.js +278 -0
- package/lib/commands/index.js +38 -5
- package/lib/commands/ingest.js +31 -31
- package/lib/commands/inline-widget-config.js +126 -0
- package/lib/commands/integration.js +93 -0
- package/lib/commands/kb.js +450 -309
- package/lib/commands/login.js +86 -86
- package/lib/commands/logs.js +680 -0
- package/lib/commands/magento.js +210 -0
- package/lib/commands/mcp-key.js +188 -159
- package/lib/commands/migrate.js +134 -0
- package/lib/commands/migration-status.js +66 -0
- package/lib/commands/monday.js +137 -0
- package/lib/commands/netsuite.js +87 -0
- package/lib/commands/notifications.js +63 -0
- package/lib/commands/notion.js +70 -0
- package/lib/commands/ops.js +267 -173
- package/lib/commands/payment-recovery.js +170 -0
- package/lib/commands/pickup.js +172 -0
- package/lib/commands/pricing.js +132 -0
- package/lib/commands/product.js +55 -0
- package/lib/commands/recruiting.js +374 -0
- package/lib/commands/report.js +462 -0
- package/lib/commands/routing.js +304 -0
- package/lib/commands/rule.js +85 -85
- package/lib/commands/sharepoint.js +167 -0
- package/lib/commands/site-provision.js +68 -0
- package/lib/commands/site.js +62 -62
- package/lib/commands/sitesync.js +158 -0
- package/lib/commands/slack.js +64 -0
- package/lib/commands/squarespace.js +108 -0
- package/lib/commands/status.js +24 -24
- package/lib/commands/subscription.js +43 -0
- package/lib/commands/support.js +128 -0
- package/lib/commands/survey.js +216 -0
- package/lib/commands/team.js +144 -144
- package/lib/commands/teams-phone.js +131 -0
- package/lib/commands/teams.js +106 -0
- package/lib/commands/telephony.js +99 -0
- package/lib/commands/update.js +47 -47
- package/lib/commands/webflow.js +128 -0
- package/lib/commands/whoami.js +25 -22
- package/lib/commands/widget-container.js +152 -0
- package/lib/commands/woocommerce.js +240 -0
- package/lib/commands/workflow.js +233 -98
- package/lib/config.js +85 -83
- package/lib/kb-screenshot.js +320 -0
- package/lib/migrations/amscro.json +72 -0
- package/lib/migrations/azenta.json +68 -0
- package/lib/migrations/bluefire.json +49 -0
- package/lib/migrations/donaldson.json +75 -0
- package/lib/oauth.js +149 -135
- package/lib/run.js +21 -16
- package/lib/sharepoint-auth.js +138 -0
- package/lib/subscription.js +41 -39
- package/lib/track.js +35 -35
- package/lib/update-check.js +64 -64
- package/package.json +34 -19
- package/scripts/postinstall.js +12 -0
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
const DIM = '\x1b[2m';
|
|
9
|
+
|
|
10
|
+
function formatContainer(c) {
|
|
11
|
+
const enabled = c.isEnabled ? `${GRN}enabled${RESET}` : `${YEL}disabled${RESET}`;
|
|
12
|
+
const widgets = (c.widgetIds ?? []).length;
|
|
13
|
+
return ` #${c.id} | ${CYN}${c.name}${RESET} | style:${c.style} | pos:${c.position} | widgets:${widgets} | ${enabled}\n` +
|
|
14
|
+
` ${DIM}containerId: ${c.containerId}${RESET}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// ── list ─────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
const listCommand = {
|
|
20
|
+
command: 'list',
|
|
21
|
+
describe: 'List all widget containers for this site',
|
|
22
|
+
builder: (y) => y,
|
|
23
|
+
handler: runCommand(async () => {
|
|
24
|
+
const data = await get('/PageWidgetContainers');
|
|
25
|
+
const containers = Array.isArray(data) ? data : [];
|
|
26
|
+
if (!containers.length) {
|
|
27
|
+
console.log('\nNo widget containers configured.\n');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log(`\nWidget Containers (${containers.length})\n`);
|
|
31
|
+
for (const c of containers) console.log(formatContainer(c));
|
|
32
|
+
console.log('');
|
|
33
|
+
}),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// ── create ───────────────────────────────────────────────────────────────────
|
|
37
|
+
|
|
38
|
+
const createCommand = {
|
|
39
|
+
command: 'create',
|
|
40
|
+
describe: 'Create a new widget container',
|
|
41
|
+
builder: (y) =>
|
|
42
|
+
y
|
|
43
|
+
.option('name', { type: 'string', describe: 'Container name', demandOption: true })
|
|
44
|
+
.option('style', { type: 'string', describe: 'drawer | cluster | tabs', demandOption: true,
|
|
45
|
+
choices: ['drawer', 'cluster', 'tabs'] })
|
|
46
|
+
.option('position', { type: 'string', describe: 'Position, e.g. bottom-right', default: 'bottom-right' })
|
|
47
|
+
.option('color', { type: 'string', describe: 'Primary hex color, e.g. #2563eb', default: '#2563eb' }),
|
|
48
|
+
handler: runCommand(async (argv) => {
|
|
49
|
+
const c = await post('/PageWidgetContainers', {
|
|
50
|
+
name: argv.name,
|
|
51
|
+
style: argv.style,
|
|
52
|
+
position: argv.position,
|
|
53
|
+
primaryColor: argv.color,
|
|
54
|
+
widgetIds: [],
|
|
55
|
+
isEnabled: true,
|
|
56
|
+
});
|
|
57
|
+
console.log(`\nCreated container "${c.name}" (id:${c.id})`);
|
|
58
|
+
console.log(` containerId: ${c.containerId}`);
|
|
59
|
+
console.log(`\nEmbed snippet:`);
|
|
60
|
+
console.log(` <script>`);
|
|
61
|
+
console.log(` window.__velaro_pw_container = { siteId: "YOUR_SITE_ID", containerId: "${c.containerId}" };`);
|
|
62
|
+
console.log(` </script>`);
|
|
63
|
+
console.log(` <script src="https://messaging.velaro.com/widget.js" async></script>\n`);
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// ── update ───────────────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
const updateCommand = {
|
|
70
|
+
command: 'update <id>',
|
|
71
|
+
describe: 'Update an existing widget container',
|
|
72
|
+
builder: (y) =>
|
|
73
|
+
y
|
|
74
|
+
.positional('id', { type: 'number', describe: 'Container ID' })
|
|
75
|
+
.option('name', { type: 'string' })
|
|
76
|
+
.option('style', { type: 'string', choices: ['drawer', 'cluster', 'tabs'] })
|
|
77
|
+
.option('position', { type: 'string' })
|
|
78
|
+
.option('color', { type: 'string', describe: 'Primary hex color' })
|
|
79
|
+
.option('enable', { type: 'boolean', describe: 'Enable the container' })
|
|
80
|
+
.option('disable', { type: 'boolean', describe: 'Disable the container' })
|
|
81
|
+
.option('widgets', { type: 'string', describe: 'Comma-separated widgetId UUIDs (replaces current list)' }),
|
|
82
|
+
handler: runCommand(async (argv) => {
|
|
83
|
+
const body = {};
|
|
84
|
+
if (argv.name) body.name = argv.name;
|
|
85
|
+
if (argv.style) body.style = argv.style;
|
|
86
|
+
if (argv.position) body.position = argv.position;
|
|
87
|
+
if (argv.color) body.primaryColor = argv.color;
|
|
88
|
+
if (argv.enable) body.isEnabled = true;
|
|
89
|
+
if (argv.disable) body.isEnabled = false;
|
|
90
|
+
if (argv.widgets) body.widgetIds = argv.widgets.split(',').map(s => s.trim()).filter(Boolean);
|
|
91
|
+
|
|
92
|
+
if (!Object.keys(body).length) {
|
|
93
|
+
console.error('No fields to update. Pass at least one option.');
|
|
94
|
+
process.exitCode = 1;
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const c = await request('PUT', `/PageWidgetContainers/${argv.id}`, body);
|
|
99
|
+
console.log(`\nUpdated container "${c.name}" (id:${c.id})\n`);
|
|
100
|
+
console.log(formatContainer(c));
|
|
101
|
+
console.log('');
|
|
102
|
+
}),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// ── delete ───────────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
const deleteCommand = {
|
|
108
|
+
command: 'delete <id>',
|
|
109
|
+
describe: 'Soft-delete a widget container',
|
|
110
|
+
builder: (y) => y.positional('id', { type: 'number', describe: 'Container ID' }),
|
|
111
|
+
handler: runCommand(async (argv) => {
|
|
112
|
+
await del(`/PageWidgetContainers/${argv.id}`);
|
|
113
|
+
console.log(`\nContainer #${argv.id} deleted.\n`);
|
|
114
|
+
}),
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// ── embed ─────────────────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
const embedCommand = {
|
|
120
|
+
command: 'embed <id>',
|
|
121
|
+
describe: 'Print the embed snippet for a container',
|
|
122
|
+
builder: (y) => y.positional('id', { type: 'number', describe: 'Container ID' }),
|
|
123
|
+
handler: runCommand(async (argv) => {
|
|
124
|
+
const c = await get(`/PageWidgetContainers/${argv.id}`);
|
|
125
|
+
console.log(`\nEmbed snippet for "${c.name}" (containerId: ${c.containerId}):\n`);
|
|
126
|
+
console.log(`<script>`);
|
|
127
|
+
console.log(` window.__velaro_pw_container = {`);
|
|
128
|
+
console.log(` siteId: "YOUR_SITE_ID",`);
|
|
129
|
+
console.log(` containerId: "${c.containerId}"`);
|
|
130
|
+
console.log(` };`);
|
|
131
|
+
console.log(`</script>`);
|
|
132
|
+
console.log(`<script src="https://messaging.velaro.com/widget.js" async></script>\n`);
|
|
133
|
+
console.log(`Widgets in container (${(c.widgetIds || []).length}): ${(c.widgetIds || []).join(', ') || 'none'}`);
|
|
134
|
+
console.log('');
|
|
135
|
+
}),
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// ── root command ──────────────────────────────────────────────────────────────
|
|
139
|
+
|
|
140
|
+
export const widgetContainerCommand = {
|
|
141
|
+
command: 'widget-container <subcommand>',
|
|
142
|
+
describe: 'Manage page widget containers (group multiple widgets into a drawer, cluster, or tab strip)',
|
|
143
|
+
builder: (yargs) =>
|
|
144
|
+
yargs
|
|
145
|
+
.command(listCommand)
|
|
146
|
+
.command(createCommand)
|
|
147
|
+
.command(updateCommand)
|
|
148
|
+
.command(deleteCommand)
|
|
149
|
+
.command(embedCommand)
|
|
150
|
+
.demandCommand(1, 'Specify a subcommand: list, create, update, delete, embed'),
|
|
151
|
+
handler: () => {},
|
|
152
|
+
};
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* velaro woocommerce — WooCommerce store management
|
|
3
|
+
*
|
|
4
|
+
* velaro woocommerce status Show connection status for the current site
|
|
5
|
+
* velaro woocommerce connect <storeUrl> Start the WooCommerce store connection flow
|
|
6
|
+
* velaro woocommerce disconnect Disconnect the WooCommerce store
|
|
7
|
+
* velaro woocommerce skills List available WooCommerce AI skills
|
|
8
|
+
* velaro woocommerce orders Search orders by email or order ID
|
|
9
|
+
* velaro woocommerce products Search the product catalog
|
|
10
|
+
* velaro woocommerce logs View integration activity logs
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { request } from '../api.js';
|
|
14
|
+
|
|
15
|
+
const GRN = '\x1b[32m';
|
|
16
|
+
const RED = '\x1b[31m';
|
|
17
|
+
const CYN = '\x1b[36m';
|
|
18
|
+
const YLW = '\x1b[33m';
|
|
19
|
+
const DIM = '\x1b[2m';
|
|
20
|
+
const BOLD = '\x1b[1m';
|
|
21
|
+
const RST = '\x1b[0m';
|
|
22
|
+
|
|
23
|
+
// ── status ────────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
async function statusHandler(_argv) {
|
|
26
|
+
// /WooCommerce/billing/status resolves site from the JWT — no siteId param needed.
|
|
27
|
+
// Returns: billingStatus, planName, oauthConnected, hasActiveSubscription.
|
|
28
|
+
const r = await request('GET', `/WooCommerce/billing/status`);
|
|
29
|
+
if (!r) {
|
|
30
|
+
console.log('\nNo WooCommerce connection found for this site.\n');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const connected = r.oauthConnected ?? r.hasActiveSubscription ?? false;
|
|
34
|
+
const statusLabel = connected ? `${GRN}connected${RST}` : `${RED}not connected${RST}`;
|
|
35
|
+
console.log(`\n${BOLD}WooCommerce Status${RST}\n`);
|
|
36
|
+
console.log(` Status: ${statusLabel}`);
|
|
37
|
+
if (r.planName) console.log(` Plan: ${r.planName}`);
|
|
38
|
+
if (r.billingStatus) console.log(` Billing: ${r.billingStatus}`);
|
|
39
|
+
if (r.oauthConnectedAt) console.log(` OAuth Connected:${DIM}${new Date(r.oauthConnectedAt).toLocaleString()}${RST}`);
|
|
40
|
+
console.log('');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ── connect ───────────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
async function connectHandler(argv) {
|
|
46
|
+
if (!argv.storeUrl) {
|
|
47
|
+
console.error(`${RED}✗ <storeUrl> is required (e.g. velaro woocommerce connect https://mystore.com)${RST}`);
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const r = await request('GET', `/WooCommerce/auth/start?storeUrl=${encodeURIComponent(argv.storeUrl)}`);
|
|
53
|
+
if (!r?.authUrl) {
|
|
54
|
+
console.error(`${RED}✗ Server did not return an authUrl — check that the store URL is correct${RST}`);
|
|
55
|
+
process.exitCode = 1;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
console.log(`\n${BOLD}WooCommerce Connection Flow${RST}\n`);
|
|
59
|
+
console.log(` Visit this URL in your browser to authorize Velaro:\n`);
|
|
60
|
+
console.log(` ${CYN}${r.authUrl}${RST}\n`);
|
|
61
|
+
console.log(` ${DIM}WooCommerce will redirect back to Velaro after approval.${RST}\n`);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.error(`\n${RED}✗ Failed to start connection: ${e.message}${RST}\n`);
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ── disconnect ────────────────────────────────────────────────────────────────
|
|
69
|
+
|
|
70
|
+
async function disconnectHandler(argv) {
|
|
71
|
+
const params = argv.site ? `?siteId=${argv.site}` : '';
|
|
72
|
+
try {
|
|
73
|
+
await request('POST', `/WooCommerce/auth/disconnect${params}`, {});
|
|
74
|
+
console.log(`\n${GRN}✓ WooCommerce store disconnected${RST}\n`);
|
|
75
|
+
} catch (e) {
|
|
76
|
+
console.error(`\n${RED}✗ Disconnect failed: ${e.message}${RST}\n`);
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ── skills ────────────────────────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
async function skillsHandler(argv) {
|
|
84
|
+
const params = argv.site ? `?siteId=${argv.site}` : '';
|
|
85
|
+
const data = await request('GET', `/AI/Skills${params}`);
|
|
86
|
+
const skills = Array.isArray(data) ? data : (data?.skills ?? []);
|
|
87
|
+
const wooSkills = skills.filter(s => s.category === 'WooCommerce');
|
|
88
|
+
if (wooSkills.length === 0) {
|
|
89
|
+
console.log(`\n${YLW}No WooCommerce skills available for this site.${RST}`);
|
|
90
|
+
console.log(`${DIM}Enable in SuperAdmin → Subscription: EnableWooCommerce (core/read), EnableWooCommerceWrite (write tier), EnableDestructiveAiSkills (cancel/refund/coupon).${RST}\n`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
console.log(`\n${BOLD}${wooSkills.length} WooCommerce AI skill(s)${RST}\n`);
|
|
94
|
+
for (const s of wooSkills) {
|
|
95
|
+
const tier = s.tier ? ` ${DIM}[${s.tier}]${RST}` : '';
|
|
96
|
+
const gate = s.subscriptionFlag ? ` ${DIM}(${s.subscriptionFlag})${RST}` : '';
|
|
97
|
+
console.log(` ${BOLD}${s.toolName ?? s.name}${RST}${tier}${gate}`);
|
|
98
|
+
if (s.displayName && s.displayName !== s.toolName) console.log(` ${DIM}${s.displayName}${RST}`);
|
|
99
|
+
}
|
|
100
|
+
console.log('');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ── orders ────────────────────────────────────────────────────────────────────
|
|
104
|
+
|
|
105
|
+
async function ordersHandler(argv) {
|
|
106
|
+
if (!argv.email && !argv.id) {
|
|
107
|
+
console.error(`${RED}✗ --email or --id is required${RST}`);
|
|
108
|
+
process.exitCode = 1;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const q = argv.id ?? argv.email;
|
|
112
|
+
const limit = Math.min(50, argv.limit ?? 10);
|
|
113
|
+
const orders = await request('GET', `/WooCommerce/data/orders/search?q=${encodeURIComponent(q)}&limit=${limit}`);
|
|
114
|
+
if (!Array.isArray(orders) || orders.length === 0) {
|
|
115
|
+
console.log(`\nNo orders found for "${q}".\n`);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
console.log(`\n${BOLD}${orders.length} order(s)${RST}\n`);
|
|
119
|
+
for (const o of orders) {
|
|
120
|
+
const date = (o.dateCreated ?? o.date_created ?? '').slice(0, 10);
|
|
121
|
+
const total = o.total ?? o.grandTotal ?? '0.00';
|
|
122
|
+
const status = o.status ?? 'unknown';
|
|
123
|
+
console.log(` [#${o.id ?? o.orderId}] ${status.padEnd(14)} $${String(total).padStart(9)} ${DIM}${date}${RST}`);
|
|
124
|
+
if (argv.verbose && o.billingEmail) console.log(` ${DIM}${o.billingEmail}${RST}`);
|
|
125
|
+
}
|
|
126
|
+
console.log('');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ── products ──────────────────────────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
async function productsHandler(argv) {
|
|
132
|
+
if (!argv.query) {
|
|
133
|
+
console.error(`${RED}✗ --query is required${RST}`);
|
|
134
|
+
process.exitCode = 1;
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const limit = Math.min(50, argv.limit ?? 10);
|
|
138
|
+
const products = await request('GET', `/WooCommerce/data/products?search=${encodeURIComponent(argv.query)}&limit=${limit}`);
|
|
139
|
+
if (!Array.isArray(products) || products.length === 0) {
|
|
140
|
+
console.log(`\nNo products found for "${argv.query}".\n`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
console.log(`\n${BOLD}${products.length} product(s)${RST}\n`);
|
|
144
|
+
for (const p of products) {
|
|
145
|
+
const stock = p.stockStatus === 'instock' ? `${GRN}in stock${RST}` : `${RED}${p.stockStatus ?? 'unknown'}${RST}`;
|
|
146
|
+
console.log(` [${p.sku ?? p.id}] ${BOLD}${p.name}${RST} $${p.price} ${stock}`);
|
|
147
|
+
if (p.permalink) console.log(` ${DIM}${p.permalink}${RST}`);
|
|
148
|
+
}
|
|
149
|
+
console.log('');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ── logs ──────────────────────────────────────────────────────────────────────
|
|
153
|
+
|
|
154
|
+
async function logsHandler(argv) {
|
|
155
|
+
const params = new URLSearchParams();
|
|
156
|
+
if (argv.severity) params.set('severity', argv.severity);
|
|
157
|
+
if (argv.search) params.set('search', argv.search);
|
|
158
|
+
params.set('pageSize', String(Math.min(100, argv.pageSize ?? 25)));
|
|
159
|
+
const data = await request('GET', `/Integration/Logs/WooCommerce?${params}`);
|
|
160
|
+
const items = data?.items ?? [];
|
|
161
|
+
if (items.length === 0) {
|
|
162
|
+
console.log('\nNo WooCommerce activity log entries found.\n');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
console.log(`\n${BOLD}${items.length} of ${data.total} WooCommerce activity entries${RST}\n`);
|
|
166
|
+
for (const item of items) {
|
|
167
|
+
const ts = new Date(item.createdAt).toISOString().replace('T', ' ').slice(0, 19);
|
|
168
|
+
const sev = item.severity === 'Error' ? `${RED}${item.severity}${RST} ` :
|
|
169
|
+
item.severity === 'Warning' ? `${YLW}${item.severity}${RST}` :
|
|
170
|
+
`${DIM}${item.severity}${RST} `;
|
|
171
|
+
console.log(` ${DIM}${ts}${RST} ${sev} [${item.category ?? '?'}] ${item.message ?? ''}`);
|
|
172
|
+
if (item.additionalInfo) console.log(` ${DIM}${item.additionalInfo}${RST}`);
|
|
173
|
+
}
|
|
174
|
+
if (data.total > items.length) console.log(`\n ${DIM}${data.total - items.length} more — use --page-size to see more${RST}`);
|
|
175
|
+
console.log('');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ── command export ────────────────────────────────────────────────────────────
|
|
179
|
+
|
|
180
|
+
export const woocommerceCommand = {
|
|
181
|
+
command: 'woocommerce <subcommand>',
|
|
182
|
+
describe: 'WooCommerce store management',
|
|
183
|
+
builder: y => y
|
|
184
|
+
.command({
|
|
185
|
+
command: 'status',
|
|
186
|
+
describe: 'Show WooCommerce connection status for the current site',
|
|
187
|
+
builder: yy => yy,
|
|
188
|
+
handler: statusHandler,
|
|
189
|
+
})
|
|
190
|
+
.command({
|
|
191
|
+
command: 'connect <storeUrl>',
|
|
192
|
+
describe: 'Start the WooCommerce store connection flow',
|
|
193
|
+
builder: yy => yy
|
|
194
|
+
.positional('storeUrl', { describe: 'WooCommerce store URL (e.g. https://mystore.com)', type: 'string' }),
|
|
195
|
+
handler: connectHandler,
|
|
196
|
+
})
|
|
197
|
+
.command({
|
|
198
|
+
command: 'disconnect',
|
|
199
|
+
describe: 'Disconnect the WooCommerce store',
|
|
200
|
+
builder: yy => yy
|
|
201
|
+
.option('site', { describe: 'Site ID (optional)', type: 'number' }),
|
|
202
|
+
handler: disconnectHandler,
|
|
203
|
+
})
|
|
204
|
+
.command({
|
|
205
|
+
command: 'skills',
|
|
206
|
+
describe: 'List available WooCommerce AI skills for this site',
|
|
207
|
+
builder: yy => yy
|
|
208
|
+
.option('site', { describe: 'Site ID (optional)', type: 'number' }),
|
|
209
|
+
handler: skillsHandler,
|
|
210
|
+
})
|
|
211
|
+
.command({
|
|
212
|
+
command: 'orders',
|
|
213
|
+
describe: 'Search WooCommerce orders by email or order ID',
|
|
214
|
+
builder: yy => yy
|
|
215
|
+
.option('email', { describe: 'Customer email address', type: 'string' })
|
|
216
|
+
.option('id', { describe: 'Order ID', type: 'number' })
|
|
217
|
+
.option('limit', { describe: 'Max results (default 10)', type: 'number', default: 10 })
|
|
218
|
+
.option('verbose', { describe: 'Show additional fields', type: 'boolean', default: false }),
|
|
219
|
+
handler: ordersHandler,
|
|
220
|
+
})
|
|
221
|
+
.command({
|
|
222
|
+
command: 'products',
|
|
223
|
+
describe: 'Search the WooCommerce product catalog',
|
|
224
|
+
builder: yy => yy
|
|
225
|
+
.option('query', { describe: 'Search term', type: 'string' })
|
|
226
|
+
.option('limit', { describe: 'Max results (default 10)', type: 'number', default: 10 }),
|
|
227
|
+
handler: productsHandler,
|
|
228
|
+
})
|
|
229
|
+
.command({
|
|
230
|
+
command: 'logs',
|
|
231
|
+
describe: 'View WooCommerce integration activity logs',
|
|
232
|
+
builder: yy => yy
|
|
233
|
+
.option('severity', { describe: 'Filter by severity (Error, Warning, Info)', type: 'string' })
|
|
234
|
+
.option('search', { describe: 'Search within log messages', type: 'string' })
|
|
235
|
+
.option('page-size', { describe: 'Number of entries to return (max 100)', type: 'number', default: 25 }),
|
|
236
|
+
handler: logsHandler,
|
|
237
|
+
})
|
|
238
|
+
.demandCommand(1, 'Specify a subcommand. Run "velaro woocommerce --help" for options.'),
|
|
239
|
+
handler: () => {},
|
|
240
|
+
};
|