@audienti/cli 0.1.41 → 0.1.44

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/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to the Audienti CLI are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.44] - 2026-09-01
8
+
9
+ ### Added
10
+
11
+ - Add `audienti analytics metrics` for one-request account-scoped outbound operation cohorts, canonical operation and attempt counts, daily or weekly rows, six leaf outcome filters plus success/failure umbrellas, exact JSON output, and filters for account users, motions, tags, lists, offers, ICPs, Social Cookies, platforms, and actions.
12
+
13
+ ## [0.1.42] - 2026-08-28
14
+
15
+ ### Changed
16
+
17
+ - Track the account Operator API contract update for tenant-scoped projected queue reads, explicit count availability, legacy cursor fallback, and asynchronous outcome reconciliation.
18
+
7
19
  ## [0.1.41] - 2026-08-26
8
20
 
9
21
  ### Fixed
package/README.md CHANGED
@@ -169,6 +169,7 @@ audienti lists routing-rules <list_id> apply
169
169
  audienti users activity --window 7d
170
170
  audienti analytics prospects --window 24h
171
171
  audienti analytics dashboard --play-tag wine_campaign
172
+ audienti analytics metrics --cohort-preset week-to-date
172
173
  audienti analytics cohorts create-list --name "Blank note test" --start 2026-07-20 --end 2026-07-20 --note-mode blank
173
174
  audienti analytics users --user me --window 30d
174
175
  audienti analytics visibility --window 24h --user me
@@ -259,6 +260,46 @@ To compare recent weekly prospect cohorts by their current pipeline stages:
259
260
  audienti analytics prospects cohort-analysis --weeks 4 --motion <motn_id>
260
261
  ```
261
262
 
263
+ To inspect the current outcomes of outbound operations created in a date range,
264
+ use the account-scoped metrics report:
265
+
266
+ ```bash
267
+ audienti analytics metrics --cohort-start 2026-08-24 --cohort-end 2026-08-30 --interval daily
268
+ audienti analytics metrics --cohort-start 2026-08-24 --cohort-end 2026-08-30 --interval weekly
269
+ audienti analytics metrics --cohort-preset week-to-date --user me --motion <motn_id> --play-tag <tag> --list <list_id> --offer <offr_id> --icp <icp_id> --social-cookie <scok_id> --platform linkedin --action messaging.message_sent --outcome succeeded_after_retry
270
+ audienti analytics metrics --cohort-preset week-to-date --json
271
+ ```
272
+
273
+ This is an `events.created_at` root-operation cohort, and each operation is
274
+ classified by its current outcome across all of its attempts. It is distinct
275
+ from the `AccountProspect.created_at` entry cohorts used by dashboard, stages,
276
+ and prospect cohort analysis. The command
277
+ makes one authenticated request to the account Metrics API. Plain text formats
278
+ only the returned cohort ranges, Operations, First-try success, Recovered, Final
279
+ failures, In progress, Attempts, selected daily or weekly grid rows, action rows,
280
+ and account-wide Social Cookie rows. `--json` prints the API response deeply
281
+ unchanged; the CLI does not recalculate cohorts, outcomes, counts, or rates.
282
+
283
+ The six leaf outcomes are `first_attempt_success`, `succeeded_after_retry`,
284
+ `failed_without_retry`, `failed_after_retry`, `in_progress`, and `unresolved`.
285
+ The `success` and `failure` values are umbrella filters over their corresponding
286
+ two terminal leaf outcomes.
287
+
288
+ For example, the human output uses the server-provided values directly:
289
+
290
+ ```text
291
+ Outbound metrics
292
+ Cohort: 2026-08-24 to 2026-08-30 (events.created_at)
293
+ Current: 2026-08-24T00:00:00-05:00 to 2026-08-31T00:00:00-05:00
294
+ Previous: 2026-08-17T00:00:00-05:00 to 2026-08-24T00:00:00-05:00
295
+ Operations: 1347
296
+ First-try success: 1275 (94.7%)
297
+ Recovered: 40 (3%)
298
+ Final failures: 16 (1.2%)
299
+ In progress: 16 (1.2%)
300
+ Attempts: 1400
301
+ ```
302
+
262
303
  To materialize a connection-request activity cohort as a reusable list selector,
263
304
  then reuse it in analytics:
264
305
 
@@ -269,8 +310,9 @@ audienti analytics prospects --list <list_id> --window 30d
269
310
  audienti analytics users --user me --list <list_id> --start 2026-07-01 --end 2026-07-31
270
311
  ```
