@agent-analytics/cli 0.1.8 → 0.1.9
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 +5 -0
- package/bin/cli.mjs +184 -5
- package/lib/api.mjs +32 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -34,6 +34,11 @@ npx @agent-analytics/cli stats <name> # Stats (last 7 days)
|
|
|
34
34
|
npx @agent-analytics/cli stats <name> --days 30 # Stats (last 30 days)
|
|
35
35
|
npx @agent-analytics/cli events <name> # Recent events
|
|
36
36
|
npx @agent-analytics/cli properties-received <name> # Property keys per event
|
|
37
|
+
npx @agent-analytics/cli insights <name> # Period-over-period comparison (--period 7d)
|
|
38
|
+
npx @agent-analytics/cli breakdown <name> --property path # Top values for a property
|
|
39
|
+
npx @agent-analytics/cli pages <name> # Landing page performance (--type entry|exit|both)
|
|
40
|
+
npx @agent-analytics/cli sessions-dist <name> # Session duration histogram
|
|
41
|
+
npx @agent-analytics/cli heatmap <name> # Peak hours & busiest days
|
|
37
42
|
|
|
38
43
|
# Security
|
|
39
44
|
npx @agent-analytics/cli revoke-key # Revoke and regenerate API key
|
package/bin/cli.mjs
CHANGED
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
* npx @agent-analytics/cli stats <name> — Get stats for a project
|
|
11
11
|
* npx @agent-analytics/cli events <name> — Get recent events
|
|
12
12
|
* npx @agent-analytics/cli properties-received <name> — Show property keys per event
|
|
13
|
+
* npx @agent-analytics/cli insights <name> — Period-over-period comparison
|
|
14
|
+
* npx @agent-analytics/cli breakdown <name> — Property value distribution
|
|
15
|
+
* npx @agent-analytics/cli pages <name> — Entry/exit page stats
|
|
16
|
+
* npx @agent-analytics/cli sessions-dist <name> — Session duration distribution
|
|
17
|
+
* npx @agent-analytics/cli heatmap <name> — Peak hours & busiest days
|
|
13
18
|
* npx @agent-analytics/cli init <name> — Alias for create
|
|
14
19
|
* npx @agent-analytics/cli delete <id> — Delete a project
|
|
15
20
|
* npx @agent-analytics/cli revoke-key — Revoke and regenerate API key
|
|
@@ -257,6 +262,151 @@ async function cmdPropertiesReceived(project, opts = {}) {
|
|
|
257
262
|
}
|
|
258
263
|
}
|
|
259
264
|
|
|
265
|
+
async function cmdInsights(project, period = '7d') {
|
|
266
|
+
if (!project) error('Usage: npx @agent-analytics/cli insights <project-name> [--period 7d]');
|
|
267
|
+
|
|
268
|
+
const api = requireKey();
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
const data = await api.getInsights(project, { period });
|
|
272
|
+
|
|
273
|
+
heading(`Insights: ${project} (${period} vs previous)`);
|
|
274
|
+
log('');
|
|
275
|
+
|
|
276
|
+
const m = data.metrics;
|
|
277
|
+
for (const [key, metric] of Object.entries(m)) {
|
|
278
|
+
const label = key.replace(/_/g, ' ');
|
|
279
|
+
const arrow = metric.change > 0 ? `${GREEN}↑` : metric.change < 0 ? `${RED}↓` : `${DIM}—`;
|
|
280
|
+
const pct = metric.change_pct !== null ? ` (${metric.change_pct > 0 ? '+' : ''}${metric.change_pct}%)` : '';
|
|
281
|
+
log(` ${BOLD}${label}:${RESET} ${metric.current} ${arrow}${pct}${RESET} ${DIM}was ${metric.previous}${RESET}`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
log('');
|
|
285
|
+
log(` ${BOLD}Trend:${RESET} ${data.trend}`);
|
|
286
|
+
log('');
|
|
287
|
+
} catch (err) {
|
|
288
|
+
error(`Failed to get insights: ${err.message}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async function cmdBreakdown(project, property, opts = {}) {
|
|
293
|
+
if (!project || !property) error('Usage: npx @agent-analytics/cli breakdown <project-name> --property <key> [--event page_view] [--limit 20]');
|
|
294
|
+
|
|
295
|
+
const api = requireKey();
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
const data = await api.getBreakdown(project, { property, ...opts });
|
|
299
|
+
|
|
300
|
+
heading(`Breakdown: ${project} — ${property}${data.event ? ` (${data.event})` : ''}`);
|
|
301
|
+
log('');
|
|
302
|
+
|
|
303
|
+
if (!data.values || data.values.length === 0) {
|
|
304
|
+
log(' No data found.');
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
for (const v of data.values) {
|
|
309
|
+
log(` ${BOLD}${v.value}${RESET} ${v.count} events ${DIM}(${v.unique_users} users)${RESET}`);
|
|
310
|
+
}
|
|
311
|
+
log(`\n${DIM}${data.total_with_property} of ${data.total_events} events have this property${RESET}`);
|
|
312
|
+
log('');
|
|
313
|
+
} catch (err) {
|
|
314
|
+
error(`Failed to get breakdown: ${err.message}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
async function cmdPages(project, type = 'entry', opts = {}) {
|
|
319
|
+
if (!project) error('Usage: npx @agent-analytics/cli pages <project-name> [--type entry|exit|both] [--limit 20]');
|
|
320
|
+
|
|
321
|
+
const api = requireKey();
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
const data = await api.getPages(project, { type, ...opts });
|
|
325
|
+
|
|
326
|
+
heading(`Pages: ${project} (${type})`);
|
|
327
|
+
log('');
|
|
328
|
+
|
|
329
|
+
const pages = data.entry_pages || data.exit_pages || [];
|
|
330
|
+
if (pages.length === 0) {
|
|
331
|
+
log(' No page data found.');
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
for (const p of pages) {
|
|
336
|
+
const bounceStr = `${Math.round(p.bounce_rate * 100)}% bounce`;
|
|
337
|
+
const durStr = `${Math.round(p.avg_duration / 1000)}s avg`;
|
|
338
|
+
log(` ${BOLD}${p.page}${RESET} ${p.sessions} sessions ${DIM}${bounceStr} ${durStr} ${p.avg_events} events/session${RESET}`);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (data.exit_pages && data.entry_pages) {
|
|
342
|
+
log('');
|
|
343
|
+
heading('Exit pages:');
|
|
344
|
+
for (const p of data.exit_pages) {
|
|
345
|
+
log(` ${BOLD}${p.page}${RESET} ${p.sessions} sessions`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
log('');
|
|
349
|
+
} catch (err) {
|
|
350
|
+
error(`Failed to get pages: ${err.message}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async function cmdSessionsDist(project) {
|
|
355
|
+
if (!project) error('Usage: npx @agent-analytics/cli sessions-dist <project-name>');
|
|
356
|
+
|
|
357
|
+
const api = requireKey();
|
|
358
|
+
|
|
359
|
+
try {
|
|
360
|
+
const data = await api.getSessionDistribution(project);
|
|
361
|
+
|
|
362
|
+
heading(`Session Distribution: ${project}`);
|
|
363
|
+
log('');
|
|
364
|
+
|
|
365
|
+
if (!data.distribution || data.distribution.length === 0) {
|
|
366
|
+
log(' No session data found.');
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
for (const b of data.distribution) {
|
|
371
|
+
const bar = '█'.repeat(Math.min(Math.ceil(b.pct / 2), 40));
|
|
372
|
+
log(` ${b.bucket.padEnd(7)} ${GREEN}${bar}${RESET} ${b.sessions} (${b.pct}%)`);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
log('');
|
|
376
|
+
log(` ${BOLD}Median:${RESET} ${data.median_bucket} ${BOLD}Engaged:${RESET} ${data.engaged_pct}% (sessions ≥30s)`);
|
|
377
|
+
log('');
|
|
378
|
+
} catch (err) {
|
|
379
|
+
error(`Failed to get session distribution: ${err.message}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
async function cmdHeatmap(project) {
|
|
384
|
+
if (!project) error('Usage: npx @agent-analytics/cli heatmap <project-name>');
|
|
385
|
+
|
|
386
|
+
const api = requireKey();
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
const data = await api.getHeatmap(project);
|
|
390
|
+
|
|
391
|
+
heading(`Heatmap: ${project}`);
|
|
392
|
+
log('');
|
|
393
|
+
|
|
394
|
+
if (!data.heatmap || data.heatmap.length === 0) {
|
|
395
|
+
log(' No heatmap data found.');
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (data.peak) {
|
|
400
|
+
log(` ${BOLD}Peak:${RESET} ${data.peak.day_name} at ${data.peak.hour}:00 (${data.peak.events} events, ${data.peak.users} users)`);
|
|
401
|
+
}
|
|
402
|
+
log(` ${BOLD}Busiest day:${RESET} ${data.busiest_day}`);
|
|
403
|
+
log(` ${BOLD}Busiest hour:${RESET} ${data.busiest_hour}:00`);
|
|
404
|
+
log('');
|
|
405
|
+
} catch (err) {
|
|
406
|
+
error(`Failed to get heatmap: ${err.message}`);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
260
410
|
async function cmdDelete(id) {
|
|
261
411
|
if (!id) error('Usage: npx @agent-analytics/cli delete <project-id>');
|
|
262
412
|
|
|
@@ -331,16 +481,25 @@ ${BOLD}COMMANDS${RESET}
|
|
|
331
481
|
${CYAN}stats${RESET} <name> Get stats for a project
|
|
332
482
|
${CYAN}events${RESET} <name> Get recent events
|
|
333
483
|
${CYAN}properties-received${RESET} <name> Show property keys per event
|
|
484
|
+
${CYAN}insights${RESET} <name> Period-over-period comparison
|
|
485
|
+
${CYAN}breakdown${RESET} <name> Property value distribution
|
|
486
|
+
${CYAN}pages${RESET} <name> Entry/exit page performance
|
|
487
|
+
${CYAN}sessions-dist${RESET} <name> Session duration distribution
|
|
488
|
+
${CYAN}heatmap${RESET} <name> Peak hours & busiest days
|
|
334
489
|
${CYAN}whoami${RESET} Show current account
|
|
335
490
|
${CYAN}revoke-key${RESET} Revoke and regenerate API key
|
|
336
491
|
${CYAN}delete-account${RESET} Delete your account (opens dashboard)
|
|
337
492
|
|
|
338
493
|
${BOLD}OPTIONS${RESET}
|
|
339
494
|
--days <N> Days of data (default: 7)
|
|
340
|
-
--limit <N> Max events to return (default: 100)
|
|
495
|
+
--limit <N> Max events/rows to return (default: 100)
|
|
341
496
|
--domain <url> Your site domain (required for create)
|
|
342
497
|
--since <date> ISO date for properties-received (default: 7 days)
|
|
343
498
|
--sample <N> Max events to sample (default: 5000)
|
|
499
|
+
--period <P> Period for insights: 1d, 7d, 14d, 30d, 90d (default: 7d)
|
|
500
|
+
--property <key> Property key for breakdown (required)
|
|
501
|
+
--event <name> Filter by event name (breakdown only)
|
|
502
|
+
--type <T> Page type: entry, exit, both (default: entry)
|
|
344
503
|
|
|
345
504
|
${BOLD}ENVIRONMENT${RESET}
|
|
346
505
|
AGENT_ANALYTICS_API_KEY API key (overrides config file)
|
|
@@ -388,20 +547,40 @@ try {
|
|
|
388
547
|
await cmdProjects();
|
|
389
548
|
break;
|
|
390
549
|
case 'stats':
|
|
391
|
-
await cmdStats(args[1], parseInt(getArg('--days') || '7'));
|
|
550
|
+
await cmdStats(args[1], parseInt(getArg('--days') || '7', 10));
|
|
392
551
|
break;
|
|
393
552
|
case 'events':
|
|
394
553
|
await cmdEvents(args[1], {
|
|
395
|
-
days: parseInt(getArg('--days') || '7'),
|
|
396
|
-
limit: parseInt(getArg('--limit') || '100'),
|
|
554
|
+
days: parseInt(getArg('--days') || '7', 10),
|
|
555
|
+
limit: parseInt(getArg('--limit') || '100', 10),
|
|
397
556
|
});
|
|
398
557
|
break;
|
|
399
558
|
case 'properties-received':
|
|
400
559
|
await cmdPropertiesReceived(args[1], {
|
|
401
560
|
since: getArg('--since'),
|
|
402
|
-
sample: getArg('--sample') ? parseInt(getArg('--sample')) : undefined,
|
|
561
|
+
sample: getArg('--sample') ? parseInt(getArg('--sample'), 10) : undefined,
|
|
403
562
|
});
|
|
404
563
|
break;
|
|
564
|
+
case 'insights':
|
|
565
|
+
await cmdInsights(args[1], getArg('--period') || '7d');
|
|
566
|
+
break;
|
|
567
|
+
case 'breakdown':
|
|
568
|
+
await cmdBreakdown(args[1], getArg('--property'), {
|
|
569
|
+
event: getArg('--event'),
|
|
570
|
+
limit: getArg('--limit') ? parseInt(getArg('--limit'), 10) : undefined,
|
|
571
|
+
});
|
|
572
|
+
break;
|
|
573
|
+
case 'pages':
|
|
574
|
+
await cmdPages(args[1], getArg('--type') || 'entry', {
|
|
575
|
+
limit: getArg('--limit') ? parseInt(getArg('--limit'), 10) : undefined,
|
|
576
|
+
});
|
|
577
|
+
break;
|
|
578
|
+
case 'sessions-dist':
|
|
579
|
+
await cmdSessionsDist(args[1]);
|
|
580
|
+
break;
|
|
581
|
+
case 'heatmap':
|
|
582
|
+
await cmdHeatmap(args[1]);
|
|
583
|
+
break;
|
|
405
584
|
case 'delete':
|
|
406
585
|
await cmdDelete(args[1]);
|
|
407
586
|
break;
|
package/lib/api.mjs
CHANGED
|
@@ -87,4 +87,36 @@ export class AgentAnalyticsAPI {
|
|
|
87
87
|
if (sample) qs += `&sample=${sample}`;
|
|
88
88
|
return this.request('GET', `/properties/received?${qs}`);
|
|
89
89
|
}
|
|
90
|
+
|
|
91
|
+
// Analytics
|
|
92
|
+
async getBreakdown(project, { property, event, since, limit = 20 } = {}) {
|
|
93
|
+
let qs = `project=${encodeURIComponent(project)}&property=${encodeURIComponent(property)}`;
|
|
94
|
+
if (event) qs += `&event=${encodeURIComponent(event)}`;
|
|
95
|
+
if (since) qs += `&since=${encodeURIComponent(since)}`;
|
|
96
|
+
if (limit) qs += `&limit=${limit}`;
|
|
97
|
+
return this.request('GET', `/breakdown?${qs}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async getInsights(project, { period = '7d' } = {}) {
|
|
101
|
+
return this.request('GET', `/insights?project=${encodeURIComponent(project)}&period=${period}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async getPages(project, { type = 'entry', since, limit = 20 } = {}) {
|
|
105
|
+
let qs = `project=${encodeURIComponent(project)}&type=${type}`;
|
|
106
|
+
if (since) qs += `&since=${encodeURIComponent(since)}`;
|
|
107
|
+
if (limit) qs += `&limit=${limit}`;
|
|
108
|
+
return this.request('GET', `/pages?${qs}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async getSessionDistribution(project, { since } = {}) {
|
|
112
|
+
let qs = `project=${encodeURIComponent(project)}`;
|
|
113
|
+
if (since) qs += `&since=${encodeURIComponent(since)}`;
|
|
114
|
+
return this.request('GET', `/sessions/distribution?${qs}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async getHeatmap(project, { since } = {}) {
|
|
118
|
+
let qs = `project=${encodeURIComponent(project)}`;
|
|
119
|
+
if (since) qs += `&since=${encodeURIComponent(since)}`;
|
|
120
|
+
return this.request('GET', `/heatmap?${qs}`);
|
|
121
|
+
}
|
|
90
122
|
}
|