@audienti/cli 0.1.15 → 0.1.17
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 +13 -0
- package/README.md +23 -0
- package/package.json +1 -1
- package/skills/audienti/SKILL.md +3 -0
- package/src/api-client.js +73 -0
- package/src/cli.js +505 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ All notable changes to the Audienti CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.17] - 2026-07-17
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Add `audienti dnc list/add/import/remove` for account DNC settings.
|
|
12
|
+
- Add `audienti company-rules list/create/update/remove/apply` for account-wide and user-scoped company disposition policies.
|
|
13
|
+
|
|
14
|
+
## [0.1.16] - 2026-07-17
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Add direct prospect emergency state commands: `audienti prospects set-status`, `audienti prospects lock`, and `audienti prospects unlock`.
|
|
19
|
+
|
|
7
20
|
## [0.1.15] - 2026-07-16
|
|
8
21
|
|
|
9
22
|
### Added
|
package/README.md
CHANGED
|
@@ -70,6 +70,10 @@ audienti prospects list --profiles
|
|
|
70
70
|
audienti prospects list --assigned-user unassigned
|
|
71
71
|
audienti prospects check --all --csv
|
|
72
72
|
audienti prospects assign <prsp_id> --assigned-user me
|
|
73
|
+
audienti prospects set-status <prsp_id> --status not_fit
|
|
74
|
+
audienti prospects lock <prsp_id> --note "Emergency hold"
|
|
75
|
+
audienti dnc list
|
|
76
|
+
audienti company-rules list
|
|
73
77
|
audienti users activity --window 7d
|
|
74
78
|
audienti analytics prospects --window 24h
|
|
75
79
|
audienti analytics dashboard --play-tag wine_campaign
|
|
@@ -170,6 +174,25 @@ audienti prospects assign <prsp_id> --assigned-user <account_user_id|me>
|
|
|
170
174
|
audienti prospects assign <prsp_id> --assigned-user unassign
|
|
171
175
|
```
|
|
172
176
|
|
|
177
|
+
To make emergency prospect state changes without going through a motion:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
audienti prospects set-status <prsp_id> --status nurture
|
|
181
|
+
audienti prospects set-status <prsp_id> --status not_fit
|
|
182
|
+
audienti prospects lock <prsp_id> --note "Emergency hold"
|
|
183
|
+
audienti prospects unlock <prsp_id>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
To manage account DNC and company disposition rules from the CLI:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
audienti dnc add prospect@example.com
|
|
190
|
+
audienti dnc import --file dnc.txt
|
|
191
|
+
audienti company-rules create --linkedin-url https://www.linkedin.com/company/example --disposition monitor
|
|
192
|
+
audienti company-rules create --domain example.com --disposition not_fit --user me
|
|
193
|
+
audienti company-rules apply --all
|
|
194
|
+
```
|
|
195
|
+
|
|
173
196
|
To import multiple LinkedIn people through the same per-prospect import path:
|
|
174
197
|
|
|
175
198
|
```bash
|
package/package.json
CHANGED
package/skills/audienti/SKILL.md
CHANGED
|
@@ -53,6 +53,9 @@ audienti help agent-workflows
|
|
|
53
53
|
audienti prospects list --query "name or company" --wide --json
|
|
54
54
|
audienti prospects list --assigned-user unassigned --json
|
|
55
55
|
audienti prospects assign <prsp_id> --assigned-user me --json
|
|
56
|
+
audienti prospects set-status <prsp_id> --status not_fit --json
|
|
57
|
+
audienti prospects lock <prsp_id> --note "Emergency hold" --json
|
|
58
|
+
audienti prospects unlock <prsp_id> --json
|
|
56
59
|
audienti users activity me --window 7d --json
|
|
57
60
|
audienti prospects import-batch --file prospects.csv --motion <motn_id> --assigned-user me --json
|
|
58
61
|
audienti lists create --name "Target list" --json
|
package/src/api-client.js
CHANGED
|
@@ -115,6 +115,66 @@ export class AudientiClient {
|
|
|
115
115
|
return this.requestJson(accountPath(accountId, ["companies"], query));
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
dncEntries(accountId, query = {}) {
|
|
119
|
+
return this.requestJson(accountPath(accountId, ["dnc"], query));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
createDncEntry(accountId, body) {
|
|
123
|
+
return this.requestJson(accountPath(accountId, ["dnc"]), {
|
|
124
|
+
method: "POST",
|
|
125
|
+
body
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
importDncEntries(accountId, body) {
|
|
130
|
+
return this.requestJson(accountPath(accountId, ["dnc", "import"]), {
|
|
131
|
+
method: "POST",
|
|
132
|
+
body
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
deleteDncEntry(accountId, entryId) {
|
|
137
|
+
return this.requestJson(accountPath(accountId, ["dnc", entryId]), {
|
|
138
|
+
method: "DELETE"
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
companyRules(accountId) {
|
|
143
|
+
return this.requestJson(accountPath(accountId, ["company_rules"]));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
createCompanyRule(accountId, body) {
|
|
147
|
+
return this.requestJson(accountPath(accountId, ["company_rules"]), {
|
|
148
|
+
method: "POST",
|
|
149
|
+
body
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
updateCompanyRule(accountId, ruleId, body) {
|
|
154
|
+
return this.requestJson(accountPath(accountId, ["company_rules", ruleId]), {
|
|
155
|
+
method: "PATCH",
|
|
156
|
+
body
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
deleteCompanyRule(accountId, ruleId) {
|
|
161
|
+
return this.requestJson(accountPath(accountId, ["company_rules", ruleId]), {
|
|
162
|
+
method: "DELETE"
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
applyCompanyRule(accountId, ruleId) {
|
|
167
|
+
return this.requestJson(accountPath(accountId, ["company_rules", ruleId, "apply"]), {
|
|
168
|
+
method: "POST"
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
applyAllCompanyRules(accountId) {
|
|
173
|
+
return this.requestJson(accountPath(accountId, ["company_rules", "apply_all"]), {
|
|
174
|
+
method: "POST"
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
118
178
|
tags(accountId) {
|
|
119
179
|
return this.requestJson(accountPath(accountId, ["tags"]));
|
|
120
180
|
}
|
|
@@ -306,6 +366,19 @@ export class AudientiClient {
|
|
|
306
366
|
});
|
|
307
367
|
}
|
|
308
368
|
|
|
369
|
+
lockProspect(accountId, prospectId, body = {}) {
|
|
370
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "lock"]), {
|
|
371
|
+
method: "POST",
|
|
372
|
+
body
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
unlockProspect(accountId, prospectId) {
|
|
377
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "unlock"]), {
|
|
378
|
+
method: "POST"
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
309
382
|
prospectSequencePreview(accountId, prospectId, body = {}) {
|
|
310
383
|
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "sequence_preview"]), {
|
|
311
384
|
method: "POST",
|
package/src/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
2
|
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
3
|
-
import { dirname, join } from "node:path";
|
|
3
|
+
import { basename, dirname, join } from "node:path";
|
|
4
4
|
import { ApiError, AudientiClient, DEFAULT_HOST, normalizeHost } from "./api-client.js";
|
|
5
5
|
import { configPath, deleteConfig, maskToken, readConfig, writeConfig } from "./config.js";
|
|
6
6
|
|
|
@@ -28,16 +28,27 @@ const DEFAULT_PROFILE_IDENTIFIERS = [
|
|
|
28
28
|
];
|
|
29
29
|
const DELETE_CONFIRMATION_VALUES = new Set(["yes", "true", "y"]);
|
|
30
30
|
const MOTION_STATUS_VALUES = new Set(["draft", "preparing", "active", "paused", "archived"]);
|
|
31
|
+
const PROSPECT_STATUS_VALUES = new Set(["active", "nurture", "non_responsive", "not_fit", "rejected"]);
|
|
31
32
|
const PROSPECTS_ADD_NOTE_USAGE = "Usage: audienti prospects add-note <prsp_id> (--message <text> [--type <note|steer|voicemail_outreach|video_outreach>] [--engagement-type <key>] | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
32
33
|
const PROSPECTS_ADD_STEER_USAGE = "Usage: audienti prospects add-steer <prsp_id> (--message <text> [--engagement-type <key>] | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
33
34
|
const PROSPECTS_ADD_PROFILE_USAGE = "Usage: audienti prospects add-profile <prsp_id> --url <profile_url|email|phone> [--json] [--account <acct_id>]";
|
|
34
35
|
const PROSPECTS_REPORT_BAD_PROFILE_USAGE = "Usage: audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json] [--account <acct_id>]";
|
|
35
36
|
const PROSPECTS_ASSIGN_USAGE = "Usage: audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json] [--account <acct_id>]";
|
|
37
|
+
const PROSPECTS_SET_STATUS_USAGE = "Usage: audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|rejected> [--json] [--account <acct_id>]";
|
|
36
38
|
const PROSPECTS_REJECT_USAGE = "Usage: audienti prospects reject <prsp_id> [--json] [--account <acct_id>]";
|
|
37
39
|
const PROSPECTS_NURTURE_USAGE = "Usage: audienti prospects nurture <prsp_id> [--reason <nurture|non_responsive|not_fit>] [--json] [--account <acct_id>]";
|
|
38
40
|
const PROSPECTS_RESTORE_USAGE = "Usage: audienti prospects restore <prsp_id> [--json] [--account <acct_id>]";
|
|
41
|
+
const PROSPECTS_LOCK_USAGE = "Usage: audienti prospects lock <prsp_id> [--note <text>] [--kind <protected_relationship|company_policy>] [--json] [--account <acct_id>]";
|
|
42
|
+
const PROSPECTS_UNLOCK_USAGE = "Usage: audienti prospects unlock <prsp_id> [--json] [--account <acct_id>]";
|
|
39
43
|
const PROSPECTS_CHECK_USAGE = "Usage: audienti prospects check [--json|--csv] [filters] [--account <acct_id>]";
|
|
40
44
|
const PROSPECTS_IMPORT_BATCH_USAGE = "Usage: audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--assigned-user <id|me>] [--json] [--account <acct_id>]";
|
|
45
|
+
const DNC_ADD_USAGE = "Usage: audienti dnc add <email|citation_id|profile_url> [--json] [--account <acct_id>]";
|
|
46
|
+
const DNC_IMPORT_USAGE = "Usage: audienti dnc import --file <txt|csv> [--json] [--account <acct_id>]";
|
|
47
|
+
const DNC_REMOVE_USAGE = "Usage: audienti dnc remove <dnc_entry_id> [--json] [--account <acct_id>]";
|
|
48
|
+
const COMPANY_RULES_CREATE_USAGE = "Usage: audienti company-rules create (--linkedin-url <url> | --domain <domain>) --disposition <monitor|nurture|not_fit|reject> [--name <text>] [--user <account_user_id|email|me>] [--note <text>] [--json] [--account <acct_id>]";
|
|
49
|
+
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>]";
|
|
50
|
+
const COMPANY_RULES_REMOVE_USAGE = "Usage: audienti company-rules remove <rule_id> [--json] [--account <acct_id>]";
|
|
51
|
+
const COMPANY_RULES_APPLY_USAGE = "Usage: audienti company-rules apply (<rule_id>|--all) [--json] [--account <acct_id>]";
|
|
41
52
|
const USERS_ACTIVITY_USAGE = "Usage: audienti users activity [account_user_id|me] [--mode <actor|account_usage>] [--window <24h|7d|30d>] [--platform <linkedin|email|gmail>] [--query <text>] [--limit <n>] [--page <n>] [--json] [--account <acct_id>]";
|
|
42
53
|
const OFFERS_SHOW_USAGE = "Usage: audienti offers show <offr_id> [--json] [--account <acct_id>]";
|
|
43
54
|
const OFFERS_UPDATE_USAGE = "Usage: audienti offers update <offr_id> [--name <text>] [--description <text>] [--url <url>] [--json] [--account <acct_id>]";
|
|
@@ -157,6 +168,15 @@ async function dispatch(argv, context) {
|
|
|
157
168
|
if (normalizedResource === "icps" && action === "add-tag") return icpsTagMutation("add", rest, context, { accountOverride });
|
|
158
169
|
if (normalizedResource === "icps" && action === "remove-tag") return icpsTagMutation("remove", rest, context, { accountOverride });
|
|
159
170
|
if (normalizedResource === "companies" && action === "search") return companiesSearch(rest, context, { accountOverride });
|
|
171
|
+
if (normalizedResource === "dnc" && action === "list") return dncList(rest, context, { accountOverride });
|
|
172
|
+
if (normalizedResource === "dnc" && action === "add") return dncAdd(rest, context, { accountOverride });
|
|
173
|
+
if (normalizedResource === "dnc" && action === "import") return dncImport(rest, context, { accountOverride });
|
|
174
|
+
if (normalizedResource === "dnc" && ["remove", "delete"].includes(action)) return dncRemove(rest, context, { accountOverride });
|
|
175
|
+
if (normalizedResource === "company-rules" && action === "list") return companyRulesList(rest, context, { accountOverride });
|
|
176
|
+
if (normalizedResource === "company-rules" && action === "create") return companyRulesCreate(rest, context, { accountOverride });
|
|
177
|
+
if (normalizedResource === "company-rules" && action === "update") return companyRulesUpdate(rest, context, { accountOverride });
|
|
178
|
+
if (normalizedResource === "company-rules" && ["remove", "delete"].includes(action)) return companyRulesRemove(rest, context, { accountOverride });
|
|
179
|
+
if (normalizedResource === "company-rules" && action === "apply") return companyRulesApply(rest, context, { accountOverride });
|
|
160
180
|
if (normalizedResource === "tags" && action === "list") return tagsList(rest, context, { accountOverride });
|
|
161
181
|
if (normalizedResource === "tags" && action === "show") return tagsShow(rest, context, { accountOverride });
|
|
162
182
|
if (normalizedResource === "lists" && action === "list") return listsList(rest, context, { accountOverride });
|
|
@@ -188,9 +208,12 @@ async function dispatch(argv, context) {
|
|
|
188
208
|
if (normalizedResource === "prospects" && action === "check") return prospectsCheck(rest, context, { accountOverride });
|
|
189
209
|
if (normalizedResource === "prospects" && action === "show") return prospectsShow(rest, context, { accountOverride });
|
|
190
210
|
if (normalizedResource === "prospects" && action === "assign") return prospectsAssign(rest, context, { accountOverride });
|
|
211
|
+
if (normalizedResource === "prospects" && action === "set-status") return prospectsSetStatus(rest, context, { accountOverride });
|
|
191
212
|
if (normalizedResource === "prospects" && action === "reject") return prospectsDisposition("reject", rest, context, { accountOverride });
|
|
192
213
|
if (normalizedResource === "prospects" && action === "nurture") return prospectsDisposition("nurture", rest, context, { accountOverride });
|
|
193
214
|
if (normalizedResource === "prospects" && action === "restore") return prospectsDisposition("restore", rest, context, { accountOverride });
|
|
215
|
+
if (normalizedResource === "prospects" && action === "lock") return prospectsLock(rest, context, { accountOverride });
|
|
216
|
+
if (normalizedResource === "prospects" && action === "unlock") return prospectsUnlock(rest, context, { accountOverride });
|
|
194
217
|
if (normalizedResource === "prospects" && action === "timeline") return prospectsTimeline(rest, context, { accountOverride });
|
|
195
218
|
if (normalizedResource === "prospects" && action === "message-types") return prospectsMessageTypes(rest, context, { accountOverride });
|
|
196
219
|
if (normalizedResource === "prospects" && action === "write") return prospectsWrite(rest, context, { accountOverride });
|
|
@@ -263,6 +286,7 @@ function normalizeTopicParts(parts) {
|
|
|
263
286
|
function normalizeResource(resource) {
|
|
264
287
|
if (resource === "principals") return "users";
|
|
265
288
|
if (resource === "writers") return "writer";
|
|
289
|
+
if (resource === "company_rules" || resource === "company-rules") return "company-rules";
|
|
266
290
|
return resource === "plays" ? "motions" : resource;
|
|
267
291
|
}
|
|
268
292
|
|
|
@@ -813,6 +837,134 @@ async function companiesSearch(args, context, { accountOverride } = {}) {
|
|
|
813
837
|
renderCompanies(payload, context);
|
|
814
838
|
}
|
|
815
839
|
|
|
840
|
+
async function dncList(args, context, { accountOverride } = {}) {
|
|
841
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
842
|
+
...jsonOptions(),
|
|
843
|
+
limit: { type: "string" },
|
|
844
|
+
offset: { type: "string" }
|
|
845
|
+
});
|
|
846
|
+
if (positionals.length > 0) throw new CommandError("Usage: audienti dnc list [--limit <n>] [--offset <n>] [--json] [--account <acct_id>]");
|
|
847
|
+
|
|
848
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
849
|
+
const payload = await client.dncEntries(accountId, compactObject({ limit: values.limit, offset: values.offset }));
|
|
850
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
851
|
+
|
|
852
|
+
renderDncEntries(payload, context);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
async function dncAdd(args, context, { accountOverride } = {}) {
|
|
856
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
857
|
+
if (positionals.length !== 1) throw new CommandError(DNC_ADD_USAGE);
|
|
858
|
+
|
|
859
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
860
|
+
const payload = await client.createDncEntry(accountId, { value: positionals[0] });
|
|
861
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
862
|
+
|
|
863
|
+
writeLine(context.stdout, `DNC entry ${display(payload?.status, "created")}: ${display(payload?.dnc_entry?.canonical_value || payload?.dnc_entry?.citation_id)} (${display(payload?.dnc_entry?.prefix_id || payload?.dnc_entry?.id)}).`);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
async function dncImport(args, context, { accountOverride } = {}) {
|
|
867
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
868
|
+
...jsonOptions(),
|
|
869
|
+
file: { type: "string" }
|
|
870
|
+
});
|
|
871
|
+
if (positionals.length > 0 || !values.file) throw new CommandError(DNC_IMPORT_USAGE);
|
|
872
|
+
|
|
873
|
+
const body = await readFile(values.file, "utf8");
|
|
874
|
+
const importValues = parseDncImportValues(body);
|
|
875
|
+
if (importValues.length === 0) throw new CommandError("DNC import file did not contain any values.");
|
|
876
|
+
|
|
877
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
878
|
+
const payload = await client.importDncEntries(accountId, { values: importValues, filename: basename(values.file) });
|
|
879
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
880
|
+
|
|
881
|
+
writeLine(context.stdout, `Imported DNC entries. Accepted ${display(payload?.accepted_count, 0)}, skipped ${display(payload?.skipped_count, 0)}, invalid ${display(payload?.invalid_count, 0)}, matched ${display(payload?.matched_prospect_count, 0)}.`);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
async function dncRemove(args, context, { accountOverride } = {}) {
|
|
885
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
886
|
+
if (positionals.length !== 1) throw new CommandError(DNC_REMOVE_USAGE);
|
|
887
|
+
|
|
888
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
889
|
+
const payload = await client.deleteDncEntry(accountId, positionals[0]);
|
|
890
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
891
|
+
|
|
892
|
+
writeLine(context.stdout, `Removed DNC entry ${display(payload?.prefix_id || payload?.id || positionals[0])}.`);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
async function companyRulesList(args, context, { accountOverride } = {}) {
|
|
896
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
897
|
+
if (positionals.length > 0) throw new CommandError("Usage: audienti company-rules list [--json] [--account <acct_id>]");
|
|
898
|
+
|
|
899
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
900
|
+
const payload = await client.companyRules(accountId);
|
|
901
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
902
|
+
|
|
903
|
+
renderCompanyRules(payload, context);
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
async function companyRulesCreate(args, context, { accountOverride } = {}) {
|
|
907
|
+
const { values, positionals } = parseCommandArgs(args, companyRuleOptions());
|
|
908
|
+
if (positionals.length > 0 || (!values["linkedin-url"] && !values.domain) || !values.disposition) {
|
|
909
|
+
throw new CommandError(COMPANY_RULES_CREATE_USAGE);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
913
|
+
const payload = await client.createCompanyRule(accountId, { company_rule: companyRulePayload(values) });
|
|
914
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
915
|
+
|
|
916
|
+
const rule = payload?.company_rule;
|
|
917
|
+
writeLine(context.stdout, `Created company rule ${display(rule?.name || rule?.domain || rule?.linkedin_company_identifier)} (${display(rule?.prefix_id || rule?.id)}).`);
|
|
918
|
+
writeLine(context.stdout, `Disposition: ${display(rule?.disposition)} | Scope: ${companyRuleScopeLabel(rule)}`);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
async function companyRulesUpdate(args, context, { accountOverride } = {}) {
|
|
922
|
+
const { values, positionals } = parseCommandArgs(args, companyRuleOptions());
|
|
923
|
+
const hasUpdate = values.disposition || values.name !== undefined || values["linkedin-url"] !== undefined || values.domain !== undefined || values.user !== undefined || values.note !== undefined;
|
|
924
|
+
if (positionals.length !== 1 || !hasUpdate) throw new CommandError(COMPANY_RULES_UPDATE_USAGE);
|
|
925
|
+
|
|
926
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
927
|
+
const payload = await client.updateCompanyRule(accountId, positionals[0], { company_rule: companyRulePayload(values) });
|
|
928
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
929
|
+
|
|
930
|
+
const rule = payload?.company_rule;
|
|
931
|
+
writeLine(context.stdout, `Updated company rule ${display(rule?.name || rule?.domain || rule?.linkedin_company_identifier)} (${display(rule?.prefix_id || rule?.id)}).`);
|
|
932
|
+
writeLine(context.stdout, `Disposition: ${display(rule?.disposition)} | Scope: ${companyRuleScopeLabel(rule)}`);
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
async function companyRulesRemove(args, context, { accountOverride } = {}) {
|
|
936
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
937
|
+
if (positionals.length !== 1) throw new CommandError(COMPANY_RULES_REMOVE_USAGE);
|
|
938
|
+
|
|
939
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
940
|
+
const payload = await client.deleteCompanyRule(accountId, positionals[0]);
|
|
941
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
942
|
+
|
|
943
|
+
writeLine(context.stdout, `Removed company rule ${display(payload?.company_rule?.prefix_id || payload?.company_rule?.id || positionals[0])}.`);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
async function companyRulesApply(args, context, { accountOverride } = {}) {
|
|
947
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
948
|
+
...jsonOptions(),
|
|
949
|
+
all: { type: "boolean" }
|
|
950
|
+
});
|
|
951
|
+
if ((values.all && positionals.length > 0) || (!values.all && positionals.length !== 1)) {
|
|
952
|
+
throw new CommandError(COMPANY_RULES_APPLY_USAGE);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
956
|
+
const payload = values.all ?
|
|
957
|
+
await client.applyAllCompanyRules(accountId) :
|
|
958
|
+
await client.applyCompanyRule(accountId, positionals[0]);
|
|
959
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
960
|
+
|
|
961
|
+
if (values.all) {
|
|
962
|
+
writeLine(context.stdout, `Applied company rules. Matched ${display(payload?.matched_count, 0)}, changed ${display(payload?.applied_count, 0)}.`);
|
|
963
|
+
} else {
|
|
964
|
+
writeLine(context.stdout, `Applied company rule. Matched ${display(payload?.matched_count, 0)}, changed ${display(payload?.applied_count, 0)}.`);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
816
968
|
async function tagsList(args, context, { accountOverride } = {}) {
|
|
817
969
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
818
970
|
if (positionals.length > 0) throw new CommandError("Usage: audienti tags list [--json] [--account <acct_id>]");
|
|
@@ -1489,6 +1641,59 @@ async function prospectsDisposition(action, args, context, { accountOverride } =
|
|
|
1489
1641
|
renderProspectDisposition(payload, context, { action });
|
|
1490
1642
|
}
|
|
1491
1643
|
|
|
1644
|
+
async function prospectsSetStatus(args, context, { accountOverride } = {}) {
|
|
1645
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1646
|
+
...jsonOptions(),
|
|
1647
|
+
status: { type: "string" }
|
|
1648
|
+
});
|
|
1649
|
+
const status = String(values.status || "").trim();
|
|
1650
|
+
if (positionals.length !== 1 || !PROSPECT_STATUS_VALUES.has(status)) {
|
|
1651
|
+
throw new CommandError(PROSPECTS_SET_STATUS_USAGE);
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1655
|
+
const payload = await mutateProspectStatus(client, accountId, positionals[0], status);
|
|
1656
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1657
|
+
|
|
1658
|
+
renderProspectDisposition(payload, context, { action: "set-status" });
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
async function prospectsLock(args, context, { accountOverride } = {}) {
|
|
1662
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1663
|
+
...jsonOptions(),
|
|
1664
|
+
kind: { type: "string" },
|
|
1665
|
+
note: { type: "string" }
|
|
1666
|
+
});
|
|
1667
|
+
if (positionals.length !== 1) throw new CommandError(PROSPECTS_LOCK_USAGE);
|
|
1668
|
+
|
|
1669
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1670
|
+
const payload = await client.lockProspect(accountId, positionals[0], compactObject({
|
|
1671
|
+
lock_kind: values.kind,
|
|
1672
|
+
lock_note: values.note
|
|
1673
|
+
}));
|
|
1674
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1675
|
+
|
|
1676
|
+
renderProspectDisposition(payload, context, { action: "lock" });
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
async function prospectsUnlock(args, context, { accountOverride } = {}) {
|
|
1680
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1681
|
+
if (positionals.length !== 1) throw new CommandError(PROSPECTS_UNLOCK_USAGE);
|
|
1682
|
+
|
|
1683
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1684
|
+
const payload = await client.unlockProspect(accountId, positionals[0]);
|
|
1685
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1686
|
+
|
|
1687
|
+
renderProspectDisposition(payload, context, { action: "unlock" });
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
async function mutateProspectStatus(client, accountId, prospectId, status) {
|
|
1691
|
+
if (status === "active") return client.restoreProspect(accountId, prospectId);
|
|
1692
|
+
if (status === "rejected") return client.rejectProspect(accountId, prospectId);
|
|
1693
|
+
|
|
1694
|
+
return client.nurtureProspect(accountId, prospectId, { inactive_reason: status });
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1492
1697
|
async function prospectsTimeline(args, context, { accountOverride } = {}) {
|
|
1493
1698
|
const { values, positionals } = parseCommandArgs(args, {
|
|
1494
1699
|
...jsonOptions(),
|
|
@@ -2599,6 +2804,43 @@ function tagList(value) {
|
|
|
2599
2804
|
.filter((tag, index, tags) => tags.indexOf(tag) === index);
|
|
2600
2805
|
}
|
|
2601
2806
|
|
|
2807
|
+
function companyRuleOptions() {
|
|
2808
|
+
return {
|
|
2809
|
+
...jsonOptions(),
|
|
2810
|
+
name: { type: "string" },
|
|
2811
|
+
"linkedin-url": { type: "string" },
|
|
2812
|
+
domain: { type: "string" },
|
|
2813
|
+
disposition: { type: "string" },
|
|
2814
|
+
user: { type: "string" },
|
|
2815
|
+
note: { type: "string" }
|
|
2816
|
+
};
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
function companyRulePayload(values) {
|
|
2820
|
+
const userValue = values.user === undefined ? undefined : String(values.user || "").trim();
|
|
2821
|
+
const userCleared = userValue && ["none", "account", "all"].includes(userValue.toLowerCase());
|
|
2822
|
+
|
|
2823
|
+
return compactObject({
|
|
2824
|
+
name: values.name,
|
|
2825
|
+
linkedin_company_url: values["linkedin-url"],
|
|
2826
|
+
domain: values.domain,
|
|
2827
|
+
disposition: values.disposition,
|
|
2828
|
+
note: values.note,
|
|
2829
|
+
scope_kind: userValue === undefined ? undefined : (userCleared ? "account" : "account_user"),
|
|
2830
|
+
account_user_id: userValue === undefined ? undefined : (userCleared ? "" : userValue)
|
|
2831
|
+
});
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
function parseDncImportValues(body) {
|
|
2835
|
+
return String(body || "")
|
|
2836
|
+
.split(/\r?\n/)
|
|
2837
|
+
.map((line) => line.trim())
|
|
2838
|
+
.filter(Boolean)
|
|
2839
|
+
.map((line) => line.split(",")[0])
|
|
2840
|
+
.map((value) => value.trim().replace(/^"|"$/g, ""))
|
|
2841
|
+
.filter(Boolean);
|
|
2842
|
+
}
|
|
2843
|
+
|
|
2602
2844
|
function filterRecordsByTag(records, value, field) {
|
|
2603
2845
|
const tag = tagList(value)?.[0];
|
|
2604
2846
|
if (!tag) return records;
|
|
@@ -3117,6 +3359,54 @@ function renderCompanies(payload, context) {
|
|
|
3117
3359
|
}
|
|
3118
3360
|
}
|
|
3119
3361
|
|
|
3362
|
+
function renderDncEntries(payload, context) {
|
|
3363
|
+
const entries = Array.isArray(payload?.dnc_entries) ? payload.dnc_entries : [];
|
|
3364
|
+
if (entries.length === 0) return writeLine(context.stdout, "No DNC entries found.");
|
|
3365
|
+
|
|
3366
|
+
writeLine(context.stdout, "DNC ID\tKIND\tVALUE\tIDENTIFIER\tSOURCE\tPROSPECT");
|
|
3367
|
+
for (const entry of entries) {
|
|
3368
|
+
writeLine(
|
|
3369
|
+
context.stdout,
|
|
3370
|
+
[
|
|
3371
|
+
display(entry.prefix_id || entry.id),
|
|
3372
|
+
display(entry.key_kind),
|
|
3373
|
+
display(entry.canonical_value || entry.citation_id),
|
|
3374
|
+
display(entry.identifier),
|
|
3375
|
+
display(entry.source_kind),
|
|
3376
|
+
display(entry.prospect_id)
|
|
3377
|
+
].join("\t")
|
|
3378
|
+
);
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
|
|
3382
|
+
function renderCompanyRules(payload, context) {
|
|
3383
|
+
const rules = Array.isArray(payload?.company_rules) ? payload.company_rules : [];
|
|
3384
|
+
if (rules.length === 0) return writeLine(context.stdout, "No company rules found.");
|
|
3385
|
+
|
|
3386
|
+
writeLine(context.stdout, "RULE ID\tCOMPANY\tDOMAIN\tDISPOSITION\tSCOPE\tACTIVE");
|
|
3387
|
+
for (const rule of rules) {
|
|
3388
|
+
writeLine(
|
|
3389
|
+
context.stdout,
|
|
3390
|
+
[
|
|
3391
|
+
display(rule.prefix_id || rule.id),
|
|
3392
|
+
display(rule.name || rule.linkedin_company_identifier || rule.linkedin_company_url),
|
|
3393
|
+
display(rule.domain),
|
|
3394
|
+
display(rule.disposition),
|
|
3395
|
+
companyRuleScopeLabel(rule),
|
|
3396
|
+
rule.active ? "yes" : "no"
|
|
3397
|
+
].join("\t")
|
|
3398
|
+
);
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3402
|
+
function companyRuleScopeLabel(rule) {
|
|
3403
|
+
if (rule?.scope_kind === "account_user") {
|
|
3404
|
+
return `user:${display(rule.account_user_email || rule.account_user_id)}`;
|
|
3405
|
+
}
|
|
3406
|
+
|
|
3407
|
+
return "account";
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3120
3410
|
async function performBulkMutation(perform) {
|
|
3121
3411
|
try {
|
|
3122
3412
|
return { payload: await perform(), rejected: false };
|
|
@@ -3265,12 +3555,18 @@ function renderProspectDisposition(payload, context, { action }) {
|
|
|
3265
3555
|
const actionLabel = {
|
|
3266
3556
|
reject: "Rejected",
|
|
3267
3557
|
nurture: "Moved to nurture",
|
|
3268
|
-
restore: "Restored"
|
|
3558
|
+
restore: "Restored",
|
|
3559
|
+
"set-status": "Set status for",
|
|
3560
|
+
lock: "Locked",
|
|
3561
|
+
unlock: "Unlocked"
|
|
3269
3562
|
}[action] || display(payload?.status, "Updated");
|
|
3270
3563
|
|
|
3271
3564
|
writeLine(context.stdout, `${actionLabel} prospect ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)}).`);
|
|
3272
3565
|
if (accountProspect.status) writeLine(context.stdout, `Status: ${accountProspect.status}`);
|
|
3273
3566
|
if (accountProspect.inactive_reason) writeLine(context.stdout, `Inactive reason: ${accountProspect.inactive_reason}`);
|
|
3567
|
+
if (accountProspect.locked_at) writeLine(context.stdout, `Locked at: ${accountProspect.locked_at}`);
|
|
3568
|
+
if (accountProspect.lock_kind) writeLine(context.stdout, `Lock kind: ${accountProspect.lock_kind}`);
|
|
3569
|
+
if (accountProspect.lock_note) writeLine(context.stdout, `Lock note: ${accountProspect.lock_note}`);
|
|
3274
3570
|
if (payload?.system_list?.name) writeLine(context.stdout, `List: ${payload.system_list.name} (${display(payload.system_list.prefix_id)})`);
|
|
3275
3571
|
}
|
|
3276
3572
|
|
|
@@ -4546,9 +4842,12 @@ const HELP_TOPICS = new Map([
|
|
|
4546
4842
|
" audienti prospects check [filters]",
|
|
4547
4843
|
" audienti prospects show <prsp_id>",
|
|
4548
4844
|
" audienti prospects assign <prsp_id> --assigned-user <id|me|unassign>",
|
|
4845
|
+
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|rejected>",
|
|
4846
|
+
" audienti prospects lock <prsp_id> [--note <text>]",
|
|
4549
4847
|
" audienti prospects reject <prsp_id>",
|
|
4550
4848
|
" audienti prospects nurture <prsp_id> [--reason <reason>]",
|
|
4551
4849
|
" audienti prospects restore <prsp_id>",
|
|
4850
|
+
" audienti prospects unlock <prsp_id>",
|
|
4552
4851
|
" audienti prospects timeline <prsp_id>",
|
|
4553
4852
|
" audienti prospects import <linkedin_url> [--motion <motn_id>]",
|
|
4554
4853
|
" audienti prospects import-batch --file <csv|jsonl|json>",
|
|
@@ -4572,6 +4871,10 @@ const HELP_TOPICS = new Map([
|
|
|
4572
4871
|
" audienti icps add-tag <icp_id> <tag>",
|
|
4573
4872
|
" audienti icps remove-tag <icp_id> <tag>",
|
|
4574
4873
|
" audienti companies search --query <text>",
|
|
4874
|
+
" audienti dnc list",
|
|
4875
|
+
" audienti dnc add <email|citation_id|profile_url>",
|
|
4876
|
+
" audienti company-rules list",
|
|
4877
|
+
" audienti company-rules create (--linkedin-url <url> | --domain <domain>) --disposition <state>",
|
|
4575
4878
|
"",
|
|
4576
4879
|
" Writer",
|
|
4577
4880
|
" audienti writer test-run <prsp_id>",
|
|
@@ -5155,6 +5458,148 @@ const HELP_TOPICS = new Map([
|
|
|
5155
5458
|
" companies[].location: string | null"
|
|
5156
5459
|
].join("\n")],
|
|
5157
5460
|
|
|
5461
|
+
["dnc", [
|
|
5462
|
+
"Usage:",
|
|
5463
|
+
" audienti dnc list [--json]",
|
|
5464
|
+
` ${DNC_ADD_USAGE.slice("Usage: ".length)}`,
|
|
5465
|
+
` ${DNC_IMPORT_USAGE.slice("Usage: ".length)}`,
|
|
5466
|
+
` ${DNC_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
5467
|
+
"",
|
|
5468
|
+
"Status: implemented",
|
|
5469
|
+
"",
|
|
5470
|
+
"Purpose:",
|
|
5471
|
+
" Manage account-level do-not-contact entries through the same settings/API path as the app."
|
|
5472
|
+
].join("\n")],
|
|
5473
|
+
|
|
5474
|
+
["dnc list", [
|
|
5475
|
+
"Usage:",
|
|
5476
|
+
" audienti dnc list [--limit <n>] [--offset <n>] [--json] [--account <acct_id>]",
|
|
5477
|
+
"",
|
|
5478
|
+
"Status: implemented",
|
|
5479
|
+
"",
|
|
5480
|
+
"API:",
|
|
5481
|
+
" GET /api/v1/accounts/:account_id/dnc.json"
|
|
5482
|
+
].join("\n")],
|
|
5483
|
+
|
|
5484
|
+
["dnc add", [
|
|
5485
|
+
"Usage:",
|
|
5486
|
+
` ${DNC_ADD_USAGE.slice("Usage: ".length)}`,
|
|
5487
|
+
"",
|
|
5488
|
+
"Status: implemented",
|
|
5489
|
+
"",
|
|
5490
|
+
"Input shape:",
|
|
5491
|
+
" value: email, citation ID, or supported person profile URL",
|
|
5492
|
+
"",
|
|
5493
|
+
"Behavior:",
|
|
5494
|
+
" Creates or reactivates an account DNC entry and retroactively rejects matching account prospects.",
|
|
5495
|
+
"",
|
|
5496
|
+
"API:",
|
|
5497
|
+
" POST /api/v1/accounts/:account_id/dnc.json"
|
|
5498
|
+
].join("\n")],
|
|
5499
|
+
|
|
5500
|
+
["dnc import", [
|
|
5501
|
+
"Usage:",
|
|
5502
|
+
` ${DNC_IMPORT_USAGE.slice("Usage: ".length)}`,
|
|
5503
|
+
"",
|
|
5504
|
+
"Status: implemented",
|
|
5505
|
+
"",
|
|
5506
|
+
"Input shape:",
|
|
5507
|
+
" file: text or CSV file. The CLI sends one value per line using column one for CSV-like rows.",
|
|
5508
|
+
"",
|
|
5509
|
+
"API:",
|
|
5510
|
+
" POST /api/v1/accounts/:account_id/dnc/import.json"
|
|
5511
|
+
].join("\n")],
|
|
5512
|
+
|
|
5513
|
+
["dnc remove", [
|
|
5514
|
+
"Usage:",
|
|
5515
|
+
` ${DNC_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
5516
|
+
"",
|
|
5517
|
+
"Status: implemented",
|
|
5518
|
+
"",
|
|
5519
|
+
"API:",
|
|
5520
|
+
" DELETE /api/v1/accounts/:account_id/dnc/:id.json"
|
|
5521
|
+
].join("\n")],
|
|
5522
|
+
|
|
5523
|
+
["company-rules", [
|
|
5524
|
+
"Usage:",
|
|
5525
|
+
" audienti company-rules list [--json]",
|
|
5526
|
+
` ${COMPANY_RULES_CREATE_USAGE.slice("Usage: ".length)}`,
|
|
5527
|
+
` ${COMPANY_RULES_UPDATE_USAGE.slice("Usage: ".length)}`,
|
|
5528
|
+
` ${COMPANY_RULES_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
5529
|
+
` ${COMPANY_RULES_APPLY_USAGE.slice("Usage: ".length)}`,
|
|
5530
|
+
"",
|
|
5531
|
+
"Status: implemented",
|
|
5532
|
+
"",
|
|
5533
|
+
"Purpose:",
|
|
5534
|
+
" Manage account-wide and user-scoped company disposition rules keyed by LinkedIn company URL or domain."
|
|
5535
|
+
].join("\n")],
|
|
5536
|
+
|
|
5537
|
+
["company-rules list", [
|
|
5538
|
+
"Usage:",
|
|
5539
|
+
" audienti company-rules list [--json] [--account <acct_id>]",
|
|
5540
|
+
"",
|
|
5541
|
+
"Status: implemented",
|
|
5542
|
+
"",
|
|
5543
|
+
"API:",
|
|
5544
|
+
" GET /api/v1/accounts/:account_id/company_rules.json"
|
|
5545
|
+
].join("\n")],
|
|
5546
|
+
|
|
5547
|
+
["company-rules create", [
|
|
5548
|
+
"Usage:",
|
|
5549
|
+
` ${COMPANY_RULES_CREATE_USAGE.slice("Usage: ".length)}`,
|
|
5550
|
+
"",
|
|
5551
|
+
"Status: implemented",
|
|
5552
|
+
"",
|
|
5553
|
+
"Input shape:",
|
|
5554
|
+
" linkedin-url: LinkedIn company URL | optional when domain is present",
|
|
5555
|
+
" domain: company domain | optional when linkedin-url is present",
|
|
5556
|
+
" disposition: monitor | nurture | not_fit | reject",
|
|
5557
|
+
" user: account user id, email, or me | optional. Omit for account-wide.",
|
|
5558
|
+
"",
|
|
5559
|
+
"Behavior:",
|
|
5560
|
+
" Matching prospects are always created first. Rule application then applies the disposition; monitor locks activity with lock_kind=company_policy until dedicated monitor mode exists.",
|
|
5561
|
+
"",
|
|
5562
|
+
"API:",
|
|
5563
|
+
" POST /api/v1/accounts/:account_id/company_rules.json"
|
|
5564
|
+
].join("\n")],
|
|
5565
|
+
|
|
5566
|
+
["company-rules update", [
|
|
5567
|
+
"Usage:",
|
|
5568
|
+
` ${COMPANY_RULES_UPDATE_USAGE.slice("Usage: ".length)}`,
|
|
5569
|
+
"",
|
|
5570
|
+
"Status: implemented",
|
|
5571
|
+
"",
|
|
5572
|
+
"Input shape:",
|
|
5573
|
+
" user: account user id, email, me, or none. none makes the rule account-wide.",
|
|
5574
|
+
"",
|
|
5575
|
+
"API:",
|
|
5576
|
+
" PATCH /api/v1/accounts/:account_id/company_rules/:id.json"
|
|
5577
|
+
].join("\n")],
|
|
5578
|
+
|
|
5579
|
+
["company-rules remove", [
|
|
5580
|
+
"Usage:",
|
|
5581
|
+
` ${COMPANY_RULES_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
5582
|
+
"",
|
|
5583
|
+
"Status: implemented",
|
|
5584
|
+
"",
|
|
5585
|
+
"API:",
|
|
5586
|
+
" DELETE /api/v1/accounts/:account_id/company_rules/:id.json"
|
|
5587
|
+
].join("\n")],
|
|
5588
|
+
|
|
5589
|
+
["company-rules apply", [
|
|
5590
|
+
"Usage:",
|
|
5591
|
+
` ${COMPANY_RULES_APPLY_USAGE.slice("Usage: ".length)}`,
|
|
5592
|
+
"",
|
|
5593
|
+
"Status: implemented",
|
|
5594
|
+
"",
|
|
5595
|
+
"Behavior:",
|
|
5596
|
+
" Backfills active visible account prospects through the same company-rule applicator used after profile writes.",
|
|
5597
|
+
"",
|
|
5598
|
+
"API:",
|
|
5599
|
+
" POST /api/v1/accounts/:account_id/company_rules/:id/apply.json",
|
|
5600
|
+
" POST /api/v1/accounts/:account_id/company_rules/apply_all.json"
|
|
5601
|
+
].join("\n")],
|
|
5602
|
+
|
|
5158
5603
|
["tags", [
|
|
5159
5604
|
"Usage:",
|
|
5160
5605
|
" audienti tags list [--json]",
|
|
@@ -5867,9 +6312,12 @@ const HELP_TOPICS = new Map([
|
|
|
5867
6312
|
" audienti prospects check [--json|--csv] [filters]",
|
|
5868
6313
|
" audienti prospects show <prsp_id> [--json]",
|
|
5869
6314
|
" audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json]",
|
|
6315
|
+
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|rejected> [--json]",
|
|
5870
6316
|
" audienti prospects reject <prsp_id> [--json]",
|
|
5871
6317
|
" audienti prospects nurture <prsp_id> [--reason <reason>] [--json]",
|
|
5872
6318
|
" audienti prospects restore <prsp_id> [--json]",
|
|
6319
|
+
" audienti prospects lock <prsp_id> [--note <text>] [--json]",
|
|
6320
|
+
" audienti prospects unlock <prsp_id> [--json]",
|
|
5873
6321
|
" audienti prospects timeline <prsp_id> [--json]",
|
|
5874
6322
|
" audienti prospects message-types <prsp_id> [--json]",
|
|
5875
6323
|
" audienti prospects write <prsp_id> --type <surface_key> [--json]",
|
|
@@ -5883,7 +6331,7 @@ const HELP_TOPICS = new Map([
|
|
|
5883
6331
|
" audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--json]",
|
|
5884
6332
|
" audienti prospects import-status <primp_id> [--json]",
|
|
5885
6333
|
"",
|
|
5886
|
-
"Status: read commands, assignment, disposition, per-prospect draft preview, sequence preview, and import implemented",
|
|
6334
|
+
"Status: read commands, assignment, disposition, lock/unlock, per-prospect draft preview, sequence preview, and import implemented",
|
|
5887
6335
|
"",
|
|
5888
6336
|
"Filters:",
|
|
5889
6337
|
" --query <text>",
|
|
@@ -6012,6 +6460,27 @@ const HELP_TOPICS = new Map([
|
|
|
6012
6460
|
" }"
|
|
6013
6461
|
].join("\n")],
|
|
6014
6462
|
|
|
6463
|
+
["prospects set-status", [
|
|
6464
|
+
"Usage:",
|
|
6465
|
+
` ${PROSPECTS_SET_STATUS_USAGE.slice("Usage: ".length)}`,
|
|
6466
|
+
"",
|
|
6467
|
+
"Status: implemented",
|
|
6468
|
+
"",
|
|
6469
|
+
"Purpose:",
|
|
6470
|
+
" Set the account-scoped prospect disposition directly, without routing through a motion.",
|
|
6471
|
+
"",
|
|
6472
|
+
"Input shape:",
|
|
6473
|
+
" status: active | nurture | non_responsive | not_fit | rejected",
|
|
6474
|
+
"",
|
|
6475
|
+
"Behavior:",
|
|
6476
|
+
" active restores the prospect, rejected uses the rejection/DNC path, and nurture/non_responsive/not_fit use the shared inactive disposition path.",
|
|
6477
|
+
"",
|
|
6478
|
+
"API:",
|
|
6479
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/restore.json",
|
|
6480
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/reject.json",
|
|
6481
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/nurture.json"
|
|
6482
|
+
].join("\n")],
|
|
6483
|
+
|
|
6015
6484
|
["prospects show", [
|
|
6016
6485
|
"Usage:",
|
|
6017
6486
|
" audienti prospects show <prsp_id> [--json] [--account <acct_id>]",
|
|
@@ -6067,6 +6536,36 @@ const HELP_TOPICS = new Map([
|
|
|
6067
6536
|
" POST /api/v1/accounts/:account_id/prospects/:id/restore.json"
|
|
6068
6537
|
].join("\n")],
|
|
6069
6538
|
|
|
6539
|
+
["prospects lock", [
|
|
6540
|
+
"Usage:",
|
|
6541
|
+
` ${PROSPECTS_LOCK_USAGE.slice("Usage: ".length)}`,
|
|
6542
|
+
"",
|
|
6543
|
+
"Status: implemented",
|
|
6544
|
+
"",
|
|
6545
|
+
"Purpose:",
|
|
6546
|
+
" Lock one prospect immediately through the same protected-relationship path used by the prospect page.",
|
|
6547
|
+
"",
|
|
6548
|
+
"Input shape:",
|
|
6549
|
+
" kind: protected_relationship | company_policy. Defaults to protected_relationship.",
|
|
6550
|
+
" note: optional operator note explaining the lock.",
|
|
6551
|
+
"",
|
|
6552
|
+
"API:",
|
|
6553
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/lock.json"
|
|
6554
|
+
].join("\n")],
|
|
6555
|
+
|
|
6556
|
+
["prospects unlock", [
|
|
6557
|
+
"Usage:",
|
|
6558
|
+
` ${PROSPECTS_UNLOCK_USAGE.slice("Usage: ".length)}`,
|
|
6559
|
+
"",
|
|
6560
|
+
"Status: implemented",
|
|
6561
|
+
"",
|
|
6562
|
+
"Purpose:",
|
|
6563
|
+
" Clear one prospect lock through the same unlock path used by the prospect page.",
|
|
6564
|
+
"",
|
|
6565
|
+
"API:",
|
|
6566
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/unlock.json"
|
|
6567
|
+
].join("\n")],
|
|
6568
|
+
|
|
6070
6569
|
["prospects timeline", [
|
|
6071
6570
|
"Usage:",
|
|
6072
6571
|
" audienti prospects timeline <prsp_id> [--json] [--types <post,comment,reaction>] [--limit <n>] [--account <acct_id>]",
|
|
@@ -6776,9 +7275,12 @@ const HELP_TOPICS = new Map([
|
|
|
6776
7275
|
" audienti prospects add-profile <prsp_id> --url prospect@example.com",
|
|
6777
7276
|
" audienti prospects report-bad-profile <prsp_id> <prof_id>",
|
|
6778
7277
|
" audienti prospects add-note <prsp_id> --type steer --message \"Meeting will not happen\" --engagement-type action.meeting.canceled",
|
|
7278
|
+
" audienti prospects set-status <prsp_id> --status not_fit",
|
|
7279
|
+
" audienti prospects lock <prsp_id> --note \"Emergency hold\"",
|
|
6779
7280
|
" audienti prospects reject <prsp_id>",
|
|
6780
7281
|
" audienti prospects nurture <prsp_id>",
|
|
6781
7282
|
" audienti prospects restore <prsp_id>",
|
|
7283
|
+
" audienti prospects unlock <prsp_id>",
|
|
6782
7284
|
" audienti prospects sequence-preview <prsp_id>",
|
|
6783
7285
|
" audienti writer test-run <prsp_id>",
|
|
6784
7286
|
" audienti prospects sequence-export <prsp_id> --csv",
|