@audienti/cli 0.1.44 → 0.1.50
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 +49 -0
- package/README.md +135 -1
- package/package.json +1 -1
- package/skills/audienti/SKILL.md +97 -1
- package/src/api-client.js +42 -2
- package/src/cli.js +760 -11
package/src/cli.js
CHANGED
|
@@ -33,7 +33,7 @@ const DEFAULT_PROFILE_IDENTIFIERS = [
|
|
|
33
33
|
"email/profile"
|
|
34
34
|
];
|
|
35
35
|
const DELETE_CONFIRMATION_VALUES = new Set(["yes", "true", "y"]);
|
|
36
|
-
const MOTION_STATUS_VALUES = new Set(["draft", "preparing", "active", "paused", "archived"]);
|
|
36
|
+
const MOTION_STATUS_VALUES = new Set(["draft", "preparing", "active", "closing", "paused", "archived"]);
|
|
37
37
|
const PROSPECT_INACTIVE_REASON_VALUES = new Set(["nurture", "non_responsive", "not_fit", "bad_data_404"]);
|
|
38
38
|
const PROSPECT_STATUS_VALUES = new Set(["active", ...PROSPECT_INACTIVE_REASON_VALUES, "rejected"]);
|
|
39
39
|
const OUTBOUND_METRICS_OUTCOMES = new Set([
|
|
@@ -51,6 +51,7 @@ const PROSPECTS_ADD_STEER_USAGE = "Usage: audienti prospects add-steer <prsp_id>
|
|
|
51
51
|
const PROSPECTS_ADD_PROFILE_USAGE = "Usage: audienti prospects add-profile <prsp_id> --url <profile_url|email|phone> [--json] [--account <acct_id>]";
|
|
52
52
|
const PROSPECTS_REPORT_BAD_PROFILE_USAGE = "Usage: audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json] [--account <acct_id>]";
|
|
53
53
|
const PROSPECTS_ASSIGN_USAGE = "Usage: audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json] [--account <acct_id>]";
|
|
54
|
+
const PROSPECTS_MOVE_ACCOUNT_USAGE = "Usage: audienti prospects move-account <prsp_id> --target-account <acct_id> [--assigned-user <id|me>] [--target-motion <motn_id>] [--target-list <list_id>] [--apply] [--json] [--account <source_acct_id>]";
|
|
54
55
|
const PROSPECTS_SET_STATUS_USAGE = "Usage: audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected> [--json] [--account <acct_id>]";
|
|
55
56
|
const PROSPECTS_REPLAN_USAGE = "Usage: audienti prospects replan <prsp_id> [--apply] [--json] [--account <acct_id>]";
|
|
56
57
|
const PROSPECTS_REENRICH_USAGE = "Usage: audienti prospects reenrich <prsp_id> [--profile <prof_id|citation_id>] [--apply] [--json] [--account <acct_id>]";
|
|
@@ -75,6 +76,8 @@ const TASKS_LIST_USAGE = "Usage: audienti tasks list [--status <open|completed>]
|
|
|
75
76
|
const TASKS_ADD_USAGE = "Usage: audienti tasks add --title <text> --due <time> [--prospect <prsp_id>] [--list <list_id>] [--assigned-user <id|me>] [--notes <text>] [--json] [--account <acct_id>]";
|
|
76
77
|
const TASKS_COMPLETE_USAGE = "Usage: audienti tasks complete <ptsk_id> [--json] [--account <acct_id>]";
|
|
77
78
|
const USERS_ACTIVITY_USAGE = "Usage: audienti users activity [account_user_id|me] [--mode <actor|account_usage|related>] [--window <24h|7d|30d>] [--platform <linkedin|email|gmail>] [--query <text>] [--limit <n>] [--page <n>] [--json] [--account <acct_id>]";
|
|
79
|
+
const USERS_AUTOMATION_SHOW_USAGE = "Usage: audienti users automation show <account_user_id|me> [--platform linkedin] [--json] [--account <acct_id>]";
|
|
80
|
+
const USERS_AUTOMATION_UPDATE_USAGE = "Usage: audienti users automation update <account_user_id|me> --payload <file.json> [--apply] [--json] [--account <acct_id>]";
|
|
78
81
|
const SETUP_PLAY_PREFLIGHT_USAGE = "Usage: audienti setup play preflight [--principal <account_user_id|email|name|me>] [--platform linkedin] [--json] [--account <acct_id>]";
|
|
79
82
|
const OFFERS_SHOW_USAGE = "Usage: audienti offers show <offr_id> [--json] [--account <acct_id>]";
|
|
80
83
|
const OFFERS_UPDATE_USAGE = "Usage: audienti offers update <offr_id> [--name <text>] [--description <text>] [--url <url>] [--json] [--account <acct_id>]";
|
|
@@ -82,7 +85,7 @@ const OFFERS_DELETE_USAGE = "Usage: audienti offers delete <offr_id> --confirm <
|
|
|
82
85
|
const WRITER_TEST_RUN_USAGE = "Usage: audienti writer test-run <prsp_id> [--json] [--mode <plan|report|step>] [--branch <both|no-accept|accepted>] [--step <step_key|row_number>] [--report <rprt_id>] [--no-wait] [--timeout-seconds <n>] [--poll-interval-seconds <n>] [--account <acct_id>]";
|
|
83
86
|
const WRITER_TEST_RUN_SHOW_USAGE = "Usage: audienti writer test-run show <prsp_id> <rprt_id> [--json] [--account <acct_id>]";
|
|
84
87
|
const MOTIONS_ANALYTICS_USAGE = "Usage: audienti motions analytics <motn_id> [--window 30d] [--json] [--account <acct_id>]";
|
|
85
|
-
const MOTIONS_UPDATE_USAGE = "Usage: audienti motions update <motn_id> ([--status <draft|preparing|active|paused|archived>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>] [--start-date <YYYY-MM-DD|none>] [--end-date <YYYY-MM-DD|none>] [--maximum-company-count <n|none>] | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
88
|
+
const MOTIONS_UPDATE_USAGE = "Usage: audienti motions update <motn_id> ([--status <draft|preparing|active|closing|paused|archived>] [--tags <tag[,tag...]>] [--own-post-engagement <true|false>] [--start-date <YYYY-MM-DD|none>] [--end-date <YYYY-MM-DD|none>] [--maximum-company-count <n|none>] | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
86
89
|
const CONTENT_PROGRAMS_USAGE = "Usage: audienti content programs [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
|
|
87
90
|
const CONTENT_PLAN_USAGE = "Usage: audienti content plan <cprg_id> [--week <n>] [--due] [--json] [--account <acct_id>]";
|
|
88
91
|
const CONTENT_SHOW_USAGE = "Usage: audienti content show <cpwi_id> [--json] [--account <acct_id>]";
|
|
@@ -104,7 +107,10 @@ const MOTIONS_ABM_COMPANIES_LIST_USAGE = "Usage: audienti motions abm-companies
|
|
|
104
107
|
const MOTIONS_ABM_COMPANIES_ADD_USAGE = "Usage: audienti motions abm-companies <motn_id> add (<domain_or_linkedin_url>... | --file <txt|json>) [--json] [--account <acct_id>]";
|
|
105
108
|
const MOTIONS_ABM_COMPANIES_REMOVE_USAGE = "Usage: audienti motions abm-companies <motn_id> remove <row_id> [--json] [--account <acct_id>]";
|
|
106
109
|
const ICPS_SHOW_USAGE = "Usage: audienti icps show <icp_id> [--json] [--account <acct_id>]";
|
|
110
|
+
const ICPS_LIST_USAGE = "Usage: audienti icps list [--status <active|archived|all>] [--tag <tag>] [--json] [--account <acct_id>]";
|
|
107
111
|
const ICPS_UPDATE_USAGE = "Usage: audienti icps update <icp_id> ([--name <text>] [--notes <text>] [--discovery-keyword <text>] [--tags <tag[,tag...]>] | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
112
|
+
const ICPS_ARCHIVE_USAGE = "Usage: audienti icps archive <icp_id> [--json] [--account <acct_id>]";
|
|
113
|
+
const ICPS_RESTORE_USAGE = "Usage: audienti icps restore <icp_id> [--json] [--account <acct_id>]";
|
|
108
114
|
const ICPS_ADD_TAG_USAGE = "Usage: audienti icps add-tag <icp_id> <tag> [--json] [--account <acct_id>]";
|
|
109
115
|
const ICPS_REMOVE_TAG_USAGE = "Usage: audienti icps remove-tag <icp_id> <tag> [--json] [--account <acct_id>]";
|
|
110
116
|
const LISTS_ADD_TAG_USAGE = "Usage: audienti lists add-tag <list_id> <tag> [--json] [--account <acct_id>]";
|
|
@@ -119,6 +125,8 @@ const ANALYTICS_PROSPECTS_USAGE = "Usage: audienti analytics prospects [--window
|
|
|
119
125
|
const ANALYTICS_PROSPECTS_COHORT_ANALYSIS_USAGE = "Usage: audienti analytics prospects cohort-analysis [--weeks <n>] [--window 24h] [--motion <motn_id>] [--list <list_id>] [--provenance <source>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
|
|
120
126
|
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>] [--list <list_id>] [--provenance <source>] [--platform <linkedin|email|gmail>] [--json] [--account <acct_id>]";
|
|
121
127
|
const ANALYTICS_DASHBOARD_USAGE = "Usage: audienti analytics dashboard [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--list <list_id>] [--offer <offr_id>] [--icp <icp_id>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
|
|
128
|
+
const ANALYTICS_MOTIONS_USAGE = "Usage: audienti analytics motions [--json] [--account <acct_id>]";
|
|
129
|
+
const ANALYTICS_ICPS_USAGE = "Usage: audienti analytics icps [--json] [--account <acct_id>]";
|
|
122
130
|
const ANALYTICS_METRICS_USAGE = "Usage: audienti analytics metrics [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD | --cohort-preset week-to-date] [--interval <daily|weekly>] [--user <account_user_id|email|name|me>] [--motion <motn_id>] [--play-tag <tag>] [--list <list_id>] [--offer <offr_id>] [--icp <icp_id>] [--social-cookie <scok_id>] [--platform <platform>] [--action <action_key>] [--outcome <success|failure|first_attempt_success|succeeded_after_retry|failed_without_retry|failed_after_retry|in_progress|unresolved>] [--json] [--account <acct_id>]";
|
|
123
131
|
const ANALYTICS_STAGES_USAGE = "Usage: audienti analytics stages [--interval weekly|monthly] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--list <list_id>] [--offer <offr_id>] [--icp <icp_id>] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]";
|
|
124
132
|
const ANALYTICS_COHORT_LIST_USAGE = "Usage: audienti analytics cohorts create-list --name <text> --start YYYY-MM-DD --end YYYY-MM-DD [--event connection_request_sent] [--user <account_user_id|email|name|me>] [--note-mode <any|with_note|blank>] [--motion <motn_id>] [--offer <offr_id>] [--icp <icp_id>] [--play-tag <tag>] [--json] [--account <acct_id>]";
|
|
@@ -218,6 +226,7 @@ async function dispatch(argv, context) {
|
|
|
218
226
|
if (normalizedResource === "users" && action === "list") return usersList(rest, context, { accountOverride });
|
|
219
227
|
if (normalizedResource === "users" && action === "select") return usersSelect(rest, context, { accountOverride });
|
|
220
228
|
if (normalizedResource === "users" && action === "activity") return usersActivity(rest, context, { accountOverride });
|
|
229
|
+
if (normalizedResource === "users" && action === "automation") return usersAutomation(rest, context, { accountOverride });
|
|
221
230
|
if (normalizedResource === "setup" && action === "play" && rest[0] === "preflight") return setupPlayPreflight(rest.slice(1), context, { accountOverride });
|
|
222
231
|
if (normalizedResource === "offers" && action === "list") return offersList(rest, context, { accountOverride });
|
|
223
232
|
if (normalizedResource === "offers" && action === "show") return offersShow(rest, context, { accountOverride });
|
|
@@ -226,8 +235,11 @@ async function dispatch(argv, context) {
|
|
|
226
235
|
if (normalizedResource === "offers" && action === "delete") return offersDelete(rest, context, { accountOverride });
|
|
227
236
|
if (normalizedResource === "icps" && action === "list") return icpsList(rest, context, { accountOverride });
|
|
228
237
|
if (normalizedResource === "icps" && action === "show") return icpsShow(rest, context, { accountOverride });
|
|
238
|
+
if (normalizedResource === "icps" && action === "analytics") return analyticsIcps(rest, context, { accountOverride });
|
|
229
239
|
if (normalizedResource === "icps" && action === "create") return icpsCreate(rest, context, { accountOverride });
|
|
230
240
|
if (normalizedResource === "icps" && action === "update") return icpsUpdate(rest, context, { accountOverride });
|
|
241
|
+
if (normalizedResource === "icps" && action === "archive") return icpsLifecycleMutation("archive", rest, context, { accountOverride });
|
|
242
|
+
if (normalizedResource === "icps" && action === "restore") return icpsLifecycleMutation("restore", rest, context, { accountOverride });
|
|
231
243
|
if (normalizedResource === "icps" && action === "add-tag") return icpsTagMutation("add", rest, context, { accountOverride });
|
|
232
244
|
if (normalizedResource === "icps" && action === "remove-tag") return icpsTagMutation("remove", rest, context, { accountOverride });
|
|
233
245
|
if (normalizedResource === "companies" && action === "search") return companiesSearch(rest, context, { accountOverride });
|
|
@@ -287,6 +299,7 @@ async function dispatch(argv, context) {
|
|
|
287
299
|
if (normalizedResource === "prospects" && action === "check") return prospectsCheck(rest, context, { accountOverride });
|
|
288
300
|
if (normalizedResource === "prospects" && action === "show") return prospectsShow(rest, context, { accountOverride });
|
|
289
301
|
if (normalizedResource === "prospects" && action === "assign") return prospectsAssign(rest, context, { accountOverride });
|
|
302
|
+
if (normalizedResource === "prospects" && action === "move-account") return prospectsMoveAccount(rest, context, { accountOverride });
|
|
290
303
|
if (normalizedResource === "prospects" && action === "set-status") return prospectsSetStatus(rest, context, { accountOverride });
|
|
291
304
|
if (normalizedResource === "prospects" && action === "replan") return prospectsReplan(rest, context, { accountOverride });
|
|
292
305
|
if (normalizedResource === "prospects" && action === "reenrich") return prospectsReenrich(rest, context, { accountOverride });
|
|
@@ -322,6 +335,8 @@ async function dispatch(argv, context) {
|
|
|
322
335
|
if (normalizedResource === "analytics" && ["visibility", "visops"].includes(action)) return analyticsVisibility(rest, context, { accountOverride });
|
|
323
336
|
if (normalizedResource === "analytics" && action === "content") return analyticsContent(rest, context, { accountOverride });
|
|
324
337
|
if (normalizedResource === "analytics" && ["dashboard", "campaign", "campaigns"].includes(action)) return analyticsDashboard(rest, context, { accountOverride });
|
|
338
|
+
if (normalizedResource === "analytics" && ["motions", "plays"].includes(action)) return analyticsMotions(rest, context, { accountOverride });
|
|
339
|
+
if (normalizedResource === "analytics" && ["icps", "icp"].includes(action)) return analyticsIcps(rest, context, { accountOverride });
|
|
325
340
|
if (normalizedResource === "analytics" && action === "metrics") return analyticsMetrics(rest, context, { accountOverride });
|
|
326
341
|
if (normalizedResource === "analytics" && action === "stages") return analyticsStages(rest, context, { accountOverride });
|
|
327
342
|
if (normalizedResource === "analytics" && ["cohorts", "cohort"].includes(action)) return analyticsCohorts(rest, context, { accountOverride });
|
|
@@ -896,6 +911,60 @@ async function usersActivity(args, context, { accountOverride } = {}) {
|
|
|
896
911
|
renderUserActivity(payload, context);
|
|
897
912
|
}
|
|
898
913
|
|
|
914
|
+
async function usersAutomation(args, context, { accountOverride } = {}) {
|
|
915
|
+
const [action, ...rest] = args;
|
|
916
|
+
if (action === "show") return usersAutomationShow(rest, context, { accountOverride });
|
|
917
|
+
if (action === "update") return usersAutomationUpdate(rest, context, { accountOverride });
|
|
918
|
+
|
|
919
|
+
throw new CommandError(`${USERS_AUTOMATION_SHOW_USAGE}\n${USERS_AUTOMATION_UPDATE_USAGE}`);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
async function usersAutomationShow(args, context, { accountOverride } = {}) {
|
|
923
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
924
|
+
...jsonOptions(),
|
|
925
|
+
platform: { type: "string" }
|
|
926
|
+
});
|
|
927
|
+
if (positionals.length !== 1) throw new CommandError(USERS_AUTOMATION_SHOW_USAGE);
|
|
928
|
+
|
|
929
|
+
const platform = automationPlatform(values.platform);
|
|
930
|
+
const { client, accountId, config } = await requireAccountContext(context, { accountOverride });
|
|
931
|
+
const accountUserId = resolveAccountUserId(positionals[0], config, { accountOverride });
|
|
932
|
+
const payload = await client.userAutomation(accountId, accountUserId, { platform });
|
|
933
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
934
|
+
|
|
935
|
+
renderUserAutomation(payload, context);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
async function usersAutomationUpdate(args, context, { accountOverride } = {}) {
|
|
939
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
940
|
+
...jsonOptions(),
|
|
941
|
+
payload: { type: "string" },
|
|
942
|
+
apply: { type: "boolean" }
|
|
943
|
+
});
|
|
944
|
+
if (positionals.length !== 1 || !values.payload) throw new CommandError(USERS_AUTOMATION_UPDATE_USAGE);
|
|
945
|
+
|
|
946
|
+
const platform = automationPlatform();
|
|
947
|
+
const requestedAutomation = await readJsonPayload(values.payload);
|
|
948
|
+
const { client, accountId, config } = await requireAccountContext(context, { accountOverride });
|
|
949
|
+
const accountUserId = resolveAccountUserId(positionals[0], config, { accountOverride });
|
|
950
|
+
const payload = await client.updateUserAutomation(
|
|
951
|
+
accountId,
|
|
952
|
+
accountUserId,
|
|
953
|
+
{ automation: { ...requestedAutomation, platform, apply: Boolean(values.apply) } },
|
|
954
|
+
{ platform }
|
|
955
|
+
);
|
|
956
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
957
|
+
|
|
958
|
+
renderUserAutomation(payload, context);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
function automationPlatform(value = "linkedin") {
|
|
962
|
+
const platform = String(value || "").trim().toLowerCase();
|
|
963
|
+
if (platform !== "linkedin") throw new CommandError("--platform must be linkedin.");
|
|
964
|
+
|
|
965
|
+
return platform;
|
|
966
|
+
}
|
|
967
|
+
|
|
899
968
|
async function setupPlayPreflight(args, context, { accountOverride } = {}) {
|
|
900
969
|
const { values, positionals } = parseCommandArgs(args, {
|
|
901
970
|
...jsonOptions(),
|
|
@@ -1008,17 +1077,35 @@ async function offersDelete(args, context, { accountOverride } = {}) {
|
|
|
1008
1077
|
async function icpsList(args, context, { accountOverride } = {}) {
|
|
1009
1078
|
const { values, positionals } = parseCommandArgs(args, {
|
|
1010
1079
|
...jsonOptions(),
|
|
1011
|
-
tag: { type: "string" }
|
|
1080
|
+
tag: { type: "string" },
|
|
1081
|
+
status: { type: "string" }
|
|
1012
1082
|
});
|
|
1013
|
-
|
|
1083
|
+
const status = values.status;
|
|
1084
|
+
if (positionals.length > 0 || (status && !["active", "archived", "all"].includes(status))) throw new CommandError(ICPS_LIST_USAGE);
|
|
1014
1085
|
|
|
1015
1086
|
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1016
|
-
const icps = filterRecordsByTag(await client.icps(accountId), values.tag, "tags");
|
|
1087
|
+
const icps = filterRecordsByTag(await client.icps(accountId, { status }), values.tag, "tags");
|
|
1017
1088
|
if (values.json) return writeJson(context.stdout, icps);
|
|
1018
1089
|
|
|
1019
1090
|
renderIcps(icps, context);
|
|
1020
1091
|
}
|
|
1021
1092
|
|
|
1093
|
+
async function icpsLifecycleMutation(action, args, context, { accountOverride } = {}) {
|
|
1094
|
+
const usageText = action === "archive" ? ICPS_ARCHIVE_USAGE : ICPS_RESTORE_USAGE;
|
|
1095
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1096
|
+
if (positionals.length !== 1) throw new CommandError(usageText);
|
|
1097
|
+
|
|
1098
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1099
|
+
const result = action === "archive" ?
|
|
1100
|
+
await client.archiveIcp(accountId, positionals[0]) :
|
|
1101
|
+
await client.restoreIcp(accountId, positionals[0]);
|
|
1102
|
+
if (values.json) return writeJson(context.stdout, result);
|
|
1103
|
+
|
|
1104
|
+
const verb = action === "archive" ? "Archived" : "Restored";
|
|
1105
|
+
writeLine(context.stdout, `${verb} ICP ${display(result?.icp?.name)} (${display(result?.icp?.prefix_id)}).`);
|
|
1106
|
+
writeIcpLifecycleEffects(result, context);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1022
1109
|
async function icpsShow(args, context, { accountOverride } = {}) {
|
|
1023
1110
|
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
1024
1111
|
if (positionals.length !== 1) throw new CommandError(ICPS_SHOW_USAGE);
|
|
@@ -2396,6 +2483,53 @@ async function prospectsShow(args, context, { accountOverride } = {}) {
|
|
|
2396
2483
|
renderProspect(prospect, context);
|
|
2397
2484
|
}
|
|
2398
2485
|
|
|
2486
|
+
async function prospectsMoveAccount(args, context, { accountOverride } = {}) {
|
|
2487
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
2488
|
+
...jsonOptions(),
|
|
2489
|
+
"target-account": { type: "string" },
|
|
2490
|
+
"assigned-user": { type: "string" },
|
|
2491
|
+
"target-motion": { type: "string" },
|
|
2492
|
+
"target-list": { type: "string" },
|
|
2493
|
+
apply: { type: "boolean" }
|
|
2494
|
+
});
|
|
2495
|
+
if (positionals.length !== 1 || !values["target-account"]) {
|
|
2496
|
+
throw new CommandError(PROSPECTS_MOVE_ACCOUNT_USAGE);
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
2500
|
+
const prospectId = positionals[0];
|
|
2501
|
+
const request = compactObject({
|
|
2502
|
+
target_account_id: values["target-account"],
|
|
2503
|
+
assigned_user_id: values["assigned-user"],
|
|
2504
|
+
target_motion_id: values["target-motion"],
|
|
2505
|
+
target_list_id: values["target-list"]
|
|
2506
|
+
});
|
|
2507
|
+
const preview = await performProspectAccountMove(() =>
|
|
2508
|
+
client.moveProspectAccount(accountId, prospectId, { ...request, apply: false }));
|
|
2509
|
+
|
|
2510
|
+
if (!values.apply) {
|
|
2511
|
+
if (values.json) writeJson(context.stdout, preview.payload);
|
|
2512
|
+
else renderProspectAccountMove(preview.payload, context, { applying: false });
|
|
2513
|
+
return preview.rejected ? 1 : 0;
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
if (preview.rejected || preview.payload?.success !== true || preview.payload?.eligible !== true || !preview.payload?.manifest_digest) {
|
|
2517
|
+
if (values.json) writeJson(context.stdout, preview.payload);
|
|
2518
|
+
else renderProspectAccountMove(preview.payload, context, { applying: true });
|
|
2519
|
+
return 1;
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
const final = await performProspectAccountMove(() => client.moveProspectAccount(accountId, prospectId, {
|
|
2523
|
+
...request,
|
|
2524
|
+
apply: true,
|
|
2525
|
+
manifest_digest: preview.payload.manifest_digest
|
|
2526
|
+
}));
|
|
2527
|
+
if (values.json) writeJson(context.stdout, final.payload);
|
|
2528
|
+
else renderProspectAccountMove(final.payload, context, { applying: true });
|
|
2529
|
+
|
|
2530
|
+
return final.rejected || final.payload?.applied !== true ? 1 : 0;
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2399
2533
|
async function prospectsReplan(args, context, { accountOverride } = {}) {
|
|
2400
2534
|
const { values, positionals } = parseCommandArgs(args, {
|
|
2401
2535
|
...jsonOptions(),
|
|
@@ -3271,6 +3405,28 @@ async function analyticsDashboard(args, context, { accountOverride } = {}) {
|
|
|
3271
3405
|
renderAnalyticsDashboard(payload, context);
|
|
3272
3406
|
}
|
|
3273
3407
|
|
|
3408
|
+
async function analyticsMotions(args, context, { accountOverride } = {}) {
|
|
3409
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
3410
|
+
if (positionals.length > 0) throw new CommandError(ANALYTICS_MOTIONS_USAGE);
|
|
3411
|
+
|
|
3412
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
3413
|
+
const payload = await client.analyticsMotions(accountId);
|
|
3414
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
3415
|
+
|
|
3416
|
+
renderAnalyticsMotions(payload, context);
|
|
3417
|
+
}
|
|
3418
|
+
|
|
3419
|
+
async function analyticsIcps(args, context, { accountOverride } = {}) {
|
|
3420
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
3421
|
+
if (positionals.length > 0) throw new CommandError(ANALYTICS_ICPS_USAGE);
|
|
3422
|
+
|
|
3423
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
3424
|
+
const payload = await client.analyticsIcps(accountId);
|
|
3425
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
3426
|
+
|
|
3427
|
+
renderAnalyticsIcps(payload, context);
|
|
3428
|
+
}
|
|
3429
|
+
|
|
3274
3430
|
async function analyticsMetrics(args, context, { accountOverride } = {}) {
|
|
3275
3431
|
const { values, positionals } = parseCommandArgs(args, analyticsMetricsOptions());
|
|
3276
3432
|
if (positionals.length > 0) throw new CommandError(ANALYTICS_METRICS_USAGE);
|
|
@@ -4571,6 +4727,77 @@ function renderUserActivity(payload, context) {
|
|
|
4571
4727
|
}
|
|
4572
4728
|
}
|
|
4573
4729
|
|
|
4730
|
+
function renderUserAutomation(payload, context) {
|
|
4731
|
+
const accountUser = payload?.account_user || {};
|
|
4732
|
+
const socialCookie = payload?.social_cookie || {};
|
|
4733
|
+
const snapshot = payload?.current || payload?.after || {};
|
|
4734
|
+
const mode = payload?.applied === true ? "applied" : (payload?.preview === true ? "preview" : "current");
|
|
4735
|
+
const platform = socialCookie.service_identifier || "linkedin";
|
|
4736
|
+
|
|
4737
|
+
writeLine(
|
|
4738
|
+
context.stdout,
|
|
4739
|
+
`Automation ${mode}: ${accountUserLabel(accountUser)} | ${platform} | policy ${display(snapshot.policy_source, "unknown")}`
|
|
4740
|
+
);
|
|
4741
|
+
renderUserAutomationSchedule(snapshot, context);
|
|
4742
|
+
renderUserAutomationControls(snapshot, context);
|
|
4743
|
+
renderUserAutomationLimits(snapshot?.limits, context);
|
|
4744
|
+
|
|
4745
|
+
if (payload?.preview === true) {
|
|
4746
|
+
writeLine(context.stdout, "No changes applied. Review the preview, then rerun with --apply.");
|
|
4747
|
+
} else if (payload?.applied === true && payload?.audit_id) {
|
|
4748
|
+
writeLine(context.stdout, `Audit: ${payload.audit_id}`);
|
|
4749
|
+
}
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
function renderUserAutomationSchedule(snapshot, context) {
|
|
4753
|
+
if (!snapshot?.time_zone && snapshot?.in_working_hours === undefined) return;
|
|
4754
|
+
|
|
4755
|
+
const parts = [display(snapshot.time_zone, "unknown timezone")];
|
|
4756
|
+
if (snapshot.in_working_hours !== undefined) {
|
|
4757
|
+
parts.push(snapshot.in_working_hours ? "in working hours" : "outside working hours");
|
|
4758
|
+
}
|
|
4759
|
+
if (snapshot.today_window?.summary) parts.push(`today ${snapshot.today_window.summary}`);
|
|
4760
|
+
writeLine(context.stdout, `Schedule: ${parts.join(" | ")}`);
|
|
4761
|
+
}
|
|
4762
|
+
|
|
4763
|
+
function renderUserAutomationControls(snapshot, context) {
|
|
4764
|
+
const controls = snapshot?.controls || {};
|
|
4765
|
+
const entries = [
|
|
4766
|
+
["automatic sending", controls.automatic_sending_enabled],
|
|
4767
|
+
["visibility operations", controls.visibility_operations_autopilot_enabled],
|
|
4768
|
+
["risk cooldown", snapshot?.risk_cooldown_enabled]
|
|
4769
|
+
].filter(([, enabled]) => enabled !== undefined);
|
|
4770
|
+
if (entries.length === 0) return;
|
|
4771
|
+
|
|
4772
|
+
writeLine(context.stdout, `Controls: ${entries.map(([label, enabled]) => `${label} ${enabled ? "on" : "off"}`).join(" | ")}`);
|
|
4773
|
+
}
|
|
4774
|
+
|
|
4775
|
+
function renderUserAutomationLimits(limits, context) {
|
|
4776
|
+
const categories = Array.isArray(limits?.categories) ? limits.categories : [];
|
|
4777
|
+
const categorySummaries = categories.map(automationDailyLimitSummary).filter(Boolean);
|
|
4778
|
+
if (categorySummaries.length > 0) {
|
|
4779
|
+
writeLine(context.stdout, `Daily category limits: ${categorySummaries.join(" | ")}`);
|
|
4780
|
+
}
|
|
4781
|
+
|
|
4782
|
+
const aggregateSummary = automationDailyLimitSummary(limits?.aggregate_visibility);
|
|
4783
|
+
if (aggregateSummary) writeLine(context.stdout, `Aggregate visibility: ${aggregateSummary.replace(/^Aggregate visibility\s+/i, "")}`);
|
|
4784
|
+
|
|
4785
|
+
const bindingLimits = Array.isArray(limits?.binding_limits) ? limits.binding_limits.filter(Boolean) : [];
|
|
4786
|
+
if (bindingLimits.length > 0) writeLine(context.stdout, `Binding limits: ${bindingLimits.join(", ")}`);
|
|
4787
|
+
}
|
|
4788
|
+
|
|
4789
|
+
function automationDailyLimitSummary(limit) {
|
|
4790
|
+
if (!limit || typeof limit !== "object") return null;
|
|
4791
|
+
|
|
4792
|
+
const label = display(limit.label || limit.category, "Limit");
|
|
4793
|
+
const used = limit.used?.daily ?? limit.usage?.daily;
|
|
4794
|
+
const effective = limit.effective?.daily;
|
|
4795
|
+
const remaining = limit.remaining?.daily;
|
|
4796
|
+
if (used === undefined && effective === undefined && remaining === undefined) return null;
|
|
4797
|
+
|
|
4798
|
+
return `${label} ${display(used, "?")}/${display(effective, "?")} daily (${display(remaining, "?")} remaining)`;
|
|
4799
|
+
}
|
|
4800
|
+
|
|
4574
4801
|
function renderSetupPlayPreflight(payload, context) {
|
|
4575
4802
|
const accountUser = payload?.account_user || {};
|
|
4576
4803
|
const socialCookie = payload?.social_cookie || null;
|
|
@@ -4581,6 +4808,7 @@ function renderSetupPlayPreflight(payload, context) {
|
|
|
4581
4808
|
`Setup preflight: ${display(payload?.platform, "linkedin")} for ${display(accountUser.name || accountUser.email)} (${display(accountUser.id)})`
|
|
4582
4809
|
);
|
|
4583
4810
|
writeLine(context.stdout, `Status: ${payload?.ready ? "ready" : "blocked"} (${display(payload?.reason, "unknown")})`);
|
|
4811
|
+
renderSetupUserLocation(accountUser.location, context);
|
|
4584
4812
|
|
|
4585
4813
|
if (socialCookie) {
|
|
4586
4814
|
writeLine(
|
|
@@ -4590,6 +4818,7 @@ function renderSetupPlayPreflight(payload, context) {
|
|
|
4590
4818
|
writeLine(context.stdout, `Connection status: ${display(socialCookie.status)}`);
|
|
4591
4819
|
writeLine(context.stdout, `Mapped to account: ${socialCookie.accessible_to_account ? "yes" : "no"}`);
|
|
4592
4820
|
writeLine(context.stdout, `Actionable: ${socialCookie.actionable ? "yes" : "no"}`);
|
|
4821
|
+
renderSetupProxyLocation(socialCookie.proxy_location, context);
|
|
4593
4822
|
renderSetupAutomationSummary(socialCookie.automation || {}, context);
|
|
4594
4823
|
} else {
|
|
4595
4824
|
writeLine(context.stdout, "Connected account: none");
|
|
@@ -4614,6 +4843,101 @@ function renderSetupAutomationSummary(automation, context) {
|
|
|
4614
4843
|
];
|
|
4615
4844
|
|
|
4616
4845
|
writeLine(context.stdout, `Automation: ${summary.join(", ")}`);
|
|
4846
|
+
if (automation.time_zone || automation.today_window || automation.in_working_hours !== undefined) {
|
|
4847
|
+
writeLine(
|
|
4848
|
+
context.stdout,
|
|
4849
|
+
[
|
|
4850
|
+
`Working hours: ${display(automation.time_zone, "unknown timezone")}`,
|
|
4851
|
+
`today ${display(automation.today_window?.summary, "unknown")}`,
|
|
4852
|
+
`currently ${automation.in_working_hours ? "inside" : "outside"}`
|
|
4853
|
+
].join(", ")
|
|
4854
|
+
);
|
|
4855
|
+
}
|
|
4856
|
+
renderSetupPacingSummary(automation.pacing, context);
|
|
4857
|
+
}
|
|
4858
|
+
|
|
4859
|
+
function renderSetupUserLocation(location, context) {
|
|
4860
|
+
const country = location?.country_code || "not configured";
|
|
4861
|
+
const place = [location?.city, location?.state_code].filter(Boolean).join(", ");
|
|
4862
|
+
const details = [place, location?.time_zone].filter(Boolean).join("; ");
|
|
4863
|
+
writeLine(context.stdout, `User location: ${country}${details ? ` (${details})` : ""}`);
|
|
4864
|
+
}
|
|
4865
|
+
|
|
4866
|
+
function renderSetupProxyLocation(proxyLocation, context) {
|
|
4867
|
+
const configured = proxyLocation?.configured || {};
|
|
4868
|
+
const configuredCountry = configured.country_code || "not configured";
|
|
4869
|
+
const configuredPlace = [configured.city, configured.state_code].filter(Boolean).join(", ");
|
|
4870
|
+
const configuredDetails = [configuredPlace, configured.postal_code].filter(Boolean).join(" ");
|
|
4871
|
+
writeLine(
|
|
4872
|
+
context.stdout,
|
|
4873
|
+
`Cookie proxy location: ${configuredCountry}${configuredDetails ? ` (${configuredDetails})` : ""}`
|
|
4874
|
+
);
|
|
4875
|
+
|
|
4876
|
+
const effective = proxyLocation?.effective || {};
|
|
4877
|
+
const effectivePlace = [effective.country_code, effective.region, effective.city].filter(Boolean).join(", ");
|
|
4878
|
+
if (!effectivePlace && proxyLocation?.source && proxyLocation.source !== "unavailable") {
|
|
4879
|
+
writeLine(context.stdout, `Effective proxy: not verified (${proxyLocation.source})`);
|
|
4880
|
+
return;
|
|
4881
|
+
}
|
|
4882
|
+
if (!effectivePlace || proxyLocation?.source === "unavailable") {
|
|
4883
|
+
writeLine(context.stdout, "Effective proxy: unavailable");
|
|
4884
|
+
return;
|
|
4885
|
+
}
|
|
4886
|
+
|
|
4887
|
+
const evidence = [proxyLocation?.source, effective.checked_at ? `checked ${effective.checked_at}` : null]
|
|
4888
|
+
.filter(Boolean)
|
|
4889
|
+
.join("; ");
|
|
4890
|
+
writeLine(context.stdout, `Effective proxy: ${effectivePlace}${evidence ? ` (${evidence})` : ""}`);
|
|
4891
|
+
}
|
|
4892
|
+
|
|
4893
|
+
function renderSetupPacingSummary(pacing, context) {
|
|
4894
|
+
if (!pacing) return;
|
|
4895
|
+
|
|
4896
|
+
const quotas = pacing.weekly_quotas || {};
|
|
4897
|
+
writeLine(
|
|
4898
|
+
context.stdout,
|
|
4899
|
+
[
|
|
4900
|
+
`Weekly quotas: profile visits ${formatSetupQuota(quotas.profile_visits)}`,
|
|
4901
|
+
`invitations ${formatSetupQuota(quotas.invitations)}`,
|
|
4902
|
+
`messages ${formatSetupQuota(quotas.messages)}`
|
|
4903
|
+
].join(", ")
|
|
4904
|
+
);
|
|
4905
|
+
const motionActiveDays = Array.isArray(pacing.motion_active_days) ? pacing.motion_active_days : [];
|
|
4906
|
+
writeLine(context.stdout, `Motion active days: ${motionActiveDays.join(", ") || "none"}`);
|
|
4907
|
+
writeLine(context.stdout, `Outstanding invitation cap: ${display(pacing.outstanding_invitation_cap)}`);
|
|
4908
|
+
|
|
4909
|
+
const ramp = pacing.ramp_config || {};
|
|
4910
|
+
writeLine(
|
|
4911
|
+
context.stdout,
|
|
4912
|
+
`Invitation ramp: ${display(ramp.starting_daily_invitations)}/day start, +${display(ramp.weekly_increment)}/week`
|
|
4913
|
+
);
|
|
4914
|
+
|
|
4915
|
+
const current = pacing.current || {};
|
|
4916
|
+
const inventoryBlocked = Boolean(current.inventory_blocking_reason);
|
|
4917
|
+
writeLine(
|
|
4918
|
+
context.stdout,
|
|
4919
|
+
[
|
|
4920
|
+
`${inventoryBlocked ? "Invitation pacing headroom" : "Invitation capacity"}: ${display(current.daily_usage)} used today`,
|
|
4921
|
+
`${display(current.daily_target)} daily target`,
|
|
4922
|
+
`${display(current.ramp_limit_today)} ramp limit today`,
|
|
4923
|
+
`${display(current.effective_available)} ${inventoryBlocked ? "headroom" : "available"} (binding: ${display(current.binding_constraint)})`
|
|
4924
|
+
].join(", ")
|
|
4925
|
+
);
|
|
4926
|
+
if (current.current_outstanding !== undefined || current.remaining_outstanding_slots !== undefined) {
|
|
4927
|
+
writeLine(
|
|
4928
|
+
context.stdout,
|
|
4929
|
+
`Outstanding invitations: ${display(current.current_outstanding)} current, ${display(current.remaining_outstanding_slots)} slots remaining`
|
|
4930
|
+
);
|
|
4931
|
+
}
|
|
4932
|
+
if (current.inventory_blocking_reason) {
|
|
4933
|
+
writeLine(context.stdout, `Invitation inventory: blocked (${current.inventory_blocking_reason})`);
|
|
4934
|
+
}
|
|
4935
|
+
}
|
|
4936
|
+
|
|
4937
|
+
function formatSetupQuota(value) {
|
|
4938
|
+
if (value === null) return "unlimited";
|
|
4939
|
+
if (value === undefined) return "unknown";
|
|
4940
|
+
return display(value);
|
|
4617
4941
|
}
|
|
4618
4942
|
|
|
4619
4943
|
function renderCountRows(context, label, rows) {
|
|
@@ -4647,13 +4971,14 @@ function renderOffer(offer, context) {
|
|
|
4647
4971
|
function renderIcps(icps, context) {
|
|
4648
4972
|
if (!Array.isArray(icps) || icps.length === 0) return writeLine(context.stdout, "No ICPs found.");
|
|
4649
4973
|
|
|
4650
|
-
writeLine(context.stdout, "ICP ID\tNAME\tTAGS\tDISCOVERY KEYWORD\tSENIORITY MODE\tAGENT");
|
|
4974
|
+
writeLine(context.stdout, "ICP ID\tNAME\tSTATUS\tTAGS\tDISCOVERY KEYWORD\tSENIORITY MODE\tAGENT");
|
|
4651
4975
|
for (const icp of icps) {
|
|
4652
4976
|
writeLine(
|
|
4653
4977
|
context.stdout,
|
|
4654
4978
|
[
|
|
4655
4979
|
display(icp.prefix_id),
|
|
4656
4980
|
display(icp.name),
|
|
4981
|
+
icp.archived === true ? "archived" : "active",
|
|
4657
4982
|
display(Array.isArray(icp.tags) && icp.tags.length > 0 ? icp.tags.join(",") : "-"),
|
|
4658
4983
|
display(icp.discovery_keyword),
|
|
4659
4984
|
display(icp.seniority_match_mode),
|
|
@@ -4665,6 +4990,7 @@ function renderIcps(icps, context) {
|
|
|
4665
4990
|
|
|
4666
4991
|
function renderIcp(icp, context) {
|
|
4667
4992
|
writeLine(context.stdout, `ICP: ${display(icp?.name)} (${display(icp?.prefix_id)})`);
|
|
4993
|
+
writeLine(context.stdout, `Status: ${icp?.archived === true ? "archived" : "active"}`);
|
|
4668
4994
|
if (Array.isArray(icp?.tags)) writeLine(context.stdout, `Tags: ${display(icp.tags.join(", "), "-")}`);
|
|
4669
4995
|
if (icp?.notes) writeLine(context.stdout, `Notes: ${icp.notes}`);
|
|
4670
4996
|
if (icp?.discovery_keyword) writeLine(context.stdout, `Discovery keyword: ${icp.discovery_keyword}`);
|
|
@@ -4672,6 +4998,19 @@ function renderIcp(icp, context) {
|
|
|
4672
4998
|
if (icp?.agent?.name) writeLine(context.stdout, `Agent: ${icp.agent.name}`);
|
|
4673
4999
|
}
|
|
4674
5000
|
|
|
5001
|
+
function writeIcpLifecycleEffects(result, context) {
|
|
5002
|
+
const motions = Array.isArray(result?.primary_motions) ? result.primary_motions : [];
|
|
5003
|
+
if (motions.length > 0) {
|
|
5004
|
+
const counts = new Map();
|
|
5005
|
+
for (const motion of motions) counts.set(motion.status, (counts.get(motion.status) || 0) + 1);
|
|
5006
|
+
const summary = [...counts.entries()].map(([status, count]) => `${count} ${status}`).join(", ");
|
|
5007
|
+
writeLine(context.stdout, `Primary motions: ${summary}.`);
|
|
5008
|
+
} else {
|
|
5009
|
+
writeLine(context.stdout, "Primary motions: none.");
|
|
5010
|
+
}
|
|
5011
|
+
writeLine(context.stdout, `Secondary motion links preserved: ${display(result?.secondary_motion_count, 0)}.`);
|
|
5012
|
+
}
|
|
5013
|
+
|
|
4675
5014
|
function renderCompanies(payload, context) {
|
|
4676
5015
|
const companies = Array.isArray(payload?.companies) ? payload.companies : [];
|
|
4677
5016
|
if (companies.length === 0) return writeLine(context.stdout, "No companies found.");
|
|
@@ -4751,6 +5090,93 @@ async function performBulkMutation(perform) {
|
|
|
4751
5090
|
}
|
|
4752
5091
|
}
|
|
4753
5092
|
|
|
5093
|
+
async function performProspectAccountMove(perform) {
|
|
5094
|
+
try {
|
|
5095
|
+
return { payload: await perform(), rejected: false };
|
|
5096
|
+
} catch (error) {
|
|
5097
|
+
const body = error instanceof ApiError && error.body && typeof error.body === "object" ? error.body : null;
|
|
5098
|
+
if (body && (body.schema_version !== undefined || body.error_kind !== undefined)) {
|
|
5099
|
+
return { payload: body, rejected: true };
|
|
5100
|
+
}
|
|
5101
|
+
throw error;
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
|
|
5105
|
+
function renderProspectAccountMove(payload, context, { applying }) {
|
|
5106
|
+
const phase = payload?.applied ? "applied" : "preview";
|
|
5107
|
+
writeLine(context.stdout, `Move account ${phase} for ${entityLabel(payload?.prospect)}.`);
|
|
5108
|
+
writeLine(context.stdout, `Source: ${entityLabel(payload?.source)}`);
|
|
5109
|
+
writeLine(context.stdout, `Target: ${entityLabel(payload?.target)}`);
|
|
5110
|
+
writeLine(context.stdout, `Eligible: ${payload?.eligible ? "yes" : "no"}`);
|
|
5111
|
+
writeLine(context.stdout, `Applied: ${payload?.applied ? "yes" : "no"}`);
|
|
5112
|
+
|
|
5113
|
+
const source = payload?.source || {};
|
|
5114
|
+
const sourceLists = Array.isArray(source.lists) ? source.lists.map(entityLabel).filter(Boolean) : [];
|
|
5115
|
+
writeLine(context.stdout, `Current assignee: ${entityLabel(source.assigned_user) || "unassigned"}`);
|
|
5116
|
+
writeLine(context.stdout, `Current motion: ${entityLabel(source.motion) || "none"}`);
|
|
5117
|
+
writeLine(context.stdout, `Current lists: ${sourceLists.join(", ") || "none"}`);
|
|
5118
|
+
|
|
5119
|
+
const mappings = payload?.mappings || {};
|
|
5120
|
+
writeLine(context.stdout, `Assigned user: ${entityLabel(mappings.assigned_user) || "not mapped"}`);
|
|
5121
|
+
writeLine(context.stdout, `Target motion: ${entityLabel(mappings.motion) || "not mapped"}`);
|
|
5122
|
+
writeLine(context.stdout, `Target list: ${entityLabel(mappings.list) || "not mapped"}`);
|
|
5123
|
+
|
|
5124
|
+
renderProspectAccountMoveCounts("Last 30 days", payload?.summary_30_days, context);
|
|
5125
|
+
renderProspectAccountMoveCounts("All time", payload?.all_time_counts, context);
|
|
5126
|
+
|
|
5127
|
+
for (const [disposition, counts] of Object.entries(payload?.dispositions || {})) {
|
|
5128
|
+
renderProspectAccountMoveCounts(humanize(disposition), counts, context);
|
|
5129
|
+
}
|
|
5130
|
+
renderProspectAccountMoveExpectedState(payload?.expected_state, context);
|
|
5131
|
+
renderProspectAccountMoveIssues("Blockers", payload?.blockers, context);
|
|
5132
|
+
renderProspectAccountMoveIssues("Warnings", payload?.warnings, context);
|
|
5133
|
+
if (payload?.refresh?.status) {
|
|
5134
|
+
writeLine(context.stdout, `Refresh: ${display(payload.refresh.status)}`);
|
|
5135
|
+
}
|
|
5136
|
+
if (payload?.error) writeLine(context.stdout, `Error: ${singleLine(payload.error)}`);
|
|
5137
|
+
|
|
5138
|
+
if (!applying && payload?.success && !payload?.applied) {
|
|
5139
|
+
writeLine(context.stdout, "Run again with --apply to move this prospect.");
|
|
5140
|
+
} else if (applying && payload?.eligible !== true) {
|
|
5141
|
+
writeLine(context.stdout, "The preview is not eligible to apply.");
|
|
5142
|
+
} else if (applying && !payload?.applied) {
|
|
5143
|
+
writeLine(context.stdout, "The account move was not applied.");
|
|
5144
|
+
}
|
|
5145
|
+
}
|
|
5146
|
+
|
|
5147
|
+
function renderProspectAccountMoveCounts(label, counts, context) {
|
|
5148
|
+
if (!counts || typeof counts !== "object") return;
|
|
5149
|
+
|
|
5150
|
+
const entries = Object.entries(counts).filter(([, count]) => Number(count) !== 0);
|
|
5151
|
+
if (entries.length === 0) return;
|
|
5152
|
+
writeLine(context.stdout, `${label}: ${entries.map(([key, count]) => `${humanize(key)} ${display(count)}`).join(", ")}`);
|
|
5153
|
+
}
|
|
5154
|
+
|
|
5155
|
+
function renderProspectAccountMoveIssues(label, issues, context) {
|
|
5156
|
+
if (!Array.isArray(issues) || issues.length === 0) return;
|
|
5157
|
+
|
|
5158
|
+
writeLine(context.stdout, `${label}: ${issues.length}`);
|
|
5159
|
+
for (const issue of issues) {
|
|
5160
|
+
const message = typeof issue === "string" ? issue : issue?.message || issue?.error || issue?.reason || JSON.stringify(issue);
|
|
5161
|
+
writeLine(context.stdout, `- ${singleLine(message)}`);
|
|
5162
|
+
}
|
|
5163
|
+
}
|
|
5164
|
+
|
|
5165
|
+
function renderProspectAccountMoveExpectedState(expectedState, context) {
|
|
5166
|
+
if (!expectedState || typeof expectedState !== "object") return;
|
|
5167
|
+
|
|
5168
|
+
const source = expectedState.source || {};
|
|
5169
|
+
const target = expectedState.target || {};
|
|
5170
|
+
writeLine(
|
|
5171
|
+
context.stdout,
|
|
5172
|
+
`Expected source: account prospect ${source.account_prospect ? "present" : "absent"}, executable work ${source.executable_work ? "present" : "absent"}`
|
|
5173
|
+
);
|
|
5174
|
+
writeLine(
|
|
5175
|
+
context.stdout,
|
|
5176
|
+
`Expected target: account prospect ${target.account_prospect ? "present" : "absent"}, events ${display(target.event_count, 0)}`
|
|
5177
|
+
);
|
|
5178
|
+
}
|
|
5179
|
+
|
|
4754
5180
|
function renderBulkMutationResult(payload, context, { successLabel, zeroSuccessLabel }) {
|
|
4755
5181
|
const failed = Array.isArray(payload?.failed) ? payload.failed : [];
|
|
4756
5182
|
|
|
@@ -5966,6 +6392,132 @@ function renderAnalyticsDashboard(payload, context) {
|
|
|
5966
6392
|
writeCountTable(context, "Current pipeline stages", payload?.pipeline_stage_counts, ["STAGE", "COUNT"], countRow);
|
|
5967
6393
|
}
|
|
5968
6394
|
|
|
6395
|
+
function renderAnalyticsMotions(payload, context) {
|
|
6396
|
+
const current = payload?.current || {};
|
|
6397
|
+
const recent = payload?.recent || {};
|
|
6398
|
+
const totals = payload?.totals || {};
|
|
6399
|
+
|
|
6400
|
+
writeLine(context.stdout, "Motion portfolio analytics");
|
|
6401
|
+
writeLine(context.stdout, `Current prospects: ${integerLabel(current.total_count)}`);
|
|
6402
|
+
writeLine(context.stdout, `Last 7 days: ${integerLabel(recent.total_count)} (${motionAnalyticsWindowLabel(recent.window)})`);
|
|
6403
|
+
writeLine(context.stdout, `Motions: ${integerLabel(totals.motion_count)}`);
|
|
6404
|
+
writeLine(context.stdout, `Contributing motions: ${integerLabel(totals.contributing_motion_count)}`);
|
|
6405
|
+
writeLine(context.stdout, `Active without contribution: ${integerLabel(totals.active_without_contribution_count)}`);
|
|
6406
|
+
writeLine(context.stdout, `Current attribution uses the current motion association. Unattributed currently means ${display(current.unattributed_label, "No current motion")}.`);
|
|
6407
|
+
writeLine(context.stdout, `Last 7 days uses the recorded source motion. Unattributed means ${display(recent.unattributed_label, "No attributable source motion")}.`);
|
|
6408
|
+
|
|
6409
|
+
writeMotionMixTable(payload?.prospect_mix, context);
|
|
6410
|
+
writeMotionContributionTable(payload?.motions, context);
|
|
6411
|
+
}
|
|
6412
|
+
|
|
6413
|
+
function renderAnalyticsIcps(payload, context) {
|
|
6414
|
+
const current = payload?.current || {};
|
|
6415
|
+
const recent = payload?.recent || {};
|
|
6416
|
+
const totals = payload?.totals || {};
|
|
6417
|
+
|
|
6418
|
+
writeLine(context.stdout, "ICP portfolio analytics");
|
|
6419
|
+
writeLine(context.stdout, `Current prospects: ${integerLabel(current.total_count)}`);
|
|
6420
|
+
writeLine(context.stdout, `Last 7 days: ${integerLabel(recent.total_count)} (${motionAnalyticsWindowLabel(recent.window)})`);
|
|
6421
|
+
writeLine(context.stdout, `ICPs: ${integerLabel(totals.icp_count)}`);
|
|
6422
|
+
writeLine(context.stdout, `Contributing ICPs: ${integerLabel(totals.contributing_icp_count)}`);
|
|
6423
|
+
writeLine(context.stdout, `No recent contribution: ${integerLabel(totals.without_recent_contribution_count)}`);
|
|
6424
|
+
writeLine(context.stdout, `Current and last-seven-day counts use the recorded source ICP. Unattributed means ${display(current.unattributed_label, "No attributable source ICP")}.`);
|
|
6425
|
+
|
|
6426
|
+
writeIcpMixTable(payload?.prospect_mix, context);
|
|
6427
|
+
writeIcpContributionTable(payload?.icps, context);
|
|
6428
|
+
}
|
|
6429
|
+
|
|
6430
|
+
function writeIcpMixTable(rows, context) {
|
|
6431
|
+
const mix = Array.isArray(rows) ? rows : [];
|
|
6432
|
+
writeLine(context.stdout, "");
|
|
6433
|
+
writeLine(context.stdout, "Prospect mix");
|
|
6434
|
+
if (mix.length === 0) return writeLine(context.stdout, "None");
|
|
6435
|
+
|
|
6436
|
+
writeAlignedTable(context, ["ICP", "STATUS", "AGE", "CURRENT", "CURRENT %", "LAST 7 DAYS", "LAST 7 DAYS %"], mix.map((row) => [
|
|
6437
|
+
display(row?.name, "Unattributed"),
|
|
6438
|
+
row?.archived === true ? "archived" : (row?.id ? "active" : "-"),
|
|
6439
|
+
compactAgeLabel(row?.created_at, context.now()),
|
|
6440
|
+
display(row?.current?.count, 0),
|
|
6441
|
+
percentageLabel(row?.current?.percentage),
|
|
6442
|
+
display(row?.recent?.count, 0),
|
|
6443
|
+
percentageLabel(row?.recent?.percentage)
|
|
6444
|
+
]), { numericColumns: [false, false, false, true, true, true, true] });
|
|
6445
|
+
}
|
|
6446
|
+
|
|
6447
|
+
function writeIcpContributionTable(rows, context) {
|
|
6448
|
+
const icps = Array.isArray(rows) ? rows : [];
|
|
6449
|
+
writeLine(context.stdout, "");
|
|
6450
|
+
writeLine(context.stdout, "ICP contribution");
|
|
6451
|
+
if (icps.length === 0) return writeLine(context.stdout, "None");
|
|
6452
|
+
|
|
6453
|
+
writeAlignedTable(context, ["ICP", "ID", "STATUS", "MOTIONS", "CURRENT", "LAST 7 DAYS", "CONTRIBUTING"], icps.map((row) => [
|
|
6454
|
+
display(row?.name, "Unattributed"),
|
|
6455
|
+
display(row?.prefix_id, "-"),
|
|
6456
|
+
row?.archived === true ? "archived" : (row?.id ? "active" : "-"),
|
|
6457
|
+
display(row?.linked_motion_count, 0),
|
|
6458
|
+
display(row?.current_prospect_count, 0),
|
|
6459
|
+
display(row?.recent_prospect_count, 0),
|
|
6460
|
+
row?.contributing === true ? "yes" : "no"
|
|
6461
|
+
]), { numericColumns: [false, false, false, true, true, true, false] });
|
|
6462
|
+
}
|
|
6463
|
+
|
|
6464
|
+
function writeMotionMixTable(rows, context) {
|
|
6465
|
+
const mix = Array.isArray(rows) ? rows : [];
|
|
6466
|
+
writeLine(context.stdout, "");
|
|
6467
|
+
writeLine(context.stdout, "Prospect mix");
|
|
6468
|
+
if (mix.length === 0) return writeLine(context.stdout, "None");
|
|
6469
|
+
|
|
6470
|
+
writeAlignedTable(context, ["TYPE", "CURRENT", "CURRENT %", "LAST 7 DAYS", "LAST 7 DAYS %"], mix.map((row) => [
|
|
6471
|
+
display(row?.label || row?.key),
|
|
6472
|
+
display(row?.current?.count, 0),
|
|
6473
|
+
percentageLabel(row?.current?.percentage),
|
|
6474
|
+
display(row?.recent?.count, 0),
|
|
6475
|
+
percentageLabel(row?.recent?.percentage)
|
|
6476
|
+
]), { numericColumns: [false, true, true, true, true] });
|
|
6477
|
+
}
|
|
6478
|
+
|
|
6479
|
+
function writeMotionContributionTable(rows, context) {
|
|
6480
|
+
const motions = Array.isArray(rows) ? rows : [];
|
|
6481
|
+
writeLine(context.stdout, "");
|
|
6482
|
+
writeLine(context.stdout, "Motion contribution");
|
|
6483
|
+
if (motions.length === 0) return writeLine(context.stdout, "None");
|
|
6484
|
+
|
|
6485
|
+
writeAlignedTable(context, ["MOTION", "ID", "TYPE", "STATUS", "CURRENT", "LAST 7 DAYS", "CONTRIBUTING"], motions.map((row) => [
|
|
6486
|
+
display(row?.name, "Unattributed"),
|
|
6487
|
+
display(row?.prefix_id, "-"),
|
|
6488
|
+
display(row?.kind, "unattributed"),
|
|
6489
|
+
display(row?.status, "-"),
|
|
6490
|
+
display(row?.current_prospect_count, 0),
|
|
6491
|
+
display(row?.recent_prospect_count, 0),
|
|
6492
|
+
row?.contributing === true ? "yes" : "no"
|
|
6493
|
+
]), { numericColumns: [false, false, false, false, true, true, false] });
|
|
6494
|
+
}
|
|
6495
|
+
|
|
6496
|
+
function motionAnalyticsWindowLabel(window) {
|
|
6497
|
+
if (!window?.started_at || !window?.ended_at) return "rolling window";
|
|
6498
|
+
|
|
6499
|
+
return `${window.started_at} to ${window.ended_at}`;
|
|
6500
|
+
}
|
|
6501
|
+
|
|
6502
|
+
function integerLabel(value) {
|
|
6503
|
+
const number = Number(value);
|
|
6504
|
+
return Number.isFinite(number) ? number.toLocaleString("en-US") : display(value, 0);
|
|
6505
|
+
}
|
|
6506
|
+
|
|
6507
|
+
function compactAgeLabel(createdAt, now) {
|
|
6508
|
+
if (!createdAt) return "-";
|
|
6509
|
+
|
|
6510
|
+
const created = new Date(createdAt);
|
|
6511
|
+
const reference = now instanceof Date ? now : new Date(now);
|
|
6512
|
+
if (Number.isNaN(created.getTime()) || Number.isNaN(reference.getTime())) return "-";
|
|
6513
|
+
|
|
6514
|
+
const days = Math.max(0, Math.floor((reference.getTime() - created.getTime()) / 86_400_000));
|
|
6515
|
+
if (days < 30) return `${days}d`;
|
|
6516
|
+
if (days < 365) return `${Math.floor(days / 30)}mo`;
|
|
6517
|
+
|
|
6518
|
+
return `${Math.floor(days / 365)}y`;
|
|
6519
|
+
}
|
|
6520
|
+
|
|
5969
6521
|
function renderAnalyticsMetrics(payload, context) {
|
|
5970
6522
|
const cohort = payload?.cohort || {};
|
|
5971
6523
|
const summary = payload?.summary || {};
|
|
@@ -6873,6 +7425,8 @@ const HELP_TOPICS = new Map([
|
|
|
6873
7425
|
" audienti users list",
|
|
6874
7426
|
" audienti users select <account_user_id|email|name|me>",
|
|
6875
7427
|
" audienti users activity [account_user_id|me]",
|
|
7428
|
+
" audienti users automation show <account_user_id|me>",
|
|
7429
|
+
" audienti users automation update <account_user_id|me> --payload <file.json> [--apply]",
|
|
6876
7430
|
"",
|
|
6877
7431
|
" Motions / plays",
|
|
6878
7432
|
" audienti motions list",
|
|
@@ -6909,6 +7463,7 @@ const HELP_TOPICS = new Map([
|
|
|
6909
7463
|
" audienti prospects check [filters]",
|
|
6910
7464
|
" audienti prospects show <prsp_id>",
|
|
6911
7465
|
" audienti prospects assign <prsp_id> --assigned-user <id|me|unassign>",
|
|
7466
|
+
" audienti prospects move-account <prsp_id> --target-account <acct_id> [--apply]",
|
|
6912
7467
|
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected>",
|
|
6913
7468
|
" audienti prospects replan <prsp_id> [--apply]",
|
|
6914
7469
|
" audienti prospects reenrich <prsp_id> [--apply]",
|
|
@@ -6941,9 +7496,11 @@ const HELP_TOPICS = new Map([
|
|
|
6941
7496
|
" audienti offers show <offr_id>",
|
|
6942
7497
|
" audienti offers update <offr_id> [--name <text>]",
|
|
6943
7498
|
" audienti offers delete <offr_id> --confirm <yes|true|Y|y>",
|
|
6944
|
-
" audienti icps list [--tag <tag>]",
|
|
7499
|
+
" audienti icps list [--status <active|archived|all>] [--tag <tag>]",
|
|
6945
7500
|
" audienti icps show <icp_id>",
|
|
6946
7501
|
" audienti icps update <icp_id> [--tags <tag[,tag...]> | --payload <file.json>]",
|
|
7502
|
+
" audienti icps archive <icp_id>",
|
|
7503
|
+
" audienti icps restore <icp_id>",
|
|
6947
7504
|
" audienti icps add-tag <icp_id> <tag>",
|
|
6948
7505
|
" audienti icps remove-tag <icp_id> <tag>",
|
|
6949
7506
|
" audienti companies search --query <text>",
|
|
@@ -6965,6 +7522,7 @@ const HELP_TOPICS = new Map([
|
|
|
6965
7522
|
" audienti operator failed-drafts requeue <row_id>",
|
|
6966
7523
|
"",
|
|
6967
7524
|
" Analytics",
|
|
7525
|
+
" audienti analytics motions",
|
|
6968
7526
|
" audienti analytics prospects --window 24h",
|
|
6969
7527
|
" audienti analytics dashboard --play-tag <tag>",
|
|
6970
7528
|
" audienti analytics metrics --cohort-preset week-to-date",
|
|
@@ -6989,6 +7547,7 @@ const HELP_TOPICS = new Map([
|
|
|
6989
7547
|
" Inspect a prospect: audienti prospects show <prsp_id> --json",
|
|
6990
7548
|
" Preview a campaign: audienti writer test-run <prsp_id>",
|
|
6991
7549
|
" Analyze one motion: audienti motions analytics <motn_id>",
|
|
7550
|
+
" Audit motion mix: audienti analytics motions",
|
|
6992
7551
|
" Count one campaign: audienti analytics dashboard --play-tag <tag>",
|
|
6993
7552
|
" Inspect outcomes: audienti analytics metrics --cohort-preset week-to-date",
|
|
6994
7553
|
" Compare stage rates: audienti analytics stages --interval weekly",
|
|
@@ -7230,6 +7789,13 @@ const HELP_TOPICS = new Map([
|
|
|
7230
7789
|
" ready: true when the selected principal has a mapped, actionable platform account",
|
|
7231
7790
|
" reason: ready | needs_setup | needs_account_access | needs_reconnect",
|
|
7232
7791
|
" setup_url: direct operations URL for creating a connected account",
|
|
7792
|
+
" social_cookie.automation.active_days: normalized active day tokens used by server automation guards",
|
|
7793
|
+
" social_cookie.automation.working_hours: normalized timed windows by day token; omitted days are all-day or inactive based on active_days",
|
|
7794
|
+
" social_cookie.automation.time_zone: effective timezone used by server automation guards",
|
|
7795
|
+
" social_cookie.automation.in_working_hours: server-side current schedule decision",
|
|
7796
|
+
" account_user.location: configured user location used as the proxy fallback; unknown fields are null",
|
|
7797
|
+
" social_cookie.proxy_location: configured and last-verified effective proxy geography plus its source",
|
|
7798
|
+
" social_cookie.automation.pacing: effective LinkedIn quotas, ramp settings, invitation inventory authority, and current capacity",
|
|
7233
7799
|
" social_cookie.urls.mapping_url: owner URL for granting account access",
|
|
7234
7800
|
" social_cookie.urls.edit_url: operations URL for reconnect/settings review when mapped",
|
|
7235
7801
|
"",
|
|
@@ -7246,6 +7812,8 @@ const HELP_TOPICS = new Map([
|
|
|
7246
7812
|
" audienti users list [--json]",
|
|
7247
7813
|
" audienti users select <account_user_id|email|name|me>",
|
|
7248
7814
|
" audienti users activity [account_user_id|me] [--json]",
|
|
7815
|
+
" audienti users automation show <account_user_id|me> [--platform linkedin] [--json]",
|
|
7816
|
+
" audienti users automation update <account_user_id|me> --payload <file.json> [--apply] [--json]",
|
|
7249
7817
|
"",
|
|
7250
7818
|
"Status: implemented",
|
|
7251
7819
|
"",
|
|
@@ -7256,6 +7824,61 @@ const HELP_TOPICS = new Map([
|
|
|
7256
7824
|
" `principals` is accepted anywhere `users` is accepted"
|
|
7257
7825
|
].join("\n")],
|
|
7258
7826
|
|
|
7827
|
+
["users automation", [
|
|
7828
|
+
"Usage:",
|
|
7829
|
+
` ${USERS_AUTOMATION_SHOW_USAGE.slice("Usage: ".length)}`,
|
|
7830
|
+
` ${USERS_AUTOMATION_UPDATE_USAGE.slice("Usage: ".length)}`,
|
|
7831
|
+
"",
|
|
7832
|
+
"Status: implemented",
|
|
7833
|
+
"",
|
|
7834
|
+
"Purpose:",
|
|
7835
|
+
" Inspect or propose account-user-specific LinkedIn automation controls and safety limits.",
|
|
7836
|
+
" Updates preview by default. Only --apply requests persistence."
|
|
7837
|
+
].join("\n")],
|
|
7838
|
+
|
|
7839
|
+
["users automation show", [
|
|
7840
|
+
"Usage:",
|
|
7841
|
+
` ${USERS_AUTOMATION_SHOW_USAGE.slice("Usage: ".length)}`,
|
|
7842
|
+
"",
|
|
7843
|
+
"Status: implemented",
|
|
7844
|
+
"",
|
|
7845
|
+
"Purpose:",
|
|
7846
|
+
" Read the selected account user's configured and effective automation policy, current usage, remaining capacity, and binding limits.",
|
|
7847
|
+
"",
|
|
7848
|
+
"Behavior:",
|
|
7849
|
+
" platform defaults to linkedin and currently accepts linkedin only.",
|
|
7850
|
+
" JSON output is the unchanged server response.",
|
|
7851
|
+
"",
|
|
7852
|
+
"API:",
|
|
7853
|
+
" GET /api/v1/accounts/:account_id/users/:id/automation.json?platform=linkedin"
|
|
7854
|
+
].join("\n")],
|
|
7855
|
+
|
|
7856
|
+
["users automation update", [
|
|
7857
|
+
"Usage:",
|
|
7858
|
+
` ${USERS_AUTOMATION_UPDATE_USAGE.slice("Usage: ".length)}`,
|
|
7859
|
+
"",
|
|
7860
|
+
"Status: implemented",
|
|
7861
|
+
"",
|
|
7862
|
+
"Purpose:",
|
|
7863
|
+
" Preview or apply principal-specific LinkedIn controls and hourly, daily, or weekly safety limits.",
|
|
7864
|
+
"",
|
|
7865
|
+
"Behavior:",
|
|
7866
|
+
" The command does not persist without --apply.",
|
|
7867
|
+
" The CLI merges platform=linkedin and apply=false|true into the payload; those values cannot be overridden by the file.",
|
|
7868
|
+
" Omitted controls are preserved by the server. JSON output is the unchanged server response.",
|
|
7869
|
+
"",
|
|
7870
|
+
"Payload fields:",
|
|
7871
|
+
" automation_controls: automation booleans, including writing, contact, visibility, and risk-cooldown gates",
|
|
7872
|
+
" action_limits: hourly/daily/weekly caps keyed by profile_view, follow, like, invite, message, comment, or aggregate visibility",
|
|
7873
|
+
" visibility_ramp: enabled, starting_daily_limit, weekly_increment, and optional started_at",
|
|
7874
|
+
"",
|
|
7875
|
+
"Request body:",
|
|
7876
|
+
" { \"automation\": { ...payload, \"platform\": \"linkedin\", \"apply\": false } }",
|
|
7877
|
+
"",
|
|
7878
|
+
"API:",
|
|
7879
|
+
" PATCH /api/v1/accounts/:account_id/users/:id/automation.json?platform=linkedin"
|
|
7880
|
+
].join("\n")],
|
|
7881
|
+
|
|
7259
7882
|
["users list", [
|
|
7260
7883
|
"Usage:",
|
|
7261
7884
|
" audienti users list [--json] [--account <acct_id>]",
|
|
@@ -7420,12 +8043,15 @@ const HELP_TOPICS = new Map([
|
|
|
7420
8043
|
|
|
7421
8044
|
["icps", [
|
|
7422
8045
|
"Usage:",
|
|
7423
|
-
" audienti icps list [--tag <tag>] [--json]",
|
|
8046
|
+
" audienti icps list [--status <active|archived|all>] [--tag <tag>] [--json]",
|
|
7424
8047
|
" audienti icps show <icp_id> [--json]",
|
|
7425
8048
|
" audienti icps create (--name <text> | --payload <file.json>) [--json]",
|
|
7426
8049
|
" audienti icps update <icp_id> ([--tags <tag[,tag...]>] | --payload <file.json>) [--json]",
|
|
8050
|
+
" audienti icps analytics [--json]",
|
|
7427
8051
|
" audienti icps add-tag <icp_id> <tag> [--json]",
|
|
7428
8052
|
" audienti icps remove-tag <icp_id> <tag> [--json]",
|
|
8053
|
+
" audienti icps archive <icp_id> [--json]",
|
|
8054
|
+
" audienti icps restore <icp_id> [--json]",
|
|
7429
8055
|
"",
|
|
7430
8056
|
"Status: implemented",
|
|
7431
8057
|
"",
|
|
@@ -7433,13 +8059,31 @@ const HELP_TOPICS = new Map([
|
|
|
7433
8059
|
" List the ICPs available to the current account so an agent can choose icp_id for motion creation or targeting work."
|
|
7434
8060
|
].join("\n")],
|
|
7435
8061
|
|
|
8062
|
+
["icps analytics", [
|
|
8063
|
+
"Usage:",
|
|
8064
|
+
` ${ANALYTICS_ICPS_USAGE.slice("Usage: ".length)}`,
|
|
8065
|
+
"",
|
|
8066
|
+
"Status: implemented",
|
|
8067
|
+
"",
|
|
8068
|
+
"Purpose:",
|
|
8069
|
+
" Show the account ICP portfolio's current prospect source mix and rolling seven-day contribution.",
|
|
8070
|
+
"",
|
|
8071
|
+
"Attribution:",
|
|
8072
|
+
" Current and last-seven-day counts use the recorded source ICP and fall back to the current motion ICP only when source is blank.",
|
|
8073
|
+
" Unattributed means no attributable account source ICP.",
|
|
8074
|
+
"",
|
|
8075
|
+
"API:",
|
|
8076
|
+
" GET /api/v1/accounts/:account_id/analytics/icps.json"
|
|
8077
|
+
].join("\n")],
|
|
8078
|
+
|
|
7436
8079
|
["icps list", [
|
|
7437
8080
|
"Usage:",
|
|
7438
|
-
"
|
|
8081
|
+
` ${ICPS_LIST_USAGE.slice("Usage: ".length)}`,
|
|
7439
8082
|
"",
|
|
7440
8083
|
"Status: implemented",
|
|
7441
8084
|
"",
|
|
7442
8085
|
"Options:",
|
|
8086
|
+
" --status <active|archived|all> Default: active",
|
|
7443
8087
|
" --tag <tag> Filter locally to ICPs whose tags include the normalized tag",
|
|
7444
8088
|
"",
|
|
7445
8089
|
"API:",
|
|
@@ -7449,12 +8093,40 @@ const HELP_TOPICS = new Map([
|
|
|
7449
8093
|
" id: integer",
|
|
7450
8094
|
" prefix_id: icpp_",
|
|
7451
8095
|
" name: string",
|
|
8096
|
+
" archived: boolean",
|
|
8097
|
+
" archived_at: ISO-8601 string | null",
|
|
7452
8098
|
" notes: string | null",
|
|
7453
8099
|
" tags: [string]",
|
|
7454
8100
|
" discovery_keyword: string | null",
|
|
7455
8101
|
" agent: { id, name } | null"
|
|
7456
8102
|
].join("\n")],
|
|
7457
8103
|
|
|
8104
|
+
["icps archive", [
|
|
8105
|
+
"Usage:",
|
|
8106
|
+
` ${ICPS_ARCHIVE_USAGE.slice("Usage: ".length)}`,
|
|
8107
|
+
"",
|
|
8108
|
+
"Status: implemented",
|
|
8109
|
+
"",
|
|
8110
|
+
"Behavior:",
|
|
8111
|
+
" Hides the ICP from new selection. Active primary motions enter closing; inactive and transition primary motions archive; secondary links remain.",
|
|
8112
|
+
"",
|
|
8113
|
+
"API:",
|
|
8114
|
+
" POST /api/v1/accounts/:account_id/icps/:id/archive.json"
|
|
8115
|
+
].join("\n")],
|
|
8116
|
+
|
|
8117
|
+
["icps restore", [
|
|
8118
|
+
"Usage:",
|
|
8119
|
+
` ${ICPS_RESTORE_USAGE.slice("Usage: ".length)}`,
|
|
8120
|
+
"",
|
|
8121
|
+
"Status: implemented",
|
|
8122
|
+
"",
|
|
8123
|
+
"Behavior:",
|
|
8124
|
+
" Makes the ICP selectable again without reactivating any motion.",
|
|
8125
|
+
"",
|
|
8126
|
+
"API:",
|
|
8127
|
+
" POST /api/v1/accounts/:account_id/icps/:id/restore.json"
|
|
8128
|
+
].join("\n")],
|
|
8129
|
+
|
|
7458
8130
|
["icps create", [
|
|
7459
8131
|
"Usage:",
|
|
7460
8132
|
" audienti icps create (--name <text> [--notes <text>] [--discovery-keyword <text>] [--tags <tag[,tag...]>] | --payload <file.json>) [--json] [--account <acct_id>]",
|
|
@@ -8556,7 +9228,9 @@ const HELP_TOPICS = new Map([
|
|
|
8556
9228
|
"",
|
|
8557
9229
|
"Input shape:",
|
|
8558
9230
|
" motn_id: motn_ prefix id",
|
|
8559
|
-
" status: draft | preparing | active | paused | archived | optional",
|
|
9231
|
+
" status: draft | preparing | active | closing | paused | archived | optional",
|
|
9232
|
+
" principal_account_user_id: account user id | me | optional in payload mode",
|
|
9233
|
+
" list_id: list_ prefix id, numeric id, or null | optional in payload mode",
|
|
8560
9234
|
" tags: comma-separated tag list | optional",
|
|
8561
9235
|
" start-date: YYYY-MM-DD | none | optional",
|
|
8562
9236
|
" end-date: YYYY-MM-DD | none | optional",
|
|
@@ -8565,6 +9239,7 @@ const HELP_TOPICS = new Map([
|
|
|
8565
9239
|
"",
|
|
8566
9240
|
"Behavior:",
|
|
8567
9241
|
" Choose either --payload or simple flags. Updates only the provided fields. Use none to clear a schedule date or company cap. Sending --tags replaces the motion's full tag set.",
|
|
9242
|
+
" Payload mode can replace the motion principal and backing list. The principal must belong to the selected account; list_id null clears the backing list.",
|
|
8568
9243
|
" The company cap stops only new company discovery; existing company research, people discovery, prospect intake, and automation continue.",
|
|
8569
9244
|
" Payload mode supports outbound signal_rows or legacy signal_questions; supplied rows replace the motion's active ready signals.",
|
|
8570
9245
|
" posting_language is only supported on company-scope hiring signal rows; use topics for person discussion evidence.",
|
|
@@ -8735,6 +9410,7 @@ const HELP_TOPICS = new Map([
|
|
|
8735
9410
|
" audienti prospects check [--json|--csv] [filters]",
|
|
8736
9411
|
" audienti prospects show <prsp_id> [--json]",
|
|
8737
9412
|
" audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json]",
|
|
9413
|
+
" audienti prospects move-account <prsp_id> --target-account <acct_id> [--apply] [--json]",
|
|
8738
9414
|
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected> [--json]",
|
|
8739
9415
|
" audienti prospects replan <prsp_id> [--apply] [--json]",
|
|
8740
9416
|
" audienti prospects reenrich <prsp_id> [--profile <prof_id|citation_id>] [--apply] [--json]",
|
|
@@ -8886,6 +9562,30 @@ const HELP_TOPICS = new Map([
|
|
|
8886
9562
|
" }"
|
|
8887
9563
|
].join("\n")],
|
|
8888
9564
|
|
|
9565
|
+
["prospects move-account", [
|
|
9566
|
+
"Usage:",
|
|
9567
|
+
` ${PROSPECTS_MOVE_ACCOUNT_USAGE.slice("Usage: ".length)}`,
|
|
9568
|
+
"",
|
|
9569
|
+
"Status: implemented",
|
|
9570
|
+
"",
|
|
9571
|
+
"Purpose:",
|
|
9572
|
+
" Move one prospect and its account-scoped history between accounts where you are an administrator.",
|
|
9573
|
+
"",
|
|
9574
|
+
"Behavior:",
|
|
9575
|
+
" The command previews before applying and never applies an ineligible preview.",
|
|
9576
|
+
" Pass --apply to run a fresh preview, then apply that exact manifest digest.",
|
|
9577
|
+
" --account selects the source account; --target-account selects the destination.",
|
|
9578
|
+
" --json prints the final server response unchanged.",
|
|
9579
|
+
"",
|
|
9580
|
+
"Optional target mappings:",
|
|
9581
|
+
" --assigned-user <account_user_id|me>",
|
|
9582
|
+
" --target-motion <motn_id>",
|
|
9583
|
+
" --target-list <list_id>",
|
|
9584
|
+
"",
|
|
9585
|
+
"API:",
|
|
9586
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/move_account.json"
|
|
9587
|
+
].join("\n")],
|
|
9588
|
+
|
|
8889
9589
|
["prospects set-status", [
|
|
8890
9590
|
"Usage:",
|
|
8891
9591
|
` ${PROSPECTS_SET_STATUS_USAGE.slice("Usage: ".length)}`,
|
|
@@ -9752,6 +10452,8 @@ const HELP_TOPICS = new Map([
|
|
|
9752
10452
|
|
|
9753
10453
|
["analytics", [
|
|
9754
10454
|
"Usage:",
|
|
10455
|
+
" audienti analytics motions [--json]",
|
|
10456
|
+
" audienti analytics icps [--json]",
|
|
9755
10457
|
" audienti analytics prospects [--window 24h] [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--motion <motn_id>] [--list <list_id>] [--user <account_user_id|email|name|me>] [--json]",
|
|
9756
10458
|
" audienti analytics dashboard [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD] [--play-tag <tag>] [--motion <motn_id>] [--list <list_id>] [--json]",
|
|
9757
10459
|
" audienti analytics metrics [--cohort-start YYYY-MM-DD --cohort-end YYYY-MM-DD | --cohort-preset week-to-date] [--interval <daily|weekly>] [--user <account_user_id|email|name|me>] [--motion <motn_id>] [--play-tag <tag>] [--list <list_id>] [--offer <offr_id>] [--icp <icp_id>] [--social-cookie <scok_id>] [--platform <platform>] [--action <action_key>] [--outcome <success|failure|first_attempt_success|succeeded_after_retry|failed_without_retry|failed_after_retry|in_progress|unresolved>] [--json]",
|
|
@@ -9781,7 +10483,54 @@ const HELP_TOPICS = new Map([
|
|
|
9781
10483
|
" --user <account_user_id|email|name|me> Narrow analytics to one account user. For prospect analytics, this means prospects assigned to that account user. Email/name partials are accepted when they match exactly one account user.",
|
|
9782
10484
|
"",
|
|
9783
10485
|
"Output:",
|
|
9784
|
-
" Account-scoped analytics for prospects, campaign dashboard counts, users, visibility engagement, and ContentOps publishing."
|
|
10486
|
+
" Account-scoped analytics for the motion portfolio, ICP portfolio, prospects, campaign dashboard counts, users, visibility engagement, and ContentOps publishing."
|
|
10487
|
+
].join("\n")],
|
|
10488
|
+
|
|
10489
|
+
["analytics motions", [
|
|
10490
|
+
"Usage:",
|
|
10491
|
+
` ${ANALYTICS_MOTIONS_USAGE.slice("Usage: ".length)}`,
|
|
10492
|
+
"",
|
|
10493
|
+
"Status: implemented",
|
|
10494
|
+
"",
|
|
10495
|
+
"Purpose:",
|
|
10496
|
+
" Show the account motion portfolio's current prospect mix and rolling seven-day contribution.",
|
|
10497
|
+
"",
|
|
10498
|
+
"Attribution:",
|
|
10499
|
+
" Current counts use each prospect's current motion association; Unattributed means no current motion.",
|
|
10500
|
+
" Last-seven-day counts use the recorded source motion and fall back to the current motion only when source is blank.",
|
|
10501
|
+
" Recent Unattributed means no attributable account source motion.",
|
|
10502
|
+
"",
|
|
10503
|
+
"Output shape:",
|
|
10504
|
+
" current and recent: totals plus explicit attribution semantics",
|
|
10505
|
+
" totals: motion and contribution counts",
|
|
10506
|
+
" prospect_mix[]: overall and rolling-seven-day count and percentage by motion type",
|
|
10507
|
+
" motions[]: current and rolling-seven-day prospect counts for every account motion",
|
|
10508
|
+
"",
|
|
10509
|
+
"API:",
|
|
10510
|
+
" GET /api/v1/accounts/:account_id/analytics/motions.json"
|
|
10511
|
+
].join("\n")],
|
|
10512
|
+
|
|
10513
|
+
["analytics icps", [
|
|
10514
|
+
"Usage:",
|
|
10515
|
+
` ${ANALYTICS_ICPS_USAGE.slice("Usage: ".length)}`,
|
|
10516
|
+
"",
|
|
10517
|
+
"Status: implemented",
|
|
10518
|
+
"",
|
|
10519
|
+
"Purpose:",
|
|
10520
|
+
" Show the account ICP portfolio's current prospect source mix and rolling seven-day contribution.",
|
|
10521
|
+
"",
|
|
10522
|
+
"Attribution:",
|
|
10523
|
+
" Current and last-seven-day counts use the recorded source ICP and fall back to the current motion ICP only when source is blank.",
|
|
10524
|
+
" Unattributed means no attributable account source ICP.",
|
|
10525
|
+
"",
|
|
10526
|
+
"Output shape:",
|
|
10527
|
+
" current and recent: totals plus explicit attribution semantics",
|
|
10528
|
+
" totals: ICP and contribution counts",
|
|
10529
|
+
" prospect_mix[]: ICP created_at plus overall and rolling-seven-day count and percentage",
|
|
10530
|
+
" icps[]: ICP created_at plus current and rolling-seven-day prospect counts",
|
|
10531
|
+
"",
|
|
10532
|
+
"API:",
|
|
10533
|
+
" GET /api/v1/accounts/:account_id/analytics/icps.json"
|
|
9785
10534
|
].join("\n")],
|
|
9786
10535
|
|
|
9787
10536
|
["analytics dashboard", [
|