@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 +15 -0
- package/README.md +32 -1
- package/package.json +1 -1
- package/src/api-client.js +38 -0
- package/src/cli.js +462 -10
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,
|
|
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
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
|
|
8030
|
-
" audienti analytics
|
|
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
|
-
"
|
|
8083
|
-
"
|
|
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",
|