@audienti/cli 0.1.28 → 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,14 @@ 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
+
7
15
  ## [0.1.28] - 2026-07-23
8
16
 
9
17
  ### 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.28",
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
  }
@@ -555,6 +572,13 @@ export class AudientiClient {
555
572
  return this.requestJson(accountPath(accountId, ["analytics", "dashboard"], query));
556
573
  }
557
574
 
575
+ createAnalyticsCohortList(accountId, body = {}) {
576
+ return this.requestJson(accountPath(accountId, ["analytics", "cohort_lists"]), {
577
+ method: "POST",
578
+ body
579
+ });
580
+ }
581
+
558
582
  async requestJson(path, { method = "GET", body } = {}) {
559
583
  const url = new URL(path, `${this.host}/`);
560
584
  let response;
package/src/cli.js CHANGED
@@ -57,6 +57,9 @@ const COMPANY_RULES_CREATE_USAGE = "Usage: audienti company-rules create (--link
57
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>]";
58
58
  const COMPANY_RULES_REMOVE_USAGE = "Usage: audienti company-rules remove <rule_id> [--json] [--account <acct_id>]";
59
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>]";
60
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>]";
61
64
  const OFFERS_SHOW_USAGE = "Usage: audienti offers show <offr_id> [--json] [--account <acct_id>]";
62
65
  const OFFERS_UPDATE_USAGE = "Usage: audienti offers update <offr_id> [--name <text>] [--description <text>] [--url <url>] [--json] [--account <acct_id>]";
@@ -87,10 +90,11 @@ const ICPS_ADD_TAG_USAGE = "Usage: audienti icps add-tag <icp_id> <tag> [--json]
87
90
  const ICPS_REMOVE_TAG_USAGE = "Usage: audienti icps remove-tag <icp_id> <tag> [--json] [--account <acct_id>]";
88
91
  const LISTS_ADD_TAG_USAGE = "Usage: audienti lists add-tag <list_id> <tag> [--json] [--account <acct_id>]";
89
92
  const LISTS_REMOVE_TAG_USAGE = "Usage: audienti lists remove-tag <list_id> <tag> [--json] [--account <acct_id>]";
90
- 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>]";
91
- 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>]";
92
- 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>]";
93
- 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>]";
94
98
  const TOOLS_LIST_USAGE = "Usage: audienti tools list [--json]";
95
99
  const TOOLS_LINKEDIN_REVIEW_USAGE = "Usage: audienti tools linkedin-review --url <linkedin_url> [--icp <icp_id>] [--json] [--account <acct_id>]";
96
100
  const TOOLS_LINKEDIN_REVIEW_REPORTS_USAGE = "Usage: audienti tools linkedin-review reports [--limit <n>] [--json] [--account <acct_id>]";
@@ -208,6 +212,9 @@ async function dispatch(argv, context) {
208
212
  if (normalizedResource === "company-rules" && action === "apply") return companyRulesApply(rest, context, { accountOverride });
209
213
  if (normalizedResource === "tags" && action === "list") return tagsList(rest, context, { accountOverride });
210
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 });
211
218
  if (normalizedResource === "lists" && action === "list") return listsList(rest, context, { accountOverride });
212
219
  if (normalizedResource === "lists" && action === "create") return listsCreate(rest, context, { accountOverride });
213
220
  if (normalizedResource === "lists" && action === "show") return listsShow(rest, context, { accountOverride });
@@ -281,6 +288,7 @@ async function dispatch(argv, context) {
281
288
  if (normalizedResource === "analytics" && ["visibility", "visops"].includes(action)) return analyticsVisibility(rest, context, { accountOverride });
282
289
  if (normalizedResource === "analytics" && action === "content") return analyticsContent(rest, context, { accountOverride });
283
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 });
284
292
 
285
293
  throw new CommandError(usage(), { exitCode: resource ? 1 : 0 });
286
294
  }
@@ -1076,6 +1084,55 @@ async function tagsShow(args, context, { accountOverride } = {}) {
1076
1084
  renderTagDetails(payload, context);
1077
1085
  }
