@audienti/cli 0.1.27 → 0.1.29

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,21 @@ All notable changes to the Audienti CLI are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.29] - 2026-07-23
8
+
9
+ ### Added
10
+
11
+ - Add `audienti analytics cohorts create-list` to materialize event-date cohorts as reusable analytics list filters.
12
+ - Add `--list <list_id>` to prospects, dashboard, users, and prospect cohort-analysis analytics commands.
13
+ - Add `audienti tasks list`, `audienti tasks manage`, `audienti tasks add`, and `audienti tasks complete` for plain operator reminders.
14
+
15
+ ## [0.1.28] - 2026-07-23
16
+
17
+ ### Added
18
+
19
+ - Add `audienti prospects reenrich` for dry-running or queueing one forced LinkedIn person profile re-enrichment.
20
+ - Add `audienti prospects refresh-queue` for dry-running or applying account-scoped next-action and operator draft cache repair for one prospect.
21
+
7
22
  ## [0.1.27] - 2026-07-22
8
23
 
9
24
  ### Added
package/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  Audienti CLI is the agent-first command-line client for the Audienti production
4
4
  API. It lets local coding agents and operators inspect accounts, create and
5
- manage plays, import prospects, build lists, and work supported operator flows.
5
+ manage plays, import prospects, build lists, manage task reminders, and work
6
+ supported operator flows.
6
7
 
7
8
  ## Install
8
9
 
@@ -77,11 +78,15 @@ audienti prospects check --all --csv
77
78
  audienti prospects assign <prsp_id> --assigned-user me
78
79
  audienti prospects set-status <prsp_id> --status not_fit
79
80
  audienti prospects lock <prsp_id> --note "Emergency hold"
81
+ audienti tasks list
82
+ audienti tasks add --title "Review Cristina" --due 2026-07-24T11:00 --prospect <prsp_id> --notes "Check the renewal note before replying."
83
+ audienti tasks complete <ptsk_id>
80
84
  audienti dnc list
81
85
  audienti company-rules list
82
86
  audienti users activity --window 7d
83
87
  audienti analytics prospects --window 24h
84
88
  audienti analytics dashboard --play-tag wine_campaign
89
+ audienti analytics cohorts create-list --name "Blank note test" --start 2026-07-20 --end 2026-07-20 --note-mode blank
85
90
  audienti analytics users --user me --window 30d
86
91
  audienti analytics visibility --window 24h --user me
87
92
  audienti analytics content --window week
@@ -107,6 +112,15 @@ audienti operator next --plan
107
112
  audienti operator next --done --note "Connection request sent."
108
113
  ```
109
114
 
115
+ To manage simple reminders for yourself:
116
+
117
+ ```bash
118
+ audienti tasks list
119
+ audienti tasks list --status completed
120
+ audienti tasks add --title "Review target account" --due 2026-07-24T11:00 --list <list_id> --notes "Check the latest notes."
121
+ audienti tasks complete <ptsk_id>
122
+ ```
123
+
110
124
  To inspect activity for prospects that entered the account during a specific
111
125
  cohort while keeping a separate activity window:
112
126
 
@@ -120,6 +134,23 @@ To compare recent weekly prospect cohorts by their current pipeline stages:
120
134
  audienti analytics prospects cohort-analysis --weeks 4 --motion <motn_id>
121
135
  ```
122
136
 
137
+ To materialize a connection-request activity cohort as a reusable list selector,
138
+ then reuse it in analytics:
139
+
140
+ ```bash
141
+ audienti analytics cohorts create-list --name "Connection requests 2026-07-01 to 2026-07-07" --event connection_request_sent --start 2026-07-01 --end 2026-07-07
142
+ audienti analytics dashboard --list <list_id>
143
+ audienti analytics prospects --list <list_id> --window 30d
144
+ audienti analytics users --user me --list <list_id> --start 2026-07-01 --end 2026-07-31
145
+ ```
146
+
147
+ Use `--cohort-start` and `--cohort-end` when the cohort is based on when people
148
+ entered Audienti, a motion, or a receiving segment. Use `analytics cohorts
149
+ create-list` followed by `--list` when the cohort is based on an event that
150
+ happened later, such as connection requests sent in a date range. Rebuild the
151
+ list when the event definition or date window changes so the analytics question
152
+ stays auditable.
153
+
123
154
  To see whether one motion is producing prospects by day, and where each
124
155
  produced-day cohort currently sits in the funnel:
125
156
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audienti/cli",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "description": "Agent-first command-line client for Audienti.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api-client.js CHANGED
@@ -180,6 +180,23 @@ export class AudientiClient {
180
180
  return this.requestJson(accountPath(accountId, ["tags"]));
181
181
  }
182
182
 
183
+ tasks(accountId, query = {}) {
184
+ return this.requestJson(accountPath(accountId, ["tasks"], query));
185
+ }
186
+
187
+ createTask(accountId, body) {
188
+ return this.requestJson(accountPath(accountId, ["tasks"]), {
189
+ method: "POST",
190
+ body
191
+ });
192
+ }
193
+
194
+ completeTask(accountId, taskId) {
195
+ return this.requestJson(accountPath(accountId, ["tasks", taskId, "complete"]), {
196
+ method: "PATCH"
197
+ });
198
+ }
199
+
183
200
  lists(accountId) {
184
201
  return this.requestJson(accountPath(accountId, ["lists"]));
185
202
  }
@@ -373,6 +390,20 @@ export class AudientiClient {
373
390
  });
374
391
  }
375
392
 
