@audienti/cli 0.1.15 → 0.1.18
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 +20 -0
- package/README.md +28 -0
- package/package.json +1 -1
- package/skills/audienti/SKILL.md +3 -0
- package/src/api-client.js +113 -0
- package/src/cli.js +775 -9
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,26 @@ All notable changes to the Audienti CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.18] - 2026-07-17
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Add ContentOps CLI commands for inspecting programs, reviewing plan rows, approving/scheduling/publishing work items, and handling comment tasks.
|
|
12
|
+
- Add `audienti motions update <motn_id> --own-post-engagement <true|false>` to enable or disable owned-post engagement intake for inbound motions.
|
|
13
|
+
|
|
14
|
+
## [0.1.17] - 2026-07-17
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Add `audienti dnc list/add/import/remove` for account DNC settings.
|
|
19
|
+
- Add `audienti company-rules list/create/update/remove/apply` for account-wide and user-scoped company disposition policies.
|
|
20
|
+
|
|
21
|
+
## [0.1.16] - 2026-07-17
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Add direct prospect emergency state commands: `audienti prospects set-status`, `audienti prospects lock`, and `audienti prospects unlock`.
|
|
26
|
+
|
|
7
27
|
## [0.1.15] - 2026-07-16
|
|
8
28
|
|
|
9
29
|
### Added
|
package/README.md
CHANGED
|
@@ -63,13 +63,22 @@ audienti writer test-run <prsp_id>
|
|
|
63
63
|
audienti motions analytics <motn_id>
|
|
64
64
|
audienti motions run-discovery <motn_id>
|
|
65
65
|
audienti motions update <motn_id> --status paused
|
|
66
|
+
audienti motions update <motn_id> --own-post-engagement true
|
|
66
67
|
audienti motions activate <motn_id>
|
|
67
68
|
audienti motions delete <motn_id> --confirm yes
|
|
69
|
+
audienti content programs
|
|
70
|
+
audienti content plan <cprg_id>
|
|
71
|
+
audienti content approve <cpwi_id>
|
|
72
|
+
audienti content comments
|
|
68
73
|
audienti prospects show <prsp_id> --json
|
|
69
74
|
audienti prospects list --profiles
|
|
70
75
|
audienti prospects list --assigned-user unassigned
|
|
71
76
|
audienti prospects check --all --csv
|
|
72
77
|
audienti prospects assign <prsp_id> --assigned-user me
|
|
78
|
+
audienti prospects set-status <prsp_id> --status not_fit
|
|
79
|
+
audienti prospects lock <prsp_id> --note "Emergency hold"
|
|
80
|
+
audienti dnc list
|
|
81
|
+
audienti company-rules list
|
|
73
82
|
audienti users activity --window 7d
|
|
74
83
|
audienti analytics prospects --window 24h
|
|
75
84
|
audienti analytics dashboard --play-tag wine_campaign
|
|
@@ -170,6 +179,25 @@ audienti prospects assign <prsp_id> --assigned-user <account_user_id|me>
|
|
|
170
179
|
audienti prospects assign <prsp_id> --assigned-user unassign
|
|
171
180
|
```
|
|
172
181
|
|
|
182
|
+
To make emergency prospect state changes without going through a motion:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
audienti prospects set-status <prsp_id> --status nurture
|
|
186
|
+
audienti prospects set-status <prsp_id> --status not_fit
|
|
187
|
+
audienti prospects lock <prsp_id> --note "Emergency hold"
|
|
188
|
+
audienti prospects unlock <prsp_id>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
To manage account DNC and company disposition rules from the CLI:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
audienti dnc add prospect@example.com
|
|
195
|
+
audienti dnc import --file dnc.txt
|
|
196
|
+
audienti company-rules create --linkedin-url https://www.linkedin.com/company/example --disposition monitor
|
|
197
|
+
audienti company-rules create --domain example.com --disposition not_fit --user me
|
|
198
|
+
audienti company-rules apply --all
|
|
199
|
+
```
|
|
200
|
+
|
|
173
201
|
To import multiple LinkedIn people through the same per-prospect import path:
|
|
174
202
|
|
|
175
203
|
```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
|
}
|
|
@@ -201,6 +261,46 @@ export class AudientiClient {
|
|
|
201
261
|
});
|
|
202
262
|
}
|
|
203
263
|
|
|
264
|
+
contentPrograms(accountId, query = {}) {
|
|
265
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "programs"], query));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
contentPlan(accountId, programId, query = {}) {
|
|
269
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "programs", programId, "plan"], query));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
contentWorkItem(accountId, workItemId) {
|
|
273
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "work_items", workItemId]));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
contentFeedback(accountId, workItemId, body) {
|
|
277
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "work_items", workItemId, "feedback"]), { method: "POST", body });
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
contentApprove(accountId, workItemId) {
|
|
281
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "work_items", workItemId, "approve"]), { method: "POST" });
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
contentSchedule(accountId, workItemId, body) {
|
|
285
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "work_items", workItemId, "schedule"]), { method: "POST", body });
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
contentPublish(accountId, workItemId, body) {
|
|
289
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "work_items", workItemId, "publish"]), { method: "POST", body });
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
contentComments(accountId, query = {}) {
|
|
293
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "comment_tasks"], query));
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
contentReply(accountId, commentTaskId, body) {
|
|
297
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "comment_tasks", commentTaskId, "send_reply"]), { method: "POST", body });
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
contentDismiss(accountId, commentTaskId) {
|
|
301
|
+
return this.requestJson(accountPath(accountId, ["content_ops", "comment_tasks", commentTaskId, "dismiss"]), { method: "POST" });
|
|
302
|
+
}
|
|
303
|
+
|
|
204
304
|
addMotionTag(accountId, motionId, body) {
|
|
205
305
|
return this.requestJson(accountPath(accountId, ["motions", motionId, "add_tag"]), {
|
|
206
306
|
method: "POST",
|
|
@@ -306,6 +406,19 @@ export class AudientiClient {
|
|
|
306
406
|
});
|
|
307
407
|
}
|
|
308
408
|
|
|
409
|
+
lockProspect(accountId, prospectId, body = {}) {
|
|
410
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "lock"]), {
|
|
411
|
+
method: "POST",
|
|
412
|
+
body
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
unlockProspect(accountId, prospectId) {
|
|
417
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "unlock"]), {
|
|
418
|
+
method: "POST"
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
309
422
|
prospectSequencePreview(accountId, prospectId, body = {}) {
|
|
310
423
|
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "sequence_preview"]), {
|
|
311
424
|
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,23 +28,44 @@ 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>]";
|
|
44
55
|
const OFFERS_DELETE_USAGE = "Usage: audienti offers delete <offr_id> --confirm <yes|true|Y|y> [--json] [--account <acct_id>]";
|
|
45
56
|
const WRITER_TEST_RUN_USAGE = "Usage: audienti writer test-run <prsp_id> [--json] [--mode <report|plan|step>] [--branch <both|no-accept|accepted>] [--step <step_key|row_number>] [--no-cache] [--clear-cache] [--account <acct_id>]";
|
|
46
57
|
const MOTIONS_ANALYTICS_USAGE = "Usage: audienti motions analytics <motn_id> [--window 30d] [--json] [--account <acct_id>]";
|
|
47
|
-
const MOTIONS_UPDATE_USAGE = "Usage: audienti motions update <motn_id> [--status <draft|preparing|active|paused|archived>] [--tags <tag[,tag...]>] [--json] [--account <acct_id>]";
|
|
58
|
+
const MOTIONS_UPDATE_USAGE = "Usage: audienti motions update <motn_id> [--status <draft|preparing|active|paused|archived>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>] [--json] [--account <acct_id>]";
|
|
59
|
+
const CONTENT_PROGRAMS_USAGE = "Usage: audienti content programs [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
|
|
60
|
+
const CONTENT_PLAN_USAGE = "Usage: audienti content plan <cprg_id> [--week <n>] [--due] [--json] [--account <acct_id>]";
|
|
61
|
+
const CONTENT_SHOW_USAGE = "Usage: audienti content show <cpwi_id> [--json] [--account <acct_id>]";
|
|
62
|
+
const CONTENT_FEEDBACK_USAGE = "Usage: audienti content feedback <cpwi_id> (--message <text> | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
63
|
+
const CONTENT_APPROVE_USAGE = "Usage: audienti content approve <cpwi_id> [--json] [--account <acct_id>]";
|
|
64
|
+
const CONTENT_SCHEDULE_USAGE = "Usage: audienti content schedule <cpwi_id> --at <time> [--json] [--account <acct_id>]";
|
|
65
|
+
const CONTENT_PUBLISH_USAGE = "Usage: audienti content publish <cpwi_id> --url <permalink> [--json] [--account <acct_id>]";
|
|
66
|
+
const CONTENT_COMMENTS_USAGE = "Usage: audienti content comments [--unresolved] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
|
|
67
|
+
const CONTENT_REPLY_USAGE = "Usage: audienti content reply <cctk_id> [--body <text>] [--json] [--account <acct_id>]";
|
|
68
|
+
const CONTENT_DISMISS_USAGE = "Usage: audienti content dismiss <cctk_id> [--json] [--account <acct_id>]";
|
|
48
69
|
const MOTIONS_ADD_TAG_USAGE = "Usage: audienti motions add-tag <motn_id> <tag> [--json] [--account <acct_id>]";
|
|
49
70
|
const MOTIONS_REMOVE_TAG_USAGE = "Usage: audienti motions remove-tag <motn_id> <tag> [--json] [--account <acct_id>]";
|
|
50
71
|
const MOTIONS_DELETE_USAGE = "Usage: audienti motions delete <motn_id> --confirm <yes|true|Y|y> [--json] [--account <acct_id>]";
|
|
@@ -157,6 +178,15 @@ async function dispatch(argv, context) {
|
|
|
157
178
|
if (normalizedResource === "icps" && action === "add-tag") return icpsTagMutation("add", rest, context, { accountOverride });
|
|
158
179
|
if (normalizedResource === "icps" && action === "remove-tag") return icpsTagMutation("remove", rest, context, { accountOverride });
|
|
159
180
|
if (normalizedResource === "companies" && action === "search") return companiesSearch(rest, context, { accountOverride });
|
|
181
|
+
if (normalizedResource === "dnc" && action === "list") return dncList(rest, context, { accountOverride });
|
|
182
|
+
if (normalizedResource === "dnc" && action === "add") return dncAdd(rest, context, { accountOverride });
|
|
183
|
+
if (normalizedResource === "dnc" && action === "import") return dncImport(rest, context, { accountOverride });
|
|
184
|
+
if (normalizedResource === "dnc" && ["remove", "delete"].includes(action)) return dncRemove(rest, context, { accountOverride });
|
|
185
|
+
if (normalizedResource === "company-rules" && action === "list") return companyRulesList(rest, context, { accountOverride });
|
|
186
|
+
if (normalizedResource === "company-rules" && action === "create") return companyRulesCreate(rest, context, { accountOverride });
|
|
187
|
+
if (normalizedResource === "company-rules" && action === "update") return companyRulesUpdate(rest, context, { accountOverride });
|
|
188
|
+
if (normalizedResource === "company-rules" && ["remove", "delete"].includes(action)) return companyRulesRemove(rest, context, { accountOverride });
|
|
189
|
+
if (normalizedResource === "company-rules" && action === "apply") return companyRulesApply(rest, context, { accountOverride });
|
|
160
190
|
if (normalizedResource === "tags" && action === "list") return tagsList(rest, context, { accountOverride });
|
|
161
191
|
if (normalizedResource === "tags" && action === "show") return tagsShow(rest, context, { accountOverride });
|
|
162
192
|
if (normalizedResource === "lists" && action === "list") return listsList(rest, context, { accountOverride });
|
|
@@ -184,13 +214,26 @@ async function dispatch(argv, context) {
|
|
|
184
214
|
if (normalizedResource === "motions" && action === "clone") return motionsClone(rest, context, { accountOverride });
|
|
185
215
|
if (normalizedResource === "motions" && action === "move-prospects") return motionsMoveProspects(rest, context, { accountOverride });
|
|
186
216
|
if (normalizedResource === "motions" && action === "run-discovery") return motionsRunDiscovery(rest, context, { accountOverride });
|
|
217
|
+
if (normalizedResource === "content" && action === "programs") return contentPrograms(rest, context, { accountOverride });
|
|
218
|
+
if (normalizedResource === "content" && action === "plan") return contentPlan(rest, context, { accountOverride });
|
|
219
|
+
if (normalizedResource === "content" && action === "show") return contentShow(rest, context, { accountOverride });
|
|
220
|
+
if (normalizedResource === "content" && action === "feedback") return contentFeedback(rest, context, { accountOverride });
|
|
221
|
+
if (normalizedResource === "content" && action === "approve") return contentApprove(rest, context, { accountOverride });
|
|
222
|
+
if (normalizedResource === "content" && action === "schedule") return contentSchedule(rest, context, { accountOverride });
|
|
223
|
+
if (normalizedResource === "content" && action === "publish") return contentPublish(rest, context, { accountOverride });
|
|
224
|
+
if (normalizedResource === "content" && action === "comments") return contentComments(rest, context, { accountOverride });
|
|
225
|
+
if (normalizedResource === "content" && action === "reply") return contentReply(rest, context, { accountOverride });
|
|
226
|
+
if (normalizedResource === "content" && action === "dismiss") return contentDismiss(rest, context, { accountOverride });
|
|
187
227
|
if (normalizedResource === "prospects" && action === "list") return prospectsList(rest, context, { accountOverride });
|
|
188
228
|
if (normalizedResource === "prospects" && action === "check") return prospectsCheck(rest, context, { accountOverride });
|
|
189
229
|
if (normalizedResource === "prospects" && action === "show") return prospectsShow(rest, context, { accountOverride });
|
|
190
230
|
if (normalizedResource === "prospects" && action === "assign") return prospectsAssign(rest, context, { accountOverride });
|
|
231
|
+
if (normalizedResource === "prospects" && action === "set-status") return prospectsSetStatus(rest, context, { accountOverride });
|
|
191
232
|
if (normalizedResource === "prospects" && action === "reject") return prospectsDisposition("reject", rest, context, { accountOverride });
|
|
192
233
|
if (normalizedResource === "prospects" && action === "nurture") return prospectsDisposition("nurture", rest, context, { accountOverride });
|
|
193
234
|
if (normalizedResource === "prospects" && action === "restore") return prospectsDisposition("restore", rest, context, { accountOverride });
|
|
235
|
+
if (normalizedResource === "prospects" && action === "lock") return prospectsLock(rest, context, { accountOverride });
|
|
236
|
+
if (normalizedResource === "prospects" && action === "unlock") return prospectsUnlock(rest, context, { accountOverride });
|
|
194
237
|
if (normalizedResource === "prospects" && action === "timeline") return prospectsTimeline(rest, context, { accountOverride });
|
|
195
238
|
if (normalizedResource === "prospects" && action === "message-types") return prospectsMessageTypes(rest, context, { accountOverride });
|
|
196
239
|
if (normalizedResource === "prospects" && action === "write") return prospectsWrite(rest, context, { accountOverride });
|
|
@@ -263,6 +306,7 @@ function normalizeTopicParts(parts) {
|
|
|
263
306
|
function normalizeResource(resource) {
|
|
264
307
|
if (resource === "principals") return "users";
|
|
265
308
|
if (resource === "writers") return "writer";
|
|
309
|
+
if (resource === "company_rules" || resource === "company-rules") return "company-rules";
|
|
266
310
|
return resource === "plays" ? "motions" : resource;
|
|
267
311
|
}
|
|
268
312
|
|
|
@@ -813,6 +857,134 @@ async function companiesSearch(args, context, { accountOverride } = {}) {
|
|
|
813
857
|
renderCompanies(payload, context);
|
|
814
858
|
}
|
|
815
859
|
|
|
860
|
+
async function dncList(args, context, { accountOverride } = {}) {
|
|
861
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
862
|
+
...jsonOptions(),
|
|
863
|
+
limit: { type: "string" },
|
|
864
|
+
offset: { type: "string" }
|
|
865
|
+
});
|
|
866
|
+
if (positionals.length > 0) throw new CommandError("Usage: audienti dnc list [--limit <n>] [--offset <n>] [--json] [--account <acct_id>]");
|
|
867
|
+
|
|
868
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
869
|
+
const payload = await client.dncEntries(accountId, compactObject({ limit: values.limit, offset: values.offset }));
|
|
870
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
871
|
+
|
|
872
|
+
renderDncEntries(payload, context);
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
async function dncAdd(args, context, { accountOverride } = {}) {
|
|
876
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
877
|
+
if (positionals.length !== 1) throw new CommandError(DNC_ADD_USAGE);
|
|
878
|
+
|
|
879
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
880
|
+
const payload = await client.createDncEntry(accountId, { value: positionals[0] });
|
|
881
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
882
|
+
|
|
883
|
+
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)}).`);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
async function dncImport(args, context, { accountOverride } = {}) {
|
|
887
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
888
|
+
...jsonOptions(),
|
|
889
|
+
file: { type: "string" }
|
|
890
|
+
});
|
|
891
|
+
if (positionals.length > 0 || !values.file) throw new CommandError(DNC_IMPORT_USAGE);
|
|
892
|
+
|
|
893
|
+
const body = await readFile(values.file, "utf8");
|
|
894
|
+
const importValues = parseDncImportValues(body);
|
|
895
|
+
if (importValues.length === 0) throw new CommandError("DNC import file did not contain any values.");
|
|
896
|
+
|
|
897
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
898
|
+
const payload = await client.importDncEntries(accountId, { values: importValues, filename: basename(values.file) });
|
|
899
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
900
|
+
|
|
901
|
+
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)}.`);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
async function dncRemove(args, context, { accountOverride } = {}) {
|
|
905
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
906
|
+
if (positionals.length !== 1) throw new CommandError(DNC_REMOVE_USAGE);
|
|
907
|
+
|
|
908
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
909
|
+
const payload = await client.deleteDncEntry(accountId, positionals[0]);
|
|
910
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
911
|
+
|
|
912
|
+
writeLine(context.stdout, `Removed DNC entry ${display(payload?.prefix_id || payload?.id || positionals[0])}.`);
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
async function companyRulesList(args, context, { accountOverride } = {}) {
|
|
916
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
917
|
+
if (positionals.length > 0) throw new CommandError("Usage: audienti company-rules list [--json] [--account <acct_id>]");
|
|
918
|
+
|
|
919
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
920
|
+
const payload = await client.companyRules(accountId);
|
|
921
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
922
|
+
|
|
923
|
+
renderCompanyRules(payload, context);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
async function companyRulesCreate(args, context, { accountOverride } = {}) {
|
|
927
|
+
const { values, positionals } = parseCommandArgs(args, companyRuleOptions());
|
|
928
|
+
if (positionals.length > 0 || (!values["linkedin-url"] && !values.domain) || !values.disposition) {
|
|
929
|
+
throw new CommandError(COMPANY_RULES_CREATE_USAGE);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
933
|
+
const payload = await client.createCompanyRule(accountId, { company_rule: companyRulePayload(values) });
|
|
934
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
935
|
+
|
|
936
|
+
const rule = payload?.company_rule;
|
|
937
|
+
writeLine(context.stdout, `Created company rule ${display(rule?.name || rule?.domain || rule?.linkedin_company_identifier)} (${display(rule?.prefix_id || rule?.id)}).`);
|
|
938
|
+
writeLine(context.stdout, `Disposition: ${display(rule?.disposition)} | Scope: ${companyRuleScopeLabel(rule)}`);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
async function companyRulesUpdate(args, context, { accountOverride } = {}) {
|
|
942
|
+
const { values, positionals } = parseCommandArgs(args, companyRuleOptions());
|
|
943
|
+
const hasUpdate = values.disposition || values.name !== undefined || values["linkedin-url"] !== undefined || values.domain !== undefined || values.user !== undefined || values.note !== undefined;
|
|
944
|
+
if (positionals.length !== 1 || !hasUpdate) throw new CommandError(COMPANY_RULES_UPDATE_USAGE);
|
|
945
|
+
|
|
946
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
947
|
+
const payload = await client.updateCompanyRule(accountId, positionals[0], { company_rule: companyRulePayload(values) });
|
|
948
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
949
|
+
|
|
950
|
+
const rule = payload?.company_rule;
|
|
951
|
+
writeLine(context.stdout, `Updated company rule ${display(rule?.name || rule?.domain || rule?.linkedin_company_identifier)} (${display(rule?.prefix_id || rule?.id)}).`);
|
|
952
|
+
writeLine(context.stdout, `Disposition: ${display(rule?.disposition)} | Scope: ${companyRuleScopeLabel(rule)}`);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
async function companyRulesRemove(args, context, { accountOverride } = {}) {
|
|
956
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
957
|
+
if (positionals.length !== 1) throw new CommandError(COMPANY_RULES_REMOVE_USAGE);
|
|
958
|
+
|
|
959
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
960
|
+
const payload = await client.deleteCompanyRule(accountId, positionals[0]);
|
|
961
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
962
|
+
|
|
963
|
+
writeLine(context.stdout, `Removed company rule ${display(payload?.company_rule?.prefix_id || payload?.company_rule?.id || positionals[0])}.`);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
async function companyRulesApply(args, context, { accountOverride } = {}) {
|
|
967
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
968
|
+
...jsonOptions(),
|
|
969
|
+
all: { type: "boolean" }
|
|
970
|
+
});
|
|
971
|
+
if ((values.all && positionals.length > 0) || (!values.all && positionals.length !== 1)) {
|
|
972
|
+
throw new CommandError(COMPANY_RULES_APPLY_USAGE);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
976
|
+
const payload = values.all ?
|
|
977
|
+
await client.applyAllCompanyRules(accountId) :
|
|
978
|
+
await client.applyCompanyRule(accountId, positionals[0]);
|
|
979
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
980
|
+
|
|
981
|
+
if (values.all) {
|
|
982
|
+
writeLine(context.stdout, `Applied company rules. Matched ${display(payload?.matched_count, 0)}, changed ${display(payload?.applied_count, 0)}.`);
|
|
983
|
+
} else {
|
|
984
|
+
writeLine(context.stdout, `Applied company rule. Matched ${display(payload?.matched_count, 0)}, changed ${display(payload?.applied_count, 0)}.`);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
816
988
|
async function tagsList(args, context, { accountOverride } = {}) {
|
|
817
989
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
818
990
|
if (positionals.length > 0) throw new CommandError("Usage: audienti tags list [--json] [--account <acct_id>]");
|
|
@@ -1208,9 +1380,10 @@ async function motionsUpdate(args, context, { accountOverride } = {}) {
|
|
|
1208
1380
|
const { values, positionals } = parseCommandArgs(args, {
|
|
1209
1381
|
...jsonOptions(),
|
|
1210
1382
|
status: { type: "string" },
|
|
1211
|
-
tags: { type: "string" }
|
|
1383
|
+
tags: { type: "string" },
|
|
1384
|
+
"own-post-engagement": { type: "string" }
|
|
1212
1385
|
});
|
|
1213
|
-
const hasUpdateField = values.status || values.tags !== undefined;
|
|
1386
|
+
const hasUpdateField = values.status || values.tags !== undefined || values["own-post-engagement"] !== undefined;
|
|
1214
1387
|
if (positionals.length !== 1 || !hasUpdateField) {
|
|
1215
1388
|
throw new CommandError(MOTIONS_UPDATE_USAGE);
|
|
1216
1389
|
}
|
|
@@ -1218,7 +1391,8 @@ async function motionsUpdate(args, context, { accountOverride } = {}) {
|
|
|
1218
1391
|
const normalizedStatus = normalizeMotionStatus(values.status);
|
|
1219
1392
|
const motionAttributes = compactObject({
|
|
1220
1393
|
status: normalizedStatus,
|
|
1221
|
-
play_tags: values.tags !== undefined ? tagList(values.tags) : undefined
|
|
1394
|
+
play_tags: values.tags !== undefined ? tagList(values.tags) : undefined,
|
|
1395
|
+
own_post_engagement: values["own-post-engagement"] !== undefined ? parseBooleanString(values["own-post-engagement"], "--own-post-engagement") : undefined
|
|
1222
1396
|
});
|
|
1223
1397
|
|
|
1224
1398
|
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
@@ -1259,6 +1433,149 @@ async function updateMotionStatus(motionId, status, context, { accountOverride,
|
|
|
1259
1433
|
renderMotion(motion, context);
|
|
1260
1434
|
}
|
|
1261
1435
|
|
|
1436
|
+
async function contentPrograms(args, context, { accountOverride } = {}) {
|
|
1437
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1438
|
+
...jsonOptions(),
|
|
1439
|
+
user: { type: "string" }
|
|
1440
|
+
});
|
|
1441
|
+
if (positionals.length > 0) throw new CommandError(CONTENT_PROGRAMS_USAGE);
|
|
1442
|
+
|
|
1443
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1444
|
+
const programs = await client.contentPrograms(accountId, compactObject({ user: values.user }));
|
|
1445
|
+
if (values.json) return writeJson(context.stdout, programs);
|
|
1446
|
+
|
|
1447
|
+
renderContentPrograms(programs, context);
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
async function contentPlan(args, context, { accountOverride } = {}) {
|
|
1451
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1452
|
+
...jsonOptions(),
|
|
1453
|
+
week: { type: "string" },
|
|
1454
|
+
due: { type: "boolean" }
|
|
1455
|
+
});
|
|
1456
|
+
if (positionals.length !== 1) throw new CommandError(CONTENT_PLAN_USAGE);
|
|
1457
|
+
|
|
1458
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1459
|
+
const payload = await client.contentPlan(accountId, positionals[0]);
|
|
1460
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1461
|
+
|
|
1462
|
+
const week = values.week ? Number.parseInt(values.week, 10) : null;
|
|
1463
|
+
let rows = Array.isArray(payload?.rows) ? payload.rows : [];
|
|
1464
|
+
if (week) rows = rows.filter((row) => Number(row.week_number) === week);
|
|
1465
|
+
if (values.due) rows = rows.filter((row) => ["researching", "drafting", "needs_operator_review", "needs_operator_approval", "scheduled", "ready_to_post"].includes(row.stage));
|
|
1466
|
+
renderContentPlanRows(rows, context);
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
async function contentShow(args, context, { accountOverride } = {}) {
|
|
1470
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1471
|
+
if (positionals.length !== 1) throw new CommandError(CONTENT_SHOW_USAGE);
|
|
1472
|
+
|
|
1473
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1474
|
+
const item = await client.contentWorkItem(accountId, positionals[0]);
|
|
1475
|
+
if (values.json) return writeJson(context.stdout, item);
|
|
1476
|
+
|
|
1477
|
+
renderContentWorkItem(item, context);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
async function contentFeedback(args, context, { accountOverride } = {}) {
|
|
1481
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1482
|
+
...jsonOptions(),
|
|
1483
|
+
message: { type: "string" },
|
|
1484
|
+
payload: { type: "string" }
|
|
1485
|
+
});
|
|
1486
|
+
if (positionals.length !== 1 || (!values.message && !values.payload)) throw new CommandError(CONTENT_FEEDBACK_USAGE);
|
|
1487
|
+
|
|
1488
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1489
|
+
const payload = values.payload ? await readJsonPayload(values.payload) : { draft_feedback: values.message };
|
|
1490
|
+
const item = await client.contentFeedback(accountId, positionals[0], payload);
|
|
1491
|
+
if (values.json) return writeJson(context.stdout, item);
|
|
1492
|
+
|
|
1493
|
+
writeLine(context.stdout, `Queued feedback for ${display(item?.prefix_id)}.`);
|
|
1494
|
+
renderContentWorkItem(item, context);
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
async function contentApprove(args, context, { accountOverride } = {}) {
|
|
1498
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1499
|
+
if (positionals.length !== 1) throw new CommandError(CONTENT_APPROVE_USAGE);
|
|
1500
|
+
|
|
1501
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1502
|
+
const item = await client.contentApprove(accountId, positionals[0]);
|
|
1503
|
+
if (values.json) return writeJson(context.stdout, item);
|
|
1504
|
+
|
|
1505
|
+
writeLine(context.stdout, `Approved ${display(item?.prefix_id)}.`);
|
|
1506
|
+
renderContentWorkItem(item, context);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
async function contentSchedule(args, context, { accountOverride } = {}) {
|
|
1510
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1511
|
+
...jsonOptions(),
|
|
1512
|
+
at: { type: "string" }
|
|
1513
|
+
});
|
|
1514
|
+
if (positionals.length !== 1 || !values.at) throw new CommandError(CONTENT_SCHEDULE_USAGE);
|
|
1515
|
+
|
|
1516
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1517
|
+
const item = await client.contentSchedule(accountId, positionals[0], { scheduled_at: values.at });
|
|
1518
|
+
if (values.json) return writeJson(context.stdout, item);
|
|
1519
|
+
|
|
1520
|
+
writeLine(context.stdout, `Scheduled ${display(item?.prefix_id)}.`);
|
|
1521
|
+
renderContentWorkItem(item, context);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
async function contentPublish(args, context, { accountOverride } = {}) {
|
|
1525
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1526
|
+
...jsonOptions(),
|
|
1527
|
+
url: { type: "string" }
|
|
1528
|
+
});
|
|
1529
|
+
if (positionals.length !== 1 || !values.url) throw new CommandError(CONTENT_PUBLISH_USAGE);
|
|
1530
|
+
|
|
1531
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1532
|
+
const item = await client.contentPublish(accountId, positionals[0], { permalink: values.url });
|
|
1533
|
+
if (values.json) return writeJson(context.stdout, item);
|
|
1534
|
+
|
|
1535
|
+
writeLine(context.stdout, `Published ${display(item?.prefix_id)}.`);
|
|
1536
|
+
renderContentWorkItem(item, context);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
async function contentComments(args, context, { accountOverride } = {}) {
|
|
1540
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1541
|
+
...jsonOptions(),
|
|
1542
|
+
unresolved: { type: "boolean" },
|
|
1543
|
+
user: { type: "string" }
|
|
1544
|
+
});
|
|
1545
|
+
if (positionals.length > 0) throw new CommandError(CONTENT_COMMENTS_USAGE);
|
|
1546
|
+
|
|
1547
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1548
|
+
const comments = await client.contentComments(accountId, compactObject({ unresolved: values.unresolved === false ? false : true, user: values.user }));
|
|
1549
|
+
if (values.json) return writeJson(context.stdout, comments);
|
|
1550
|
+
|
|
1551
|
+
renderContentComments(comments, context);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
async function contentReply(args, context, { accountOverride } = {}) {
|
|
1555
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1556
|
+
...jsonOptions(),
|
|
1557
|
+
body: { type: "string" }
|
|
1558
|
+
});
|
|
1559
|
+
if (positionals.length !== 1) throw new CommandError(CONTENT_REPLY_USAGE);
|
|
1560
|
+
|
|
1561
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1562
|
+
const comment = await client.contentReply(accountId, positionals[0], compactObject({ body: values.body }));
|
|
1563
|
+
if (values.json) return writeJson(context.stdout, comment);
|
|
1564
|
+
|
|
1565
|
+
writeLine(context.stdout, `Sent reply for ${display(comment?.prefix_id)}.`);
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
async function contentDismiss(args, context, { accountOverride } = {}) {
|
|
1569
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1570
|
+
if (positionals.length !== 1) throw new CommandError(CONTENT_DISMISS_USAGE);
|
|
1571
|
+
|
|
1572
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1573
|
+
const comment = await client.contentDismiss(accountId, positionals[0]);
|
|
1574
|
+
if (values.json) return writeJson(context.stdout, comment);
|
|
1575
|
+
|
|
1576
|
+
writeLine(context.stdout, `Dismissed ${display(comment?.prefix_id)}.`);
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1262
1579
|
function normalizeMotionStatus(status) {
|
|
1263
1580
|
if (status === undefined) return undefined;
|
|
1264
1581
|
|
|
@@ -1270,6 +1587,14 @@ function normalizeMotionStatus(status) {
|
|
|
1270
1587
|
return normalizedStatus;
|
|
1271
1588
|
}
|
|
1272
1589
|
|
|
1590
|
+
function parseBooleanString(value, flagName) {
|
|
1591
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
1592
|
+
if (["true", "1", "yes", "y"].includes(normalized)) return true;
|
|
1593
|
+
if (["false", "0", "no", "n"].includes(normalized)) return false;
|
|
1594
|
+
|
|
1595
|
+
throw new CommandError(`${flagName} must be true or false.`);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1273
1598
|
async function motionsTagMutation(action, args, context, { accountOverride } = {}) {
|
|
1274
1599
|
const usageText = action === "add" ? MOTIONS_ADD_TAG_USAGE : MOTIONS_REMOVE_TAG_USAGE;
|
|
1275
1600
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
@@ -1489,6 +1814,59 @@ async function prospectsDisposition(action, args, context, { accountOverride } =
|
|
|
1489
1814
|
renderProspectDisposition(payload, context, { action });
|
|
1490
1815
|
}
|
|
1491
1816
|
|
|
1817
|
+
async function prospectsSetStatus(args, context, { accountOverride } = {}) {
|
|
1818
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1819
|
+
...jsonOptions(),
|
|
1820
|
+
status: { type: "string" }
|
|
1821
|
+
});
|
|
1822
|
+
const status = String(values.status || "").trim();
|
|
1823
|
+
if (positionals.length !== 1 || !PROSPECT_STATUS_VALUES.has(status)) {
|
|
1824
|
+
throw new CommandError(PROSPECTS_SET_STATUS_USAGE);
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1828
|
+
const payload = await mutateProspectStatus(client, accountId, positionals[0], status);
|
|
1829
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1830
|
+
|
|
1831
|
+
renderProspectDisposition(payload, context, { action: "set-status" });
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1834
|
+
async function prospectsLock(args, context, { accountOverride } = {}) {
|
|
1835
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1836
|
+
...jsonOptions(),
|
|
1837
|
+
kind: { type: "string" },
|
|
1838
|
+
note: { type: "string" }
|
|
1839
|
+
});
|
|
1840
|
+
if (positionals.length !== 1) throw new CommandError(PROSPECTS_LOCK_USAGE);
|
|
1841
|
+
|
|
1842
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1843
|
+
const payload = await client.lockProspect(accountId, positionals[0], compactObject({
|
|
1844
|
+
lock_kind: values.kind,
|
|
1845
|
+
lock_note: values.note
|
|
1846
|
+
}));
|
|
1847
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1848
|
+
|
|
1849
|
+
renderProspectDisposition(payload, context, { action: "lock" });
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
async function prospectsUnlock(args, context, { accountOverride } = {}) {
|
|
1853
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1854
|
+
if (positionals.length !== 1) throw new CommandError(PROSPECTS_UNLOCK_USAGE);
|
|
1855
|
+
|
|
1856
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1857
|
+
const payload = await client.unlockProspect(accountId, positionals[0]);
|
|
1858
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1859
|
+
|
|
1860
|
+
renderProspectDisposition(payload, context, { action: "unlock" });
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
async function mutateProspectStatus(client, accountId, prospectId, status) {
|
|
1864
|
+
if (status === "active") return client.restoreProspect(accountId, prospectId);
|
|
1865
|
+
if (status === "rejected") return client.rejectProspect(accountId, prospectId);
|
|
1866
|
+
|
|
1867
|
+
return client.nurtureProspect(accountId, prospectId, { inactive_reason: status });
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1492
1870
|
async function prospectsTimeline(args, context, { accountOverride } = {}) {
|
|
1493
1871
|
const { values, positionals } = parseCommandArgs(args, {
|
|
1494
1872
|
...jsonOptions(),
|
|
@@ -2599,6 +2977,43 @@ function tagList(value) {
|
|
|
2599
2977
|
.filter((tag, index, tags) => tags.indexOf(tag) === index);
|
|
2600
2978
|
}
|
|
2601
2979
|
|
|
2980
|
+
function companyRuleOptions() {
|
|
2981
|
+
return {
|
|
2982
|
+
...jsonOptions(),
|
|
2983
|
+
name: { type: "string" },
|
|
2984
|
+
"linkedin-url": { type: "string" },
|
|
2985
|
+
domain: { type: "string" },
|
|
2986
|
+
disposition: { type: "string" },
|
|
2987
|
+
user: { type: "string" },
|
|
2988
|
+
note: { type: "string" }
|
|
2989
|
+
};
|
|
2990
|
+
}
|
|
2991
|
+
|
|
2992
|
+
function companyRulePayload(values) {
|
|
2993
|
+
const userValue = values.user === undefined ? undefined : String(values.user || "").trim();
|
|
2994
|
+
const userCleared = userValue && ["none", "account", "all"].includes(userValue.toLowerCase());
|
|
2995
|
+
|
|
2996
|
+
return compactObject({
|
|
2997
|
+
name: values.name,
|
|
2998
|
+
linkedin_company_url: values["linkedin-url"],
|
|
2999
|
+
domain: values.domain,
|
|
3000
|
+
disposition: values.disposition,
|
|
3001
|
+
note: values.note,
|
|
3002
|
+
scope_kind: userValue === undefined ? undefined : (userCleared ? "account" : "account_user"),
|
|
3003
|
+
account_user_id: userValue === undefined ? undefined : (userCleared ? "" : userValue)
|
|
3004
|
+
});
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
function parseDncImportValues(body) {
|
|
3008
|
+
return String(body || "")
|
|
3009
|
+
.split(/\r?\n/)
|
|
3010
|
+
.map((line) => line.trim())
|
|
3011
|
+
.filter(Boolean)
|
|
3012
|
+
.map((line) => line.split(",")[0])
|
|
3013
|
+
.map((value) => value.trim().replace(/^"|"$/g, ""))
|
|
3014
|
+
.filter(Boolean);
|
|
3015
|
+
}
|
|
3016
|
+
|
|
2602
3017
|
function filterRecordsByTag(records, value, field) {
|
|
2603
3018
|
const tag = tagList(value)?.[0];
|
|
2604
3019
|
if (!tag) return records;
|
|
@@ -3117,6 +3532,54 @@ function renderCompanies(payload, context) {
|
|
|
3117
3532
|
}
|
|
3118
3533
|
}
|
|
3119
3534
|
|
|
3535
|
+
function renderDncEntries(payload, context) {
|
|
3536
|
+
const entries = Array.isArray(payload?.dnc_entries) ? payload.dnc_entries : [];
|
|
3537
|
+
if (entries.length === 0) return writeLine(context.stdout, "No DNC entries found.");
|
|
3538
|
+
|
|
3539
|
+
writeLine(context.stdout, "DNC ID\tKIND\tVALUE\tIDENTIFIER\tSOURCE\tPROSPECT");
|
|
3540
|
+
for (const entry of entries) {
|
|
3541
|
+
writeLine(
|
|
3542
|
+
context.stdout,
|
|
3543
|
+
[
|
|
3544
|
+
display(entry.prefix_id || entry.id),
|
|
3545
|
+
display(entry.key_kind),
|
|
3546
|
+
display(entry.canonical_value || entry.citation_id),
|
|
3547
|
+
display(entry.identifier),
|
|
3548
|
+
display(entry.source_kind),
|
|
3549
|
+
display(entry.prospect_id)
|
|
3550
|
+
].join("\t")
|
|
3551
|
+
);
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3554
|
+
|
|
3555
|
+
function renderCompanyRules(payload, context) {
|
|
3556
|
+
const rules = Array.isArray(payload?.company_rules) ? payload.company_rules : [];
|
|
3557
|
+
if (rules.length === 0) return writeLine(context.stdout, "No company rules found.");
|
|
3558
|
+
|
|
3559
|
+
writeLine(context.stdout, "RULE ID\tCOMPANY\tDOMAIN\tDISPOSITION\tSCOPE\tACTIVE");
|
|
3560
|
+
for (const rule of rules) {
|
|
3561
|
+
writeLine(
|
|
3562
|
+
context.stdout,
|
|
3563
|
+
[
|
|
3564
|
+
display(rule.prefix_id || rule.id),
|
|
3565
|
+
display(rule.name || rule.linkedin_company_identifier || rule.linkedin_company_url),
|
|
3566
|
+
display(rule.domain),
|
|
3567
|
+
display(rule.disposition),
|
|
3568
|
+
companyRuleScopeLabel(rule),
|
|
3569
|
+
rule.active ? "yes" : "no"
|
|
3570
|
+
].join("\t")
|
|
3571
|
+
);
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
|
|
3575
|
+
function companyRuleScopeLabel(rule) {
|
|
3576
|
+
if (rule?.scope_kind === "account_user") {
|
|
3577
|
+
return `user:${display(rule.account_user_email || rule.account_user_id)}`;
|
|
3578
|
+
}
|
|
3579
|
+
|
|
3580
|
+
return "account";
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3120
3583
|
async function performBulkMutation(perform) {
|
|
3121
3584
|
try {
|
|
3122
3585
|
return { payload: await perform(), rejected: false };
|
|
@@ -3161,6 +3624,7 @@ function renderMotion(motion, context) {
|
|
|
3161
3624
|
if (motion?.offer?.name) writeLine(context.stdout, `Offer: ${motion.offer.name} (${display(motion.offer.prefix_id)})`);
|
|
3162
3625
|
if (motion?.icp?.name) writeLine(context.stdout, `ICP: ${motion.icp.name} (${display(motion.icp.prefix_id)})`);
|
|
3163
3626
|
if (motion?.list?.name) writeLine(context.stdout, `List: ${motion.list.name} (${display(motion.list.prefix_id)})`);
|
|
3627
|
+
writeLine(context.stdout, `Own-post engagement: ${motion?.own_post_engagement ? "enabled" : "disabled"}`);
|
|
3164
3628
|
if (Array.isArray(motion?.play_tags)) writeLine(context.stdout, `Tags: ${display(motion.play_tags.join(", "), "-")}`);
|
|
3165
3629
|
if (motion?.principal_account_user?.id) {
|
|
3166
3630
|
writeLine(
|
|
@@ -3170,6 +3634,59 @@ function renderMotion(motion, context) {
|
|
|
3170
3634
|
}
|
|
3171
3635
|
}
|
|
3172
3636
|
|
|
3637
|
+
function renderContentPrograms(programs, context) {
|
|
3638
|
+
if (!Array.isArray(programs) || programs.length === 0) return writeLine(context.stdout, "No ContentOps programs found.");
|
|
3639
|
+
|
|
3640
|
+
writeAlignedTable(context, ["PROGRAM ID", "OWNER", "STAGE", "BLOCKED", "CURRENT", "SCHEDULED", "STALE"], programs.map((program) => [
|
|
3641
|
+
display(program.prefix_id),
|
|
3642
|
+
display(program.owner?.name || program.owner?.email),
|
|
3643
|
+
display(program.stage),
|
|
3644
|
+
display(program.blocking_reason, "-"),
|
|
3645
|
+
display(program.current_piece?.prefix_id || program.current_piece?.piece_key, "-"),
|
|
3646
|
+
display(program.scheduled_piece?.prefix_id || program.scheduled_piece?.piece_key, "-"),
|
|
3647
|
+
program.plan_stale_motion_set ? "yes" : "no"
|
|
3648
|
+
]));
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
function renderContentPlanRows(rows, context) {
|
|
3652
|
+
if (!Array.isArray(rows) || rows.length === 0) return writeLine(context.stdout, "No ContentOps plan rows found.");
|
|
3653
|
+
|
|
3654
|
+
writeAlignedTable(context, ["DAY", "DATE", "MOTION", "STAGE", "STATUS", "TITLE"], rows.map((row) => [
|
|
3655
|
+
display(row.day_number),
|
|
3656
|
+
display(row.planned_publish_on, "-"),
|
|
3657
|
+
display(row.motion?.name || row.motion?.motion_prefix_id, "-"),
|
|
3658
|
+
display(row.stage, "-"),
|
|
3659
|
+
display(row.publish_status || row.workflow_phase, "-"),
|
|
3660
|
+
display(row.title)
|
|
3661
|
+
]));
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
function renderContentWorkItem(item, context) {
|
|
3665
|
+
writeLine(context.stdout, `Content item: ${display(item?.title)} (${display(item?.prefix_id)})`);
|
|
3666
|
+
writeLine(context.stdout, `Stage: ${display(item?.stage)}`);
|
|
3667
|
+
writeLine(context.stdout, `Blocking: ${display(item?.blocking_reason, "-")}`);
|
|
3668
|
+
if (item?.motion?.name || item?.motion?.motion_prefix_id) writeLine(context.stdout, `Motion: ${display(item.motion.name || item.motion.motion_prefix_id)}`);
|
|
3669
|
+
if (item?.scheduled_at) writeLine(context.stdout, `Scheduled: ${item.scheduled_at}`);
|
|
3670
|
+
if (item?.permalink) writeLine(context.stdout, `Permalink: ${item.permalink}`);
|
|
3671
|
+
if (item?.finalized_content) {
|
|
3672
|
+
writeLine(context.stdout, "");
|
|
3673
|
+
writeLine(context.stdout, item.finalized_content);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3677
|
+
function renderContentComments(comments, context) {
|
|
3678
|
+
if (!Array.isArray(comments) || comments.length === 0) return writeLine(context.stdout, "No ContentOps comment tasks found.");
|
|
3679
|
+
|
|
3680
|
+
writeAlignedTable(context, ["TASK ID", "STATUS", "COMMENTER", "FIT", "OUTCOME", "COMMENT"], comments.map((comment) => [
|
|
3681
|
+
display(comment.prefix_id),
|
|
3682
|
+
display(comment.status),
|
|
3683
|
+
display(comment.commenter?.name),
|
|
3684
|
+
display(comment.fit_badge?.status || comment.fit_badge, "-"),
|
|
3685
|
+
display(comment.promotion_outcome, "-"),
|
|
3686
|
+
display(truncateCliText(comment.comment_body, 80))
|
|
3687
|
+
]));
|
|
3688
|
+
}
|
|
3689
|
+
|
|
3173
3690
|
function renderMotionStatus(status, context) {
|
|
3174
3691
|
writeLine(context.stdout, `Motion: ${display(status?.name)} (${display(status?.prefix_id)})`);
|
|
3175
3692
|
writeLine(context.stdout, `State: ${display(status?.state)}`);
|
|
@@ -3265,12 +3782,18 @@ function renderProspectDisposition(payload, context, { action }) {
|
|
|
3265
3782
|
const actionLabel = {
|
|
3266
3783
|
reject: "Rejected",
|
|
3267
3784
|
nurture: "Moved to nurture",
|
|
3268
|
-
restore: "Restored"
|
|
3785
|
+
restore: "Restored",
|
|
3786
|
+
"set-status": "Set status for",
|
|
3787
|
+
lock: "Locked",
|
|
3788
|
+
unlock: "Unlocked"
|
|
3269
3789
|
}[action] || display(payload?.status, "Updated");
|
|
3270
3790
|
|
|
3271
3791
|
writeLine(context.stdout, `${actionLabel} prospect ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)}).`);
|
|
3272
3792
|
if (accountProspect.status) writeLine(context.stdout, `Status: ${accountProspect.status}`);
|
|
3273
3793
|
if (accountProspect.inactive_reason) writeLine(context.stdout, `Inactive reason: ${accountProspect.inactive_reason}`);
|
|
3794
|
+
if (accountProspect.locked_at) writeLine(context.stdout, `Locked at: ${accountProspect.locked_at}`);
|
|
3795
|
+
if (accountProspect.lock_kind) writeLine(context.stdout, `Lock kind: ${accountProspect.lock_kind}`);
|
|
3796
|
+
if (accountProspect.lock_note) writeLine(context.stdout, `Lock note: ${accountProspect.lock_note}`);
|
|
3274
3797
|
if (payload?.system_list?.name) writeLine(context.stdout, `List: ${payload.system_list.name} (${display(payload.system_list.prefix_id)})`);
|
|
3275
3798
|
}
|
|
3276
3799
|
|
|
@@ -4531,7 +5054,7 @@ const HELP_TOPICS = new Map([
|
|
|
4531
5054
|
" audienti motions run-discovery <motn_id>",
|
|
4532
5055
|
" audienti motions prospects <motn_id>",
|
|
4533
5056
|
" audienti motions create --payload <file.json>",
|
|
4534
|
-
" audienti motions update <motn_id> [--status <state>] [--tags <tag[,tag...]>]",
|
|
5057
|
+
" audienti motions update <motn_id> [--status <state>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>]",
|
|
4535
5058
|
" audienti motions add-tag <motn_id> <tag>",
|
|
4536
5059
|
" audienti motions remove-tag <motn_id> <tag>",
|
|
4537
5060
|
" audienti motions activate <motn_id>",
|
|
@@ -4541,14 +5064,26 @@ const HELP_TOPICS = new Map([
|
|
|
4541
5064
|
" audienti motions move-prospects <source_motn_id> --target <target_motn_id> <prsp_id> [prsp_id...]",
|
|
4542
5065
|
" Tip: `plays` is accepted anywhere `motions` is accepted.",
|
|
4543
5066
|
"",
|
|
5067
|
+
" ContentOps",
|
|
5068
|
+
" audienti content programs",
|
|
5069
|
+
" audienti content plan <cprg_id>",
|
|
5070
|
+
" audienti content show <cpwi_id>",
|
|
5071
|
+
" audienti content feedback <cpwi_id> --message <text>",
|
|
5072
|
+
" audienti content approve <cpwi_id>",
|
|
5073
|
+
" audienti content publish <cpwi_id> --url <permalink>",
|
|
5074
|
+
" audienti content comments",
|
|
5075
|
+
"",
|
|
4544
5076
|
" Prospects",
|
|
4545
5077
|
" audienti prospects list [filters]",
|
|
4546
5078
|
" audienti prospects check [filters]",
|
|
4547
5079
|
" audienti prospects show <prsp_id>",
|
|
4548
5080
|
" audienti prospects assign <prsp_id> --assigned-user <id|me|unassign>",
|
|
5081
|
+
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|rejected>",
|
|
5082
|
+
" audienti prospects lock <prsp_id> [--note <text>]",
|
|
4549
5083
|
" audienti prospects reject <prsp_id>",
|
|
4550
5084
|
" audienti prospects nurture <prsp_id> [--reason <reason>]",
|
|
4551
5085
|
" audienti prospects restore <prsp_id>",
|
|
5086
|
+
" audienti prospects unlock <prsp_id>",
|
|
4552
5087
|
" audienti prospects timeline <prsp_id>",
|
|
4553
5088
|
" audienti prospects import <linkedin_url> [--motion <motn_id>]",
|
|
4554
5089
|
" audienti prospects import-batch --file <csv|jsonl|json>",
|
|
@@ -4572,6 +5107,10 @@ const HELP_TOPICS = new Map([
|
|
|
4572
5107
|
" audienti icps add-tag <icp_id> <tag>",
|
|
4573
5108
|
" audienti icps remove-tag <icp_id> <tag>",
|
|
4574
5109
|
" audienti companies search --query <text>",
|
|
5110
|
+
" audienti dnc list",
|
|
5111
|
+
" audienti dnc add <email|citation_id|profile_url>",
|
|
5112
|
+
" audienti company-rules list",
|
|
5113
|
+
" audienti company-rules create (--linkedin-url <url> | --domain <domain>) --disposition <state>",
|
|
4575
5114
|
"",
|
|
4576
5115
|
" Writer",
|
|
4577
5116
|
" audienti writer test-run <prsp_id>",
|
|
@@ -5155,6 +5694,148 @@ const HELP_TOPICS = new Map([
|
|
|
5155
5694
|
" companies[].location: string | null"
|
|
5156
5695
|
].join("\n")],
|
|
5157
5696
|
|
|
5697
|
+
["dnc", [
|
|
5698
|
+
"Usage:",
|
|
5699
|
+
" audienti dnc list [--json]",
|
|
5700
|
+
` ${DNC_ADD_USAGE.slice("Usage: ".length)}`,
|
|
5701
|
+
` ${DNC_IMPORT_USAGE.slice("Usage: ".length)}`,
|
|
5702
|
+
` ${DNC_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
5703
|
+
"",
|
|
5704
|
+
"Status: implemented",
|
|
5705
|
+
"",
|
|
5706
|
+
"Purpose:",
|
|
5707
|
+
" Manage account-level do-not-contact entries through the same settings/API path as the app."
|
|
5708
|
+
].join("\n")],
|
|
5709
|
+
|
|
5710
|
+
["dnc list", [
|
|
5711
|
+
"Usage:",
|
|
5712
|
+
" audienti dnc list [--limit <n>] [--offset <n>] [--json] [--account <acct_id>]",
|
|
5713
|
+
"",
|
|
5714
|
+
"Status: implemented",
|
|
5715
|
+
"",
|
|
5716
|
+
"API:",
|
|
5717
|
+
" GET /api/v1/accounts/:account_id/dnc.json"
|
|
5718
|
+
].join("\n")],
|
|
5719
|
+
|
|
5720
|
+
["dnc add", [
|
|
5721
|
+
"Usage:",
|
|
5722
|
+
` ${DNC_ADD_USAGE.slice("Usage: ".length)}`,
|
|
5723
|
+
"",
|
|
5724
|
+
"Status: implemented",
|
|
5725
|
+
"",
|
|
5726
|
+
"Input shape:",
|
|
5727
|
+
" value: email, citation ID, or supported person profile URL",
|
|
5728
|
+
"",
|
|
5729
|
+
"Behavior:",
|
|
5730
|
+
" Creates or reactivates an account DNC entry and retroactively rejects matching account prospects.",
|
|
5731
|
+
"",
|
|
5732
|
+
"API:",
|
|
5733
|
+
" POST /api/v1/accounts/:account_id/dnc.json"
|
|
5734
|
+
].join("\n")],
|
|
5735
|
+
|
|
5736
|
+
["dnc import", [
|
|
5737
|
+
"Usage:",
|
|
5738
|
+
` ${DNC_IMPORT_USAGE.slice("Usage: ".length)}`,
|
|
5739
|
+
"",
|
|
5740
|
+
"Status: implemented",
|
|
5741
|
+
"",
|
|
5742
|
+
"Input shape:",
|
|
5743
|
+
" file: text or CSV file. The CLI sends one value per line using column one for CSV-like rows.",
|
|
5744
|
+
"",
|
|
5745
|
+
"API:",
|
|
5746
|
+
" POST /api/v1/accounts/:account_id/dnc/import.json"
|
|
5747
|
+
].join("\n")],
|
|
5748
|
+
|
|
5749
|
+
["dnc remove", [
|
|
5750
|
+
"Usage:",
|
|
5751
|
+
` ${DNC_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
5752
|
+
"",
|
|
5753
|
+
"Status: implemented",
|
|
5754
|
+
"",
|
|
5755
|
+
"API:",
|
|
5756
|
+
" DELETE /api/v1/accounts/:account_id/dnc/:id.json"
|
|
5757
|
+
].join("\n")],
|
|
5758
|
+
|
|
5759
|
+
["company-rules", [
|
|
5760
|
+
"Usage:",
|
|
5761
|
+
" audienti company-rules list [--json]",
|
|
5762
|
+
` ${COMPANY_RULES_CREATE_USAGE.slice("Usage: ".length)}`,
|
|
5763
|
+
` ${COMPANY_RULES_UPDATE_USAGE.slice("Usage: ".length)}`,
|
|
5764
|
+
` ${COMPANY_RULES_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
5765
|
+
` ${COMPANY_RULES_APPLY_USAGE.slice("Usage: ".length)}`,
|
|
5766
|
+
"",
|
|
5767
|
+
"Status: implemented",
|
|
5768
|
+
"",
|
|
5769
|
+
"Purpose:",
|
|
5770
|
+
" Manage account-wide and user-scoped company disposition rules keyed by LinkedIn company URL or domain."
|
|
5771
|
+
].join("\n")],
|
|
5772
|
+
|
|
5773
|
+
["company-rules list", [
|
|
5774
|
+
"Usage:",
|
|
5775
|
+
" audienti company-rules list [--json] [--account <acct_id>]",
|
|
5776
|
+
"",
|
|
5777
|
+
"Status: implemented",
|
|
5778
|
+
"",
|
|
5779
|
+
"API:",
|
|
5780
|
+
" GET /api/v1/accounts/:account_id/company_rules.json"
|
|
5781
|
+
].join("\n")],
|
|
5782
|
+
|
|
5783
|
+
["company-rules create", [
|
|
5784
|
+
"Usage:",
|
|
5785
|
+
` ${COMPANY_RULES_CREATE_USAGE.slice("Usage: ".length)}`,
|
|
5786
|
+
"",
|
|
5787
|
+
"Status: implemented",
|
|
5788
|
+
"",
|
|
5789
|
+
"Input shape:",
|
|
5790
|
+
" linkedin-url: LinkedIn company URL | optional when domain is present",
|
|
5791
|
+
" domain: company domain | optional when linkedin-url is present",
|
|
5792
|
+
" disposition: monitor | nurture | not_fit | reject",
|
|
5793
|
+
" user: account user id, email, or me | optional. Omit for account-wide.",
|
|
5794
|
+
"",
|
|
5795
|
+
"Behavior:",
|
|
5796
|
+
" 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.",
|
|
5797
|
+
"",
|
|
5798
|
+
"API:",
|
|
5799
|
+
" POST /api/v1/accounts/:account_id/company_rules.json"
|
|
5800
|
+
].join("\n")],
|
|
5801
|
+
|
|
5802
|
+
["company-rules update", [
|
|
5803
|
+
"Usage:",
|
|
5804
|
+
` ${COMPANY_RULES_UPDATE_USAGE.slice("Usage: ".length)}`,
|
|
5805
|
+
"",
|
|
5806
|
+
"Status: implemented",
|
|
5807
|
+
"",
|
|
5808
|
+
"Input shape:",
|
|
5809
|
+
" user: account user id, email, me, or none. none makes the rule account-wide.",
|
|
5810
|
+
"",
|
|
5811
|
+
"API:",
|
|
5812
|
+
" PATCH /api/v1/accounts/:account_id/company_rules/:id.json"
|
|
5813
|
+
].join("\n")],
|
|
5814
|
+
|
|
5815
|
+
["company-rules remove", [
|
|
5816
|
+
"Usage:",
|
|
5817
|
+
` ${COMPANY_RULES_REMOVE_USAGE.slice("Usage: ".length)}`,
|
|
5818
|
+
"",
|
|
5819
|
+
"Status: implemented",
|
|
5820
|
+
"",
|
|
5821
|
+
"API:",
|
|
5822
|
+
" DELETE /api/v1/accounts/:account_id/company_rules/:id.json"
|
|
5823
|
+
].join("\n")],
|
|
5824
|
+
|
|
5825
|
+
["company-rules apply", [
|
|
5826
|
+
"Usage:",
|
|
5827
|
+
` ${COMPANY_RULES_APPLY_USAGE.slice("Usage: ".length)}`,
|
|
5828
|
+
"",
|
|
5829
|
+
"Status: implemented",
|
|
5830
|
+
"",
|
|
5831
|
+
"Behavior:",
|
|
5832
|
+
" Backfills active visible account prospects through the same company-rule applicator used after profile writes.",
|
|
5833
|
+
"",
|
|
5834
|
+
"API:",
|
|
5835
|
+
" POST /api/v1/accounts/:account_id/company_rules/:id/apply.json",
|
|
5836
|
+
" POST /api/v1/accounts/:account_id/company_rules/apply_all.json"
|
|
5837
|
+
].join("\n")],
|
|
5838
|
+
|
|
5158
5839
|
["tags", [
|
|
5159
5840
|
"Usage:",
|
|
5160
5841
|
" audienti tags list [--json]",
|
|
@@ -5462,7 +6143,7 @@ const HELP_TOPICS = new Map([
|
|
|
5462
6143
|
" audienti motions prospects <motn_id> [--json]",
|
|
5463
6144
|
" audienti motions add-prospects <motn_id> <prsp_id> [prsp_id...] [--json]",
|
|
5464
6145
|
" audienti motions create --payload <file.json> [--json]",
|
|
5465
|
-
" audienti motions update <motn_id> [--status <draft|preparing|active|paused|archived>] [--tags <tag[,tag...]>] [--json]",
|
|
6146
|
+
" audienti motions update <motn_id> [--status <draft|preparing|active|paused|archived>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>] [--json]",
|
|
5466
6147
|
" audienti motions add-tag <motn_id> <tag> [--json]",
|
|
5467
6148
|
" audienti motions remove-tag <motn_id> <tag> [--json]",
|
|
5468
6149
|
" audienti motions activate <motn_id> [--json]",
|
|
@@ -5481,6 +6162,34 @@ const HELP_TOPICS = new Map([
|
|
|
5481
6162
|
" motn_id: motn_ prefix id"
|
|
5482
6163
|
].join("\n")],
|
|
5483
6164
|
|
|
6165
|
+
["content", [
|
|
6166
|
+
"Usage:",
|
|
6167
|
+
" audienti content programs [--user <account_user_id|email|name|me>] [--json]",
|
|
6168
|
+
" audienti content plan <cprg_id> [--week <n>] [--due] [--json]",
|
|
6169
|
+
" audienti content show <cpwi_id> [--json]",
|
|
6170
|
+
" audienti content feedback <cpwi_id> --message <text> [--json]",
|
|
6171
|
+
" audienti content approve <cpwi_id> [--json]",
|
|
6172
|
+
" audienti content schedule <cpwi_id> --at <time> [--json]",
|
|
6173
|
+
" audienti content publish <cpwi_id> --url <permalink> [--json]",
|
|
6174
|
+
" audienti content comments [--unresolved] [--user <account_user_id|email|name|me>] [--json]",
|
|
6175
|
+
" audienti content reply <cctk_id> [--body <text>] [--json]",
|
|
6176
|
+
" audienti content dismiss <cctk_id> [--json]",
|
|
6177
|
+
"",
|
|
6178
|
+
"API:",
|
|
6179
|
+
" GET/POST /api/v1/accounts/:account_id/content_ops/..."
|
|
6180
|
+
].join("\n")],
|
|
6181
|
+
|
|
6182
|
+
["content programs", [CONTENT_PROGRAMS_USAGE].join("\n")],
|
|
6183
|
+
["content plan", [CONTENT_PLAN_USAGE].join("\n")],
|
|
6184
|
+
["content show", [CONTENT_SHOW_USAGE].join("\n")],
|
|
6185
|
+
["content feedback", [CONTENT_FEEDBACK_USAGE].join("\n")],
|
|
6186
|
+
["content approve", [CONTENT_APPROVE_USAGE].join("\n")],
|
|
6187
|
+
["content schedule", [CONTENT_SCHEDULE_USAGE].join("\n")],
|
|
6188
|
+
["content publish", [CONTENT_PUBLISH_USAGE].join("\n")],
|
|
6189
|
+
["content comments", [CONTENT_COMMENTS_USAGE].join("\n")],
|
|
6190
|
+
["content reply", [CONTENT_REPLY_USAGE].join("\n")],
|
|
6191
|
+
["content dismiss", [CONTENT_DISMISS_USAGE].join("\n")],
|
|
6192
|
+
|
|
5484
6193
|
["motions list", [
|
|
5485
6194
|
"Usage:",
|
|
5486
6195
|
" audienti motions list [--tag <tag>] [--json] [--account <acct_id>]",
|
|
@@ -5867,9 +6576,12 @@ const HELP_TOPICS = new Map([
|
|
|
5867
6576
|
" audienti prospects check [--json|--csv] [filters]",
|
|
5868
6577
|
" audienti prospects show <prsp_id> [--json]",
|
|
5869
6578
|
" audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json]",
|
|
6579
|
+
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|rejected> [--json]",
|
|
5870
6580
|
" audienti prospects reject <prsp_id> [--json]",
|
|
5871
6581
|
" audienti prospects nurture <prsp_id> [--reason <reason>] [--json]",
|
|
5872
6582
|
" audienti prospects restore <prsp_id> [--json]",
|
|
6583
|
+
" audienti prospects lock <prsp_id> [--note <text>] [--json]",
|
|
6584
|
+
" audienti prospects unlock <prsp_id> [--json]",
|
|
5873
6585
|
" audienti prospects timeline <prsp_id> [--json]",
|
|
5874
6586
|
" audienti prospects message-types <prsp_id> [--json]",
|
|
5875
6587
|
" audienti prospects write <prsp_id> --type <surface_key> [--json]",
|
|
@@ -5883,7 +6595,7 @@ const HELP_TOPICS = new Map([
|
|
|
5883
6595
|
" audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--json]",
|
|
5884
6596
|
" audienti prospects import-status <primp_id> [--json]",
|
|
5885
6597
|
"",
|
|
5886
|
-
"Status: read commands, assignment, disposition, per-prospect draft preview, sequence preview, and import implemented",
|
|
6598
|
+
"Status: read commands, assignment, disposition, lock/unlock, per-prospect draft preview, sequence preview, and import implemented",
|
|
5887
6599
|
"",
|
|
5888
6600
|
"Filters:",
|
|
5889
6601
|
" --query <text>",
|
|
@@ -6012,6 +6724,27 @@ const HELP_TOPICS = new Map([
|
|
|
6012
6724
|
" }"
|
|
6013
6725
|
].join("\n")],
|
|
6014
6726
|
|
|
6727
|
+
["prospects set-status", [
|
|
6728
|
+
"Usage:",
|
|
6729
|
+
` ${PROSPECTS_SET_STATUS_USAGE.slice("Usage: ".length)}`,
|
|
6730
|
+
"",
|
|
6731
|
+
"Status: implemented",
|
|
6732
|
+
"",
|
|
6733
|
+
"Purpose:",
|
|
6734
|
+
" Set the account-scoped prospect disposition directly, without routing through a motion.",
|
|
6735
|
+
"",
|
|
6736
|
+
"Input shape:",
|
|
6737
|
+
" status: active | nurture | non_responsive | not_fit | rejected",
|
|
6738
|
+
"",
|
|
6739
|
+
"Behavior:",
|
|
6740
|
+
" active restores the prospect, rejected uses the rejection/DNC path, and nurture/non_responsive/not_fit use the shared inactive disposition path.",
|
|
6741
|
+
"",
|
|
6742
|
+
"API:",
|
|
6743
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/restore.json",
|
|
6744
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/reject.json",
|
|
6745
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/nurture.json"
|
|
6746
|
+
].join("\n")],
|
|
6747
|
+
|
|
6015
6748
|
["prospects show", [
|
|
6016
6749
|
"Usage:",
|
|
6017
6750
|
" audienti prospects show <prsp_id> [--json] [--account <acct_id>]",
|
|
@@ -6067,6 +6800,36 @@ const HELP_TOPICS = new Map([
|
|
|
6067
6800
|
" POST /api/v1/accounts/:account_id/prospects/:id/restore.json"
|
|
6068
6801
|
].join("\n")],
|
|
6069
6802
|
|
|
6803
|
+
["prospects lock", [
|
|
6804
|
+
"Usage:",
|
|
6805
|
+
` ${PROSPECTS_LOCK_USAGE.slice("Usage: ".length)}`,
|
|
6806
|
+
"",
|
|
6807
|
+
"Status: implemented",
|
|
6808
|
+
"",
|
|
6809
|
+
"Purpose:",
|
|
6810
|
+
" Lock one prospect immediately through the same protected-relationship path used by the prospect page.",
|
|
6811
|
+
"",
|
|
6812
|
+
"Input shape:",
|
|
6813
|
+
" kind: protected_relationship | company_policy. Defaults to protected_relationship.",
|
|
6814
|
+
" note: optional operator note explaining the lock.",
|
|
6815
|
+
"",
|
|
6816
|
+
"API:",
|
|
6817
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/lock.json"
|
|
6818
|
+
].join("\n")],
|
|
6819
|
+
|
|
6820
|
+
["prospects unlock", [
|
|
6821
|
+
"Usage:",
|
|
6822
|
+
` ${PROSPECTS_UNLOCK_USAGE.slice("Usage: ".length)}`,
|
|
6823
|
+
"",
|
|
6824
|
+
"Status: implemented",
|
|
6825
|
+
"",
|
|
6826
|
+
"Purpose:",
|
|
6827
|
+
" Clear one prospect lock through the same unlock path used by the prospect page.",
|
|
6828
|
+
"",
|
|
6829
|
+
"API:",
|
|
6830
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/unlock.json"
|
|
6831
|
+
].join("\n")],
|
|
6832
|
+
|
|
6070
6833
|
["prospects timeline", [
|
|
6071
6834
|
"Usage:",
|
|
6072
6835
|
" audienti prospects timeline <prsp_id> [--json] [--types <post,comment,reaction>] [--limit <n>] [--account <acct_id>]",
|
|
@@ -6776,9 +7539,12 @@ const HELP_TOPICS = new Map([
|
|
|
6776
7539
|
" audienti prospects add-profile <prsp_id> --url prospect@example.com",
|
|
6777
7540
|
" audienti prospects report-bad-profile <prsp_id> <prof_id>",
|
|
6778
7541
|
" audienti prospects add-note <prsp_id> --type steer --message \"Meeting will not happen\" --engagement-type action.meeting.canceled",
|
|
7542
|
+
" audienti prospects set-status <prsp_id> --status not_fit",
|
|
7543
|
+
" audienti prospects lock <prsp_id> --note \"Emergency hold\"",
|
|
6779
7544
|
" audienti prospects reject <prsp_id>",
|
|
6780
7545
|
" audienti prospects nurture <prsp_id>",
|
|
6781
7546
|
" audienti prospects restore <prsp_id>",
|
|
7547
|
+
" audienti prospects unlock <prsp_id>",
|
|
6782
7548
|
" audienti prospects sequence-preview <prsp_id>",
|
|
6783
7549
|
" audienti writer test-run <prsp_id>",
|
|
6784
7550
|
" audienti prospects sequence-export <prsp_id> --csv",
|