@audienti/cli 0.1.8 → 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 +9 -0
- package/README.md +19 -0
- package/package.json +1 -1
- package/skills/audienti/SKILL.md +4 -0
- package/src/api-client.js +11 -0
- package/src/cli.js +366 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ 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
|
+
|
|
7
16
|
## [0.1.8] - 2026-07-14
|
|
8
17
|
|
|
9
18
|
### Added
|
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
|
}
|
|
@@ -167,6 +171,13 @@ export class AudientiClient {
|
|
|
167
171
|
return this.requestJson(accountPath(accountId, ["prospects", prospectId]));
|
|
168
172
|
}
|
|
169
173
|
|
|
174
|
+
assignProspects(accountId, body) {
|
|
175
|
+
return this.requestJson(accountPath(accountId, ["prospects", "assign"]), {
|
|
176
|
+
method: "POST",
|
|
177
|
+
body
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
170
181
|
prospectTimeline(accountId, prospectId, query = {}) {
|
|
171
182
|
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "timeline"], query));
|
|
172
183
|
}
|
package/src/cli.js
CHANGED
|
@@ -29,6 +29,9 @@ 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>]";
|
|
34
37
|
const MOTIONS_CLONE_USAGE = "Usage: audienti motions clone <motn_id> --name <text> [--json] [--account <acct_id>]";
|
|
@@ -117,6 +120,7 @@ async function dispatch(argv, context) {
|
|
|
117
120
|
if (normalizedResource === "accounts" && action === "list") return accountsList(rest, context, { accountOverride });
|
|
118
121
|
if (normalizedResource === "accounts" && action === "select") return accountsSelect(rest, context);
|
|
119
122
|
if (normalizedResource === "users" && action === "list") return usersList(rest, context, { accountOverride });
|
|
123
|
+
if (normalizedResource === "users" && action === "activity") return usersActivity(rest, context, { accountOverride });
|
|
120
124
|
if (normalizedResource === "offers" && action === "list") return offersList(rest, context, { accountOverride });
|
|
121
125
|
if (normalizedResource === "offers" && action === "create") return offersCreate(rest, context, { accountOverride });
|
|
122
126
|
if (normalizedResource === "icps" && action === "list") return icpsList(rest, context, { accountOverride });
|
|
@@ -141,6 +145,7 @@ async function dispatch(argv, context) {
|
|
|
141
145
|
if (normalizedResource === "motions" && action === "move-prospects") return motionsMoveProspects(rest, context, { accountOverride });
|
|
142
146
|
if (normalizedResource === "prospects" && action === "list") return prospectsList(rest, context, { accountOverride });
|
|
143
147
|
if (normalizedResource === "prospects" && action === "show") return prospectsShow(rest, context, { accountOverride });
|
|
148
|
+
if (normalizedResource === "prospects" && action === "assign") return prospectsAssign(rest, context, { accountOverride });
|
|
144
149
|
if (normalizedResource === "prospects" && action === "timeline") return prospectsTimeline(rest, context, { accountOverride });
|
|
145
150
|
if (normalizedResource === "prospects" && action === "message-types") return prospectsMessageTypes(rest, context, { accountOverride });
|
|
146
151
|
if (normalizedResource === "prospects" && action === "write") return prospectsWrite(rest, context, { accountOverride });
|
|
@@ -151,6 +156,7 @@ async function dispatch(argv, context) {
|
|
|
151
156
|
if (normalizedResource === "prospects" && action === "sequence-preview") return prospectsSequencePreview(rest, context, { accountOverride });
|
|
152
157
|
if (normalizedResource === "prospects" && action === "sequence-export") return prospectsSequenceExport(rest, context, { accountOverride });
|
|
153
158
|
if (normalizedResource === "prospects" && action === "import") return prospectsImport(rest, context, { accountOverride });
|
|
159
|
+
if (normalizedResource === "prospects" && action === "import-batch") return prospectsImportBatch(rest, context, { accountOverride });
|
|
154
160
|
if (normalizedResource === "prospects" && action === "import-status") return prospectsImportStatus(rest, context, { accountOverride });
|
|
155
161
|
if (normalizedResource === "writer" && action === "test-run") return writerTestRun(rest, context, { accountOverride });
|
|
156
162
|
if (normalizedResource === "tools" && action === "get") return toolsGet(rest, context, { accountOverride });
|
|
@@ -399,6 +405,32 @@ async function usersList(args, context, { accountOverride } = {}) {
|
|
|
399
405
|
renderUsers(users, context);
|
|
400
406
|
}
|
|
401
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
|
+
|
|
402
434
|
async function offersList(args, context, { accountOverride } = {}) {
|
|
403
435
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
404
436
|
if (positionals.length > 0) throw new CommandError("Usage: audienti offers list [--json] [--account <acct_id>]");
|
|
@@ -882,6 +914,36 @@ async function prospectsList(args, context, { accountOverride } = {}) {
|
|
|
882
914
|
renderProspects(payload, context, { wide: values.wide || values.all, profiles: values.profiles });
|
|
883
915
|
}
|
|
884
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
|
+
|
|
885
947
|
async function prospectsShow(args, context, { accountOverride } = {}) {
|
|
886
948
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
887
949
|
if (positionals.length !== 1) throw new CommandError("Usage: audienti prospects show <prsp_id> [--json] [--account <acct_id>]");
|
|
@@ -1295,6 +1357,66 @@ async function prospectsImport(args, context, { accountOverride } = {}) {
|
|
|
1295
1357
|
renderProspectImportStarted(payload, context);
|
|
1296
1358
|
}
|
|
1297
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
|
+
|
|
1298
1420
|
async function prospectsImportStatus(args, context, { accountOverride } = {}) {
|
|
1299
1421
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1300
1422
|
if (positionals.length !== 1) {
|
|
@@ -1984,6 +2106,113 @@ async function readJsonPayload(filePath) {
|
|
|
1984
2106
|
}
|
|
1985
2107
|
}
|
|
1986
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
|
+
|
|
1987
2216
|
function writeLine(stream, text = "") {
|
|
1988
2217
|
stream.write(`${text}\n`);
|
|
1989
2218
|
}
|
|
@@ -2029,6 +2258,41 @@ function renderUsers(users, context) {
|
|
|
2029
2258
|
}
|
|
2030
2259
|
}
|
|
2031
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
|
+
|
|
2032
2296
|
function renderOffers(offers, context) {
|
|
2033
2297
|
if (!Array.isArray(offers) || offers.length === 0) return writeLine(context.stdout, "No offers found.");
|
|
2034
2298
|
|
|
@@ -2564,6 +2828,30 @@ function renderProspectImportStarted(payload, context) {
|
|
|
2564
2828
|
if (payload?.prefix_id) writeLine(context.stdout, `Run \`audienti prospects import-status ${payload.prefix_id}\` to check completion.`);
|
|
2565
2829
|
}
|
|
2566
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
|
+
|
|
2567
2855
|
function renderProspectImportStatus(payload, context) {
|
|
2568
2856
|
writeLine(context.stdout, `Import: ${display(payload?.prefix_id)}`);
|
|
2569
2857
|
writeLine(context.stdout, `Status: ${display(payload?.status)}`);
|
|
@@ -3313,6 +3601,7 @@ const HELP_TOPICS = new Map([
|
|
|
3313
3601
|
" audienti auth status",
|
|
3314
3602
|
" audienti config list",
|
|
3315
3603
|
" audienti users list",
|
|
3604
|
+
" audienti users activity <account_user_id|me>",
|
|
3316
3605
|
"",
|
|
3317
3606
|
" Motions / plays",
|
|
3318
3607
|
" audienti motions list",
|
|
@@ -3327,8 +3616,10 @@ const HELP_TOPICS = new Map([
|
|
|
3327
3616
|
" Prospects",
|
|
3328
3617
|
" audienti prospects list [filters]",
|
|
3329
3618
|
" audienti prospects show <prsp_id>",
|
|
3619
|
+
" audienti prospects assign <prsp_id> --assigned-user <id|me|unassign>",
|
|
3330
3620
|
" audienti prospects timeline <prsp_id>",
|
|
3331
3621
|
" audienti prospects import <linkedin_url> [--motion <motn_id>]",
|
|
3622
|
+
" audienti prospects import-batch --file <csv|jsonl|json>",
|
|
3332
3623
|
" audienti prospects add-note <prsp_id> --message <text>",
|
|
3333
3624
|
" audienti prospects add-profile <prsp_id> --url <profile_url|email|phone>",
|
|
3334
3625
|
"",
|
|
@@ -3505,6 +3796,7 @@ const HELP_TOPICS = new Map([
|
|
|
3505
3796
|
["users", [
|
|
3506
3797
|
"Usage:",
|
|
3507
3798
|
" audienti users list [--json]",
|
|
3799
|
+
" audienti users activity <account_user_id|me> [--json]",
|
|
3508
3800
|
"",
|
|
3509
3801
|
"Status: implemented",
|
|
3510
3802
|
"",
|
|
@@ -3533,6 +3825,25 @@ const HELP_TOPICS = new Map([
|
|
|
3533
3825
|
" current: boolean"
|
|
3534
3826
|
].join("\n")],
|
|
3535
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
|
+
|
|
3536
3847
|
["offers", [
|
|
3537
3848
|
"Usage:",
|
|
3538
3849
|
" audienti offers list [--json]",
|
|
@@ -4131,6 +4442,7 @@ const HELP_TOPICS = new Map([
|
|
|
4131
4442
|
"Usage:",
|
|
4132
4443
|
" audienti prospects list [--json] [filters]",
|
|
4133
4444
|
" audienti prospects show <prsp_id> [--json]",
|
|
4445
|
+
" audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json]",
|
|
4134
4446
|
" audienti prospects timeline <prsp_id> [--json]",
|
|
4135
4447
|
" audienti prospects message-types <prsp_id> [--json]",
|
|
4136
4448
|
" audienti prospects write <prsp_id> --type <surface_key> [--json]",
|
|
@@ -4141,9 +4453,10 @@ const HELP_TOPICS = new Map([
|
|
|
4141
4453
|
" audienti prospects sequence-preview <prsp_id> [--json]",
|
|
4142
4454
|
" audienti prospects sequence-export <prsp_id> [--csv]",
|
|
4143
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]",
|
|
4144
4457
|
" audienti prospects import-status <primp_id> [--json]",
|
|
4145
4458
|
"",
|
|
4146
|
-
"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",
|
|
4147
4460
|
"",
|
|
4148
4461
|
"Filters:",
|
|
4149
4462
|
" --query <text>",
|
|
@@ -4153,7 +4466,7 @@ const HELP_TOPICS = new Map([
|
|
|
4153
4466
|
" --play <motn_id>",
|
|
4154
4467
|
" --list <list_id>",
|
|
4155
4468
|
" --stage <stage>",
|
|
4156
|
-
" --assigned-user <account_user_id|me>",
|
|
4469
|
+
" --assigned-user <account_user_id|me|unassigned>",
|
|
4157
4470
|
" --limit <n>",
|
|
4158
4471
|
" --page <n>",
|
|
4159
4472
|
" --offset <n>",
|
|
@@ -4181,7 +4494,7 @@ const HELP_TOPICS = new Map([
|
|
|
4181
4494
|
" --play <motn_id> Filter to a play using the same motion relationship",
|
|
4182
4495
|
" --list <list_id> Filter to a prospect list",
|
|
4183
4496
|
" --stage <stage> Filter to a pipeline stage",
|
|
4184
|
-
" --assigned-user <id|me>
|
|
4497
|
+
" --assigned-user <id|me|unassigned> Filter by assigned account user",
|
|
4185
4498
|
" --limit <n> Max rows for one page; with --all it caps total rows up to 1000",
|
|
4186
4499
|
" --page <n> 1-based page number",
|
|
4187
4500
|
" --offset <n> Row offset for manual pagination",
|
|
@@ -4208,9 +4521,33 @@ const HELP_TOPICS = new Map([
|
|
|
4208
4521
|
"",
|
|
4209
4522
|
"Examples:",
|
|
4210
4523
|
" audienti prospects list --stage identified --page 2 --limit 50",
|
|
4524
|
+
" audienti prospects list --assigned-user unassigned",
|
|
4211
4525
|
" audienti prospects list --all --csv"
|
|
4212
4526
|
].join("\n")],
|
|
4213
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
|
+
|
|
4214
4551
|
["prospects show", [
|
|
4215
4552
|
"Usage:",
|
|
4216
4553
|
" audienti prospects show <prsp_id> [--json] [--account <acct_id>]",
|
|
@@ -4536,6 +4873,28 @@ const HELP_TOPICS = new Map([
|
|
|
4536
4873
|
" }"
|
|
4537
4874
|
].join("\n")],
|
|
4538
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
|
+
|
|
4539
4898
|
["prospects import-status", [
|
|
4540
4899
|
"Usage:",
|
|
4541
4900
|
" audienti prospects import-status <primp_id> [--json] [--account <acct_id>]",
|
|
@@ -4879,12 +5238,15 @@ const HELP_TOPICS = new Map([
|
|
|
4879
5238
|
"3. Add a new prospect from LinkedIn and poll enrichment",
|
|
4880
5239
|
" audienti lists create --name \"Target list\"",
|
|
4881
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",
|
|
4882
5242
|
" audienti prospects import-status <primp_id>",
|
|
4883
5243
|
" audienti prospects show <prsp_id>",
|
|
4884
5244
|
" audienti tools get email --url https://www.linkedin.com/in/example",
|
|
4885
5245
|
"",
|
|
4886
5246
|
"4. Find an existing prospect and inspect next step",
|
|
4887
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",
|
|
4888
5250
|
" audienti companies search --query \"Honeywell\"",
|
|
4889
5251
|
" audienti prospects list --company-profile <prof_id>",
|
|
4890
5252
|
" audienti prospects show <prsp_id>",
|
|
@@ -4908,6 +5270,7 @@ const HELP_TOPICS = new Map([
|
|
|
4908
5270
|
" audienti operator outcome <row_id> --payload <file.json>",
|
|
4909
5271
|
"",
|
|
4910
5272
|
"7. Inspect account analytics",
|
|
5273
|
+
" audienti users activity me --window 7d",
|
|
4911
5274
|
" audienti analytics prospects --window 24h",
|
|
4912
5275
|
" audienti analytics users --user me --window 30d",
|
|
4913
5276
|
" audienti analytics visibility --window 24h --user me",
|