@velaro/cli 1.4.73 → 1.4.74
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/bin/velaro.js +2 -0
- package/lib/commands/executive-insights.js +91 -0
- package/package.json +1 -1
package/bin/velaro.js
CHANGED
|
@@ -46,6 +46,7 @@ import { reportBackfillCommand } from '../lib/commands/report-backfill.js';
|
|
|
46
46
|
import { staffCommand } from '../lib/commands/staff.js';
|
|
47
47
|
import { reportExplainCommand } from '../lib/commands/report-explain.js';
|
|
48
48
|
import { conversationEfficiencyCommand } from '../lib/commands/conversation-efficiency.js';
|
|
49
|
+
import { executiveInsightsCommand } from '../lib/commands/executive-insights.js';
|
|
49
50
|
import { dbCommand } from '../lib/commands/db.js';
|
|
50
51
|
import { focusCommand } from '../lib/commands/focus.js';
|
|
51
52
|
import { triageCommand } from '../lib/commands/triage.js';
|
|
@@ -147,6 +148,7 @@ await yargs(hideBin(process.argv))
|
|
|
147
148
|
.command(bookingCommand)
|
|
148
149
|
.command(reportCommand)
|
|
149
150
|
.command(conversationEfficiencyCommand)
|
|
151
|
+
.command(executiveInsightsCommand)
|
|
150
152
|
.command(scheduleAdherenceCommand)
|
|
151
153
|
.command(experienceImpactCommand)
|
|
152
154
|
.command(reportSubscriptionCommand)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { writeFileSync } from 'node:fs';
|
|
2
|
+
import { messagingGet, messagingPost } from '../api.js';
|
|
3
|
+
import { runCommand } from '../run.js';
|
|
4
|
+
|
|
5
|
+
// -- velaro executive-insights ---------------------------------------------------
|
|
6
|
+
// CLI for the Friction Radar, the Executive Brief and the CSV data export. Endpoints live in
|
|
7
|
+
// velaro-messaging at /api/executive-insights/*; the site always comes from the login, never from
|
|
8
|
+
// CLI args. Gated on the Chat Intelligence entitlement (403 when not entitled).
|
|
9
|
+
// Scheduling reuses report subscriptions: `velaro executive-insights subscribe`.
|
|
10
|
+
|
|
11
|
+
function rangeArgs(argv) {
|
|
12
|
+
const days = Math.min(Math.max(Number(argv.days) || 7, 1), 92);
|
|
13
|
+
const to = argv.to ? new Date(argv.to) : new Date();
|
|
14
|
+
const from = argv.from ? new Date(argv.from) : new Date(to.getTime() - days * 86400000);
|
|
15
|
+
return new URLSearchParams({ from: from.toISOString(), to: to.toISOString() });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const rangeOptions = (y) => y
|
|
19
|
+
.option('days', { type: 'number', default: 7, describe: 'Look-back window in days (max 92)' })
|
|
20
|
+
.option('from', { type: 'string', describe: 'ISO start (overrides --days)' })
|
|
21
|
+
.option('to', { type: 'string', describe: 'ISO end (default now)' });
|
|
22
|
+
|
|
23
|
+
const frictionCommand = {
|
|
24
|
+
command: 'friction-radar',
|
|
25
|
+
describe: 'Topics ranked by estimated agent cost with week-over-week growth and example chats',
|
|
26
|
+
builder: (y) => rangeOptions(y).option('limit', { type: 'number', default: 20 }),
|
|
27
|
+
handler: runCommand(async (argv) => {
|
|
28
|
+
const qs = rangeArgs(argv);
|
|
29
|
+
qs.set('limit', String(argv.limit ?? 20));
|
|
30
|
+
const r = await messagingGet(`/executive-insights/friction-radar?${qs}`);
|
|
31
|
+
console.log(`Friction radar: ${r.conversationsScanned} conversations scanned${r.truncated ? ' (truncated)' : ''}`);
|
|
32
|
+
for (const t of r.topics ?? []) {
|
|
33
|
+
const growth = t.isNew ? 'new' : t.growthPct == null ? 'n/a' : `${t.growthPct}%`;
|
|
34
|
+
console.log(` #${t.costRank} ${t.topic}: ${t.volume} chats (volume rank ${t.volumeRank}, ${growth}), ${t.escalations} escalated, ${t.abandoned} abandoned, ~${Math.round(t.estimatedCostMinutes)} agent min, examples ${t.exampleConversationIds.join(', ') || '-'}`);
|
|
35
|
+
}
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const briefCommand = {
|
|
40
|
+
command: 'brief',
|
|
41
|
+
describe: 'Executive brief: volume, sentiment, QA, Experience Impact, rising keywords, top friction',
|
|
42
|
+
builder: rangeOptions,
|
|
43
|
+
handler: runCommand(async (argv) => {
|
|
44
|
+
const r = await messagingGet(`/executive-insights/brief?${rangeArgs(argv)}`);
|
|
45
|
+
console.log(JSON.stringify(r.brief, null, 2));
|
|
46
|
+
}),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const exportCommand = {
|
|
50
|
+
command: 'export',
|
|
51
|
+
describe: 'CSV of conversations with sentiment, QA score, tag, escalations, handle time and keywords',
|
|
52
|
+
builder: (y) => rangeOptions(y).option('out', { type: 'string', describe: 'Write the CSV to this file (default: stdout)' }),
|
|
53
|
+
handler: runCommand(async (argv) => {
|
|
54
|
+
const r = await messagingGet(`/executive-insights/export?${rangeArgs(argv)}`);
|
|
55
|
+
if (argv.out) {
|
|
56
|
+
writeFileSync(argv.out, r.csv, 'utf8');
|
|
57
|
+
console.log(`Wrote ${r.rows} rows to ${argv.out}${r.truncated ? ' (truncated at the row cap)' : ''}`);
|
|
58
|
+
} else {
|
|
59
|
+
process.stdout.write(r.csv);
|
|
60
|
+
}
|
|
61
|
+
}),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const subscribeCommand = {
|
|
65
|
+
command: 'subscribe <type>',
|
|
66
|
+
describe: 'Email yourself the executive-brief (Monday 7 AM site time by default) or data-export on a schedule',
|
|
67
|
+
builder: (y) => y
|
|
68
|
+
.positional('type', { choices: ['executive-brief', 'data-export'] })
|
|
69
|
+
.option('frequency', { type: 'string', default: 'weekly', choices: ['daily', 'biweekly', 'weekly', 'monthly'] })
|
|
70
|
+
.option('hour', { type: 'number', default: 7, describe: 'Site-local delivery hour 0-23' }),
|
|
71
|
+
handler: runCommand(async (argv) => {
|
|
72
|
+
await messagingPost('/report-subscriptions', {
|
|
73
|
+
reportType: argv.type,
|
|
74
|
+
frequency: argv.frequency,
|
|
75
|
+
deliveryHour: argv.hour,
|
|
76
|
+
});
|
|
77
|
+
console.log(`Subscribed to ${argv.type} (${argv.frequency}, ${argv.hour}:00 site time).`);
|
|
78
|
+
}),
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const executiveInsightsCommand = {
|
|
82
|
+
command: 'executive-insights',
|
|
83
|
+
describe: 'Friction radar, executive brief and data export (Chat Intelligence)',
|
|
84
|
+
builder: (y) => y
|
|
85
|
+
.command(frictionCommand)
|
|
86
|
+
.command(briefCommand)
|
|
87
|
+
.command(exportCommand)
|
|
88
|
+
.command(subscribeCommand)
|
|
89
|
+
.demandCommand(1, 'Specify a subcommand. Run "velaro executive-insights --help" for options.'),
|
|
90
|
+
handler: () => {},
|
|
91
|
+
};
|
package/package.json
CHANGED