393
+ reenrichProspect(accountId, prospectId, body = {}) {
394
+ return this.requestJson(accountPath(accountId, ["prospects", prospectId, "reenrich"]), {
395
+ method: "POST",
396
+ body
397
+ });
398
+ }
399
+
400
+ refreshProspectQueue(accountId, prospectId, body = {}) {
401
+ return this.requestJson(accountPath(accountId, ["prospects", prospectId, "refresh_queue"]), {
402
+ method: "POST",
403
+ body
404
+ });
405
+ }
406
+
376
407
  assignProspects(accountId, body) {
377
408
  return this.requestJson(accountPath(accountId, ["prospects", "assign"]), {
378
409
  method: "POST",
@@ -541,6 +572,13 @@ export class AudientiClient {
541
572
  return this.requestJson(accountPath(accountId, ["analytics", "dashboard"], query));
542
573
  }
543
574
 
575
+ createAnalyticsCohortList(accountId, body = {}) {
576
+ return this.requestJson(accountPath(accountId, ["analytics", "cohort_lists"]), {
577
+ method: "POST",
578
+ body
579
+ });
580
+ }
581
+
544
582
  async requestJson(path, { method = "GET", body } = {}) {
545
583
  const url = new URL(path, `${this.host}/`);
546
584
  let response;
package/src/cli.js CHANGED
@@ -39,6 +39,8 @@ const PROSPECTS_REPORT_BAD_PROFILE_USAGE = "Usage: audienti prospects report-bad
39
39
  const PROSPECTS_ASSIGN_USAGE = "Usage: audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json] [--account <acct_id>]";
40
40
  const PROSPECTS_SET_STATUS_USAGE = "Usage: audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected> [--json] [--account <acct_id>]";
41
41
  const PROSPECTS_REPLAN_USAGE = "Usage: audienti prospects replan <prsp_id> [--apply] [--json] [--account <acct_id>]";
42
+ const PROSPECTS_REENRICH_USAGE = "Usage: audienti prospects reenrich <prsp_id> [--profile <prof_id|citation_id>] [--apply] [--json] [--account <acct_id>]";
43
+ const PROSPECTS_REFRESH_QUEUE_USAGE = "Usage: audienti prospects refresh-queue <prsp_id> [--apply] [--json] [--account <acct_id>]";
42
44
  const PROSPECTS_REJECT_USAGE = "Usage: audienti prospects reject <prsp_id> [--json] [--account <acct_id>]";
43
45
  const PROSPECTS_NURTURE_USAGE = "Usage: audienti prospects nurture <prsp_id> [--reason <nurture|non_responsive|not_fit|bad_data_404>] [--json] [--account <acct_id>]";
44
46
  const PROSPECTS_RESTORE_USAGE = "Usage: audienti prospects restore <prsp_id> [--json] [--account <acct_id>]";
@@ -55,6 +57,9 @@ const COMPANY_RULES_CREATE_USAGE = "Usage: audienti company-rules create (--link
55
57
  const COMPANY_RULES_UPDATE_USAGE = "Usage: audienti company-rules update <rule_id> [--linkedin-url <url>] [--domain <domain>] [--disposition <monitor|nurture|not_fit|reject>] [--name <text>] [--user <account_user_id|email|me|none>] [--note <text>] [--json] [--account <acct_id>]";
56
58
  const COMPANY_RULES_REMOVE_USAGE = "Usage: audienti company-rules remove <rule_id> [--json] [--account <acct_id>]";
57
59
  const COMPANY_RULES_APPLY_USAGE = "Usage: audienti company-rules apply (<rule_id>|--all) [--json] [--account <acct_id>]";
60
+ const TASKS_LIST_USAGE = "Usage: audienti tasks list [--status <open|completed>] [--limit <n>] [--json] [--account <acct_id>]";
61
+ const TASKS_ADD_USAGE = "Usage: audienti tasks add --title <text> --due <time> [--prospect <prsp_id>] [--list <list_id>] [--assigned-user <id|me>] [--notes <text>] [--json] [--account <acct_id>]";
62
+ const TASKS_COMPLETE_USAGE = "Usage: audienti tasks complete <ptsk_id> [--json] [--account <acct_id>]";
58
63
  const USERS_ACTIVITY_USAGE = "Usage: audienti users activity [account_user_id|me] [--mode <actor|account_usage|related>] [--window <24h|7d|30d>] [--platform <linkedin|email|gmail>] [--query <text>] [--limit <n>] [--page <n>] [--json] [--account <acct_id>]";
59
64
  const OFFERS_SHOW_USAGE = "Usage: audienti offers show <offr_id> [--json] [--account <acct_id>]";
60
65
  const OFFERS_UPDATE_USAGE = "Usage: audienti offers update <offr_id> [--name <text>] [--description <text>] [--url <url>] [--json] [--account <acct_id>]";
@@ -85,10 +90,11 @@ const ICPS_ADD_TAG_USAGE = "Usage: audienti icps add-tag <icp_id> <tag> [--json]
85
90
  const ICPS_REMOVE_TAG_USAGE = "Usage: audienti icps remove-tag <icp_id> <tag> [--json] [--account <acct_id>]";
86
91
  const LISTS_ADD_TAG_USAGE = "Usage: audienti lists add-tag <list_id> <tag> [--json] [--account <acct_id>]";
87
92
  const LISTS_REMOVE_TAG_USAGE = "Usage: audienti lists remove-tag <list_id> <tag> [--json] [--account <acct_id>]";
88
- const ANALYTICS_PROSPECTS_USAGE = "Usage: audienti analytics prospects [--window 24h] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--motion <motn_id>] [--provenance <source>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
89
- const ANALYTICS_PROSPECTS_COHORT_ANALYSIS_USAGE = "Usage: audienti analytics prospects cohort-analysis [--weeks <n>] [--window 24h] [--motion <motn_id>] [--provenance <source>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
90
- 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>] [--provenance <source>] [--platform <linkedin|email|gmail>] [--json] [--account <acct_id>]";
91
- const ANALYTICS_DASHBOARD_USAGE = "Usage: audienti analytics dashboard [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--offer <offr_id>] [--icp <icp_id>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
93
+ const ANALYTICS_PROSPECTS_USAGE = "Usage: audienti analytics prospects [--window 24h] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--motion <motn_id>] [--list <list_id>] [--provenance <source>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
94
+ 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>]";
95
+ 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>]";
96
+ 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>]";
97
+ 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>]";
92
98
  const TOOLS_LIST_USAGE = "Usage: audienti tools list [--json]";
93
99
  const TOOLS_LINKEDIN_REVIEW_USAGE = "Usage: audienti tools linkedin-review --url <linkedin_url> [--icp <icp_id>] [--json] [--account <acct_id>]";
94
100
  const TOOLS_LINKEDIN_REVIEW_REPORTS_USAGE = "Usage: audienti tools linkedin-review reports [--limit <n>] [--json] [--account <acct_id>]";