1078
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
+
1079
1136
  async function listsCreate(args, context, { accountOverride } = {}) {
1080
1137
  const { values, positionals } = parseCommandArgs(args, {
1081
1138
  ...jsonOptions(),
@@ -2608,6 +2665,7 @@ async function analyticsProspectsCohortAnalysis(args, context, { accountOverride
2608
2665
  weeks: { type: "string" },
2609
2666
  window: { type: "string" },
2610
2667
  motion: { type: "string" },
2668
+ list: { type: "string" },
2611
2669
  provenance: { type: "string" },
2612
2670
  user: { type: "string" }
2613
2671
  });
@@ -2623,6 +2681,7 @@ async function analyticsProspectsCohortAnalysis(args, context, { accountOverride
2623
2681
  window: values.window,
2624
2682
  account_user_id: resolveAccountUserId(values.user, config, { accountOverride }),
2625
2683
  motion_id: values.motion,
2684
+ list_id: values.list,
2626
2685
  provenance: values.provenance,
2627
2686
  cohort_start: cohort.start_date,
2628
2687
  cohort_end: cohort.end_date
@@ -2635,6 +2694,7 @@ async function analyticsProspectsCohortAnalysis(args, context, { accountOverride
2635
2694
  weeks,
2636
2695
  window: values.window || "24h",
2637
2696
  motion: rows.find((row) => row.motion)?.motion || motionPayload(values.motion),
2697
+ list: rows.find((row) => row.list)?.list || listPayload(values.list),
2638
2698
  provenance: rows.find((row) => row.provenance)?.provenance || provenancePayload(values.provenance),
2639
2699
  account_user: rows.find((row) => row.account_user)?.account_user || null,
2640
2700
  cohorts: rows
@@ -2691,6 +2751,33 @@ async function analyticsDashboard(args, context, { accountOverride } = {}) {
2691
2751
  renderAnalyticsDashboard(payload, context);
2692
2752
  }
2693
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
+
2694
2781
  function parseCommandArgs(args, options) {
2695
2782
  try {
2696
2783
  return parseArgs({
@@ -2774,6 +2861,31 @@ function boundedListLimit(value) {
2774
2861
  return Math.min(parsed, API_MAX_LIST_LIMIT);
2775
2862
  }
2776
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
+
2777
2889
  function operatorFilterOptions(extra = {}) {
2778
2890
  return {
2779
2891
  ...jsonOptions(),
@@ -2875,6 +2987,7 @@ function analyticsProspectsOptions() {
2875
2987
  "cohort-start": { type: "string" },
2876
2988
  "cohort-end": { type: "string" },
2877
2989
  motion: { type: "string" },
2990
+ list: { type: "string" },
2878
2991
  provenance: { type: "string" }
2879
2992
  };
2880
2993
  }
@@ -2889,6 +3002,7 @@ function analyticsUsersOptions() {
2889
3002
  "cohort-start": { type: "string" },
2890
3003
  "cohort-end": { type: "string" },
2891
3004
  motion: { type: "string" },
3005
+ list: { type: "string" },
2892
3006
  provenance: { type: "string" },
2893
3007
  platform: { type: "string" },
2894
3008
  channel: { type: "string" }
@@ -2903,18 +3017,37 @@ function analyticsDashboardOptions() {
2903
3017
  "play-tag": { type: "string" },
2904
3018
  tag: { type: "string" },
2905
3019
  motion: { type: "string" },
3020
+ list: { type: "string" },
2906
3021
  offer: { type: "string" },
2907
3022
  icp: { type: "string" },
2908
3023
  user: { type: "string" }
2909
3024
  };
2910
3025
  }
2911
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
+
2912
3044
  function analyticsQuery(values, config = {}, { accountOverride } = {}) {
2913
3045
  return compactObject({
2914
3046
  window: values.window,
2915
3047
  cohort_start: values["cohort-start"],
2916
3048
  cohort_end: values["cohort-end"],
2917
3049
  motion_id: values.motion,
3050
+ list_id: values.list,
2918
3051
  provenance: values.provenance,
2919
3052
  account_user_id: resolveAccountUserId(values.user, config, { accountOverride })
2920
3053
  });
@@ -2930,6 +3063,7 @@ function analyticsUsersQuery(values, config = {}, { accountOverride } = {}) {
2930
3063
  cohort_start: values["cohort-start"],
2931
3064
  cohort_end: values["cohort-end"],
2932
3065
  motion_id: values.motion,
3066
+ list_id: values.list,
2933
3067
  provenance: values.provenance,
2934
3068
  platform: values.platform || values.channel
2935
3069
  });
@@ -2941,6 +3075,7 @@ function analyticsDashboardQuery(values, config = {}, { accountOverride } = {})
2941
3075
  cohort_end_date: values["cohort-end"],
2942
3076
  play_tag: values["play-tag"] || values.tag,
2943
3077
  motion_id: values.motion,
3078
+ list_id: values.list,
2944
3079
  offer_id: values.offer,
2945
3080
  icp_id: values.icp,
2946
3081
  account_user_id: resolveAccountUserId(values.user, config, { accountOverride })
@@ -3027,6 +3162,7 @@ function cohortAnalysisRow(payload, fallbackCohort) {
3027
3162
  label: `${display(cohort.start_date)} to ${display(cohort.end_date)}`,
3028
3163
  total_count: payload?.cohort_prospects_count ?? payload?.prospects_added_count ?? 0,
3029
3164
  motion: payload?.motion || null,
3165
+ list: payload?.list || null,
3030
3166
  provenance: payload?.provenance || null,
3031
3167
  account_user: payload?.account_user || null,
3032
3168
  stages,
@@ -3050,6 +3186,12 @@ function provenancePayload(provenance) {
3050
3186
  };
3051
3187
  }
3052
3188
 
3189
+ function listPayload(listId) {
3190
+ if (!listId) return null;
3191
+
3192
+ return { prefix_id: listId, name: listId };
3193
+ }
3194
+
3053
3195
  function compactObject(object) {
3054
3196
  return Object.fromEntries(
3055
3197
  Object.entries(object).filter(([, value]) => {
@@ -3654,6 +3796,38 @@ function renderTagDetails(payload, context) {
3654
3796
  renderMotions(motions, context);
3655
3797
  }
3656
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
+
3657
3831
  function renderUsers(users, context) {
3658
3832
  if (!Array.isArray(users) || users.length === 0) return writeLine(context.stdout, "No account users found.");
3659
3833
 
@@ -4933,12 +5107,23 @@ function renderAnalyticsDashboard(payload, context) {
4933
5107
  writeCountTable(context, "Current pipeline stages", payload?.pipeline_stage_counts, ["STAGE", "COUNT"], countRow);
4934
5108
  }
4935
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
+
4936
5120
  function renderAnalyticsProspectCohortAnalysis(payload, context) {
4937
5121
  const cohorts = Array.isArray(payload?.cohorts) ? payload.cohorts : [];
4938
5122
  writeLine(context.stdout, `Prospect cohort analysis (${display(payload?.weeks, cohorts.length)} weeks)`);
4939
5123
  writeLine(context.stdout, `Activity window: ${display(payload?.window, "24h")}`);
4940
5124
  writeLine(context.stdout, "Cohorts: account_prospects.created_at, calendar weeks, oldest first");
4941
5125
  writeAnalyticsMotion(payload, context);
5126
+ writeAnalyticsList(payload, context);
4942
5127
  writeAnalyticsProvenance(payload, context);
4943
5128
  if (payload?.account_user) {
4944
5129
  writeLine(context.stdout, `User: ${entityLabel(payload.account_user)}`);
@@ -4999,6 +5184,7 @@ function renderAnalyticsContent(payload, context) {
4999
5184
 
5000
5185
  function writeAnalyticsScope(payload, context) {
5001
5186
  writeAnalyticsMotion(payload, context);
5187
+ writeAnalyticsList(payload, context);
5002
5188
  writeAnalyticsProvenance(payload, context);
5003
5189
  if (payload?.account_user) {
5004
5190
  writeLine(context.stdout, `User: ${entityLabel(payload.account_user)}`);
@@ -5011,6 +5197,7 @@ function writeDashboardFilters(payload, context) {
5011
5197
  const filters = payload?.filters || {};
5012
5198
  if (filters.motion) writeLine(context.stdout, `Motion: ${entityLabel(filters.motion)}`);
5013
5199
  if (filters.play_tag) writeLine(context.stdout, `Tag: ${filters.play_tag}`);
5200
+ if (filters.list) writeLine(context.stdout, `List: ${entityLabel(filters.list)}`);
5014
5201
  if (filters.offer) writeLine(context.stdout, `Offer: ${entityLabel(filters.offer)}`);
5015
5202
  if (filters.icp) writeLine(context.stdout, `ICP: ${entityLabel(filters.icp)}`);
5016
5203
  if (filters.account_user) {
@@ -5034,6 +5221,12 @@ function writeAnalyticsMotion(payload, context) {
5034
5221
  writeLine(context.stdout, `Motion: ${entityLabel(payload.motion)}`);
5035
5222
  }
5036
5223
 
5224
+ function writeAnalyticsList(payload, context) {
5225
+ if (!payload?.list) return;
5226
+
5227
+ writeLine(context.stdout, `List: ${entityLabel(payload.list)}`);
5228
+ }
5229
+
5037
5230
  function writeAnalyticsProvenance(payload, context) {
5038
5231
  if (!payload?.provenance) return;
5039
5232
 
@@ -5688,6 +5881,9 @@ const HELP_TOPICS = new Map([
5688
5881
  " audienti lists remove-tag <list_id> <tag>",
5689
5882
  " audienti tags list",
5690
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>",
5691
5887
  " audienti offers list",
5692
5888
  " audienti offers show <offr_id>",
5693
5889
  " audienti offers update <offr_id> [--name <text>]",
@@ -5718,6 +5914,7 @@ const HELP_TOPICS = new Map([
5718
5914
  " Analytics",
5719
5915
  " audienti analytics prospects --window 24h",
5720
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",
5721
5918
  " audienti analytics prospects cohort-analysis --weeks 4 --motion <motn_id>",
5722
5919
  " audienti analytics users --user me --window 30d",
5723
5920
  " audienti analytics visibility --window 24h --user me",
@@ -5738,6 +5935,7 @@ const HELP_TOPICS = new Map([
5738
5935
  " Analyze one motion: audienti motions analytics <motn_id>",
5739
5936
  " Count one campaign: audienti analytics dashboard --play-tag <tag>",
5740
5937
  " Audit your work: audienti analytics users --user me --window 30d",
5938
+ " Review reminders: audienti tasks list",
5741
5939
  "",
5742
5940
  "Global options:",
5743
5941
  " --account <acct_id> Use an account for one command without saving it",
@@ -6487,6 +6685,82 @@ const HELP_TOPICS = new Map([
6487
6685
  " motions[]: motion rows whose play_tags include tag"
6488
6686
  ].join("\n")],
6489
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
+
6490
6764
  ["lists", [
6491
6765
  "Usage:",
6492
6766
  " audienti lists list [--tag <tag>] [--json]",
@@ -8166,10 +8440,11 @@ const HELP_TOPICS = new Map([
8166
8440
 
8167
8441
  ["analytics", [
8168
8442
  "Usage:",
8169
- " 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]",
8170
- " audienti analytics dashboard [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--json]",
8171
- " audienti analytics prospects cohort-analysis [--weeks <n>] [--window 24h] [--motion <motn_id>] [--user <account_user_id|email|name|me>] [--json]",
8172
- " 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]",
8173
8448
  " audienti analytics visibility [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
8174
8449
  " audienti analytics visops [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
8175
8450
  " audienti analytics content [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
@@ -8181,10 +8456,12 @@ const HELP_TOPICS = new Map([
8181
8456
  " --start <YYYY-MM-DD> --end <YYYY-MM-DD> For user analytics, select the events.created_at activity range instead of --window.",
8182
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.",
8183
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.",
8184
8460
  " --play-tag <tag> For dashboard analytics, filter to motions/lists tagged with a campaign tag.",
8185
8461
  " --provenance <source> Optional lower-level AccountProspect.intake_source filter.",
8186
8462
  " --platform <linkedin|email|gmail> For user analytics, filter events.platform. --channel is accepted as an alias.",
8187
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.",
8188
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.",
8189
8466
  "",
8190
8467
  "Output:",
@@ -8204,6 +8481,7 @@ const HELP_TOPICS = new Map([
8204
8481
  " --cohort-start <YYYY-MM-DD> --cohort-end <YYYY-MM-DD> Select the AccountProspect.created_at cohort.",
8205
8482
  " --play-tag <tag> Filter to motions/lists tagged with a campaign tag. --tag is accepted as an alias.",
8206
8483
  " --motion <motn_id> Filter to one motion/play.",
8484
+ " --list <list_id> Filter to prospects in one list, including analytics cohort lists.",
8207
8485
  " --offer <offr_id> Filter to one offer.",
8208
8486
  " --icp <icp_id> Filter to one ICP.",
8209
8487
  " --user <account_user_id|email|name|me> Filter to prospects assigned to one account user.",
@@ -8221,8 +8499,8 @@ const HELP_TOPICS = new Map([
8221
8499
 
8222
8500
  ["analytics prospects", [
8223
8501
  "Usage:",
8224
- " 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>]",
8225
- " 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)}`,
8226
8504
  "",
8227
8505
  "Status: implemented",
8228
8506
  "",
@@ -8230,6 +8508,7 @@ const HELP_TOPICS = new Map([
8230
8508
  " window: activity/event period for actions",
8231
8509
  " cohort: selected AccountProspect.created_at cohort when cohort dates are provided",
8232
8510
  " motion: selected motion/play when --motion is provided",
8511
+ " list: selected list when --list is provided",
8233
8512
  " provenance: selected AccountProspect.intake_source when --provenance is provided",
8234
8513
  " prospects_added_count: account prospects added in the window, or cohort size when cohort dates are provided",
8235
8514
  " cohort_prospects_count: selected AccountProspect.created_at cohort size when cohort dates are provided",
@@ -8255,6 +8534,7 @@ const HELP_TOPICS = new Map([
8255
8534
  " --weeks <n> Number of calendar-week cohorts to inspect. Defaults to 4. Maximum 26.",
8256
8535
  " --window <w> Activity window passed through to each analytics call. Defaults to 24h.",
8257
8536
  " --motion <motn_id> Optional motion/play filter.",
8537
+ " --list <list_id> Optional list filter.",
8258
8538
  " --provenance <source> Optional AccountProspect.intake_source filter.",
8259
8539
  " --user <id> Optional account-user filter.",
8260
8540
  "",
@@ -8284,6 +8564,7 @@ const HELP_TOPICS = new Map([
8284
8564
  " --start <YYYY-MM-DD> --end <YYYY-MM-DD> Explicit events.created_at activity range.",
8285
8565
  " --cohort-start <YYYY-MM-DD> --cohort-end <YYYY-MM-DD> Optional AccountProspect.created_at cohort filter.",
8286
8566
  " --motion <motn_id> Optional motion/play filter.",
8567
+ " --list <list_id> Optional list filter.",
8287
8568
  " --provenance <source> Optional AccountProspect.intake_source filter.",
8288
8569
  " --platform <linkedin|email|gmail> Optional events.platform filter. `email` includes email and gmail rows; --channel is an alias.",
8289
8570
  "",
@@ -8299,6 +8580,34 @@ const HELP_TOPICS = new Map([
8299
8580
  " GET /api/v1/accounts/:account_id/analytics/users.json"
8300
8581
  ].join("\n")],
8301
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
+
8302
8611
  ["analytics user", [
8303
8612
  "Usage:",
8304
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>]",
@@ -8416,6 +8725,7 @@ const HELP_TOPICS = new Map([
8416
8725
  " audienti users activity me --window 7d",
8417
8726
  " audienti analytics prospects --window 24h",
8418
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",
8419
8729
  " audienti analytics users --user me --window 30d",
8420
8730
  " audienti analytics visibility --window 24h --user me",
8421
8731
  " audienti analytics content --window week",