271
312
 
272
- Use `--cohort-start` and `--cohort-end` when the cohort is based on when people
273
- entered Audienti, a motion, or a receiving segment. Use `analytics cohorts
313
+ For prospect, dashboard, and stages analytics, use `--cohort-start` and
314
+ `--cohort-end` when the cohort is based on when people entered Audienti, a
315
+ motion, or a receiving segment. Use `analytics cohorts
274
316
  create-list` followed by `--list` when the cohort is based on an event that
275
317
  happened later, such as connection requests sent in a date range. Rebuild the
276
318
  list when the event definition or date window changes so the analytics question
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audienti/cli",
3
- "version": "0.1.41",
3
+ "version": "0.1.44",
4
4
  "description": "Agent-first command-line client for Audienti.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api-client.js CHANGED
@@ -663,6 +663,10 @@ export class AudientiClient {
663
663
  return this.requestJson(accountPath(accountId, ["analytics", "dashboard"], query));
664
664
  }
665
665
 
666
+ analyticsMetrics(accountId, query = {}) {
667
+ return this.requestJson(accountPath(accountId, ["analytics", "metrics"], query));
668
+ }
669
+
666
670
  analyticsStages(accountId, query = {}) {
667
671
  return this.requestJson(accountPath(accountId, ["analytics", "stages"], query));
668
672
  }
package/src/cli.js CHANGED
@@ -36,6 +36,16 @@ const DELETE_CONFIRMATION_VALUES = new Set(["yes", "true", "y"]);
36
36
  const MOTION_STATUS_VALUES = new Set(["draft", "preparing", "active", "paused", "archived"]);
37
37
  const PROSPECT_INACTIVE_REASON_VALUES = new Set(["nurture", "non_responsive", "not_fit", "bad_data_404"]);
38
38
  const PROSPECT_STATUS_VALUES = new Set(["active", ...PROSPECT_INACTIVE_REASON_VALUES, "rejected"]);
39
+ const OUTBOUND_METRICS_OUTCOMES = new Set([
40
+ "success",
41
+ "failure",
42
+ "first_attempt_success",
43
+ "succeeded_after_retry",
44
+ "failed_without_retry",
45
+ "failed_after_retry",
46
+ "in_progress",
47
+ "unresolved"
48
+ ]);
39
49
  const PROSPECTS_ADD_NOTE_USAGE = "Usage: audienti prospects add-note <prsp_id> (--message <text> [--type <note|steer|voicemail_outreach|video_outreach>] [--engagement-type <key>] | --payload <file.json>) [--json] [--account <acct_id>]";
40
50
  const PROSPECTS_ADD_STEER_USAGE = "Usage: audienti prospects add-steer <prsp_id> (--message <text> [--engagement-type <key>] | --payload <file.json>) [--json] [--account <acct_id>]";
41
51
  const PROSPECTS_ADD_PROFILE_USAGE = "Usage: audienti prospects add-profile <prsp_id> --url <profile_url|email|phone> [--json] [--account <acct_id>]";
@@ -109,6 +119,7 @@ const ANALYTICS_PROSPECTS_USAGE = "Usage: audienti analytics prospects [--window
109
119
  const ANALYTICS_PROSPECTS_COHORT_ANALYSIS_USAGE = "Usage: audienti analytics prospects cohort-analysis [--weeks <n>] [--window 24h] [--motion <motn_id>] [--list <list_id>] [--provenance <source>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
110
120
  const ANALYTICS_USERS_USAGE = "Usage: audienti analytics users [--user <account_user_id|email|name|me>] [--window 30d | --start YYYY-MM-DD --end YYYY-MM-DD] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--motion <motn_id>] [--list <list_id>] [--provenance <source>] [--platform <linkedin|email|gmail>] [--json] [--account <acct_id>]";
111
121
  const ANALYTICS_DASHBOARD_USAGE = "Usage: audienti analytics dashboard [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--list <list_id>] [--offer <offr_id>] [--icp <icp_id>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
122
+ const ANALYTICS_METRICS_USAGE = "Usage: audienti analytics metrics [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD | --cohort-preset week-to-date] [--interval <daily|weekly>] [--user <account_user_id|email|name|me>] [--motion <motn_id>] [--play-tag <tag>] [--list <list_id>] [--offer <offr_id>] [--icp <icp_id>] [--social-cookie <scok_id>] [--platform <platform>] [--action <action_key>] [--outcome <success|failure|first_attempt_success|succeeded_after_retry|failed_without_retry|failed_after_retry|in_progress|unresolved>] [--json] [--account <acct_id>]";
112
123
  const ANALYTICS_STAGES_USAGE = "Usage: audienti analytics stages [--interval weekly|monthly] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--list <list_id>] [--offer <offr_id>] [--icp <icp_id>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
113
124
  const ANALYTICS_COHORT_LIST_USAGE = "Usage: audienti analytics cohorts create-list --name <text> --start YYYY-MM-DD --end YYYY-MM-DD [--event connection_request_sent] [--user <account_user_id|email|name|me>] [--note-mode <any|with_note|blank>] [--motion <motn_id>] [--offer <offr_id>] [--icp <icp_id>] [--play-tag <tag>] [--json] [--account <acct_id>]";
114
125
  const TOOLS_LIST_USAGE = "Usage: audienti tools list [--json]";
@@ -311,6 +322,7 @@ async function dispatch(argv, context) {
311
322
  if (normalizedResource === "analytics" && ["visibility", "visops"].includes(action)) return analyticsVisibility(rest, context, { accountOverride });
312
323
  if (normalizedResource === "analytics" && action === "content") return analyticsContent(rest, context, { accountOverride });
313
324
  if (normalizedResource === "analytics" && ["dashboard", "campaign", "campaigns"].includes(action)) return analyticsDashboard(rest, context, { accountOverride });
325
+ if (normalizedResource === "analytics" && action === "metrics") return analyticsMetrics(rest, context, { accountOverride });
314
326
  if (normalizedResource === "analytics" && action === "stages") return analyticsStages(rest, context, { accountOverride });
315
327
  if (normalizedResource === "analytics" && ["cohorts", "cohort"].includes(action)) return analyticsCohorts(rest, context, { accountOverride });
316
328
 
@@ -325,13 +337,15 @@ function extractGlobalOptions(argv) {
325
337
  const arg = argv[index];
326
338
 
327
339
  if (arg === "--account") {
328
- accountOverride = argv[index + 1];
329
- if (!accountOverride || accountOverride.startsWith("--")) {
340
+ const rawAccountOverride = argv[index + 1];
341
+ if (!rawAccountOverride || rawAccountOverride.startsWith("--")) {
330
342
  throw new CommandError("--account requires an account id.");
331
343
  }
344
+ accountOverride = rawAccountOverride.trim();
345
+ if (!accountOverride) throw new CommandError("--account requires an account id.");
332
346
  index += 1;
333
347
  } else if (arg.startsWith("--account=")) {
334
- accountOverride = arg.slice("--account=".length);
348
+ accountOverride = arg.slice("--account=".length).trim();
335
349
  if (!accountOverride) throw new CommandError("--account requires an account id.");
336
350
  } else {
337
351
  args.push(arg);
@@ -3257,6 +3271,18 @@ async function analyticsDashboard(args, context, { accountOverride } = {}) {
3257
3271
  renderAnalyticsDashboard(payload, context);
3258
3272
  }
3259
3273
 
3274
+ async function analyticsMetrics(args, context, { accountOverride } = {}) {
3275
+ const { values, positionals } = parseCommandArgs(args, analyticsMetricsOptions());
3276
+ if (positionals.length > 0) throw new CommandError(ANALYTICS_METRICS_USAGE);
3277
+ validateAnalyticsMetricsValues(values);
3278
+
3279
+ const { client, accountId, config } = await requireAccountContext(context, { accountOverride });
3280
+ const payload = await client.analyticsMetrics(accountId, analyticsMetricsQuery(values, config, { accountOverride }));
3281
+ if (values.json) return writeJson(context.stdout, payload);
3282
+
3283
+ renderAnalyticsMetrics(payload, context);
3284
+ }
3285
+
3260
3286
  async function analyticsStages(args, context, { accountOverride } = {}) {
3261
3287
  const { values, positionals } = parseCommandArgs(args, analyticsStagesOptions());
3262
3288
  if (positionals.length > 0) throw new CommandError(ANALYTICS_STAGES_USAGE);
@@ -3549,6 +3575,26 @@ function analyticsStagesOptions() {
3549
3575
  };
3550
3576
  }
3551
3577
 
3578
+ function analyticsMetricsOptions() {
3579
+ return {
3580
+ ...jsonOptions(),
3581
+ "cohort-start": { type: "string" },
3582
+ "cohort-end": { type: "string" },
3583
+ "cohort-preset": { type: "string" },
3584
+ interval: { type: "string" },
3585
+ user: { type: "string" },
3586
+ motion: { type: "string" },
3587
+ "play-tag": { type: "string" },
3588
+ list: { type: "string" },
3589
+ offer: { type: "string" },
3590
+ icp: { type: "string" },
3591
+ "social-cookie": { type: "string" },
3592
+ platform: { type: "string" },
3593
+ action: { type: "string" },
3594
+ outcome: { type: "string" }
3595
+ };
3596
+ }
3597
+
3552
3598
  function analyticsCohortListOptions() {
3553
3599
  return {
3554
3600
  ...jsonOptions(),
@@ -3614,6 +3660,59 @@ function analyticsStagesQuery(values, config = {}, { accountOverride } = {}) {
3614
3660
  });
3615
3661
  }
3616
3662
 
3663
+ function analyticsMetricsQuery(values, config = {}, { accountOverride } = {}) {
3664
+ return compactObject({
3665
+ cohort_start_date: values["cohort-start"],
3666
+ cohort_end_date: values["cohort-end"],
3667
+ cohort_preset: values["cohort-preset"] === "week-to-date" ? "week_to_date" : values["cohort-preset"],
3668
+ interval: values.interval,
3669
+ account_user_id: resolveAccountUserId(values.user, config, { accountOverride }),
3670
+ motion_id: values.motion,
3671
+ play_tag: values["play-tag"],
3672
+ list_id: values.list,
3673
+ offer_id: values.offer,
3674
+ icp_id: values.icp,
3675
+ social_cookie_id: values["social-cookie"],
3676
+ platform: values.platform,
3677
+ action_key: values.action,
3678
+ outcome: values.outcome
3679
+ });
3680
+ }
3681
+
3682
+ function validateAnalyticsMetricsValues(values) {
3683
+ for (const [key, value] of Object.entries(values)) {
3684
+ if (key !== "json" && typeof value === "string" && value.trim() === "") {
3685
+ throw new CommandError(`--${key} cannot be blank.`);
3686
+ }
3687
+ }
3688
+
3689
+ validateDatePair(values["cohort-start"], values["cohort-end"], "--cohort-start", "--cohort-end");
3690
+ validateIsoDate(values["cohort-start"], "--cohort-start");
3691
+ validateIsoDate(values["cohort-end"], "--cohort-end");
3692
+
3693
+ if (values["cohort-preset"] && (values["cohort-start"] || values["cohort-end"])) {
3694
+ throw new CommandError("--cohort-preset cannot be combined with --cohort-start or --cohort-end.");
3695
+ }
3696
+ if (values["cohort-preset"] && values["cohort-preset"] !== "week-to-date") {
3697
+ throw new CommandError("--cohort-preset must be week-to-date.");
3698
+ }
3699
+ if (values.interval && !["daily", "weekly"].includes(values.interval)) {
3700
+ throw new CommandError("--interval must be daily or weekly.");
3701
+ }
3702
+ if (values.outcome && !OUTBOUND_METRICS_OUTCOMES.has(values.outcome)) {
3703
+ throw new CommandError("--outcome must be one of success, failure, first_attempt_success, succeeded_after_retry, failed_without_retry, failed_after_retry, in_progress, unresolved.");
3704
+ }
3705
+ }
3706
+
3707
+ function validateIsoDate(value, flagName) {
3708
+ if (!value) return;
3709
+
3710
+ const match = String(value).match(/^(\d{4})-(\d{2})-(\d{2})$/);
3711
+ const date = match ? new Date(`${value}T00:00:00Z`) : null;
3712
+ const valid = date && !Number.isNaN(date.getTime()) && date.toISOString().slice(0, 10) === value;
3713
+ if (!valid) throw new CommandError(`${flagName} must be a valid date in YYYY-MM-DD format.`);
3714
+ }
3715
+
3617
3716
  function validateDatePair(start, end, startFlag, endFlag) {
3618
3717
  if ((start && !end) || (!start && end)) {
3619
3718
  throw new CommandError(`${startFlag} and ${endFlag} must be provided together.`);
@@ -5867,6 +5966,102 @@ function renderAnalyticsDashboard(payload, context) {
5867
5966
  writeCountTable(context, "Current pipeline stages", payload?.pipeline_stage_counts, ["STAGE", "COUNT"], countRow);
5868
5967
  }
5869
5968
 
5969
+ function renderAnalyticsMetrics(payload, context) {
5970
+ const cohort = payload?.cohort || {};
5971
+ const summary = payload?.summary || {};
5972
+ writeLine(context.stdout, "Outbound metrics");
5973
+ writeLine(context.stdout, `Cohort: ${display(cohort.start_date, "-")} to ${display(cohort.end_date, "-")} (${display(cohort.field, "-")})`);
5974
+ writeLine(context.stdout, `Current: ${metricsRangeLabel(cohort.start_at, cohort.end_at)}`);
5975
+ writeLine(context.stdout, `Previous: ${metricsRangeLabel(cohort.previous_start_at, cohort.previous_end_at)}`);
5976
+ writeLine(context.stdout, `Operations: ${display(summary.operation_count, "-")}`);
5977
+ writeLine(context.stdout, `First-try success: ${metricsCountRateLabel(summary, "first_attempt_success")}`);
5978
+ writeLine(context.stdout, `Recovered: ${metricsCountRateLabel(summary, "succeeded_after_retry")}`);
5979
+ writeLine(context.stdout, `Final failures: ${metricsCountRateLabel(summary, "ultimate_failure")}`);
5980
+ writeLine(context.stdout, `In progress: ${metricsCountRateLabel(summary, "in_progress")}`);
5981
+ writeLine(context.stdout, `Attempts: ${display(summary.attempt_count, "-")}`);
5982
+
5983
+ renderAnalyticsMetricsGrid(payload?.grid, context);
5984
+ renderAnalyticsMetricsActions(payload?.action_rows, context);
5985
+ if (payload?.scope?.social_cookie == null) renderAnalyticsMetricsCookies(payload?.social_cookie_rows, context);
5986
+ }
5987
+
5988
+ function metricsRangeLabel(startAt, endAt) {
5989
+ return startAt && endAt ? `${startAt} to ${endAt}` : "not available";
5990
+ }
5991
+
5992
+ function metricsCountRateLabel(summary, bucket) {
5993
+ return `${display(summary?.[`${bucket}_count`], "-")} (${percentageLabel(summary?.[`${bucket}_rate`])})`;
5994
+ }
5995
+
5996
+ function renderAnalyticsMetricsGrid(grid, context) {
5997
+ const rows = Array.isArray(grid?.rows) ? grid.rows : [];
5998
+ const intervalLabel = grid?.interval === "weekly" ? "Weekly" : "Daily";
5999
+ writeLine(context.stdout, "");
6000
+ writeLine(context.stdout, `${intervalLabel} rows`);
6001
+ if (rows.length === 0) return writeLine(context.stdout, "None");
6002
+
6003
+ writeAlignedTable(context, [
6004
+ grid?.row_heading?.toUpperCase() || "PERIOD",
6005
+ "OPERATIONS",
6006
+ "FIRST-TRY SUCCESS",
6007
+ "RECOVERED",
6008
+ "FINAL FAILURES",
6009
+ "IN PROGRESS",
6010
+ "ATTEMPTS"
6011
+ ], rows.map((row) => [
6012
+ display(row?.label, "-"),
6013
+ display(row?.summary?.operation_count, "-"),
6014
+ metricsCountRateLabel(row?.summary, "first_attempt_success"),
6015
+ metricsCountRateLabel(row?.summary, "succeeded_after_retry"),
6016
+ metricsCountRateLabel(row?.summary, "ultimate_failure"),
6017
+ metricsCountRateLabel(row?.summary, "in_progress"),
6018
+ display(row?.summary?.attempt_count, "-")
6019
+ ]), { numericColumns: [false, true, true, true, true, true, true] });
6020
+ }
6021
+
6022
+ function renderAnalyticsMetricsActions(rows, context) {
6023
+ const actions = Array.isArray(rows) ? rows : [];
6024
+ writeLine(context.stdout, "");
6025
+ writeLine(context.stdout, "Action breakdown");
6026
+ if (actions.length === 0) return writeLine(context.stdout, "None");
6027
+
6028
+ writeAnalyticsMetricsSummaryTable(context, ["ACTION", "KEY"], actions.map((row) => [
6029
+ display(row?.label, "-"),
6030
+ display(row?.key, "-")
6031
+ ]), actions.map((row) => row?.summary));
6032
+ }
6033
+
6034
+ function renderAnalyticsMetricsCookies(rows, context) {
6035
+ const cookies = Array.isArray(rows) ? rows : [];
6036
+ writeLine(context.stdout, "");
6037
+ writeLine(context.stdout, "Social Cookie breakdown");
6038
+ if (cookies.length === 0) return writeLine(context.stdout, "None");
6039
+
6040
+ writeAnalyticsMetricsSummaryTable(context, ["SOCIAL COOKIE", "ID"], cookies.map((row) => [
6041
+ display(row?.label, "-"),
6042
+ display(row?.prefix_id, "-")
6043
+ ]), cookies.map((row) => row?.summary));
6044
+ }
6045
+
6046
+ function writeAnalyticsMetricsSummaryTable(context, identityHeaders, identityRows, summaries) {
6047
+ const summaryHeaders = ["OPERATIONS", "FIRST-TRY SUCCESS", "RECOVERED", "FINAL FAILURES", "IN PROGRESS", "ATTEMPTS"];
6048
+ const rows = identityRows.map((identity, index) => {
6049
+ const summary = summaries[index];
6050
+ return [
6051
+ ...identity,
6052
+ display(summary?.operation_count, "-"),
6053
+ metricsCountRateLabel(summary, "first_attempt_success"),
6054
+ metricsCountRateLabel(summary, "succeeded_after_retry"),
6055
+ metricsCountRateLabel(summary, "ultimate_failure"),
6056
+ metricsCountRateLabel(summary, "in_progress"),
6057
+ display(summary?.attempt_count, "-")
6058
+ ];
6059
+ });
6060
+ writeAlignedTable(context, [...identityHeaders, ...summaryHeaders], rows, {
6061
+ numericColumns: [...identityHeaders.map(() => false), true, true, true, true, true, true]
6062
+ });
6063
+ }
6064
+
5870
6065
  function renderAnalyticsStages(payload, context) {
5871
6066
  const conversionGrid = payload?.conversion_grid || {};
5872
6067
  writeLine(context.stdout, `Stage analytics (${display(payload?.cohort?.label, "selected cohort")})`);
@@ -6772,6 +6967,7 @@ const HELP_TOPICS = new Map([
6772
6967
  " Analytics",
6773
6968
  " audienti analytics prospects --window 24h",
6774
6969
  " audienti analytics dashboard --play-tag <tag>",
6970
+ " audienti analytics metrics --cohort-preset week-to-date",
6775
6971
  " audienti analytics stages --interval weekly",
6776
6972
  " audienti analytics cohorts create-list --name \"Blank note test\" --start 2026-07-20 --end 2026-07-20 --note-mode blank",
6777
6973
  " audienti analytics prospects cohort-analysis --weeks 4 --motion <motn_id>",
@@ -6794,6 +6990,7 @@ const HELP_TOPICS = new Map([
6794
6990
  " Preview a campaign: audienti writer test-run <prsp_id>",
6795
6991
  " Analyze one motion: audienti motions analytics <motn_id>",
6796
6992
  " Count one campaign: audienti analytics dashboard --play-tag <tag>",
6993
+ " Inspect outcomes: audienti analytics metrics --cohort-preset week-to-date",
6797
6994
  " Compare stage rates: audienti analytics stages --interval weekly",
6798
6995
  " Audit your work: audienti analytics users --user me --window 30d",
6799
6996
  " Review reminders: audienti tasks list",
@@ -9557,6 +9754,7 @@ const HELP_TOPICS = new Map([
9557
9754
  "Usage:",
9558
9755
  " audienti analytics prospects [--window 24h] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--motion <motn_id>] [--list <list_id>] [--user <account_user_id|email|name|me>] [--json]",
9559
9756
  " audienti analytics dashboard [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--list <list_id>] [--json]",
9757
+ " audienti analytics metrics [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD | --cohort-preset week-to-date] [--interval <daily|weekly>] [--user <account_user_id|email|name|me>] [--motion <motn_id>] [--play-tag <tag>] [--list <list_id>] [--offer <offr_id>] [--icp <icp_id>] [--social-cookie <scok_id>] [--platform <platform>] [--action <action_key>] [--outcome <success|failure|first_attempt_success|succeeded_after_retry|failed_without_retry|failed_after_retry|in_progress|unresolved>] [--json]",
9560
9758
  " audienti analytics stages [--interval weekly|monthly] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--list <list_id>] [--json]",
9561
9759
  " audienti analytics cohorts create-list --name <text> --start YYYY-MM-DD --end YYYY-MM-DD [--note-mode <any|with_note|blank>] [--user <account_user_id|email|name|me>] [--json]",
9562
9760
  " audienti analytics prospects cohort-analysis [--weeks <n>] [--window 24h] [--motion <motn_id>] [--list <list_id>] [--user <account_user_id|email|name|me>] [--json]",
@@ -9575,6 +9773,7 @@ const HELP_TOPICS = new Map([
9575
9773
  " --list <list_id> Filter analytics to prospects in one list, including analytics cohort lists.",
9576
9774
  " --play-tag <tag> For dashboard analytics, filter to motions/lists tagged with a campaign tag.",
9577
9775
  " --interval <weekly|monthly> For stages analytics, select the conversion cohort grain.",
9776
+ " Metrics uses events.created_at root-operation cohorts and reports each operation's current outcome across its attempts; it is not an AccountProspect.created_at entry cohort.",
9578
9777
  " --provenance <source> Optional lower-level AccountProspect.intake_source filter.",
9579
9778
  " --platform <linkedin|email|gmail> For user analytics, filter events.platform. --channel is accepted as an alias.",
9580
9779
  " cohort-analysis loops over recent weekly AccountProspect.created_at cohorts and compares their current stages.",
@@ -9614,6 +9813,43 @@ const HELP_TOPICS = new Map([
9614
9813
  " GET /api/v1/accounts/:account_id/analytics/dashboard.json"
9615
9814
  ].join("\n")],
9616
9815
 
9816
+ ["analytics metrics", [
9817
+ "Usage:",
9818
+ ` ${ANALYTICS_METRICS_USAGE.slice("Usage: ".length)}`,
9819
+ "",
9820
+ "Status: implemented",
9821
+ "",
9822
+ "Purpose:",
9823
+ " Return account-scoped outbound operation outcomes with exactly one authenticated API request.",
9824
+ " The cohort is events.created_at: root operations created in the selected period, measured by their current outcomes.",
9825
+ " This differs from AccountProspect.created_at entry cohorts used by dashboard, stages, and prospect cohort analysis.",
9826
+ "",
9827
+ "Options:",
9828
+ " --cohort-start <YYYY-MM-DD> --cohort-end <YYYY-MM-DD> Select an explicit inclusive operation cohort.",
9829
+ " --cohort-preset <week-to-date> Select the server-defined week-to-date cohort; cannot be combined with explicit dates.",
9830
+ " --interval <daily|weekly> Request daily or weekly operation rows. The server default is daily.",
9831
+ " --user <account_user_id|email|name|me> Filter to one account user.",
9832
+ " --motion <motn_id> Filter operations to prospects in one motion/play.",
9833
+ " --play-tag <tag> Filter operations to prospects in motions/lists with the tag.",
9834
+ " --list <list_id> Filter operations to prospects in one list.",
9835
+ " --offer <offr_id> Filter operations to prospects for one offer.",
9836
+ " --icp <icp_id> Filter operations to prospects for one ICP.",
9837
+ " --social-cookie <scok_id> Filter to one account-accessible Social Cookie.",
9838
+ " --platform <platform> Filter by the normalized event platform.",
9839
+ " --action <action_key> Filter by the exact outbound action key.",
9840
+ " --outcome <success|failure|first_attempt_success|succeeded_after_retry|failed_without_retry|failed_after_retry|in_progress|unresolved>",
9841
+ " Umbrella filters: success, failure.",
9842
+ " Leaf outcomes: first_attempt_success, succeeded_after_retry, failed_without_retry, failed_after_retry, in_progress, unresolved.",
9843
+ " --json Print the API response deeply unchanged.",
9844
+ "",
9845
+ "Output:",
9846
+ " Plain text formats only API-returned operation counts/rates, selected grid rows, actions, and account-wide cookie rows.",
9847
+ " JSON is the canonical outbound_metrics response without client-side cohort, outcome, count, or rate calculations.",
9848
+ "",
9849
+ "API:",
9850
+ " GET /api/v1/accounts/:account_id/analytics/metrics.json"
9851
+ ].join("\n")],
9852
+
9617
9853
  ["analytics stages", [
9618
9854
  "Usage:",
9619
9855
  ` ${ANALYTICS_STAGES_USAGE.slice("Usage: ".length)}`,
@@ -9874,6 +10110,7 @@ const HELP_TOPICS = new Map([
9874
10110
  " audienti users activity me --window 7d",
9875
10111
  " audienti analytics prospects --window 24h",
9876
10112
  " audienti analytics dashboard --play-tag wine_campaign",
10113
+ " audienti analytics metrics --cohort-preset week-to-date",
9877
10114
  " audienti analytics stages --interval weekly --play-tag wine_campaign",
9878
10115
  " audienti analytics cohorts create-list --name \"Connection requests 2026-07-20\" --start 2026-07-20 --end 2026-07-20",
9879
10116
  " audienti analytics users --user me --window 30d",