@@ -206,6 +212,9 @@ async function dispatch(argv, context) {
206
212
  if (normalizedResource === "company-rules" && action === "apply") return companyRulesApply(rest, context, { accountOverride });
207
213
  if (normalizedResource === "tags" && action === "list") return tagsList(rest, context, { accountOverride });
208
214
  if (normalizedResource === "tags" && action === "show") return tagsShow(rest, context, { accountOverride });
215
+ if (normalizedResource === "tasks" && ["list", "manage"].includes(action)) return tasksList(rest, context, { accountOverride });
216
+ if (normalizedResource === "tasks" && action === "add") return tasksAdd(rest, context, { accountOverride });
217
+ if (normalizedResource === "tasks" && action === "complete") return tasksComplete(rest, context, { accountOverride });
209
218
  if (normalizedResource === "lists" && action === "list") return listsList(rest, context, { accountOverride });
210
219
  if (normalizedResource === "lists" && action === "create") return listsCreate(rest, context, { accountOverride });
211
220
  if (normalizedResource === "lists" && action === "show") return listsShow(rest, context, { accountOverride });
@@ -247,6 +256,8 @@ async function dispatch(argv, context) {
247
256
  if (normalizedResource === "prospects" && action === "assign") return prospectsAssign(rest, context, { accountOverride });
248
257
  if (normalizedResource === "prospects" && action === "set-status") return prospectsSetStatus(rest, context, { accountOverride });
249
258
  if (normalizedResource === "prospects" && action === "replan") return prospectsReplan(rest, context, { accountOverride });
259
+ if (normalizedResource === "prospects" && action === "reenrich") return prospectsReenrich(rest, context, { accountOverride });
260
+ if (normalizedResource === "prospects" && action === "refresh-queue") return prospectsRefreshQueue(rest, context, { accountOverride });
250
261
  if (normalizedResource === "prospects" && action === "reject") return prospectsDisposition("reject", rest, context, { accountOverride });
251
262
  if (normalizedResource === "prospects" && action === "nurture") return prospectsDisposition("nurture", rest, context, { accountOverride });
252
263
  if (normalizedResource === "prospects" && action === "restore") return prospectsDisposition("restore", rest, context, { accountOverride });
@@ -277,6 +288,7 @@ async function dispatch(argv, context) {
277
288
  if (normalizedResource === "analytics" && ["visibility", "visops"].includes(action)) return analyticsVisibility(rest, context, { accountOverride });
278
289
  if (normalizedResource === "analytics" && action === "content") return analyticsContent(rest, context, { accountOverride });
279
290
  if (normalizedResource === "analytics" && ["dashboard", "campaign", "campaigns"].includes(action)) return analyticsDashboard(rest, context, { accountOverride });
291
+ if (normalizedResource === "analytics" && ["cohorts", "cohort"].includes(action)) return analyticsCohorts(rest, context, { accountOverride });
280
292
 
281
293
  throw new CommandError(usage(), { exitCode: resource ? 1 : 0 });
282
294
  }
@@ -1072,6 +1084,55 @@ async function tagsShow(args, context, { accountOverride } = {}) {
1072
1084
  renderTagDetails(payload, context);
1073
1085
  }
1074
1086
 
1087
+ async function tasksList(args, context, { accountOverride } = {}) {
1088
+ const { values, positionals } = parseCommandArgs(args, taskListOptions());
1089
+ if (positionals.length > 0) throw new CommandError(TASKS_LIST_USAGE);
1090
+ validateTaskStatus(values.status);
1091
+
1092
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
1093
+ const payload = await client.tasks(accountId, compactObject({
1094
+ status: values.status,
1095
+ limit: values.limit ? boundedListLimit(values.limit) : undefined
1096
+ }));
1097
+ if (values.json) return writeJson(context.stdout, payload);
1098
+
1099
+ renderTasks(payload, context);
1100
+ }
1101
+
1102
+ async function tasksAdd(args, context, { accountOverride } = {}) {
1103
+ const { values, positionals } = parseCommandArgs(args, taskAddOptions());
1104
+ if (positionals.length > 0 || !values.title || !values.due) throw new CommandError(TASKS_ADD_USAGE);
1105
+ if (values.prospect && values.list) throw new CommandError("Use either --prospect or --list, not both.");
1106
+
1107
+ const { client, accountId, config } = await requireAccountContext(context, { accountOverride });
1108
+ const task = compactObject({
1109
+ title: values.title,
1110
+ due_at: values.due,
1111
+ notes: values.notes,
1112
+ prospect_id: values.prospect,
1113
+ list_id: values.list,
1114
+ assignee_account_user_id: resolveAccountUserId(values["assigned-user"], config, { accountOverride })
1115
+ });
1116
+ const payload = await client.createTask(accountId, { task });
1117
+ if (values.json) return writeJson(context.stdout, payload);
1118
+
1119
+ writeLine(context.stdout, `Created task ${display(payload?.prefix_id || payload?.id)}.`);
1120
+ writeLine(context.stdout, `Title: ${display(payload?.title)}`);
1121
+ if (payload?.notes) writeLine(context.stdout, `Description: ${payload.notes}`);
1122
+ writeLine(context.stdout, `Due: ${display(payload?.due_at, "-")} | Association: ${taskAssociationLabel(payload)}`);
1123
+ }
1124
+
1125
+ async function tasksComplete(args, context, { accountOverride } = {}) {
1126
+ const { values, positionals } = parseCommandArgs(args, jsonOptions());
1127
+ if (positionals.length !== 1) throw new CommandError(TASKS_COMPLETE_USAGE);
1128
+
1129
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
1130
+ const payload = await client.completeTask(accountId, positionals[0]);
1131
+ if (values.json) return writeJson(context.stdout, payload);
1132
+
1133
+ writeLine(context.stdout, `Completed task ${display(payload?.prefix_id || payload?.id || positionals[0])}.`);
1134
+ }
1135
+
1075
1136
  async function listsCreate(args, context, { accountOverride } = {}) {
1076
1137
  const { values, positionals } = parseCommandArgs(args, {
1077
1138
  ...jsonOptions(),
@@ -1861,6 +1922,40 @@ async function prospectsReplan(args, context, { accountOverride } = {}) {
1861
1922
  renderProspectReplan(payload, context);
1862
1923
  }
1863
1924
 
1925
+ async function prospectsReenrich(args, context, { accountOverride } = {}) {
1926
+ const { values, positionals } = parseCommandArgs(args, {
1927
+ ...jsonOptions(),
1928
+ apply: { type: "boolean" },
1929
+ profile: { type: "string" }
1930
+ });
1931
+ if (positionals.length !== 1) throw new CommandError(PROSPECTS_REENRICH_USAGE);
1932
+
1933
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
1934
+ const payload = await client.reenrichProspect(accountId, positionals[0], compactObject({
1935
+ apply: values.apply,
1936
+ profile_id: values.profile
1937
+ }));
1938
+ if (values.json) return writeJson(context.stdout, payload);
1939
+
1940
+ renderProspectReenrich(payload, context);
1941
+ }
1942
+
1943
+ async function prospectsRefreshQueue(args, context, { accountOverride } = {}) {
1944
+ const { values, positionals } = parseCommandArgs(args, {
1945
+ ...jsonOptions(),
1946
+ apply: { type: "boolean" }
1947
+ });
1948
+ if (positionals.length !== 1) throw new CommandError(PROSPECTS_REFRESH_QUEUE_USAGE);
1949
+
1950
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
1951
+ const payload = await client.refreshProspectQueue(accountId, positionals[0], compactObject({
1952
+ apply: values.apply
1953
+ }));
1954
+ if (values.json) return writeJson(context.stdout, payload);
1955
+
1956
+ renderProspectRefreshQueue(payload, context);
1957
+ }
1958
+
1864
1959
  async function prospectsDisposition(action, args, context, { accountOverride } = {}) {
1865
1960
  const usageText = {
1866
1961
  reject: PROSPECTS_REJECT_USAGE,
@@ -2570,6 +2665,7 @@ async function analyticsProspectsCohortAnalysis(args, context, { accountOverride
2570
2665
  weeks: { type: "string" },
2571
2666
  window: { type: "string" },
2572
2667
  motion: { type: "string" },
2668
+ list: { type: "string" },
2573
2669
  provenance: { type: "string" },
2574
2670
  user: { type: "string" }
2575
2671
  });
@@ -2585,6 +2681,7 @@ async function analyticsProspectsCohortAnalysis(args, context, { accountOverride
2585
2681
  window: values.window,
2586
2682
  account_user_id: resolveAccountUserId(values.user, config, { accountOverride }),
2587
2683
  motion_id: values.motion,
2684
+ list_id: values.list,
2588
2685
  provenance: values.provenance,
2589
2686
  cohort_start: cohort.start_date,
2590
2687
  cohort_end: cohort.end_date
@@ -2597,6 +2694,7 @@ async function analyticsProspectsCohortAnalysis(args, context, { accountOverride
2597
2694
  weeks,
2598
2695
  window: values.window || "24h",
2599
2696
  motion: rows.find((row) => row.motion)?.motion || motionPayload(values.motion),
2697
+ list: rows.find((row) => row.list)?.list || listPayload(values.list),
2600
2698
  provenance: rows.find((row) => row.provenance)?.provenance || provenancePayload(values.provenance),
2601
2699
  account_user: rows.find((row) => row.account_user)?.account_user || null,
2602
2700
  cohorts: rows
@@ -2653,6 +2751,33 @@ async function analyticsDashboard(args, context, { accountOverride } = {}) {
2653
2751
  renderAnalyticsDashboard(payload, context);
2654
2752
  }
2655
2753
 
2754
+ async function analyticsCohorts(args, context, { accountOverride } = {}) {
2755
+ const action = args[0];
2756
+ if (action !== "create-list") throw new CommandError(ANALYTICS_COHORT_LIST_USAGE);
2757
+
2758
+ const { values, positionals } = parseCommandArgs(args.slice(1), analyticsCohortListOptions());
2759
+ if (positionals.length > 0 || !values.name || !values.start || !values.end) {
2760
+ throw new CommandError(ANALYTICS_COHORT_LIST_USAGE);
2761
+ }
2762
+
2763
+ const { client, accountId, config } = await requireAccountContext(context, { accountOverride });
2764
+ const payload = await client.createAnalyticsCohortList(accountId, compactObject({
2765
+ name: values.name,
2766
+ start_date: values.start,
2767
+ end_date: values.end,
2768
+ event_type: values.event || "connection_request_sent",
2769
+ account_user_id: resolveAccountUserId(values.user, config, { accountOverride }),
2770
+ note_mode: values["note-mode"],
2771
+ motion_id: values.motion,
2772
+ offer_id: values.offer,
2773
+ icp_id: values.icp,
2774
+ play_tag: values["play-tag"] || values.tag
2775
+ }));
2776
+ if (values.json) return writeJson(context.stdout, payload);
2777
+
2778
+ renderAnalyticsCohortList(payload, context);
2779
+ }
2780
+
2656
2781
  function parseCommandArgs(args, options) {
2657
2782
  try {
2658
2783
  return parseArgs({
@@ -2736,6 +2861,31 @@ function boundedListLimit(value) {
2736
2861
  return Math.min(parsed, API_MAX_LIST_LIMIT);
2737
2862
  }
2738
2863
 
2864
+ function taskListOptions() {
2865
+ return {
2866
+ ...jsonOptions(),
2867
+ status: { type: "string" },
2868
+ limit: { type: "string" }
2869
+ };
2870
+ }
2871
+
2872
+ function taskAddOptions() {
2873
+ return {
2874
+ ...jsonOptions(),
2875
+ title: { type: "string" },
2876
+ due: { type: "string" },
2877
+ prospect: { type: "string" },
2878
+ list: { type: "string" },
2879
+ "assigned-user": { type: "string" },
2880
+ notes: { type: "string" }
2881
+ };
2882
+ }
2883
+
2884
+ function validateTaskStatus(status) {
2885
+ if (!status) return;
2886
+ if (!["open", "completed"].includes(status)) throw new CommandError("--status must be open or completed.");
2887
+ }
2888
+
2739
2889
  function operatorFilterOptions(extra = {}) {
2740
2890
  return {
2741
2891
  ...jsonOptions(),
@@ -2837,6 +2987,7 @@ function analyticsProspectsOptions() {
2837
2987
  "cohort-start": { type: "string" },
2838
2988
  "cohort-end": { type: "string" },
2839
2989
  motion: { type: "string" },
2990
+ list: { type: "string" },
2840
2991
  provenance: { type: "string" }
2841
2992
  };
2842
2993
  }
@@ -2851,6 +3002,7 @@ function analyticsUsersOptions() {
2851
3002
  "cohort-start": { type: "string" },
2852
3003
  "cohort-end": { type: "string" },
2853
3004
  motion: { type: "string" },
3005
+ list: { type: "string" },
2854
3006
  provenance: { type: "string" },
2855
3007
  platform: { type: "string" },
2856
3008
  channel: { type: "string" }
@@ -2865,18 +3017,37 @@ function analyticsDashboardOptions() {
2865
3017
  "play-tag": { type: "string" },
2866
3018
  tag: { type: "string" },
2867
3019
  motion: { type: "string" },
3020
+ list: { type: "string" },
2868
3021
  offer: { type: "string" },
2869
3022
  icp: { type: "string" },
2870
3023
  user: { type: "string" }
2871
3024
  };
2872
3025
  }
2873
3026
 
3027
+ function analyticsCohortListOptions() {
3028
+ return {
3029
+ ...jsonOptions(),
3030
+ name: { type: "string" },
3031
+ start: { type: "string" },
3032
+ end: { type: "string" },
3033
+ event: { type: "string" },
3034
+ user: { type: "string" },
3035
+ "note-mode": { type: "string" },
3036
+ motion: { type: "string" },
3037
+ offer: { type: "string" },
3038
+ icp: { type: "string" },
3039
+ "play-tag": { type: "string" },
3040
+ tag: { type: "string" }
3041
+ };
3042
+ }
3043
+
2874
3044
  function analyticsQuery(values, config = {}, { accountOverride } = {}) {
2875
3045
  return compactObject({
2876
3046
  window: values.window,
2877
3047
  cohort_start: values["cohort-start"],
2878
3048
  cohort_end: values["cohort-end"],
2879
3049
  motion_id: values.motion,
3050
+ list_id: values.list,
2880
3051
  provenance: values.provenance,
2881
3052
  account_user_id: resolveAccountUserId(values.user, config, { accountOverride })
2882
3053
  });
@@ -2892,6 +3063,7 @@ function analyticsUsersQuery(values, config = {}, { accountOverride } = {}) {
2892
3063
  cohort_start: values["cohort-start"],
2893
3064
  cohort_end: values["cohort-end"],
2894
3065
  motion_id: values.motion,
3066
+ list_id: values.list,
2895
3067
  provenance: values.provenance,
2896
3068
  platform: values.platform || values.channel
2897
3069
  });
@@ -2903,6 +3075,7 @@ function analyticsDashboardQuery(values, config = {}, { accountOverride } = {})
2903
3075
  cohort_end_date: values["cohort-end"],
2904
3076
  play_tag: values["play-tag"] || values.tag,
2905
3077
  motion_id: values.motion,
3078
+ list_id: values.list,
2906
3079
  offer_id: values.offer,
2907
3080
  icp_id: values.icp,
2908
3081
  account_user_id: resolveAccountUserId(values.user, config, { accountOverride })
@@ -2989,6 +3162,7 @@ function cohortAnalysisRow(payload, fallbackCohort) {
2989
3162
  label: `${display(cohort.start_date)} to ${display(cohort.end_date)}`,
2990
3163
  total_count: payload?.cohort_prospects_count ?? payload?.prospects_added_count ?? 0,
2991
3164
  motion: payload?.motion || null,
3165
+ list: payload?.list || null,
2992
3166
  provenance: payload?.provenance || null,
2993
3167
  account_user: payload?.account_user || null,
2994
3168
  stages,
@@ -3012,6 +3186,12 @@ function provenancePayload(provenance) {
3012
3186
  };
3013
3187
  }
3014
3188
 
3189
+ function listPayload(listId) {
3190
+ if (!listId) return null;
3191
+
3192
+ return { prefix_id: listId, name: listId };
3193
+ }
3194
+
3015
3195
  function compactObject(object) {
3016
3196
  return Object.fromEntries(
3017
3197
  Object.entries(object).filter(([, value]) => {
@@ -3616,6 +3796,38 @@ function renderTagDetails(payload, context) {
3616
3796
  renderMotions(motions, context);
3617
3797
  }
3618
3798
 
3799
+ function renderTasks(payload, context) {
3800
+ const tasks = Array.isArray(payload?.tasks) ? payload.tasks : [];
3801
+ const meta = payload?.meta || {};
3802
+
3803
+ writeLine(context.stdout, `Tasks: ${display(meta.status, "open")} (${display(tasks.length, 0)} shown, ${display(meta.open_count, 0)} open, ${display(meta.completed_count, 0)} completed)`);
3804
+ if (tasks.length === 0) return writeLine(context.stdout, "No tasks found.");
3805
+
3806
+ writeAlignedTable(
3807
+ context,
3808
+ ["TASK ID", "STATUS", "DUE", "ASSOCIATION", "TITLE"],
3809
+ tasks.map((task) => [
3810
+ display(task.prefix_id || task.id),
3811
+ display(task.status_label || task.status),
3812
+ display(task.due_at, "-"),
3813
+ taskAssociationLabel(task),
3814
+ display(task.title)
3815
+ ])
3816
+ );
3817
+
3818
+ for (const task of tasks) {
3819
+ if (task?.notes) writeLine(context.stdout, `${display(task.prefix_id || task.id)} description: ${task.notes}`);
3820
+ }
3821
+ }
3822
+
3823
+ function taskAssociationLabel(task) {
3824
+ const association = task?.association || {};
3825
+ if (!association.type || association.type === "none") return "No association";
3826
+
3827
+ const name = association.name || association.id;
3828
+ return `${association.type}:${display(name)}`;
3829
+ }
3830
+
3619
3831
  function renderUsers(users, context) {
3620
3832
  if (!Array.isArray(users) || users.length === 0) return writeLine(context.stdout, "No account users found.");
3621
3833
 
@@ -3998,6 +4210,61 @@ function renderProspectReplan(payload, context) {
3998
4210
  if (payload?.status === "coach_error") writeLine(context.stdout, "The plan was not persisted. Fix the coach error and rerun with --apply.");
3999
4211
  }
4000
4212
 
4213
+ function renderProspectReenrich(payload, context) {
4214
+ const prospect = payload?.prospect || {};
4215
+ const profile = payload?.profile || {};
4216
+ const completeness = payload?.completeness || {};
4217
+ const enrichment = payload?.enrichment || {};
4218
+ const status = payload?.status === "queued" ? "queued" : (payload?.status === "not_queued" ? "not queued" : "dry run");
4219
+
4220
+ writeLine(context.stdout, `Re-enrich ${status} for ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)}).`);
4221
+ writeLine(context.stdout, `Profile: ${display(profile.prefix_id)} ${display(profile.identifier)} ${display(profile.url)}`);
4222
+ writeLine(context.stdout, `Profile status: ${display(profile.status)}`);
4223
+ writeLine(context.stdout, `Thin profile signals: ${completeness.thin_profile_signals ? "yes" : "no"}`);
4224
+ writeLine(context.stdout, `Experience entries: ${sumObjectValues(completeness.experience_counts)}`);
4225
+ writeLine(context.stdout, `Substantive bio length: ${display(completeness.substantive_bio_length, 0)}`);
4226
+ if (profile.invalid_reason) writeLine(context.stdout, `Invalid reason: ${profile.invalid_reason}`);
4227
+ if (enrichment.retry_counter_reset) writeLine(context.stdout, "A stale enrichment retry counter will be cleared.");
4228
+ if (enrichment.next_enrichment_at) writeLine(context.stdout, `Next enrichment at: ${enrichment.next_enrichment_at}`);
4229
+ if (payload?.status === "dry_run") writeLine(context.stdout, "Run again with --apply to queue full enrichment.");
4230
+ if (payload?.status === "not_queued") writeLine(context.stdout, "The profile was not queued, usually because an active enrichment is already running.");
4231
+ }
4232
+
4233
+ function renderProspectRefreshQueue(payload, context) {
4234
+ const prospect = payload?.prospect || {};
4235
+ const draftCache = payload?.draft_cache || {};
4236
+ const coachCache = payload?.coach_cache || {};
4237
+ const refresh = payload?.queue_refresh || {};
4238
+ const status = payload?.status === "applied" ? "applied" : "dry run";
4239
+
4240
+ writeLine(context.stdout, `Refresh queue ${status} for ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)}).`);
4241
+ writeLine(context.stdout, `Coach cache: ${coachCache.present ? "present" : "empty"}`);
4242
+ if (coachCache.evaluated_at) writeLine(context.stdout, `Coach evaluated at: ${coachCache.evaluated_at}`);
4243
+ writeLine(context.stdout, `Draft cache rows: ${display(draftCache.count, 0)}`);
4244
+ writeLine(context.stdout, `Draft statuses: ${formatObjectCounts(draftCache.by_status)}`);
4245
+ writeLine(context.stdout, `Action types: ${Array.isArray(draftCache.action_types) && draftCache.action_types.length > 0 ? draftCache.action_types.join(", ") : "none"}`);
4246
+ if (payload?.applied) {
4247
+ writeLine(context.stdout, `Deleted draft rows: ${display(draftCache.deleted_count, 0)}`);
4248
+ writeLine(context.stdout, `Draft prewarm queued: ${display(refresh?.draft_prewarm?.enqueued_rows, 0)}`);
4249
+ } else {
4250
+ writeLine(context.stdout, "Run again with --apply to clear coach/draft cache and rebuild the queue row.");
4251
+ }
4252
+ }
4253
+
4254
+ function sumObjectValues(value) {
4255
+ if (!value || typeof value !== "object") return 0;
4256
+
4257
+ return Object.values(value).reduce((sum, item) => sum + Number(item || 0), 0);
4258
+ }
4259
+
4260
+ function formatObjectCounts(value) {
4261
+ if (!value || typeof value !== "object" || Object.keys(value).length === 0) return "none";
4262
+
4263
+ return Object.entries(value)
4264
+ .map(([key, count]) => `${key}:${count}`)
4265
+ .join(", ");
4266
+ }
4267
+
4001
4268
  function replanStatusLabel(payload) {
4002
4269
  if (payload?.status === "dry_run") return "dry run";
4003
4270
  if (payload?.status === "coach_error") return "coach error";
@@ -4840,12 +5107,23 @@ function renderAnalyticsDashboard(payload, context) {
4840
5107
  writeCountTable(context, "Current pipeline stages", payload?.pipeline_stage_counts, ["STAGE", "COUNT"], countRow);
4841
5108
  }
4842
5109
 
5110
+ function renderAnalyticsCohortList(payload, context) {
5111
+ const list = payload?.list || {};
5112
+ writeLine(context.stdout, `Created analytics cohort list ${display(list.name)} (${display(list.prefix_id)}).`);
5113
+ writeLine(context.stdout, `Matched prospects: ${display(payload?.matched_count, 0)}`);
5114
+ const query = payload?.query || {};
5115
+ if (query.event_type) writeLine(context.stdout, `Event: ${display(query.event_type)}`);
5116
+ if (query.start_date || query.end_date) writeLine(context.stdout, `Activity: ${display(query.start_date)} to ${display(query.end_date)} (${display(query.date_field, "events.created_at")})`);
5117
+ if (query.note_mode && query.note_mode !== "any") writeLine(context.stdout, `Note mode: ${display(query.note_mode)}`);
5118
+ }
5119
+
4843
5120
  function renderAnalyticsProspectCohortAnalysis(payload, context) {
4844
5121
  const cohorts = Array.isArray(payload?.cohorts) ? payload.cohorts : [];
4845
5122
  writeLine(context.stdout, `Prospect cohort analysis (${display(payload?.weeks, cohorts.length)} weeks)`);
4846
5123
  writeLine(context.stdout, `Activity window: ${display(payload?.window, "24h")}`);
4847
5124
  writeLine(context.stdout, "Cohorts: account_prospects.created_at, calendar weeks, oldest first");
4848
5125
  writeAnalyticsMotion(payload, context);
5126
+ writeAnalyticsList(payload, context);
4849
5127
  writeAnalyticsProvenance(payload, context);
4850
5128
  if (payload?.account_user) {
4851
5129
  writeLine(context.stdout, `User: ${entityLabel(payload.account_user)}`);
@@ -4906,6 +5184,7 @@ function renderAnalyticsContent(payload, context) {
4906
5184
 
4907
5185
  function writeAnalyticsScope(payload, context) {
4908
5186
  writeAnalyticsMotion(payload, context);
5187
+ writeAnalyticsList(payload, context);
4909
5188
  writeAnalyticsProvenance(payload, context);
4910
5189
  if (payload?.account_user) {
4911
5190
  writeLine(context.stdout, `User: ${entityLabel(payload.account_user)}`);
@@ -4918,6 +5197,7 @@ function writeDashboardFilters(payload, context) {
4918
5197
  const filters = payload?.filters || {};
4919
5198
  if (filters.motion) writeLine(context.stdout, `Motion: ${entityLabel(filters.motion)}`);
4920
5199
  if (filters.play_tag) writeLine(context.stdout, `Tag: ${filters.play_tag}`);
5200
+ if (filters.list) writeLine(context.stdout, `List: ${entityLabel(filters.list)}`);
4921
5201
  if (filters.offer) writeLine(context.stdout, `Offer: ${entityLabel(filters.offer)}`);
4922
5202
  if (filters.icp) writeLine(context.stdout, `ICP: ${entityLabel(filters.icp)}`);
4923
5203
  if (filters.account_user) {
@@ -4941,6 +5221,12 @@ function writeAnalyticsMotion(payload, context) {
4941
5221
  writeLine(context.stdout, `Motion: ${entityLabel(payload.motion)}`);
4942
5222
  }
4943
5223
 
5224
+ function writeAnalyticsList(payload, context) {
5225
+ if (!payload?.list) return;
5226
+
5227
+ writeLine(context.stdout, `List: ${entityLabel(payload.list)}`);
5228
+ }
5229
+
4944
5230
  function writeAnalyticsProvenance(payload, context) {
4945
5231
  if (!payload?.provenance) return;
4946
5232
 
@@ -5575,6 +5861,8 @@ const HELP_TOPICS = new Map([
5575
5861
  " audienti prospects assign <prsp_id> --assigned-user <id|me|unassign>",
5576
5862
  " audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected>",
5577
5863
  " audienti prospects replan <prsp_id> [--apply]",
5864
+ " audienti prospects reenrich <prsp_id> [--apply]",
5865
+ " audienti prospects refresh-queue <prsp_id> [--apply]",
5578
5866
  " audienti prospects lock <prsp_id> [--note <text>]",
5579
5867
  " audienti prospects reject <prsp_id>",
5580
5868
  " audienti prospects nurture <prsp_id> [--reason <reason>]",
@@ -5593,6 +5881,9 @@ const HELP_TOPICS = new Map([
5593
5881
  " audienti lists remove-tag <list_id> <tag>",
5594
5882
  " audienti tags list",
5595
5883
  " audienti tags show <tag>",
5884
+ " audienti tasks list [--status open]",
5885
+ " audienti tasks add --title <text> --due <time>",
5886
+ " audienti tasks complete <ptsk_id>",
5596
5887
  " audienti offers list",
5597
5888
  " audienti offers show <offr_id>",
5598
5889
  " audienti offers update <offr_id> [--name <text>]",
@@ -5623,6 +5914,7 @@ const HELP_TOPICS = new Map([
5623
5914
  " Analytics",
5624
5915
  " audienti analytics prospects --window 24h",
5625
5916
  " audienti analytics dashboard --play-tag <tag>",
5917
+ " audienti analytics cohorts create-list --name \"Blank note test\" --start 2026-07-20 --end 2026-07-20 --note-mode blank",
5626
5918
  " audienti analytics prospects cohort-analysis --weeks 4 --motion <motn_id>",
5627
5919
  " audienti analytics users --user me --window 30d",
5628
5920
  " audienti analytics visibility --window 24h --user me",
@@ -5643,6 +5935,7 @@ const HELP_TOPICS = new Map([
5643
5935
  " Analyze one motion: audienti motions analytics <motn_id>",
5644
5936
  " Count one campaign: audienti analytics dashboard --play-tag <tag>",
5645
5937
  " Audit your work: audienti analytics users --user me --window 30d",
5938
+ " Review reminders: audienti tasks list",
5646
5939
  "",
5647
5940
  "Global options:",
5648
5941
  " --account <acct_id> Use an account for one command without saving it",
@@ -6392,6 +6685,82 @@ const HELP_TOPICS = new Map([
6392
6685
  " motions[]: motion rows whose play_tags include tag"
6393
6686
  ].join("\n")],
6394
6687
 
6688
+ ["tasks", [
6689
+ "Usage:",
6690
+ ` ${TASKS_LIST_USAGE.slice("Usage: ".length)}`,
6691
+ ` ${TASKS_ADD_USAGE.slice("Usage: ".length)}`,
6692
+ ` ${TASKS_COMPLETE_USAGE.slice("Usage: ".length)}`,
6693
+ "",
6694
+ "Status: implemented",
6695
+ "",
6696
+ "Purpose:",
6697
+ " Add and manage plain reminders for the current account user, optionally associated with a prospect or list.",
6698
+ "",
6699
+ "Run `audienti tasks list help`, `audienti tasks add help`, or `audienti tasks complete help` for details."
6700
+ ].join("\n")],
6701
+
6702
+ ["tasks list", [
6703
+ "Usage:",
6704
+ ` ${TASKS_LIST_USAGE.slice("Usage: ".length)}`,
6705
+ "",
6706
+ "Status: implemented",
6707
+ "",
6708
+ "Options:",
6709
+ " --status <open|completed> Defaults to open",
6710
+ " --limit <n> Defaults to 20, capped at 100",
6711
+ "",
6712
+ "API:",
6713
+ " GET /api/v1/accounts/:account_id/tasks.json",
6714
+ "",
6715
+ "Output shape:",
6716
+ " tasks[].prefix_id: ptsk_ task id",
6717
+ " tasks[].title: string",
6718
+ " tasks[].notes: task description | null",
6719
+ " tasks[].due_at: ISO timestamp",
6720
+ " tasks[].association: prospect, list, or none"
6721
+ ].join("\n")],
6722
+
6723
+ ["tasks manage", [
6724
+ "Usage:",
6725
+ ` ${TASKS_LIST_USAGE.slice("Usage: ".length)}`,
6726
+ "",
6727
+ "Status: implemented",
6728
+ "",
6729
+ "Alias:",
6730
+ " `audienti tasks manage` is the same as `audienti tasks list`."
6731
+ ].join("\n")],
6732
+
6733
+ ["tasks add", [
6734
+ "Usage:",
6735
+ ` ${TASKS_ADD_USAGE.slice("Usage: ".length)}`,
6736
+ "",
6737
+ "Status: implemented",
6738
+ "",
6739
+ "Input shape:",
6740
+ " title: short reminder name",
6741
+ " due: timestamp string accepted by the app",
6742
+ " notes: optional task description",
6743
+ " prospect: optional prsp_ id",
6744
+ " list: optional list_ id",
6745
+ " assigned-user: account user id or me; defaults to the current account user",
6746
+ "",
6747
+ "API:",
6748
+ " POST /api/v1/accounts/:account_id/tasks.json"
6749
+ ].join("\n")],
6750
+
6751
+ ["tasks complete", [
6752
+ "Usage:",
6753
+ ` ${TASKS_COMPLETE_USAGE.slice("Usage: ".length)}`,
6754
+ "",
6755
+ "Status: implemented",
6756
+ "",
6757
+ "Input shape:",
6758
+ " task_id: ptsk_ prefix id or numeric id for a task assigned to the current account user",
6759
+ "",
6760
+ "API:",
6761
+ " PATCH /api/v1/accounts/:account_id/tasks/:id/complete.json"
6762
+ ].join("\n")],
6763
+
6395
6764
  ["lists", [
6396
6765
  "Usage:",
6397
6766
  " audienti lists list [--tag <tag>] [--json]",
@@ -7080,6 +7449,8 @@ const HELP_TOPICS = new Map([
7080
7449
  " audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json]",
7081
7450
  " audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected> [--json]",
7082
7451
  " audienti prospects replan <prsp_id> [--apply] [--json]",
7452
+ " audienti prospects reenrich <prsp_id> [--profile <prof_id|citation_id>] [--apply] [--json]",
7453
+ " audienti prospects refresh-queue <prsp_id> [--apply] [--json]",
7083
7454
  " audienti prospects reject <prsp_id> [--json]",
7084
7455
  " audienti prospects nurture <prsp_id> [--reason <reason>] [--json]",
7085
7456
  " audienti prospects restore <prsp_id> [--json]",
@@ -7283,6 +7654,51 @@ const HELP_TOPICS = new Map([
7283
7654
  " }"
7284
7655
  ].join("\n")],
7285
7656
 
7657
+ ["prospects reenrich", [
7658
+ "Usage:",
7659
+ ` ${PROSPECTS_REENRICH_USAGE.slice("Usage: ".length)}`,
7660
+ "",
7661
+ "Status: implemented",
7662
+ "",
7663
+ "Purpose:",
7664
+ " Force a full LinkedIn person profile enrichment for one prospect from the CLI.",
7665
+ "",
7666
+ "Behavior:",
7667
+ " Defaults to a dry-run showing the selected profile, completeness signals, and whether a stale retry counter would be cleared.",
7668
+ " Pass --apply to queue ProfileEnrichJob with a maintenance origin and schedule expansion after enrichment.",
7669
+ "",
7670
+ "API:",
7671
+ " POST /api/v1/accounts/:account_id/prospects/:id/reenrich.json",
7672
+ "",
7673
+ "JSON body:",
7674
+ " {",
7675
+ " \"apply\": true,",
7676
+ " \"profile_id\": \"prof_abc123\"",
7677
+ " }"
7678
+ ].join("\n")],
7679
+
7680
+ ["prospects refresh-queue", [
7681
+ "Usage:",
7682
+ ` ${PROSPECTS_REFRESH_QUEUE_USAGE.slice("Usage: ".length)}`,
7683
+ "",
7684
+ "Status: implemented",
7685
+ "",
7686
+ "Purpose:",
7687
+ " Clear stale next-action coach and operator draft cache for one account prospect, then rebuild the queue row.",
7688
+ "",
7689
+ "Behavior:",
7690
+ " Defaults to a dry-run showing coach-cache and draft-cache state.",
7691
+ " Pass --apply to delete this prospect's account-scoped ProspectDraft rows, clear AccountProspect coach cache, and force the queue refresher.",
7692
+ "",
7693
+ "API:",
7694
+ " POST /api/v1/accounts/:account_id/prospects/:id/refresh_queue.json",
7695
+ "",
7696
+ "JSON body:",
7697
+ " {",
7698
+ " \"apply\": true",
7699
+ " }"
7700
+ ].join("\n")],
7701
+
7286
7702
  ["prospects reject", [
7287
7703
  "Usage:",
7288
7704
  ` ${PROSPECTS_REJECT_USAGE.slice("Usage: ".length)}`,
@@ -8024,10 +8440,11 @@ const HELP_TOPICS = new Map([
8024
8440
 
8025
8441
  ["analytics", [
8026
8442
  "Usage:",
8027
- " audienti analytics prospects [--window 24h] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--motion <motn_id>] [--user <account_user_id|email|name|me>] [--json]",
8028
- " audienti analytics dashboard [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--json]",
8029
- " audienti analytics prospects cohort-analysis [--weeks <n>] [--window 24h] [--motion <motn_id>] [--user <account_user_id|email|name|me>] [--json]",
8030
- " 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>] [--platform <linkedin|email|gmail>] [--json]",
8443
+ " 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]",
8444
+ " audienti analytics dashboard [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--list <list_id>] [--json]",
8445
+ " 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]",
8446
+ " audienti analytics prospects cohort-analysis [--weeks <n>] [--window 24h] [--motion <motn_id>] [--list <list_id>] [--user <account_user_id|email|name|me>] [--json]",
8447
+ " 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>] [--platform <linkedin|email|gmail>] [--json]",
8031
8448
  " audienti analytics visibility [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
8032
8449
  " audienti analytics visops [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
8033
8450
  " audienti analytics content [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
@@ -8039,10 +8456,12 @@ const HELP_TOPICS = new Map([
8039
8456
  " --start <YYYY-MM-DD> --end <YYYY-MM-DD> For user analytics, select the events.created_at activity range instead of --window.",
8040
8457
  " --cohort-start <YYYY-MM-DD> --cohort-end <YYYY-MM-DD> Select the AccountProspect.created_at cohort while --window or --start/--end selects the activity period.",
8041
8458
  " --motion <motn_id> For prospect and user analytics, filter AccountProspect.motion_id to one motion/play.",
8459
+ " --list <list_id> Filter analytics to prospects in one list, including analytics cohort lists.",
8042
8460
  " --play-tag <tag> For dashboard analytics, filter to motions/lists tagged with a campaign tag.",
8043
8461
  " --provenance <source> Optional lower-level AccountProspect.intake_source filter.",
8044
8462
  " --platform <linkedin|email|gmail> For user analytics, filter events.platform. --channel is accepted as an alias.",
8045
8463
  " cohort-analysis loops over recent weekly AccountProspect.created_at cohorts and compares their current stages.",
8464
+ " cohorts create-list materializes an events.created_at cohort as a normal account list for reuse in dashboard, prospects, and users analytics.",
8046
8465
  " --user <account_user_id|email|name|me> Narrow analytics to one account user. For prospect analytics, this means prospects assigned to that account user. Email/name partials are accepted when they match exactly one account user.",
8047
8466
  "",
8048
8467
  "Output:",
@@ -8062,6 +8481,7 @@ const HELP_TOPICS = new Map([
8062
8481
  " --cohort-start <YYYY-MM-DD> --cohort-end <YYYY-MM-DD> Select the AccountProspect.created_at cohort.",
8063
8482
  " --play-tag <tag> Filter to motions/lists tagged with a campaign tag. --tag is accepted as an alias.",
8064
8483
  " --motion <motn_id> Filter to one motion/play.",
8484
+ " --list <list_id> Filter to prospects in one list, including analytics cohort lists.",
8065
8485
  " --offer <offr_id> Filter to one offer.",
8066
8486
  " --icp <icp_id> Filter to one ICP.",
8067
8487
  " --user <account_user_id|email|name|me> Filter to prospects assigned to one account user.",
@@ -8079,8 +8499,8 @@ const HELP_TOPICS = new Map([
8079
8499
 
8080
8500
  ["analytics prospects", [
8081
8501
  "Usage:",
8082
- " audienti analytics prospects [--window 24h] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--motion <motn_id>] [--provenance <source>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]",
8083
- " audienti analytics prospects cohort-analysis [--weeks <n>] [--window 24h] [--motion <motn_id>] [--provenance <source>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]",
8502
+ ` ${ANALYTICS_PROSPECTS_USAGE.slice("Usage: ".length)}`,
8503
+ ` ${ANALYTICS_PROSPECTS_COHORT_ANALYSIS_USAGE.slice("Usage: ".length)}`,
8084
8504
  "",
8085
8505
  "Status: implemented",
8086
8506
  "",
@@ -8088,6 +8508,7 @@ const HELP_TOPICS = new Map([
8088
8508
  " window: activity/event period for actions",
8089
8509
  " cohort: selected AccountProspect.created_at cohort when cohort dates are provided",
8090
8510
  " motion: selected motion/play when --motion is provided",
8511
+ " list: selected list when --list is provided",
8091
8512
  " provenance: selected AccountProspect.intake_source when --provenance is provided",
8092
8513
  " prospects_added_count: account prospects added in the window, or cohort size when cohort dates are provided",
8093
8514
  " cohort_prospects_count: selected AccountProspect.created_at cohort size when cohort dates are provided",
@@ -8113,6 +8534,7 @@ const HELP_TOPICS = new Map([
8113
8534
  " --weeks <n> Number of calendar-week cohorts to inspect. Defaults to 4. Maximum 26.",
8114
8535
  " --window <w> Activity window passed through to each analytics call. Defaults to 24h.",
8115
8536
  " --motion <motn_id> Optional motion/play filter.",
8537
+ " --list <list_id> Optional list filter.",
8116
8538
  " --provenance <source> Optional AccountProspect.intake_source filter.",
8117
8539
  " --user <id> Optional account-user filter.",
8118
8540
  "",
@@ -8142,6 +8564,7 @@ const HELP_TOPICS = new Map([
8142
8564
  " --start <YYYY-MM-DD> --end <YYYY-MM-DD> Explicit events.created_at activity range.",
8143
8565
  " --cohort-start <YYYY-MM-DD> --cohort-end <YYYY-MM-DD> Optional AccountProspect.created_at cohort filter.",
8144
8566
  " --motion <motn_id> Optional motion/play filter.",
8567
+ " --list <list_id> Optional list filter.",
8145
8568
  " --provenance <source> Optional AccountProspect.intake_source filter.",
8146
8569
  " --platform <linkedin|email|gmail> Optional events.platform filter. `email` includes email and gmail rows; --channel is an alias.",
8147
8570
  "",
@@ -8157,6 +8580,34 @@ const HELP_TOPICS = new Map([
8157
8580
  " GET /api/v1/accounts/:account_id/analytics/users.json"
8158
8581
  ].join("\n")],
8159
8582
 
8583
+ ["analytics cohorts", [
8584
+ "Usage:",
8585
+ ` ${ANALYTICS_COHORT_LIST_USAGE.slice("Usage: ".length)}`,
8586
+ "",
8587
+ "Status: implemented",
8588
+ "",
8589
+ "Purpose:",
8590
+ " Materialize an events.created_at cohort as a normal account list so dashboard, prospects, and users analytics can filter by that list later.",
8591
+ "",
8592
+ "Options:",
8593
+ " --name <text> Required list name.",
8594
+ " --start <YYYY-MM-DD> --end <YYYY-MM-DD> Required activity date range.",
8595
+ " --event connection_request_sent Event selector. This is the supported event today.",
8596
+ " --note-mode <any|with_note|blank> Optional connection-request note selector.",
8597
+ " --user <account_user_id|email|name|me> Optional actor filter for the event sender.",
8598
+ " --motion <motn_id>, --offer <offr_id>, --icp <icp_id>, --play-tag <tag> Optional prospect/motion filters.",
8599
+ "",
8600
+ "API:",
8601
+ " POST /api/v1/accounts/:account_id/analytics/cohort_lists.json"
8602
+ ].join("\n")],
8603
+
8604
+ ["analytics cohorts create-list", [
8605
+ "Usage:",
8606
+ ` ${ANALYTICS_COHORT_LIST_USAGE.slice("Usage: ".length)}`,
8607
+ "",
8608
+ "Alias for `audienti analytics cohorts`."
8609
+ ].join("\n")],
8610
+
8160
8611
  ["analytics user", [
8161
8612
  "Usage:",
8162
8613
  " audienti analytics user [--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>] [--json] [--account <acct_id>]",
@@ -8274,6 +8725,7 @@ const HELP_TOPICS = new Map([
8274
8725
  " audienti users activity me --window 7d",
8275
8726
  " audienti analytics prospects --window 24h",
8276
8727
  " audienti analytics dashboard --play-tag wine_campaign",
8728
+ " audienti analytics cohorts create-list --name \"Connection requests 2026-07-20\" --start 2026-07-20 --end 2026-07-20",
8277
8729
  " audienti analytics users --user me --window 30d",
8278
8730
  " audienti analytics visibility --window 24h --user me",
8279
8731
  " audienti analytics content --window week",