@audienti/cli 0.1.7 → 0.1.9
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 +19 -0
- package/package.json +1 -1
- package/skills/audienti/SKILL.md +4 -0
- package/src/api-client.js +25 -0
- package/src/cli.js +479 -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.9] - 2026-07-15
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Add `audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign>` for reassigning existing prospects from the CLI.
|
|
12
|
+
- Add `audienti users activity <account_user_id|me>` for inspecting one account user's outbound activity feed.
|
|
13
|
+
- Add `audienti prospects import-batch --file <csv|jsonl|json>` for starting multiple normal prospect imports with shared list, motion, and assignee defaults.
|
|
14
|
+
- Add `audienti prospects list --assigned-user unassigned` for finding prospects without an owner.
|
|
15
|
+
|
|
16
|
+
## [0.1.8] - 2026-07-14
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Add `audienti motions clone <motn_id> --name <text>` to clone a motion/play config through the API without copying people.
|
|
21
|
+
- Add `audienti motions move-prospects <source_motn_id> --target <target_motn_id> <prsp_id> [prsp_id...]` to transfer prospects between motions/plays.
|
|
22
|
+
|
|
7
23
|
## [0.1.7] - 2026-07-12
|
|
8
24
|
|
|
9
25
|
### Fixed
|
package/README.md
CHANGED
|
@@ -56,6 +56,9 @@ audienti writer test-run <prsp_id>
|
|
|
56
56
|
audienti motions analytics <motn_id>
|
|
57
57
|
audienti prospects show <prsp_id> --json
|
|
58
58
|
audienti prospects list --profiles
|
|
59
|
+
audienti prospects list --assigned-user unassigned
|
|
60
|
+
audienti prospects assign <prsp_id> --assigned-user me
|
|
61
|
+
audienti users activity me --window 7d
|
|
59
62
|
audienti analytics prospects --window 24h
|
|
60
63
|
audienti analytics users --user me --window 30d
|
|
61
64
|
audienti analytics visibility --window 24h --user me
|
|
@@ -126,6 +129,22 @@ audienti prospects add-profile <prsp_id> --url https://www.linkedin.com/in/examp
|
|
|
126
129
|
audienti prospects report-bad-profile <prsp_id> <prof_id>
|
|
127
130
|
```
|
|
128
131
|
|
|
132
|
+
To reassign or clear ownership for existing prospects:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
audienti prospects assign <prsp_id> --assigned-user <account_user_id|me>
|
|
136
|
+
audienti prospects assign <prsp_id> --assigned-user unassign
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
To import multiple LinkedIn people through the same per-prospect import path:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
audienti prospects import-batch --file prospects.csv --motion <motn_id> --assigned-user me
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
CSV files should include a `linkedin_url` or `url` header. Optional row columns
|
|
146
|
+
`list_id`, `motion_id`, and `assigned_user_id` override command defaults.
|
|
147
|
+
|
|
129
148
|
## Compatibility
|
|
130
149
|
|
|
131
150
|
The CLI talks to the versioned Audienti `/api/v1` contract at
|
package/package.json
CHANGED
package/skills/audienti/SKILL.md
CHANGED
|
@@ -51,6 +51,10 @@ 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
|
|
55
59
|
audienti operator next --json
|
|
56
60
|
audienti operator next --plan
|
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,20 @@ export class AudientiClient {
|
|
|
130
134
|
});
|
|
131
135
|
}
|
|
132
136
|
|
|
137
|
+
cloneMotion(accountId, motionId, body) {
|
|
138
|
+
return this.requestJson(accountPath(accountId, ["motions", motionId, "clone"]), {
|
|
139
|
+
method: "POST",
|
|
140
|
+
body
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
moveMotionProspects(accountId, motionId, body) {
|
|
145
|
+
return this.requestJson(accountPath(accountId, ["motions", motionId, "move_prospects"]), {
|
|
146
|
+
method: "POST",
|
|
147
|
+
body
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
133
151
|
motionStatus(accountId, motionId) {
|
|
134
152
|
return this.requestJson(accountPath(accountId, ["motions", motionId, "status"]));
|
|
135
153
|
}
|
|
@@ -153,6 +171,13 @@ export class AudientiClient {
|
|
|
153
171
|
return this.requestJson(accountPath(accountId, ["prospects", prospectId]));
|
|
154
172
|
}
|
|
155
173
|
|
|
174
|
+
assignProspects(accountId, body) {
|
|
175
|
+
return this.requestJson(accountPath(accountId, ["prospects", "assign"]), {
|
|
176
|
+
method: "POST",
|
|
177
|
+
body
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
156
181
|
prospectTimeline(accountId, prospectId, query = {}) {
|
|
157
182
|
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "timeline"], query));
|
|
158
183
|
}
|
package/src/cli.js
CHANGED
|
@@ -29,8 +29,13 @@ const PROSPECTS_ADD_NOTE_USAGE = "Usage: audienti prospects add-note <prsp_id> (
|
|
|
29
29
|
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
30
|
const PROSPECTS_ADD_PROFILE_USAGE = "Usage: audienti prospects add-profile <prsp_id> --url <profile_url|email|phone> [--json] [--account <acct_id>]";
|
|
31
31
|
const PROSPECTS_REPORT_BAD_PROFILE_USAGE = "Usage: audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json] [--account <acct_id>]";
|
|
32
|
+
const PROSPECTS_ASSIGN_USAGE = "Usage: audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json] [--account <acct_id>]";
|
|
33
|
+
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>]";
|
|
34
|
+
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
35
|
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
36
|
const MOTIONS_ANALYTICS_USAGE = "Usage: audienti motions analytics <motn_id> [--window 30d] [--json] [--account <acct_id>]";
|
|
37
|
+
const MOTIONS_CLONE_USAGE = "Usage: audienti motions clone <motn_id> --name <text> [--json] [--account <acct_id>]";
|
|
38
|
+
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>]";
|
|
34
39
|
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>]";
|
|
35
40
|
const ANALYTICS_PROSPECTS_COHORT_ANALYSIS_USAGE = "Usage: audienti analytics prospects cohort-analysis [--weeks <n>] [--window 24h] [--motion <motn_id>] [--provenance <source>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
|
|
36
41
|
const ANALYTICS_USERS_USAGE = "Usage: audienti analytics users [--user <account_user_id|email|name|me>] [--window 30d | --start YYYY-MM-DD --end YYYY-MM-DD] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--motion <motn_id>] [--provenance <source>] [--platform <linkedin|email|gmail>] [--json] [--account <acct_id>]";
|
|
@@ -115,6 +120,7 @@ async function dispatch(argv, context) {
|
|
|
115
120
|
if (normalizedResource === "accounts" && action === "list") return accountsList(rest, context, { accountOverride });
|
|
116
121
|
if (normalizedResource === "accounts" && action === "select") return accountsSelect(rest, context);
|
|
117
122
|
if (normalizedResource === "users" && action === "list") return usersList(rest, context, { accountOverride });
|
|
123
|
+
if (normalizedResource === "users" && action === "activity") return usersActivity(rest, context, { accountOverride });
|
|
118
124
|
if (normalizedResource === "offers" && action === "list") return offersList(rest, context, { accountOverride });
|
|
119
125
|
if (normalizedResource === "offers" && action === "create") return offersCreate(rest, context, { accountOverride });
|
|
120
126
|
if (normalizedResource === "icps" && action === "list") return icpsList(rest, context, { accountOverride });
|
|
@@ -135,8 +141,11 @@ async function dispatch(argv, context) {
|
|
|
135
141
|
if (normalizedResource === "motions" && action === "prospects") return motionsProspects(rest, context, { accountOverride });
|
|
136
142
|
if (normalizedResource === "motions" && action === "add-prospects") return motionsAddProspects(rest, context, { accountOverride });
|
|
137
143
|
if (normalizedResource === "motions" && action === "create") return motionsCreate(rest, context, { accountOverride });
|
|
144
|
+
if (normalizedResource === "motions" && action === "clone") return motionsClone(rest, context, { accountOverride });
|
|
145
|
+
if (normalizedResource === "motions" && action === "move-prospects") return motionsMoveProspects(rest, context, { accountOverride });
|
|
138
146
|
if (normalizedResource === "prospects" && action === "list") return prospectsList(rest, context, { accountOverride });
|
|
139
147
|
if (normalizedResource === "prospects" && action === "show") return prospectsShow(rest, context, { accountOverride });
|
|
148
|
+
if (normalizedResource === "prospects" && action === "assign") return prospectsAssign(rest, context, { accountOverride });
|
|
140
149
|
if (normalizedResource === "prospects" && action === "timeline") return prospectsTimeline(rest, context, { accountOverride });
|
|
141
150
|
if (normalizedResource === "prospects" && action === "message-types") return prospectsMessageTypes(rest, context, { accountOverride });
|
|
142
151
|
if (normalizedResource === "prospects" && action === "write") return prospectsWrite(rest, context, { accountOverride });
|
|
@@ -147,6 +156,7 @@ async function dispatch(argv, context) {
|
|
|
147
156
|
if (normalizedResource === "prospects" && action === "sequence-preview") return prospectsSequencePreview(rest, context, { accountOverride });
|
|
148
157
|
if (normalizedResource === "prospects" && action === "sequence-export") return prospectsSequenceExport(rest, context, { accountOverride });
|
|
149
158
|
if (normalizedResource === "prospects" && action === "import") return prospectsImport(rest, context, { accountOverride });
|
|
159
|
+
if (normalizedResource === "prospects" && action === "import-batch") return prospectsImportBatch(rest, context, { accountOverride });
|
|
150
160
|
if (normalizedResource === "prospects" && action === "import-status") return prospectsImportStatus(rest, context, { accountOverride });
|
|
151
161
|
if (normalizedResource === "writer" && action === "test-run") return writerTestRun(rest, context, { accountOverride });
|
|
152
162
|
if (normalizedResource === "tools" && action === "get") return toolsGet(rest, context, { accountOverride });
|
|
@@ -395,6 +405,32 @@ async function usersList(args, context, { accountOverride } = {}) {
|
|
|
395
405
|
renderUsers(users, context);
|
|
396
406
|
}
|
|
397
407
|
|
|
408
|
+
async function usersActivity(args, context, { accountOverride } = {}) {
|
|
409
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
410
|
+
...jsonOptions(),
|
|
411
|
+
mode: { type: "string" },
|
|
412
|
+
window: { type: "string" },
|
|
413
|
+
platform: { type: "string" },
|
|
414
|
+
query: { type: "string" },
|
|
415
|
+
limit: { type: "string" },
|
|
416
|
+
page: { type: "string" }
|
|
417
|
+
});
|
|
418
|
+
if (positionals.length !== 1) throw new CommandError(USERS_ACTIVITY_USAGE);
|
|
419
|
+
|
|
420
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
421
|
+
const payload = await client.userActivity(accountId, positionals[0], compactObject({
|
|
422
|
+
mode: values.mode,
|
|
423
|
+
window: values.window,
|
|
424
|
+
platform: values.platform,
|
|
425
|
+
query: values.query,
|
|
426
|
+
limit: values.limit,
|
|
427
|
+
page: values.page
|
|
428
|
+
}));
|
|
429
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
430
|
+
|
|
431
|
+
renderUserActivity(payload, context);
|
|
432
|
+
}
|
|
433
|
+
|
|
398
434
|
async function offersList(args, context, { accountOverride } = {}) {
|
|
399
435
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
400
436
|
if (positionals.length > 0) throw new CommandError("Usage: audienti offers list [--json] [--account <acct_id>]");
|
|
@@ -782,6 +818,52 @@ async function motionsCreate(args, context, { accountOverride } = {}) {
|
|
|
782
818
|
renderMotion(created, context);
|
|
783
819
|
}
|
|
784
820
|
|
|
821
|
+
async function motionsClone(args, context, { accountOverride } = {}) {
|
|
822
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
823
|
+
...jsonOptions(),
|
|
824
|
+
name: { type: "string" }
|
|
825
|
+
});
|
|
826
|
+
if (positionals.length !== 1 || !values.name) {
|
|
827
|
+
throw new CommandError(MOTIONS_CLONE_USAGE);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
831
|
+
const cloned = await client.cloneMotion(accountId, positionals[0], {
|
|
832
|
+
motion: {
|
|
833
|
+
name: values.name
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
if (values.json) return writeJson(context.stdout, cloned);
|
|
837
|
+
|
|
838
|
+
writeLine(context.stdout, `Cloned motion ${display(positionals[0])} as ${display(cloned?.name)} (${display(cloned?.prefix_id)}).`);
|
|
839
|
+
renderMotion(cloned, context);
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
async function motionsMoveProspects(args, context, { accountOverride } = {}) {
|
|
843
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
844
|
+
...jsonOptions(),
|
|
845
|
+
target: { type: "string" }
|
|
846
|
+
});
|
|
847
|
+
if (positionals.length < 2 || !values.target) {
|
|
848
|
+
throw new CommandError(MOTIONS_MOVE_PROSPECTS_USAGE);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
const [sourceMotionId, ...prospectIds] = positionals;
|
|
852
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
853
|
+
const payload = await client.moveMotionProspects(accountId, sourceMotionId, {
|
|
854
|
+
target_motion_id: values.target,
|
|
855
|
+
prospect_ids: prospectIds
|
|
856
|
+
});
|
|
857
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
858
|
+
|
|
859
|
+
const moved = Number(payload?.moved || 0);
|
|
860
|
+
const failed = Array.isArray(payload?.failed) ? payload.failed.length : 0;
|
|
861
|
+
writeLine(context.stdout, `Moved ${moved} prospects from ${display(sourceMotionId)} to ${display(values.target)}.`);
|
|
862
|
+
if (failed > 0) {
|
|
863
|
+
writeLine(context.stdout, `${failed} prospects failed.`);
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
785
867
|
async function prospectsList(args, context, { accountOverride } = {}) {
|
|
786
868
|
const { values, positionals } = parseCommandArgs(args, {
|
|
787
869
|
...jsonOptions(),
|
|
@@ -832,6 +914,36 @@ async function prospectsList(args, context, { accountOverride } = {}) {
|
|
|
832
914
|
renderProspects(payload, context, { wide: values.wide || values.all, profiles: values.profiles });
|
|
833
915
|
}
|
|
834
916
|
|
|
917
|
+
async function prospectsAssign(args, context, { accountOverride } = {}) {
|
|
918
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
919
|
+
...jsonOptions(),
|
|
920
|
+
"assigned-user": { type: "string" }
|
|
921
|
+
});
|
|
922
|
+
if (positionals.length < 1 || !values["assigned-user"]) {
|
|
923
|
+
throw new CommandError(PROSPECTS_ASSIGN_USAGE);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
927
|
+
const { payload, rejected } = await performBulkMutation(() =>
|
|
928
|
+
client.assignProspects(accountId, {
|
|
929
|
+
prospect_ids: positionals,
|
|
930
|
+
assigned_user_id: values["assigned-user"]
|
|
931
|
+
}));
|
|
932
|
+
if (values.json) {
|
|
933
|
+
writeJson(context.stdout, payload);
|
|
934
|
+
return rejected ? 1 : 0;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
const successLabel = values["assigned-user"] === "unassign" ?
|
|
938
|
+
`Unassigned ${successCount(payload)} prospects.` :
|
|
939
|
+
`Assigned ${successCount(payload)} prospects to ${display(values["assigned-user"])}.`;
|
|
940
|
+
renderBulkMutationResult(payload, context, {
|
|
941
|
+
successLabel,
|
|
942
|
+
zeroSuccessLabel: "No prospects were assigned."
|
|
943
|
+
});
|
|
944
|
+
return rejected ? 1 : 0;
|
|
945
|
+
}
|
|
946
|
+
|
|
835
947
|
async function prospectsShow(args, context, { accountOverride } = {}) {
|
|
836
948
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
837
949
|
if (positionals.length !== 1) throw new CommandError("Usage: audienti prospects show <prsp_id> [--json] [--account <acct_id>]");
|
|
@@ -1245,6 +1357,66 @@ async function prospectsImport(args, context, { accountOverride } = {}) {
|
|
|
1245
1357
|
renderProspectImportStarted(payload, context);
|
|
1246
1358
|
}
|
|
1247
1359
|
|
|
1360
|
+
async function prospectsImportBatch(args, context, { accountOverride } = {}) {
|
|
1361
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1362
|
+
...jsonOptions(),
|
|
1363
|
+
file: { type: "string" },
|
|
1364
|
+
list: { type: "string" },
|
|
1365
|
+
motion: { type: "string" },
|
|
1366
|
+
"assigned-user": { type: "string" }
|
|
1367
|
+
});
|
|
1368
|
+
if (positionals.length > 0 || !values.file) {
|
|
1369
|
+
throw new CommandError(PROSPECTS_IMPORT_BATCH_USAGE);
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
const rows = await readProspectImportBatchFile(values.file);
|
|
1373
|
+
if (rows.length === 0) throw new CommandError("Import batch file did not contain any prospects.");
|
|
1374
|
+
|
|
1375
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1376
|
+
const result = {
|
|
1377
|
+
summary: {
|
|
1378
|
+
total: rows.length,
|
|
1379
|
+
started: 0,
|
|
1380
|
+
failed: 0
|
|
1381
|
+
},
|
|
1382
|
+
imports: [],
|
|
1383
|
+
failed: []
|
|
1384
|
+
};
|
|
1385
|
+
|
|
1386
|
+
for (const row of rows) {
|
|
1387
|
+
const body = compactObject({
|
|
1388
|
+
linkedin_url: row.linkedin_url,
|
|
1389
|
+
list_id: row.list_id || values.list,
|
|
1390
|
+
motion_id: row.motion_id || values.motion,
|
|
1391
|
+
assigned_user_id: row.assigned_user_id || values["assigned-user"]
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1394
|
+
try {
|
|
1395
|
+
const payload = await client.prospectImport(accountId, body);
|
|
1396
|
+
result.imports.push(payload);
|
|
1397
|
+
result.summary.started += 1;
|
|
1398
|
+
} catch (error) {
|
|
1399
|
+
if (!(error instanceof ApiError)) throw error;
|
|
1400
|
+
|
|
1401
|
+
result.failed.push({
|
|
1402
|
+
row: row.row,
|
|
1403
|
+
linkedin_url: row.linkedin_url,
|
|
1404
|
+
status: error.status,
|
|
1405
|
+
error: error.body?.error || error.message
|
|
1406
|
+
});
|
|
1407
|
+
result.summary.failed += 1;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
if (values.json) {
|
|
1412
|
+
writeJson(context.stdout, result);
|
|
1413
|
+
return result.summary.failed > 0 ? 1 : 0;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
renderProspectImportBatchResult(result, context);
|
|
1417
|
+
return result.summary.failed > 0 ? 1 : 0;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1248
1420
|
async function prospectsImportStatus(args, context, { accountOverride } = {}) {
|
|
1249
1421
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1250
1422
|
if (positionals.length !== 1) {
|
|
@@ -1934,6 +2106,113 @@ async function readJsonPayload(filePath) {
|
|
|
1934
2106
|
}
|
|
1935
2107
|
}
|
|
1936
2108
|
|
|
2109
|
+
async function readProspectImportBatchFile(filePath) {
|
|
2110
|
+
let contents;
|
|
2111
|
+
try {
|
|
2112
|
+
contents = await readFile(filePath, "utf8");
|
|
2113
|
+
} catch (error) {
|
|
2114
|
+
throw new CommandError(`Could not read import batch file ${filePath}: ${error.message}`);
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
return parseProspectImportBatch(contents, filePath);
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
function parseProspectImportBatch(contents, filePath = "batch file") {
|
|
2121
|
+
const trimmed = String(contents || "").trim();
|
|
2122
|
+
if (!trimmed) return [];
|
|
2123
|
+
|
|
2124
|
+
if (trimmed.startsWith("[") || (trimmed.startsWith("{") && !trimmed.includes("\n"))) {
|
|
2125
|
+
try {
|
|
2126
|
+
const parsed = JSON.parse(trimmed);
|
|
2127
|
+
return normalizeImportBatchRows(Array.isArray(parsed) ? parsed : [parsed], filePath);
|
|
2128
|
+
} catch (error) {
|
|
2129
|
+
throw new CommandError(`Invalid JSON import batch in ${filePath}: ${error.message}`);
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
2132
|
+
|
|
2133
|
+
const lines = trimmed.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
2134
|
+
if (lines.length === 0) return [];
|
|
2135
|
+
|
|
2136
|
+
if (looksLikeCsvHeader(lines[0])) {
|
|
2137
|
+
return parseProspectImportCsv(lines, filePath);
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
const rows = lines.map((line, index) => {
|
|
2141
|
+
if (line.startsWith("{")) {
|
|
2142
|
+
try {
|
|
2143
|
+
return { ...JSON.parse(line), row: index + 1 };
|
|
2144
|
+
} catch (error) {
|
|
2145
|
+
throw new CommandError(`Invalid JSONL row ${index + 1} in ${filePath}: ${error.message}`);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
return { linkedin_url: line, row: index + 1 };
|
|
2150
|
+
});
|
|
2151
|
+
|
|
2152
|
+
return normalizeImportBatchRows(rows, filePath);
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
function looksLikeCsvHeader(line) {
|
|
2156
|
+
const headers = parseCsvLine(line).map((header) => header.trim().toLowerCase());
|
|
2157
|
+
return headers.includes("linkedin_url") || headers.includes("url");
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
function parseProspectImportCsv(lines, filePath) {
|
|
2161
|
+
const headers = parseCsvLine(lines[0]).map((header) => header.trim());
|
|
2162
|
+
const rows = lines.slice(1).map((line, index) => {
|
|
2163
|
+
const values = parseCsvLine(line);
|
|
2164
|
+
return headers.reduce((row, header, headerIndex) => {
|
|
2165
|
+
row[header] = values[headerIndex] || "";
|
|
2166
|
+
return row;
|
|
2167
|
+
}, { row: index + 1 });
|
|
2168
|
+
});
|
|
2169
|
+
|
|
2170
|
+
return normalizeImportBatchRows(rows, filePath);
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
function parseCsvLine(line) {
|
|
2174
|
+
const values = [];
|
|
2175
|
+
let current = "";
|
|
2176
|
+
let inQuotes = false;
|
|
2177
|
+
|
|
2178
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
2179
|
+
const character = line[index];
|
|
2180
|
+
const next = line[index + 1];
|
|
2181
|
+
|
|
2182
|
+
if (character === "\"" && inQuotes && next === "\"") {
|
|
2183
|
+
current += "\"";
|
|
2184
|
+
index += 1;
|
|
2185
|
+
} else if (character === "\"") {
|
|
2186
|
+
inQuotes = !inQuotes;
|
|
2187
|
+
} else if (character === "," && !inQuotes) {
|
|
2188
|
+
values.push(current);
|
|
2189
|
+
current = "";
|
|
2190
|
+
} else {
|
|
2191
|
+
current += character;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
values.push(current);
|
|
2196
|
+
return values.map((value) => value.trim());
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
function normalizeImportBatchRows(rows, filePath) {
|
|
2200
|
+
return rows.map((row, index) => {
|
|
2201
|
+
const rowNumber = row?.row || index + 1;
|
|
2202
|
+
const normalized = typeof row === "string" ? { linkedin_url: row } : row;
|
|
2203
|
+
const linkedinUrl = normalized?.linkedin_url || normalized?.url;
|
|
2204
|
+
if (!linkedinUrl) throw new CommandError(`Missing linkedin_url on row ${rowNumber} in ${filePath}.`);
|
|
2205
|
+
|
|
2206
|
+
return compactObject({
|
|
2207
|
+
row: rowNumber,
|
|
2208
|
+
linkedin_url: linkedinUrl,
|
|
2209
|
+
list_id: normalized.list_id,
|
|
2210
|
+
motion_id: normalized.motion_id,
|
|
2211
|
+
assigned_user_id: normalized.assigned_user_id || normalized.assigned_user
|
|
2212
|
+
});
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
2215
|
+
|
|
1937
2216
|
function writeLine(stream, text = "") {
|
|
1938
2217
|
stream.write(`${text}\n`);
|
|
1939
2218
|
}
|
|
@@ -1979,6 +2258,41 @@ function renderUsers(users, context) {
|
|
|
1979
2258
|
}
|
|
1980
2259
|
}
|
|
1981
2260
|
|
|
2261
|
+
function renderUserActivity(payload, context) {
|
|
2262
|
+
const accountUser = payload?.account_user || {};
|
|
2263
|
+
const summary = payload?.summary || {};
|
|
2264
|
+
const events = Array.isArray(payload?.events) ? payload.events : [];
|
|
2265
|
+
const pagination = payload?.pagination || {};
|
|
2266
|
+
|
|
2267
|
+
writeLine(context.stdout, `User: ${display(accountUser.name || accountUser.email)} (${display(accountUser.id)})`);
|
|
2268
|
+
writeLine(context.stdout, `Window actions: ${display(summary.window_count, 0)}`);
|
|
2269
|
+
if (pagination.page || pagination.pages) {
|
|
2270
|
+
writeLine(context.stdout, `Page: ${display(pagination.page, 1)} of ${display(pagination.pages, 1)}`);
|
|
2271
|
+
}
|
|
2272
|
+
renderCountRows(context, "By platform", summary.by_platform);
|
|
2273
|
+
renderCountRows(context, "By action", summary.by_key);
|
|
2274
|
+
|
|
2275
|
+
if (events.length === 0) return writeLine(context.stdout, "No activity events found.");
|
|
2276
|
+
|
|
2277
|
+
writeLine(context.stdout, "TIME\tACTION\tPLATFORM\tPROSPECT\tCOMPANY\tDETAILS");
|
|
2278
|
+
for (const event of events) {
|
|
2279
|
+
writeLine(context.stdout, [
|
|
2280
|
+
display(event.occurred_at),
|
|
2281
|
+
display(event.action_label || event.key),
|
|
2282
|
+
display(event.platform),
|
|
2283
|
+
display(event.prospect?.name || event.prospect?.display_name || event.prospect?.prefix_id),
|
|
2284
|
+
display(event.prospect?.company),
|
|
2285
|
+
display(event.details)
|
|
2286
|
+
].join("\t"));
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
function renderCountRows(context, label, rows) {
|
|
2291
|
+
if (!Array.isArray(rows) || rows.length === 0) return;
|
|
2292
|
+
|
|
2293
|
+
writeLine(context.stdout, `${label}: ${rows.map((row) => `${display(row.label || row.key)} ${display(row.count, 0)}`).join(" | ")}`);
|
|
2294
|
+
}
|
|
2295
|
+
|
|
1982
2296
|
function renderOffers(offers, context) {
|
|
1983
2297
|
if (!Array.isArray(offers) || offers.length === 0) return writeLine(context.stdout, "No offers found.");
|
|
1984
2298
|
|
|
@@ -2514,6 +2828,30 @@ function renderProspectImportStarted(payload, context) {
|
|
|
2514
2828
|
if (payload?.prefix_id) writeLine(context.stdout, `Run \`audienti prospects import-status ${payload.prefix_id}\` to check completion.`);
|
|
2515
2829
|
}
|
|
2516
2830
|
|
|
2831
|
+
function renderProspectImportBatchResult(result, context) {
|
|
2832
|
+
const imports = Array.isArray(result?.imports) ? result.imports : [];
|
|
2833
|
+
const failed = Array.isArray(result?.failed) ? result.failed : [];
|
|
2834
|
+
|
|
2835
|
+
writeLine(context.stdout, `Started ${display(result?.summary?.started, 0)} prospect imports.`);
|
|
2836
|
+
writeLine(context.stdout, `Failures: ${display(result?.summary?.failed, 0)}`);
|
|
2837
|
+
|
|
2838
|
+
if (imports.length > 0) {
|
|
2839
|
+
writeLine(context.stdout, "IMPORT ID\tPROSPECT\tPROSPECT ID\tSTATUS");
|
|
2840
|
+
for (const payload of imports) {
|
|
2841
|
+
writeLine(context.stdout, [
|
|
2842
|
+
display(payload?.prefix_id),
|
|
2843
|
+
display(payload?.prospect?.display_name || payload?.prospect?.name),
|
|
2844
|
+
display(payload?.prospect?.prefix_id),
|
|
2845
|
+
display(payload?.status)
|
|
2846
|
+
].join("\t"));
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
for (const row of failed) {
|
|
2851
|
+
writeLine(context.stdout, `- row ${display(row.row)} ${display(row.linkedin_url)}: ${display(row.error, "failed")}`);
|
|
2852
|
+
}
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2517
2855
|
function renderProspectImportStatus(payload, context) {
|
|
2518
2856
|
writeLine(context.stdout, `Import: ${display(payload?.prefix_id)}`);
|
|
2519
2857
|
writeLine(context.stdout, `Status: ${display(payload?.status)}`);
|
|
@@ -3263,6 +3601,7 @@ const HELP_TOPICS = new Map([
|
|
|
3263
3601
|
" audienti auth status",
|
|
3264
3602
|
" audienti config list",
|
|
3265
3603
|
" audienti users list",
|
|
3604
|
+
" audienti users activity <account_user_id|me>",
|
|
3266
3605
|
"",
|
|
3267
3606
|
" Motions / plays",
|
|
3268
3607
|
" audienti motions list",
|
|
@@ -3270,13 +3609,17 @@ const HELP_TOPICS = new Map([
|
|
|
3270
3609
|
" audienti motions analytics <motn_id>",
|
|
3271
3610
|
" audienti motions prospects <motn_id>",
|
|
3272
3611
|
" audienti motions create --payload <file.json>",
|
|
3612
|
+
" audienti motions clone <motn_id> --name <text>",
|
|
3613
|
+
" audienti motions move-prospects <source_motn_id> --target <target_motn_id> <prsp_id> [prsp_id...]",
|
|
3273
3614
|
" Tip: `plays` is accepted anywhere `motions` is accepted.",
|
|
3274
3615
|
"",
|
|
3275
3616
|
" Prospects",
|
|
3276
3617
|
" audienti prospects list [filters]",
|
|
3277
3618
|
" audienti prospects show <prsp_id>",
|
|
3619
|
+
" audienti prospects assign <prsp_id> --assigned-user <id|me|unassign>",
|
|
3278
3620
|
" audienti prospects timeline <prsp_id>",
|
|
3279
3621
|
" audienti prospects import <linkedin_url> [--motion <motn_id>]",
|
|
3622
|
+
" audienti prospects import-batch --file <csv|jsonl|json>",
|
|
3280
3623
|
" audienti prospects add-note <prsp_id> --message <text>",
|
|
3281
3624
|
" audienti prospects add-profile <prsp_id> --url <profile_url|email|phone>",
|
|
3282
3625
|
"",
|
|
@@ -3453,6 +3796,7 @@ const HELP_TOPICS = new Map([
|
|
|
3453
3796
|
["users", [
|
|
3454
3797
|
"Usage:",
|
|
3455
3798
|
" audienti users list [--json]",
|
|
3799
|
+
" audienti users activity <account_user_id|me> [--json]",
|
|
3456
3800
|
"",
|
|
3457
3801
|
"Status: implemented",
|
|
3458
3802
|
"",
|
|
@@ -3481,6 +3825,25 @@ const HELP_TOPICS = new Map([
|
|
|
3481
3825
|
" current: boolean"
|
|
3482
3826
|
].join("\n")],
|
|
3483
3827
|
|
|
3828
|
+
["users activity", [
|
|
3829
|
+
"Usage:",
|
|
3830
|
+
` ${USERS_ACTIVITY_USAGE.slice("Usage: ".length)}`,
|
|
3831
|
+
"",
|
|
3832
|
+
"Status: implemented",
|
|
3833
|
+
"",
|
|
3834
|
+
"Purpose:",
|
|
3835
|
+
" Inspect one workspace user's outbound activity feed and action summary.",
|
|
3836
|
+
"",
|
|
3837
|
+
"Input shape:",
|
|
3838
|
+
" account_user_id: integer account user id, or me for the authenticated token user",
|
|
3839
|
+
" mode: actor | account_usage",
|
|
3840
|
+
" window: 24h | 7d | 30d",
|
|
3841
|
+
" platform: linkedin | email | gmail",
|
|
3842
|
+
"",
|
|
3843
|
+
"API:",
|
|
3844
|
+
" GET /api/v1/accounts/:account_id/operations/users/:user_id/activity.json"
|
|
3845
|
+
].join("\n")],
|
|
3846
|
+
|
|
3484
3847
|
["offers", [
|
|
3485
3848
|
"Usage:",
|
|
3486
3849
|
" audienti offers list [--json]",
|
|
@@ -3842,8 +4205,10 @@ const HELP_TOPICS = new Map([
|
|
|
3842
4205
|
" audienti motions prospects <motn_id> [--json]",
|
|
3843
4206
|
" audienti motions add-prospects <motn_id> <prsp_id> [prsp_id...] [--json]",
|
|
3844
4207
|
" audienti motions create --payload <file.json> [--json]",
|
|
4208
|
+
" audienti motions clone <motn_id> --name <text> [--json]",
|
|
4209
|
+
" audienti motions move-prospects <source_motn_id> --target <target_motn_id> <prsp_id> [prsp_id...] [--json]",
|
|
3845
4210
|
"",
|
|
3846
|
-
"Status: read, create, status, and prospect attachment commands implemented",
|
|
4211
|
+
"Status: read, create, clone, status, and prospect attachment commands implemented",
|
|
3847
4212
|
"",
|
|
3848
4213
|
"CLI synonym:",
|
|
3849
4214
|
" `plays` is accepted anywhere `motions` is accepted",
|
|
@@ -4017,10 +4382,67 @@ const HELP_TOPICS = new Map([
|
|
|
4017
4382
|
" Use `audienti offers list`, `audienti icps list`, and `audienti users list` to resolve valid ids before calling this command."
|
|
4018
4383
|
].join("\n")],
|
|
4019
4384
|
|
|
4385
|
+
["motions clone", [
|
|
4386
|
+
"Usage:",
|
|
4387
|
+
` ${MOTIONS_CLONE_USAGE.slice("Usage: ".length)}`,
|
|
4388
|
+
"",
|
|
4389
|
+
"Status: implemented",
|
|
4390
|
+
"",
|
|
4391
|
+
"Purpose:",
|
|
4392
|
+
" Clone one motion or play's configuration under a new name without copying its people.",
|
|
4393
|
+
"",
|
|
4394
|
+
"Input shape:",
|
|
4395
|
+
" motn_id: motn_ prefix id",
|
|
4396
|
+
" name: new motion name",
|
|
4397
|
+
"",
|
|
4398
|
+
"Behavior:",
|
|
4399
|
+
" Copies the motion kind, offer, ICP, principal, premise, approach, targeting profile, suppression policy, secondary roles, and active signal rows.",
|
|
4400
|
+
" The clone starts as draft with a new empty backing list.",
|
|
4401
|
+
"",
|
|
4402
|
+
"API:",
|
|
4403
|
+
" POST /api/v1/accounts/:account_id/motions/:id/clone.json",
|
|
4404
|
+
"",
|
|
4405
|
+
"JSON body:",
|
|
4406
|
+
" {",
|
|
4407
|
+
" \"motion\": {",
|
|
4408
|
+
" \"name\": \"Wine Campaign Restaurant Operators\"",
|
|
4409
|
+
" }",
|
|
4410
|
+
" }"
|
|
4411
|
+
].join("\n")],
|
|
4412
|
+
|
|
4413
|
+
["motions move-prospects", [
|
|
4414
|
+
"Usage:",
|
|
4415
|
+
` ${MOTIONS_MOVE_PROSPECTS_USAGE.slice("Usage: ".length)}`,
|
|
4416
|
+
"",
|
|
4417
|
+
"Status: implemented",
|
|
4418
|
+
"",
|
|
4419
|
+
"Purpose:",
|
|
4420
|
+
" Move prospects out of one motion or play and into another motion or play.",
|
|
4421
|
+
"",
|
|
4422
|
+
"Input shape:",
|
|
4423
|
+
" source_motn_id: source motn_ prefix id",
|
|
4424
|
+
" target_motn_id: target motn_ prefix id",
|
|
4425
|
+
" prsp_id: one or more prospect prefix ids",
|
|
4426
|
+
"",
|
|
4427
|
+
"Behavior:",
|
|
4428
|
+
" Move removes each selected prospect from the source motion and source backing list, then adds it to the target motion and target backing list.",
|
|
4429
|
+
" Copy is intentionally not exposed until multi-motion membership exists.",
|
|
4430
|
+
"",
|
|
4431
|
+
"API:",
|
|
4432
|
+
" POST /api/v1/accounts/:account_id/motions/:id/move_prospects.json",
|
|
4433
|
+
"",
|
|
4434
|
+
"JSON body:",
|
|
4435
|
+
" {",
|
|
4436
|
+
" \"target_motion_id\": \"motn_target\",",
|
|
4437
|
+
" \"prospect_ids\": [\"prsp_one\", \"prsp_two\"]",
|
|
4438
|
+
" }"
|
|
4439
|
+
].join("\n")],
|
|
4440
|
+
|
|
4020
4441
|
["prospects", [
|
|
4021
4442
|
"Usage:",
|
|
4022
4443
|
" audienti prospects list [--json] [filters]",
|
|
4023
4444
|
" audienti prospects show <prsp_id> [--json]",
|
|
4445
|
+
" audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json]",
|
|
4024
4446
|
" audienti prospects timeline <prsp_id> [--json]",
|
|
4025
4447
|
" audienti prospects message-types <prsp_id> [--json]",
|
|
4026
4448
|
" audienti prospects write <prsp_id> --type <surface_key> [--json]",
|
|
@@ -4031,9 +4453,10 @@ const HELP_TOPICS = new Map([
|
|
|
4031
4453
|
" audienti prospects sequence-preview <prsp_id> [--json]",
|
|
4032
4454
|
" audienti prospects sequence-export <prsp_id> [--csv]",
|
|
4033
4455
|
" audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--json]",
|
|
4456
|
+
" audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--json]",
|
|
4034
4457
|
" audienti prospects import-status <primp_id> [--json]",
|
|
4035
4458
|
"",
|
|
4036
|
-
"Status: read commands, per-prospect draft preview, sequence preview, and import implemented; disposition planned",
|
|
4459
|
+
"Status: read commands, assignment, per-prospect draft preview, sequence preview, and import implemented; disposition planned",
|
|
4037
4460
|
"",
|
|
4038
4461
|
"Filters:",
|
|
4039
4462
|
" --query <text>",
|
|
@@ -4043,7 +4466,7 @@ const HELP_TOPICS = new Map([
|
|
|
4043
4466
|
" --play <motn_id>",
|
|
4044
4467
|
" --list <list_id>",
|
|
4045
4468
|
" --stage <stage>",
|
|
4046
|
-
" --assigned-user <account_user_id|me>",
|
|
4469
|
+
" --assigned-user <account_user_id|me|unassigned>",
|
|
4047
4470
|
" --limit <n>",
|
|
4048
4471
|
" --page <n>",
|
|
4049
4472
|
" --offset <n>",
|
|
@@ -4071,7 +4494,7 @@ const HELP_TOPICS = new Map([
|
|
|
4071
4494
|
" --play <motn_id> Filter to a play using the same motion relationship",
|
|
4072
4495
|
" --list <list_id> Filter to a prospect list",
|
|
4073
4496
|
" --stage <stage> Filter to a pipeline stage",
|
|
4074
|
-
" --assigned-user <id|me>
|
|
4497
|
+
" --assigned-user <id|me|unassigned> Filter by assigned account user",
|
|
4075
4498
|
" --limit <n> Max rows for one page; with --all it caps total rows up to 1000",
|
|
4076
4499
|
" --page <n> 1-based page number",
|
|
4077
4500
|
" --offset <n> Row offset for manual pagination",
|
|
@@ -4098,9 +4521,33 @@ const HELP_TOPICS = new Map([
|
|
|
4098
4521
|
"",
|
|
4099
4522
|
"Examples:",
|
|
4100
4523
|
" audienti prospects list --stage identified --page 2 --limit 50",
|
|
4524
|
+
" audienti prospects list --assigned-user unassigned",
|
|
4101
4525
|
" audienti prospects list --all --csv"
|
|
4102
4526
|
].join("\n")],
|
|
4103
4527
|
|
|
4528
|
+
["prospects assign", [
|
|
4529
|
+
"Usage:",
|
|
4530
|
+
` ${PROSPECTS_ASSIGN_USAGE.slice("Usage: ".length)}`,
|
|
4531
|
+
"",
|
|
4532
|
+
"Status: implemented",
|
|
4533
|
+
"",
|
|
4534
|
+
"Input shape:",
|
|
4535
|
+
" prsp_id: one or more prsp_ prefix ids",
|
|
4536
|
+
" assigned_user_id: account user id, me, or unassign",
|
|
4537
|
+
"",
|
|
4538
|
+
"Behavior:",
|
|
4539
|
+
" Updates AccountProspect.assigned_to_account_user_id for existing account prospects without changing motion or list membership.",
|
|
4540
|
+
"",
|
|
4541
|
+
"API:",
|
|
4542
|
+
" POST /api/v1/accounts/:account_id/prospects/assign.json",
|
|
4543
|
+
"",
|
|
4544
|
+
"JSON body:",
|
|
4545
|
+
" {",
|
|
4546
|
+
" \"prospect_ids\": [\"prsp_abc123\", \"prsp_def456\"],",
|
|
4547
|
+
" \"assigned_user_id\": \"me\"",
|
|
4548
|
+
" }"
|
|
4549
|
+
].join("\n")],
|
|
4550
|
+
|
|
4104
4551
|
["prospects show", [
|
|
4105
4552
|
"Usage:",
|
|
4106
4553
|
" audienti prospects show <prsp_id> [--json] [--account <acct_id>]",
|
|
@@ -4426,6 +4873,28 @@ const HELP_TOPICS = new Map([
|
|
|
4426
4873
|
" }"
|
|
4427
4874
|
].join("\n")],
|
|
4428
4875
|
|
|
4876
|
+
["prospects import-batch", [
|
|
4877
|
+
"Usage:",
|
|
4878
|
+
` ${PROSPECTS_IMPORT_BATCH_USAGE.slice("Usage: ".length)}`,
|
|
4879
|
+
"",
|
|
4880
|
+
"Status: implemented",
|
|
4881
|
+
"",
|
|
4882
|
+
"Input shape:",
|
|
4883
|
+
" file: CSV with linkedin_url/url header, JSON array, JSONL objects, or newline-delimited LinkedIn URLs",
|
|
4884
|
+
" list_id: list_ prefix id | optional default for every row",
|
|
4885
|
+
" motn_id: motn_ prefix id | optional default for every row",
|
|
4886
|
+
" assigned_user_id: account user id or me | optional default for every row",
|
|
4887
|
+
"",
|
|
4888
|
+
"CSV columns:",
|
|
4889
|
+
" linkedin_url or url, list_id, motion_id, assigned_user_id",
|
|
4890
|
+
"",
|
|
4891
|
+
"Behavior:",
|
|
4892
|
+
" Starts one normal prospect import per row. Row-level list_id, motion_id, and assigned_user_id override command defaults.",
|
|
4893
|
+
"",
|
|
4894
|
+
"API:",
|
|
4895
|
+
" POST /api/v1/accounts/:account_id/prospect_imports.json"
|
|
4896
|
+
].join("\n")],
|
|
4897
|
+
|
|
4429
4898
|
["prospects import-status", [
|
|
4430
4899
|
"Usage:",
|
|
4431
4900
|
" audienti prospects import-status <primp_id> [--json] [--account <acct_id>]",
|
|
@@ -4762,17 +5231,22 @@ const HELP_TOPICS = new Map([
|
|
|
4762
5231
|
"",
|
|
4763
5232
|
"2. Create a motion or play",
|
|
4764
5233
|
" audienti motions create --payload <file.json>",
|
|
5234
|
+
" audienti motions clone <motn_id> --name \"New subset motion\"",
|
|
5235
|
+
" audienti motions move-prospects <source_motn_id> --target <target_motn_id> <prsp_id> [prsp_id...]",
|
|
4765
5236
|
" audienti motions status <motn_id>",
|
|
4766
5237
|
"",
|
|
4767
5238
|
"3. Add a new prospect from LinkedIn and poll enrichment",
|
|
4768
5239
|
" audienti lists create --name \"Target list\"",
|
|
4769
5240
|
" audienti prospects import https://www.linkedin.com/in/example --list <list_id> --assigned-user me",
|
|
5241
|
+
" audienti prospects import-batch --file prospects.csv --motion <motn_id> --assigned-user me",
|
|
4770
5242
|
" audienti prospects import-status <primp_id>",
|
|
4771
5243
|
" audienti prospects show <prsp_id>",
|
|
4772
5244
|
" audienti tools get email --url https://www.linkedin.com/in/example",
|
|
4773
5245
|
"",
|
|
4774
5246
|
"4. Find an existing prospect and inspect next step",
|
|
4775
5247
|
" audienti prospects list --query \"name or company\" --wide",
|
|
5248
|
+
" audienti prospects list --assigned-user unassigned",
|
|
5249
|
+
" audienti prospects assign <prsp_id> --assigned-user me",
|
|
4776
5250
|
" audienti companies search --query \"Honeywell\"",
|
|
4777
5251
|
" audienti prospects list --company-profile <prof_id>",
|
|
4778
5252
|
" audienti prospects show <prsp_id>",
|
|
@@ -4796,6 +5270,7 @@ const HELP_TOPICS = new Map([
|
|
|
4796
5270
|
" audienti operator outcome <row_id> --payload <file.json>",
|
|
4797
5271
|
"",
|
|
4798
5272
|
"7. Inspect account analytics",
|
|
5273
|
+
" audienti users activity me --window 7d",
|
|
4799
5274
|
" audienti analytics prospects --window 24h",
|
|
4800
5275
|
" audienti analytics users --user me --window 30d",
|
|
4801
5276
|
" audienti analytics visibility --window 24h --user me",
|