@audienti/cli 0.1.8 → 0.1.10
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 +16 -0
- package/README.md +22 -0
- package/package.json +1 -1
- package/skills/audienti/SKILL.md +7 -0
- package/src/api-client.js +24 -0
- package/src/cli.js +533 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to the Audienti CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.10] - 2026-07-15
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Add `audienti motions update <motn_id> --status <draft|preparing|active|paused|archived>` plus `activate`, `pause`, and `archive` shortcuts for motion/play lifecycle status management.
|
|
12
|
+
- Add `audienti motions delete <motn_id> --confirm <yes|true|Y|y>` to delete a motion/play through the API cleanup path.
|
|
13
|
+
|
|
14
|
+
## [0.1.9] - 2026-07-15
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Add `audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign>` for reassigning existing prospects from the CLI.
|
|
19
|
+
- Add `audienti users activity <account_user_id|me>` for inspecting one account user's outbound activity feed.
|
|
20
|
+
- Add `audienti prospects import-batch --file <csv|jsonl|json>` for starting multiple normal prospect imports with shared list, motion, and assignee defaults.
|
|
21
|
+
- Add `audienti prospects list --assigned-user unassigned` for finding prospects without an owner.
|
|
22
|
+
|
|
7
23
|
## [0.1.8] - 2026-07-14
|
|
8
24
|
|
|
9
25
|
### Added
|
package/README.md
CHANGED
|
@@ -54,8 +54,14 @@ Common inspection commands:
|
|
|
54
54
|
audienti operator next --plan
|
|
55
55
|
audienti writer test-run <prsp_id>
|
|
56
56
|
audienti motions analytics <motn_id>
|
|
57
|
+
audienti motions update <motn_id> --status paused
|
|
58
|
+
audienti motions activate <motn_id>
|
|
59
|
+
audienti motions delete <motn_id> --confirm yes
|
|
57
60
|
audienti prospects show <prsp_id> --json
|
|
58
61
|
audienti prospects list --profiles
|
|
62
|
+
audienti prospects list --assigned-user unassigned
|
|
63
|
+
audienti prospects assign <prsp_id> --assigned-user me
|
|
64
|
+
audienti users activity me --window 7d
|
|
59
65
|
audienti analytics prospects --window 24h
|
|
60
66
|
audienti analytics users --user me --window 30d
|
|
61
67
|
audienti analytics visibility --window 24h --user me
|
|
@@ -126,6 +132,22 @@ audienti prospects add-profile <prsp_id> --url https://www.linkedin.com/in/examp
|
|
|
126
132
|
audienti prospects report-bad-profile <prsp_id> <prof_id>
|
|
127
133
|
```
|
|
128
134
|
|
|
135
|
+
To reassign or clear ownership for existing prospects:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
audienti prospects assign <prsp_id> --assigned-user <account_user_id|me>
|
|
139
|
+
audienti prospects assign <prsp_id> --assigned-user unassign
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
To import multiple LinkedIn people through the same per-prospect import path:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
audienti prospects import-batch --file prospects.csv --motion <motn_id> --assigned-user me
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
CSV files should include a `linkedin_url` or `url` header. Optional row columns
|
|
149
|
+
`list_id`, `motion_id`, and `assigned_user_id` override command defaults.
|
|
150
|
+
|
|
129
151
|
## Compatibility
|
|
130
152
|
|
|
131
153
|
The CLI talks to the versioned Audienti `/api/v1` contract at
|
package/package.json
CHANGED
package/skills/audienti/SKILL.md
CHANGED
|
@@ -51,7 +51,14 @@ audienti help agent-workflows
|
|
|
51
51
|
```bash
|
|
52
52
|
audienti help agent-workflows
|
|
53
53
|
audienti prospects list --query "name or company" --wide --json
|
|
54
|
+
audienti prospects list --assigned-user unassigned --json
|
|
55
|
+
audienti prospects assign <prsp_id> --assigned-user me --json
|
|
56
|
+
audienti users activity me --window 7d --json
|
|
57
|
+
audienti prospects import-batch --file prospects.csv --motion <motn_id> --assigned-user me --json
|
|
54
58
|
audienti lists create --name "Target list" --json
|
|
59
|
+
audienti motions update <motn_id> --status paused --json
|
|
60
|
+
audienti motions activate <motn_id> --json
|
|
61
|
+
audienti motions delete <motn_id> --confirm yes --json
|
|
55
62
|
audienti operator next --json
|
|
56
63
|
audienti operator next --plan
|
|
57
64
|
audienti analytics prospects --window 24h --json
|
package/src/api-client.js
CHANGED
|
@@ -43,6 +43,10 @@ export class AudientiClient {
|
|
|
43
43
|
return this.requestJson(accountPath(accountId, ["users"]));
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
userActivity(accountId, userId, query = {}) {
|
|
47
|
+
return this.requestJson(accountPath(accountId, ["operations", "users", userId, "activity"], query));
|
|
48
|
+
}
|
|
49
|
+
|
|
46
50
|
offers(accountId) {
|
|
47
51
|
return this.requestJson(accountPath(accountId, ["offers"]));
|
|
48
52
|
}
|
|
@@ -130,6 +134,19 @@ export class AudientiClient {
|
|
|
130
134
|
});
|
|
131
135
|
}
|
|
132
136
|
|
|
137
|
+
updateMotion(accountId, motionId, body) {
|
|
138
|
+
return this.requestJson(accountPath(accountId, ["motions", motionId]), {
|
|
139
|
+
method: "PATCH",
|
|
140
|
+
body
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
deleteMotion(accountId, motionId) {
|
|
145
|
+
return this.requestJson(accountPath(accountId, ["motions", motionId]), {
|
|
146
|
+
method: "DELETE"
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
133
150
|
cloneMotion(accountId, motionId, body) {
|
|
134
151
|
return this.requestJson(accountPath(accountId, ["motions", motionId, "clone"]), {
|
|
135
152
|
method: "POST",
|
|
@@ -167,6 +184,13 @@ export class AudientiClient {
|
|
|
167
184
|
return this.requestJson(accountPath(accountId, ["prospects", prospectId]));
|
|
168
185
|
}
|
|
169
186
|
|
|
187
|
+
assignProspects(accountId, body) {
|
|
188
|
+
return this.requestJson(accountPath(accountId, ["prospects", "assign"]), {
|
|
189
|
+
method: "POST",
|
|
190
|
+
body
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
170
194
|
prospectTimeline(accountId, prospectId, query = {}) {
|
|
171
195
|
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "timeline"], query));
|
|
172
196
|
}
|
package/src/cli.js
CHANGED
|
@@ -25,12 +25,18 @@ const DEFAULT_PROFILE_IDENTIFIERS = [
|
|
|
25
25
|
"email/profile"
|
|
26
26
|
];
|
|
27
27
|
const DELETE_CONFIRMATION_VALUES = new Set(["yes", "true", "y"]);
|
|
28
|
+
const MOTION_STATUS_VALUES = new Set(["draft", "preparing", "active", "paused", "archived"]);
|
|
28
29
|
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>]";
|
|
29
30
|
const PROSPECTS_ADD_STEER_USAGE = "Usage: audienti prospects add-steer <prsp_id> (--message <text> [--engagement-type <key>] | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
30
31
|
const PROSPECTS_ADD_PROFILE_USAGE = "Usage: audienti prospects add-profile <prsp_id> --url <profile_url|email|phone> [--json] [--account <acct_id>]";
|
|
31
32
|
const PROSPECTS_REPORT_BAD_PROFILE_USAGE = "Usage: audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json] [--account <acct_id>]";
|
|
33
|
+
const PROSPECTS_ASSIGN_USAGE = "Usage: audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json] [--account <acct_id>]";
|
|
34
|
+
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>]";
|
|
35
|
+
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>]";
|
|
32
36
|
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>]";
|
|
33
37
|
const MOTIONS_ANALYTICS_USAGE = "Usage: audienti motions analytics <motn_id> [--window 30d] [--json] [--account <acct_id>]";
|
|
38
|
+
const MOTIONS_UPDATE_USAGE = "Usage: audienti motions update <motn_id> --status <draft|preparing|active|paused|archived> [--json] [--account <acct_id>]";
|
|
39
|
+
const MOTIONS_DELETE_USAGE = "Usage: audienti motions delete <motn_id> --confirm <yes|true|Y|y> [--json] [--account <acct_id>]";
|
|
34
40
|
const MOTIONS_CLONE_USAGE = "Usage: audienti motions clone <motn_id> --name <text> [--json] [--account <acct_id>]";
|
|
35
41
|
const MOTIONS_MOVE_PROSPECTS_USAGE = "Usage: audienti motions move-prospects <source_motn_id> --target <target_motn_id> <prsp_id> [prsp_id...] [--json] [--account <acct_id>]";
|
|
36
42
|
const ANALYTICS_PROSPECTS_USAGE = "Usage: audienti analytics prospects [--window 24h] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--motion <motn_id>] [--provenance <source>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
|
|
@@ -117,6 +123,7 @@ async function dispatch(argv, context) {
|
|
|
117
123
|
if (normalizedResource === "accounts" && action === "list") return accountsList(rest, context, { accountOverride });
|
|
118
124
|
if (normalizedResource === "accounts" && action === "select") return accountsSelect(rest, context);
|
|
119
125
|
if (normalizedResource === "users" && action === "list") return usersList(rest, context, { accountOverride });
|
|
126
|
+
if (normalizedResource === "users" && action === "activity") return usersActivity(rest, context, { accountOverride });
|
|
120
127
|
if (normalizedResource === "offers" && action === "list") return offersList(rest, context, { accountOverride });
|
|
121
128
|
if (normalizedResource === "offers" && action === "create") return offersCreate(rest, context, { accountOverride });
|
|
122
129
|
if (normalizedResource === "icps" && action === "list") return icpsList(rest, context, { accountOverride });
|
|
@@ -137,10 +144,14 @@ async function dispatch(argv, context) {
|
|
|
137
144
|
if (normalizedResource === "motions" && action === "prospects") return motionsProspects(rest, context, { accountOverride });
|
|
138
145
|
if (normalizedResource === "motions" && action === "add-prospects") return motionsAddProspects(rest, context, { accountOverride });
|
|
139
146
|
if (normalizedResource === "motions" && action === "create") return motionsCreate(rest, context, { accountOverride });
|
|
147
|
+
if (normalizedResource === "motions" && action === "update") return motionsUpdate(rest, context, { accountOverride });
|
|
148
|
+
if (normalizedResource === "motions" && ["activate", "pause", "archive"].includes(action)) return motionsStatusShortcut(action, rest, context, { accountOverride });
|
|
149
|
+
if (normalizedResource === "motions" && action === "delete") return motionsDelete(rest, context, { accountOverride });
|
|
140
150
|
if (normalizedResource === "motions" && action === "clone") return motionsClone(rest, context, { accountOverride });
|
|
141
151
|
if (normalizedResource === "motions" && action === "move-prospects") return motionsMoveProspects(rest, context, { accountOverride });
|
|
142
152
|
if (normalizedResource === "prospects" && action === "list") return prospectsList(rest, context, { accountOverride });
|
|
143
153
|
if (normalizedResource === "prospects" && action === "show") return prospectsShow(rest, context, { accountOverride });
|
|
154
|
+
if (normalizedResource === "prospects" && action === "assign") return prospectsAssign(rest, context, { accountOverride });
|
|
144
155
|
if (normalizedResource === "prospects" && action === "timeline") return prospectsTimeline(rest, context, { accountOverride });
|
|
145
156
|
if (normalizedResource === "prospects" && action === "message-types") return prospectsMessageTypes(rest, context, { accountOverride });
|
|
146
157
|
if (normalizedResource === "prospects" && action === "write") return prospectsWrite(rest, context, { accountOverride });
|
|
@@ -151,6 +162,7 @@ async function dispatch(argv, context) {
|
|
|
151
162
|
if (normalizedResource === "prospects" && action === "sequence-preview") return prospectsSequencePreview(rest, context, { accountOverride });
|
|
152
163
|
if (normalizedResource === "prospects" && action === "sequence-export") return prospectsSequenceExport(rest, context, { accountOverride });
|
|
153
164
|
if (normalizedResource === "prospects" && action === "import") return prospectsImport(rest, context, { accountOverride });
|
|
165
|
+
if (normalizedResource === "prospects" && action === "import-batch") return prospectsImportBatch(rest, context, { accountOverride });
|
|
154
166
|
if (normalizedResource === "prospects" && action === "import-status") return prospectsImportStatus(rest, context, { accountOverride });
|
|
155
167
|
if (normalizedResource === "writer" && action === "test-run") return writerTestRun(rest, context, { accountOverride });
|
|
156
168
|
if (normalizedResource === "tools" && action === "get") return toolsGet(rest, context, { accountOverride });
|
|
@@ -399,6 +411,32 @@ async function usersList(args, context, { accountOverride } = {}) {
|
|
|
399
411
|
renderUsers(users, context);
|
|
400
412
|
}
|
|
401
413
|
|
|
414
|
+
async function usersActivity(args, context, { accountOverride } = {}) {
|
|
415
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
416
|
+
...jsonOptions(),
|
|
417
|
+
mode: { type: "string" },
|
|
418
|
+
window: { type: "string" },
|
|
419
|
+
platform: { type: "string" },
|
|
420
|
+
query: { type: "string" },
|
|
421
|
+
limit: { type: "string" },
|
|
422
|
+
page: { type: "string" }
|
|
423
|
+
});
|
|
424
|
+
if (positionals.length !== 1) throw new CommandError(USERS_ACTIVITY_USAGE);
|
|
425
|
+
|
|
426
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
427
|
+
const payload = await client.userActivity(accountId, positionals[0], compactObject({
|
|
428
|
+
mode: values.mode,
|
|
429
|
+
window: values.window,
|
|
430
|
+
platform: values.platform,
|
|
431
|
+
query: values.query,
|
|
432
|
+
limit: values.limit,
|
|
433
|
+
page: values.page
|
|
434
|
+
}));
|
|
435
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
436
|
+
|
|
437
|
+
renderUserActivity(payload, context);
|
|
438
|
+
}
|
|
439
|
+
|
|
402
440
|
async function offersList(args, context, { accountOverride } = {}) {
|
|
403
441
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
404
442
|
if (positionals.length > 0) throw new CommandError("Usage: audienti offers list [--json] [--account <acct_id>]");
|
|
@@ -786,6 +824,68 @@ async function motionsCreate(args, context, { accountOverride } = {}) {
|
|
|
786
824
|
renderMotion(created, context);
|
|
787
825
|
}
|
|
788
826
|
|
|
827
|
+
async function motionsDelete(args, context, { accountOverride } = {}) {
|
|
828
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
829
|
+
...jsonOptions(),
|
|
830
|
+
confirm: { type: "string" }
|
|
831
|
+
});
|
|
832
|
+
const normalizedConfirm = String(values.confirm || "").trim().toLowerCase();
|
|
833
|
+
if (positionals.length !== 1 || !DELETE_CONFIRMATION_VALUES.has(normalizedConfirm)) {
|
|
834
|
+
throw new CommandError(MOTIONS_DELETE_USAGE);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
838
|
+
const payload = await client.deleteMotion(accountId, positionals[0]);
|
|
839
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
840
|
+
|
|
841
|
+
writeLine(context.stdout, `Deleted motion ${display(payload?.name)} (${display(payload?.prefix_id)}).`);
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
async function motionsUpdate(args, context, { accountOverride } = {}) {
|
|
845
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
846
|
+
...jsonOptions(),
|
|
847
|
+
status: { type: "string" }
|
|
848
|
+
});
|
|
849
|
+
if (positionals.length !== 1 || !values.status) {
|
|
850
|
+
throw new CommandError(MOTIONS_UPDATE_USAGE);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return updateMotionStatus(positionals[0], values.status, context, { accountOverride, json: values.json });
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
async function motionsStatusShortcut(action, args, context, { accountOverride } = {}) {
|
|
857
|
+
const usage = `Usage: audienti motions ${action} <motn_id> [--json] [--account <acct_id>]`;
|
|
858
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
859
|
+
if (positionals.length !== 1) {
|
|
860
|
+
throw new CommandError(usage);
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
const statusByAction = {
|
|
864
|
+
activate: "active",
|
|
865
|
+
pause: "paused",
|
|
866
|
+
archive: "archived"
|
|
867
|
+
};
|
|
868
|
+
return updateMotionStatus(positionals[0], statusByAction[action], context, { accountOverride, json: values.json });
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
async function updateMotionStatus(motionId, status, context, { accountOverride, json } = {}) {
|
|
872
|
+
const normalizedStatus = String(status || "").trim().toLowerCase();
|
|
873
|
+
if (!MOTION_STATUS_VALUES.has(normalizedStatus)) {
|
|
874
|
+
throw new CommandError(MOTIONS_UPDATE_USAGE);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
878
|
+
const motion = await client.updateMotion(accountId, motionId, {
|
|
879
|
+
motion: {
|
|
880
|
+
status: normalizedStatus
|
|
881
|
+
}
|
|
882
|
+
});
|
|
883
|
+
if (json) return writeJson(context.stdout, motion);
|
|
884
|
+
|
|
885
|
+
writeLine(context.stdout, `Updated motion ${display(motion?.name)} (${display(motion?.prefix_id)}) to ${display(motion?.status)}.`);
|
|
886
|
+
renderMotion(motion, context);
|
|
887
|
+
}
|
|
888
|
+
|
|
789
889
|
async function motionsClone(args, context, { accountOverride } = {}) {
|
|
790
890
|
const { values, positionals } = parseCommandArgs(args, {
|
|
791
891
|
...jsonOptions(),
|
|
@@ -882,6 +982,36 @@ async function prospectsList(args, context, { accountOverride } = {}) {
|
|
|
882
982
|
renderProspects(payload, context, { wide: values.wide || values.all, profiles: values.profiles });
|
|
883
983
|
}
|
|
884
984
|
|
|
985
|
+
async function prospectsAssign(args, context, { accountOverride } = {}) {
|
|
986
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
987
|
+
...jsonOptions(),
|
|
988
|
+
"assigned-user": { type: "string" }
|
|
989
|
+
});
|
|
990
|
+
if (positionals.length < 1 || !values["assigned-user"]) {
|
|
991
|
+
throw new CommandError(PROSPECTS_ASSIGN_USAGE);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
995
|
+
const { payload, rejected } = await performBulkMutation(() =>
|
|
996
|
+
client.assignProspects(accountId, {
|
|
997
|
+
prospect_ids: positionals,
|
|
998
|
+
assigned_user_id: values["assigned-user"]
|
|
999
|
+
}));
|
|
1000
|
+
if (values.json) {
|
|
1001
|
+
writeJson(context.stdout, payload);
|
|
1002
|
+
return rejected ? 1 : 0;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
const successLabel = values["assigned-user"] === "unassign" ?
|
|
1006
|
+
`Unassigned ${successCount(payload)} prospects.` :
|
|
1007
|
+
`Assigned ${successCount(payload)} prospects to ${display(values["assigned-user"])}.`;
|
|
1008
|
+
renderBulkMutationResult(payload, context, {
|
|
1009
|
+
successLabel,
|
|
1010
|
+
zeroSuccessLabel: "No prospects were assigned."
|
|
1011
|
+
});
|
|
1012
|
+
return rejected ? 1 : 0;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
885
1015
|
async function prospectsShow(args, context, { accountOverride } = {}) {
|
|
886
1016
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
887
1017
|
if (positionals.length !== 1) throw new CommandError("Usage: audienti prospects show <prsp_id> [--json] [--account <acct_id>]");
|
|
@@ -1295,6 +1425,66 @@ async function prospectsImport(args, context, { accountOverride } = {}) {
|
|
|
1295
1425
|
renderProspectImportStarted(payload, context);
|
|
1296
1426
|
}
|
|
1297
1427
|
|
|
1428
|
+
async function prospectsImportBatch(args, context, { accountOverride } = {}) {
|
|
1429
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1430
|
+
...jsonOptions(),
|
|
1431
|
+
file: { type: "string" },
|
|
1432
|
+
list: { type: "string" },
|
|
1433
|
+
motion: { type: "string" },
|
|
1434
|
+
"assigned-user": { type: "string" }
|
|
1435
|
+
});
|
|
1436
|
+
if (positionals.length > 0 || !values.file) {
|
|
1437
|
+
throw new CommandError(PROSPECTS_IMPORT_BATCH_USAGE);
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
const rows = await readProspectImportBatchFile(values.file);
|
|
1441
|
+
if (rows.length === 0) throw new CommandError("Import batch file did not contain any prospects.");
|
|
1442
|
+
|
|
1443
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1444
|
+
const result = {
|
|
1445
|
+
summary: {
|
|
1446
|
+
total: rows.length,
|
|
1447
|
+
started: 0,
|
|
1448
|
+
failed: 0
|
|
1449
|
+
},
|
|
1450
|
+
imports: [],
|
|
1451
|
+
failed: []
|
|
1452
|
+
};
|
|
1453
|
+
|
|
1454
|
+
for (const row of rows) {
|
|
1455
|
+
const body = compactObject({
|
|
1456
|
+
linkedin_url: row.linkedin_url,
|
|
1457
|
+
list_id: row.list_id || values.list,
|
|
1458
|
+
motion_id: row.motion_id || values.motion,
|
|
1459
|
+
assigned_user_id: row.assigned_user_id || values["assigned-user"]
|
|
1460
|
+
});
|
|
1461
|
+
|
|
1462
|
+
try {
|
|
1463
|
+
const payload = await client.prospectImport(accountId, body);
|
|
1464
|
+
result.imports.push(payload);
|
|
1465
|
+
result.summary.started += 1;
|
|
1466
|
+
} catch (error) {
|
|
1467
|
+
if (!(error instanceof ApiError)) throw error;
|
|
1468
|
+
|
|
1469
|
+
result.failed.push({
|
|
1470
|
+
row: row.row,
|
|
1471
|
+
linkedin_url: row.linkedin_url,
|
|
1472
|
+
status: error.status,
|
|
1473
|
+
error: error.body?.error || error.message
|
|
1474
|
+
});
|
|
1475
|
+
result.summary.failed += 1;
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
if (values.json) {
|
|
1480
|
+
writeJson(context.stdout, result);
|
|
1481
|
+
return result.summary.failed > 0 ? 1 : 0;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
renderProspectImportBatchResult(result, context);
|
|
1485
|
+
return result.summary.failed > 0 ? 1 : 0;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1298
1488
|
async function prospectsImportStatus(args, context, { accountOverride } = {}) {
|
|
1299
1489
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1300
1490
|
if (positionals.length !== 1) {
|
|
@@ -1984,6 +2174,113 @@ async function readJsonPayload(filePath) {
|
|
|
1984
2174
|
}
|
|
1985
2175
|
}
|
|
1986
2176
|
|
|
2177
|
+
async function readProspectImportBatchFile(filePath) {
|
|
2178
|
+
let contents;
|
|
2179
|
+
try {
|
|
2180
|
+
contents = await readFile(filePath, "utf8");
|
|
2181
|
+
} catch (error) {
|
|
2182
|
+
throw new CommandError(`Could not read import batch file ${filePath}: ${error.message}`);
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
return parseProspectImportBatch(contents, filePath);
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
function parseProspectImportBatch(contents, filePath = "batch file") {
|
|
2189
|
+
const trimmed = String(contents || "").trim();
|
|
2190
|
+
if (!trimmed) return [];
|
|
2191
|
+
|
|
2192
|
+
if (trimmed.startsWith("[") || (trimmed.startsWith("{") && !trimmed.includes("\n"))) {
|
|
2193
|
+
try {
|
|
2194
|
+
const parsed = JSON.parse(trimmed);
|
|
2195
|
+
return normalizeImportBatchRows(Array.isArray(parsed) ? parsed : [parsed], filePath);
|
|
2196
|
+
} catch (error) {
|
|
2197
|
+
throw new CommandError(`Invalid JSON import batch in ${filePath}: ${error.message}`);
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
const lines = trimmed.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
2202
|
+
if (lines.length === 0) return [];
|
|
2203
|
+
|
|
2204
|
+
if (looksLikeCsvHeader(lines[0])) {
|
|
2205
|
+
return parseProspectImportCsv(lines, filePath);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
const rows = lines.map((line, index) => {
|
|
2209
|
+
if (line.startsWith("{")) {
|
|
2210
|
+
try {
|
|
2211
|
+
return { ...JSON.parse(line), row: index + 1 };
|
|
2212
|
+
} catch (error) {
|
|
2213
|
+
throw new CommandError(`Invalid JSONL row ${index + 1} in ${filePath}: ${error.message}`);
|
|
2214
|
+
}
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
return { linkedin_url: line, row: index + 1 };
|
|
2218
|
+
});
|
|
2219
|
+
|
|
2220
|
+
return normalizeImportBatchRows(rows, filePath);
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
function looksLikeCsvHeader(line) {
|
|
2224
|
+
const headers = parseCsvLine(line).map((header) => header.trim().toLowerCase());
|
|
2225
|
+
return headers.includes("linkedin_url") || headers.includes("url");
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
function parseProspectImportCsv(lines, filePath) {
|
|
2229
|
+
const headers = parseCsvLine(lines[0]).map((header) => header.trim());
|
|
2230
|
+
const rows = lines.slice(1).map((line, index) => {
|
|
2231
|
+
const values = parseCsvLine(line);
|
|
2232
|
+
return headers.reduce((row, header, headerIndex) => {
|
|
2233
|
+
row[header] = values[headerIndex] || "";
|
|
2234
|
+
return row;
|
|
2235
|
+
}, { row: index + 1 });
|
|
2236
|
+
});
|
|
2237
|
+
|
|
2238
|
+
return normalizeImportBatchRows(rows, filePath);
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
function parseCsvLine(line) {
|
|
2242
|
+
const values = [];
|
|
2243
|
+
let current = "";
|
|
2244
|
+
let inQuotes = false;
|
|
2245
|
+
|
|
2246
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
2247
|
+
const character = line[index];
|
|
2248
|
+
const next = line[index + 1];
|
|
2249
|
+
|
|
2250
|
+
if (character === "\"" && inQuotes && next === "\"") {
|
|
2251
|
+
current += "\"";
|
|
2252
|
+
index += 1;
|
|
2253
|
+
} else if (character === "\"") {
|
|
2254
|
+
inQuotes = !inQuotes;
|
|
2255
|
+
} else if (character === "," && !inQuotes) {
|
|
2256
|
+
values.push(current);
|
|
2257
|
+
current = "";
|
|
2258
|
+
} else {
|
|
2259
|
+
current += character;
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
values.push(current);
|
|
2264
|
+
return values.map((value) => value.trim());
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
function normalizeImportBatchRows(rows, filePath) {
|
|
2268
|
+
return rows.map((row, index) => {
|
|
2269
|
+
const rowNumber = row?.row || index + 1;
|
|
2270
|
+
const normalized = typeof row === "string" ? { linkedin_url: row } : row;
|
|
2271
|
+
const linkedinUrl = normalized?.linkedin_url || normalized?.url;
|
|
2272
|
+
if (!linkedinUrl) throw new CommandError(`Missing linkedin_url on row ${rowNumber} in ${filePath}.`);
|
|
2273
|
+
|
|
2274
|
+
return compactObject({
|
|
2275
|
+
row: rowNumber,
|
|
2276
|
+
linkedin_url: linkedinUrl,
|
|
2277
|
+
list_id: normalized.list_id,
|
|
2278
|
+
motion_id: normalized.motion_id,
|
|
2279
|
+
assigned_user_id: normalized.assigned_user_id || normalized.assigned_user
|
|
2280
|
+
});
|
|
2281
|
+
});
|
|
2282
|
+
}
|
|
2283
|
+
|
|
1987
2284
|
function writeLine(stream, text = "") {
|
|
1988
2285
|
stream.write(`${text}\n`);
|
|
1989
2286
|
}
|
|
@@ -2029,6 +2326,41 @@ function renderUsers(users, context) {
|
|
|
2029
2326
|
}
|
|
2030
2327
|
}
|
|
2031
2328
|
|
|
2329
|
+
function renderUserActivity(payload, context) {
|
|
2330
|
+
const accountUser = payload?.account_user || {};
|
|
2331
|
+
const summary = payload?.summary || {};
|
|
2332
|
+
const events = Array.isArray(payload?.events) ? payload.events : [];
|
|
2333
|
+
const pagination = payload?.pagination || {};
|
|
2334
|
+
|
|
2335
|
+
writeLine(context.stdout, `User: ${display(accountUser.name || accountUser.email)} (${display(accountUser.id)})`);
|
|
2336
|
+
writeLine(context.stdout, `Window actions: ${display(summary.window_count, 0)}`);
|
|
2337
|
+
if (pagination.page || pagination.pages) {
|
|
2338
|
+
writeLine(context.stdout, `Page: ${display(pagination.page, 1)} of ${display(pagination.pages, 1)}`);
|
|
2339
|
+
}
|
|
2340
|
+
renderCountRows(context, "By platform", summary.by_platform);
|
|
2341
|
+
renderCountRows(context, "By action", summary.by_key);
|
|
2342
|
+
|
|
2343
|
+
if (events.length === 0) return writeLine(context.stdout, "No activity events found.");
|
|
2344
|
+
|
|
2345
|
+
writeLine(context.stdout, "TIME\tACTION\tPLATFORM\tPROSPECT\tCOMPANY\tDETAILS");
|
|
2346
|
+
for (const event of events) {
|
|
2347
|
+
writeLine(context.stdout, [
|
|
2348
|
+
display(event.occurred_at),
|
|
2349
|
+
display(event.action_label || event.key),
|
|
2350
|
+
display(event.platform),
|
|
2351
|
+
display(event.prospect?.name || event.prospect?.display_name || event.prospect?.prefix_id),
|
|
2352
|
+
display(event.prospect?.company),
|
|
2353
|
+
display(event.details)
|
|
2354
|
+
].join("\t"));
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
function renderCountRows(context, label, rows) {
|
|
2359
|
+
if (!Array.isArray(rows) || rows.length === 0) return;
|
|
2360
|
+
|
|
2361
|
+
writeLine(context.stdout, `${label}: ${rows.map((row) => `${display(row.label || row.key)} ${display(row.count, 0)}`).join(" | ")}`);
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2032
2364
|
function renderOffers(offers, context) {
|
|
2033
2365
|
if (!Array.isArray(offers) || offers.length === 0) return writeLine(context.stdout, "No offers found.");
|
|
2034
2366
|
|
|
@@ -2564,6 +2896,30 @@ function renderProspectImportStarted(payload, context) {
|
|
|
2564
2896
|
if (payload?.prefix_id) writeLine(context.stdout, `Run \`audienti prospects import-status ${payload.prefix_id}\` to check completion.`);
|
|
2565
2897
|
}
|
|
2566
2898
|
|
|
2899
|
+
function renderProspectImportBatchResult(result, context) {
|
|
2900
|
+
const imports = Array.isArray(result?.imports) ? result.imports : [];
|
|
2901
|
+
const failed = Array.isArray(result?.failed) ? result.failed : [];
|
|
2902
|
+
|
|
2903
|
+
writeLine(context.stdout, `Started ${display(result?.summary?.started, 0)} prospect imports.`);
|
|
2904
|
+
writeLine(context.stdout, `Failures: ${display(result?.summary?.failed, 0)}`);
|
|
2905
|
+
|
|
2906
|
+
if (imports.length > 0) {
|
|
2907
|
+
writeLine(context.stdout, "IMPORT ID\tPROSPECT\tPROSPECT ID\tSTATUS");
|
|
2908
|
+
for (const payload of imports) {
|
|
2909
|
+
writeLine(context.stdout, [
|
|
2910
|
+
display(payload?.prefix_id),
|
|
2911
|
+
display(payload?.prospect?.display_name || payload?.prospect?.name),
|
|
2912
|
+
display(payload?.prospect?.prefix_id),
|
|
2913
|
+
display(payload?.status)
|
|
2914
|
+
].join("\t"));
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
for (const row of failed) {
|
|
2919
|
+
writeLine(context.stdout, `- row ${display(row.row)} ${display(row.linkedin_url)}: ${display(row.error, "failed")}`);
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
|
|
2567
2923
|
function renderProspectImportStatus(payload, context) {
|
|
2568
2924
|
writeLine(context.stdout, `Import: ${display(payload?.prefix_id)}`);
|
|
2569
2925
|
writeLine(context.stdout, `Status: ${display(payload?.status)}`);
|
|
@@ -3313,6 +3669,7 @@ const HELP_TOPICS = new Map([
|
|
|
3313
3669
|
" audienti auth status",
|
|
3314
3670
|
" audienti config list",
|
|
3315
3671
|
" audienti users list",
|
|
3672
|
+
" audienti users activity <account_user_id|me>",
|
|
3316
3673
|
"",
|
|
3317
3674
|
" Motions / plays",
|
|
3318
3675
|
" audienti motions list",
|
|
@@ -3320,6 +3677,10 @@ const HELP_TOPICS = new Map([
|
|
|
3320
3677
|
" audienti motions analytics <motn_id>",
|
|
3321
3678
|
" audienti motions prospects <motn_id>",
|
|
3322
3679
|
" audienti motions create --payload <file.json>",
|
|
3680
|
+
" audienti motions update <motn_id> --status <state>",
|
|
3681
|
+
" audienti motions activate <motn_id>",
|
|
3682
|
+
" audienti motions pause <motn_id>",
|
|
3683
|
+
" audienti motions delete <motn_id> --confirm <yes|true|Y|y>",
|
|
3323
3684
|
" audienti motions clone <motn_id> --name <text>",
|
|
3324
3685
|
" audienti motions move-prospects <source_motn_id> --target <target_motn_id> <prsp_id> [prsp_id...]",
|
|
3325
3686
|
" Tip: `plays` is accepted anywhere `motions` is accepted.",
|
|
@@ -3327,8 +3688,10 @@ const HELP_TOPICS = new Map([
|
|
|
3327
3688
|
" Prospects",
|
|
3328
3689
|
" audienti prospects list [filters]",
|
|
3329
3690
|
" audienti prospects show <prsp_id>",
|
|
3691
|
+
" audienti prospects assign <prsp_id> --assigned-user <id|me|unassign>",
|
|
3330
3692
|
" audienti prospects timeline <prsp_id>",
|
|
3331
3693
|
" audienti prospects import <linkedin_url> [--motion <motn_id>]",
|
|
3694
|
+
" audienti prospects import-batch --file <csv|jsonl|json>",
|
|
3332
3695
|
" audienti prospects add-note <prsp_id> --message <text>",
|
|
3333
3696
|
" audienti prospects add-profile <prsp_id> --url <profile_url|email|phone>",
|
|
3334
3697
|
"",
|
|
@@ -3505,6 +3868,7 @@ const HELP_TOPICS = new Map([
|
|
|
3505
3868
|
["users", [
|
|
3506
3869
|
"Usage:",
|
|
3507
3870
|
" audienti users list [--json]",
|
|
3871
|
+
" audienti users activity <account_user_id|me> [--json]",
|
|
3508
3872
|
"",
|
|
3509
3873
|
"Status: implemented",
|
|
3510
3874
|
"",
|
|
@@ -3533,6 +3897,25 @@ const HELP_TOPICS = new Map([
|
|
|
3533
3897
|
" current: boolean"
|
|
3534
3898
|
].join("\n")],
|
|
3535
3899
|
|
|
3900
|
+
["users activity", [
|
|
3901
|
+
"Usage:",
|
|
3902
|
+
` ${USERS_ACTIVITY_USAGE.slice("Usage: ".length)}`,
|
|
3903
|
+
"",
|
|
3904
|
+
"Status: implemented",
|
|
3905
|
+
"",
|
|
3906
|
+
"Purpose:",
|
|
3907
|
+
" Inspect one workspace user's outbound activity feed and action summary.",
|
|
3908
|
+
"",
|
|
3909
|
+
"Input shape:",
|
|
3910
|
+
" account_user_id: integer account user id, or me for the authenticated token user",
|
|
3911
|
+
" mode: actor | account_usage",
|
|
3912
|
+
" window: 24h | 7d | 30d",
|
|
3913
|
+
" platform: linkedin | email | gmail",
|
|
3914
|
+
"",
|
|
3915
|
+
"API:",
|
|
3916
|
+
" GET /api/v1/accounts/:account_id/operations/users/:user_id/activity.json"
|
|
3917
|
+
].join("\n")],
|
|
3918
|
+
|
|
3536
3919
|
["offers", [
|
|
3537
3920
|
"Usage:",
|
|
3538
3921
|
" audienti offers list [--json]",
|
|
@@ -3894,10 +4277,15 @@ const HELP_TOPICS = new Map([
|
|
|
3894
4277
|
" audienti motions prospects <motn_id> [--json]",
|
|
3895
4278
|
" audienti motions add-prospects <motn_id> <prsp_id> [prsp_id...] [--json]",
|
|
3896
4279
|
" audienti motions create --payload <file.json> [--json]",
|
|
4280
|
+
" audienti motions update <motn_id> --status <draft|preparing|active|paused|archived> [--json]",
|
|
4281
|
+
" audienti motions activate <motn_id> [--json]",
|
|
4282
|
+
" audienti motions pause <motn_id> [--json]",
|
|
4283
|
+
" audienti motions archive <motn_id> [--json]",
|
|
4284
|
+
" audienti motions delete <motn_id> --confirm <yes|true|Y|y> [--json]",
|
|
3897
4285
|
" audienti motions clone <motn_id> --name <text> [--json]",
|
|
3898
4286
|
" audienti motions move-prospects <source_motn_id> --target <target_motn_id> <prsp_id> [prsp_id...] [--json]",
|
|
3899
4287
|
"",
|
|
3900
|
-
"Status: read, create, clone, status, and prospect attachment commands implemented",
|
|
4288
|
+
"Status: read, create, status update, delete, clone, status, and prospect attachment commands implemented",
|
|
3901
4289
|
"",
|
|
3902
4290
|
"CLI synonym:",
|
|
3903
4291
|
" `plays` is accepted anywhere `motions` is accepted",
|
|
@@ -4099,6 +4487,92 @@ const HELP_TOPICS = new Map([
|
|
|
4099
4487
|
" }"
|
|
4100
4488
|
].join("\n")],
|
|
4101
4489
|
|
|
4490
|
+
["motions update", [
|
|
4491
|
+
"Usage:",
|
|
4492
|
+
` ${MOTIONS_UPDATE_USAGE.slice("Usage: ".length)}`,
|
|
4493
|
+
"",
|
|
4494
|
+
"Status: implemented",
|
|
4495
|
+
"",
|
|
4496
|
+
"Purpose:",
|
|
4497
|
+
" Change one motion or play's lifecycle status.",
|
|
4498
|
+
"",
|
|
4499
|
+
"Input shape:",
|
|
4500
|
+
" motn_id: motn_ prefix id",
|
|
4501
|
+
" status: draft | preparing | active | paused | archived",
|
|
4502
|
+
"",
|
|
4503
|
+
"Behavior:",
|
|
4504
|
+
" Updates only the motion status. Other motion configuration stays unchanged.",
|
|
4505
|
+
"",
|
|
4506
|
+
"API:",
|
|
4507
|
+
" PATCH /api/v1/accounts/:account_id/motions/:id.json",
|
|
4508
|
+
"",
|
|
4509
|
+
"JSON body:",
|
|
4510
|
+
" {",
|
|
4511
|
+
" \"motion\": {",
|
|
4512
|
+
" \"status\": \"paused\"",
|
|
4513
|
+
" }",
|
|
4514
|
+
" }"
|
|
4515
|
+
].join("\n")],
|
|
4516
|
+
|
|
4517
|
+
["motions activate", [
|
|
4518
|
+
"Usage:",
|
|
4519
|
+
" audienti motions activate <motn_id> [--json] [--account <acct_id>]",
|
|
4520
|
+
"",
|
|
4521
|
+
"Status: implemented",
|
|
4522
|
+
"",
|
|
4523
|
+
"Purpose:",
|
|
4524
|
+
" Shortcut for `audienti motions update <motn_id> --status active`.",
|
|
4525
|
+
"",
|
|
4526
|
+
"API:",
|
|
4527
|
+
" PATCH /api/v1/accounts/:account_id/motions/:id.json"
|
|
4528
|
+
].join("\n")],
|
|
4529
|
+
|
|
4530
|
+
["motions pause", [
|
|
4531
|
+
"Usage:",
|
|
4532
|
+
" audienti motions pause <motn_id> [--json] [--account <acct_id>]",
|
|
4533
|
+
"",
|
|
4534
|
+
"Status: implemented",
|
|
4535
|
+
"",
|
|
4536
|
+
"Purpose:",
|
|
4537
|
+
" Shortcut for `audienti motions update <motn_id> --status paused`.",
|
|
4538
|
+
"",
|
|
4539
|
+
"API:",
|
|
4540
|
+
" PATCH /api/v1/accounts/:account_id/motions/:id.json"
|
|
4541
|
+
].join("\n")],
|
|
4542
|
+
|
|
4543
|
+
["motions archive", [
|
|
4544
|
+
"Usage:",
|
|
4545
|
+
" audienti motions archive <motn_id> [--json] [--account <acct_id>]",
|
|
4546
|
+
"",
|
|
4547
|
+
"Status: implemented",
|
|
4548
|
+
"",
|
|
4549
|
+
"Purpose:",
|
|
4550
|
+
" Shortcut for `audienti motions update <motn_id> --status archived`.",
|
|
4551
|
+
"",
|
|
4552
|
+
"API:",
|
|
4553
|
+
" PATCH /api/v1/accounts/:account_id/motions/:id.json"
|
|
4554
|
+
].join("\n")],
|
|
4555
|
+
|
|
4556
|
+
["motions delete", [
|
|
4557
|
+
"Usage:",
|
|
4558
|
+
` ${MOTIONS_DELETE_USAGE.slice("Usage: ".length)}`,
|
|
4559
|
+
"",
|
|
4560
|
+
"Status: implemented",
|
|
4561
|
+
"",
|
|
4562
|
+
"Purpose:",
|
|
4563
|
+
" Delete one motion or play through the same cleanup path the app uses.",
|
|
4564
|
+
"",
|
|
4565
|
+
"Input shape:",
|
|
4566
|
+
" motn_id: motn_ prefix id",
|
|
4567
|
+
" confirm: one of yes, true, Y, y",
|
|
4568
|
+
"",
|
|
4569
|
+
"Behavior:",
|
|
4570
|
+
" Removes the motion, its managed custom signals, and its dedicated finder agent. Prospect records remain in the account.",
|
|
4571
|
+
"",
|
|
4572
|
+
"API:",
|
|
4573
|
+
" DELETE /api/v1/accounts/:account_id/motions/:id.json"
|
|
4574
|
+
].join("\n")],
|
|
4575
|
+
|
|
4102
4576
|
["motions move-prospects", [
|
|
4103
4577
|
"Usage:",
|
|
4104
4578
|
` ${MOTIONS_MOVE_PROSPECTS_USAGE.slice("Usage: ".length)}`,
|
|
@@ -4131,6 +4605,7 @@ const HELP_TOPICS = new Map([
|
|
|
4131
4605
|
"Usage:",
|
|
4132
4606
|
" audienti prospects list [--json] [filters]",
|
|
4133
4607
|
" audienti prospects show <prsp_id> [--json]",
|
|
4608
|
+
" audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json]",
|
|
4134
4609
|
" audienti prospects timeline <prsp_id> [--json]",
|
|
4135
4610
|
" audienti prospects message-types <prsp_id> [--json]",
|
|
4136
4611
|
" audienti prospects write <prsp_id> --type <surface_key> [--json]",
|
|
@@ -4141,9 +4616,10 @@ const HELP_TOPICS = new Map([
|
|
|
4141
4616
|
" audienti prospects sequence-preview <prsp_id> [--json]",
|
|
4142
4617
|
" audienti prospects sequence-export <prsp_id> [--csv]",
|
|
4143
4618
|
" audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--json]",
|
|
4619
|
+
" audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--json]",
|
|
4144
4620
|
" audienti prospects import-status <primp_id> [--json]",
|
|
4145
4621
|
"",
|
|
4146
|
-
"Status: read commands, per-prospect draft preview, sequence preview, and import implemented; disposition planned",
|
|
4622
|
+
"Status: read commands, assignment, per-prospect draft preview, sequence preview, and import implemented; disposition planned",
|
|
4147
4623
|
"",
|
|
4148
4624
|
"Filters:",
|
|
4149
4625
|
" --query <text>",
|
|
@@ -4153,7 +4629,7 @@ const HELP_TOPICS = new Map([
|
|
|
4153
4629
|
" --play <motn_id>",
|
|
4154
4630
|
" --list <list_id>",
|
|
4155
4631
|
" --stage <stage>",
|
|
4156
|
-
" --assigned-user <account_user_id|me>",
|
|
4632
|
+
" --assigned-user <account_user_id|me|unassigned>",
|
|
4157
4633
|
" --limit <n>",
|
|
4158
4634
|
" --page <n>",
|
|
4159
4635
|
" --offset <n>",
|
|
@@ -4181,7 +4657,7 @@ const HELP_TOPICS = new Map([
|
|
|
4181
4657
|
" --play <motn_id> Filter to a play using the same motion relationship",
|
|
4182
4658
|
" --list <list_id> Filter to a prospect list",
|
|
4183
4659
|
" --stage <stage> Filter to a pipeline stage",
|
|
4184
|
-
" --assigned-user <id|me>
|
|
4660
|
+
" --assigned-user <id|me|unassigned> Filter by assigned account user",
|
|
4185
4661
|
" --limit <n> Max rows for one page; with --all it caps total rows up to 1000",
|
|
4186
4662
|
" --page <n> 1-based page number",
|
|
4187
4663
|
" --offset <n> Row offset for manual pagination",
|
|
@@ -4208,9 +4684,33 @@ const HELP_TOPICS = new Map([
|
|
|
4208
4684
|
"",
|
|
4209
4685
|
"Examples:",
|
|
4210
4686
|
" audienti prospects list --stage identified --page 2 --limit 50",
|
|
4687
|
+
" audienti prospects list --assigned-user unassigned",
|
|
4211
4688
|
" audienti prospects list --all --csv"
|
|
4212
4689
|
].join("\n")],
|
|
4213
4690
|
|
|
4691
|
+
["prospects assign", [
|
|
4692
|
+
"Usage:",
|
|
4693
|
+
` ${PROSPECTS_ASSIGN_USAGE.slice("Usage: ".length)}`,
|
|
4694
|
+
"",
|
|
4695
|
+
"Status: implemented",
|
|
4696
|
+
"",
|
|
4697
|
+
"Input shape:",
|
|
4698
|
+
" prsp_id: one or more prsp_ prefix ids",
|
|
4699
|
+
" assigned_user_id: account user id, me, or unassign",
|
|
4700
|
+
"",
|
|
4701
|
+
"Behavior:",
|
|
4702
|
+
" Updates AccountProspect.assigned_to_account_user_id for existing account prospects without changing motion or list membership.",
|
|
4703
|
+
"",
|
|
4704
|
+
"API:",
|
|
4705
|
+
" POST /api/v1/accounts/:account_id/prospects/assign.json",
|
|
4706
|
+
"",
|
|
4707
|
+
"JSON body:",
|
|
4708
|
+
" {",
|
|
4709
|
+
" \"prospect_ids\": [\"prsp_abc123\", \"prsp_def456\"],",
|
|
4710
|
+
" \"assigned_user_id\": \"me\"",
|
|
4711
|
+
" }"
|
|
4712
|
+
].join("\n")],
|
|
4713
|
+
|
|
4214
4714
|
["prospects show", [
|
|
4215
4715
|
"Usage:",
|
|
4216
4716
|
" audienti prospects show <prsp_id> [--json] [--account <acct_id>]",
|
|
@@ -4536,6 +5036,28 @@ const HELP_TOPICS = new Map([
|
|
|
4536
5036
|
" }"
|
|
4537
5037
|
].join("\n")],
|
|
4538
5038
|
|
|
5039
|
+
["prospects import-batch", [
|
|
5040
|
+
"Usage:",
|
|
5041
|
+
` ${PROSPECTS_IMPORT_BATCH_USAGE.slice("Usage: ".length)}`,
|
|
5042
|
+
"",
|
|
5043
|
+
"Status: implemented",
|
|
5044
|
+
"",
|
|
5045
|
+
"Input shape:",
|
|
5046
|
+
" file: CSV with linkedin_url/url header, JSON array, JSONL objects, or newline-delimited LinkedIn URLs",
|
|
5047
|
+
" list_id: list_ prefix id | optional default for every row",
|
|
5048
|
+
" motn_id: motn_ prefix id | optional default for every row",
|
|
5049
|
+
" assigned_user_id: account user id or me | optional default for every row",
|
|
5050
|
+
"",
|
|
5051
|
+
"CSV columns:",
|
|
5052
|
+
" linkedin_url or url, list_id, motion_id, assigned_user_id",
|
|
5053
|
+
"",
|
|
5054
|
+
"Behavior:",
|
|
5055
|
+
" Starts one normal prospect import per row. Row-level list_id, motion_id, and assigned_user_id override command defaults.",
|
|
5056
|
+
"",
|
|
5057
|
+
"API:",
|
|
5058
|
+
" POST /api/v1/accounts/:account_id/prospect_imports.json"
|
|
5059
|
+
].join("\n")],
|
|
5060
|
+
|
|
4539
5061
|
["prospects import-status", [
|
|
4540
5062
|
"Usage:",
|
|
4541
5063
|
" audienti prospects import-status <primp_id> [--json] [--account <acct_id>]",
|
|
@@ -4874,17 +5396,23 @@ const HELP_TOPICS = new Map([
|
|
|
4874
5396
|
" audienti motions create --payload <file.json>",
|
|
4875
5397
|
" audienti motions clone <motn_id> --name \"New subset motion\"",
|
|
4876
5398
|
" audienti motions move-prospects <source_motn_id> --target <target_motn_id> <prsp_id> [prsp_id...]",
|
|
5399
|
+
" audienti motions activate <motn_id>",
|
|
5400
|
+
" audienti motions pause <motn_id>",
|
|
5401
|
+
" audienti motions delete <motn_id> --confirm yes",
|
|
4877
5402
|
" audienti motions status <motn_id>",
|
|
4878
5403
|
"",
|
|
4879
5404
|
"3. Add a new prospect from LinkedIn and poll enrichment",
|
|
4880
5405
|
" audienti lists create --name \"Target list\"",
|
|
4881
5406
|
" audienti prospects import https://www.linkedin.com/in/example --list <list_id> --assigned-user me",
|
|
5407
|
+
" audienti prospects import-batch --file prospects.csv --motion <motn_id> --assigned-user me",
|
|
4882
5408
|
" audienti prospects import-status <primp_id>",
|
|
4883
5409
|
" audienti prospects show <prsp_id>",
|
|
4884
5410
|
" audienti tools get email --url https://www.linkedin.com/in/example",
|
|
4885
5411
|
"",
|
|
4886
5412
|
"4. Find an existing prospect and inspect next step",
|
|
4887
5413
|
" audienti prospects list --query \"name or company\" --wide",
|
|
5414
|
+
" audienti prospects list --assigned-user unassigned",
|
|
5415
|
+
" audienti prospects assign <prsp_id> --assigned-user me",
|
|
4888
5416
|
" audienti companies search --query \"Honeywell\"",
|
|
4889
5417
|
" audienti prospects list --company-profile <prof_id>",
|
|
4890
5418
|
" audienti prospects show <prsp_id>",
|
|
@@ -4908,6 +5436,7 @@ const HELP_TOPICS = new Map([
|
|
|
4908
5436
|
" audienti operator outcome <row_id> --payload <file.json>",
|
|
4909
5437
|
"",
|
|
4910
5438
|
"7. Inspect account analytics",
|
|
5439
|
+
" audienti users activity me --window 7d",
|
|
4911
5440
|
" audienti analytics prospects --window 24h",
|
|
4912
5441
|
" audienti analytics users --user me --window 30d",
|
|
4913
5442
|
" audienti analytics visibility --window 24h --user me",
|