@audienti/cli 0.1.3 → 0.1.5
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 +23 -0
- package/README.md +36 -0
- package/install +62 -0
- package/package.json +3 -1
- package/skills/audienti/SKILL.md +60 -0
- package/src/api-client.js +30 -0
- package/src/cli.js +497 -10
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,29 @@ All notable changes to the Audienti CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.5] - 2026-07-11
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Add the `https://cli.audienti.com/install` curl installer backed by the public CLI mirror and npm package.
|
|
12
|
+
- Add `audienti operator next --done|--skip|--fail|--return` shortcuts for recording the current prospect next-move outcome without hand-building a payload file.
|
|
13
|
+
- Add `audienti prospects add-profile` and `audienti prospects report-bad-profile` for updating prospect profile channels through the same server paths used by the prospect show page.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Send fingerprinted `operator next` outcome shortcuts through the server-derived row contract so queue-row semantics stay on the API side.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Reject `audienti operator next --note` and `--occurred-at` unless an outcome flag is present.
|
|
22
|
+
|
|
23
|
+
## [0.1.4] - 2026-07-11
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- Add `audienti operator next --plan` for deterministic next-action plan output.
|
|
28
|
+
- Add `audienti analytics prospects`, `audienti analytics visibility`, and `audienti analytics content` for account-scoped operational analytics.
|
|
29
|
+
|
|
7
30
|
## [0.1.3] - 2026-07-11
|
|
8
31
|
|
|
9
32
|
### Changed
|
package/README.md
CHANGED
|
@@ -8,6 +8,13 @@ manage plays, import prospects, build lists, and work supported operator flows.
|
|
|
8
8
|
|
|
9
9
|
Requires Node.js 20 or newer.
|
|
10
10
|
|
|
11
|
+
```bash
|
|
12
|
+
curl -fsSL https://cli.audienti.com/install | bash
|
|
13
|
+
audienti --help
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Or install directly through npm:
|
|
17
|
+
|
|
11
18
|
```bash
|
|
12
19
|
npm install --global @audienti/cli
|
|
13
20
|
audienti --help
|
|
@@ -41,6 +48,35 @@ Use `--json` whenever another program or agent will consume the result. Inspect
|
|
|
41
48
|
the target state before mutations, and use the command-specific help before
|
|
42
49
|
creating, changing, or deleting data.
|
|
43
50
|
|
|
51
|
+
Common inspection commands:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
audienti operator next --plan
|
|
55
|
+
audienti prospects show <prsp_id> --json
|
|
56
|
+
audienti prospects list --profiles
|
|
57
|
+
audienti analytics prospects --window 24h
|
|
58
|
+
audienti analytics visibility --window 24h --user me
|
|
59
|
+
audienti analytics content --window week
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
To work the supported prospect operator queue from the CLI, inspect the next move
|
|
63
|
+
and record the outcome against that same row:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
audienti operator next --plan
|
|
67
|
+
audienti operator next --done --note "Connection request sent."
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
To update a prospect's attached profile channels through the same paths used by
|
|
71
|
+
the prospect show page:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
audienti prospects add-profile <prsp_id> --url prospect@example.com
|
|
75
|
+
audienti prospects add-profile <prsp_id> --url +12025550123
|
|
76
|
+
audienti prospects add-profile <prsp_id> --url https://www.linkedin.com/in/example
|
|
77
|
+
audienti prospects report-bad-profile <prsp_id> <prof_id>
|
|
78
|
+
```
|
|
79
|
+
|
|
44
80
|
## Compatibility
|
|
45
81
|
|
|
46
82
|
The CLI talks to the versioned Audienti `/api/v1` contract at
|
package/install
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
package="@audienti/cli"
|
|
5
|
+
binary="audienti"
|
|
6
|
+
minimum_node_major=20
|
|
7
|
+
|
|
8
|
+
say() {
|
|
9
|
+
printf '%s\n' "$*"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
fail() {
|
|
13
|
+
printf 'Audienti CLI install failed: %s\n' "$*" >&2
|
|
14
|
+
exit 1
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
require_command() {
|
|
18
|
+
if ! command -v "$1" >/dev/null 2>&1; then
|
|
19
|
+
fail "$2"
|
|
20
|
+
fi
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
require_command node "Node.js ${minimum_node_major} or newer is required. Install Node.js, then rerun this script."
|
|
24
|
+
require_command npm "npm is required. Install Node.js ${minimum_node_major} or newer with npm, then rerun this script."
|
|
25
|
+
|
|
26
|
+
node_major="$(node -p 'Number(process.versions.node.split(".")[0])' 2>/dev/null || true)"
|
|
27
|
+
case "$node_major" in
|
|
28
|
+
''|*[!0-9]*)
|
|
29
|
+
fail "could not determine the installed Node.js version."
|
|
30
|
+
;;
|
|
31
|
+
esac
|
|
32
|
+
|
|
33
|
+
if [ "$node_major" -lt "$minimum_node_major" ]; then
|
|
34
|
+
fail "Node.js ${minimum_node_major} or newer is required. Current version: $(node --version)."
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
say "Installing ${package}..."
|
|
38
|
+
npm install --global --no-audit --no-fund "$package"
|
|
39
|
+
|
|
40
|
+
global_prefix="$(npm prefix --global 2>/dev/null || true)"
|
|
41
|
+
if [ -n "$global_prefix" ] && [ -d "$global_prefix/bin" ]; then
|
|
42
|
+
export PATH="$global_prefix/bin:$PATH"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if ! command -v "$binary" >/dev/null 2>&1; then
|
|
46
|
+
if [ -n "$global_prefix" ] && [ -x "$global_prefix/bin/$binary" ]; then
|
|
47
|
+
fail "${binary} installed at ${global_prefix}/bin/${binary}, but that directory is not on PATH."
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
fail "${binary} was not found on PATH after installation."
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
"$binary" --help >/dev/null
|
|
54
|
+
|
|
55
|
+
cat <<'NEXT'
|
|
56
|
+
Audienti CLI installed.
|
|
57
|
+
|
|
58
|
+
Next:
|
|
59
|
+
audienti auth token <token>
|
|
60
|
+
audienti accounts list --json
|
|
61
|
+
audienti accounts select <acct_id>
|
|
62
|
+
NEXT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@audienti/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Agent-first command-line client for Audienti.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"bin/",
|
|
11
11
|
"src/",
|
|
12
|
+
"skills/",
|
|
13
|
+
"install",
|
|
12
14
|
"README.md",
|
|
13
15
|
"LICENSE",
|
|
14
16
|
"CHANGELOG.md"
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audienti
|
|
3
|
+
description: Use when the user wants to operate Audienti through the production CLI, including account selection, plays, prospect imports, lists, message previews, or supported operator outcomes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Audienti CLI
|
|
7
|
+
|
|
8
|
+
Use the installed `audienti` command as the production contract. Do not build a
|
|
9
|
+
parallel wrapper or call undocumented API endpoints.
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
1. Verify the command is installed:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
audienti --help
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. If it is unavailable, install the public package:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
curl -fsSL https://cli.audienti.com/install | bash
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3. Authentication is explicit and per machine. Do not ask a user to paste a
|
|
26
|
+
production token into chat, a repository file, an issue, or a CI secret. Use
|
|
27
|
+
the existing `audienti auth token` flow only after the user supplies a token
|
|
28
|
+
through an approved secure channel.
|
|
29
|
+
|
|
30
|
+
4. Start with discovery, not mutation:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
audienti auth status
|
|
34
|
+
audienti accounts list --json
|
|
35
|
+
audienti help agent-workflows
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Operating Rules
|
|
39
|
+
|
|
40
|
+
- Use `--json` whenever another agent or tool will consume the response.
|
|
41
|
+
- Use `audienti <resource> <action> help` before a mutation when the accepted
|
|
42
|
+
payload or behavior is unclear.
|
|
43
|
+
- Inspect the current resource before a create, update, attach, delete, or
|
|
44
|
+
operator outcome writeback.
|
|
45
|
+
- Treat the production API as the source of truth. Persist durable work in
|
|
46
|
+
Audienti rather than leaving it only in agent prose.
|
|
47
|
+
- Keep current gaps explicit. Do not imply that unsupported actions execute.
|
|
48
|
+
|
|
49
|
+
## Common Entry Points
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
audienti help agent-workflows
|
|
53
|
+
audienti prospects list --query "name or company" --wide --json
|
|
54
|
+
audienti lists create --name "Target list" --json
|
|
55
|
+
audienti operator next --json
|
|
56
|
+
audienti operator next --plan
|
|
57
|
+
audienti analytics prospects --window 24h --json
|
|
58
|
+
audienti analytics visibility --window 24h --user me --json
|
|
59
|
+
audienti analytics content --window week --json
|
|
60
|
+
```
|
package/src/api-client.js
CHANGED
|
@@ -189,6 +189,20 @@ export class AudientiClient {
|
|
|
189
189
|
});
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
addProspectProfile(accountId, prospectId, body) {
|
|
193
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "profiles"]), {
|
|
194
|
+
method: "POST",
|
|
195
|
+
body
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
reportBadProspectProfile(accountId, prospectId, body) {
|
|
200
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "report_bad_profile"]), {
|
|
201
|
+
method: "POST",
|
|
202
|
+
body
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
192
206
|
prospectImport(accountId, body) {
|
|
193
207
|
return this.requestJson(accountPath(accountId, ["prospect_imports"]), {
|
|
194
208
|
method: "POST",
|
|
@@ -215,6 +229,18 @@ export class AudientiClient {
|
|
|
215
229
|
});
|
|
216
230
|
}
|
|
217
231
|
|
|
232
|
+
analyticsProspects(accountId, query = {}) {
|
|
233
|
+
return this.requestJson(accountPath(accountId, ["analytics", "prospects"], query));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
analyticsVisibility(accountId, query = {}) {
|
|
237
|
+
return this.requestJson(accountPath(accountId, ["analytics", "visibility"], query));
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
analyticsContent(accountId, query = {}) {
|
|
241
|
+
return this.requestJson(accountPath(accountId, ["analytics", "content"], query));
|
|
242
|
+
}
|
|
243
|
+
|
|
218
244
|
async requestJson(path, { method = "GET", body } = {}) {
|
|
219
245
|
const response = await this.fetchImpl(new URL(path, `${this.host}/`), {
|
|
220
246
|
method,
|
|
@@ -296,6 +322,10 @@ function errorMessage(status, body) {
|
|
|
296
322
|
return "The requested Audienti resource was not found.";
|
|
297
323
|
}
|
|
298
324
|
|
|
325
|
+
if (status === 409) {
|
|
326
|
+
return body?.error || "Audienti rejected the request because the resource changed. Re-fetch and try again.";
|
|
327
|
+
}
|
|
328
|
+
|
|
299
329
|
if (status === 422) {
|
|
300
330
|
const reasons = [body?.errors, body?.details].find(Array.isArray);
|
|
301
331
|
const details = reasons?.length > 0 ? reasons.join(", ") : body?.error;
|
package/src/cli.js
CHANGED
|
@@ -26,6 +26,8 @@ const DEFAULT_PROFILE_IDENTIFIERS = [
|
|
|
26
26
|
const DELETE_CONFIRMATION_VALUES = new Set(["yes", "true", "y"]);
|
|
27
27
|
const PROSPECTS_ADD_NOTE_USAGE = "Usage: audienti prospects add-note <prsp_id> (--message <text> [--type <note|steer|voicemail_outreach|video_outreach>] [--engagement-type <key>] | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
28
28
|
const PROSPECTS_ADD_STEER_USAGE = "Usage: audienti prospects add-steer <prsp_id> (--message <text> [--engagement-type <key>] | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
29
|
+
const PROSPECTS_ADD_PROFILE_USAGE = "Usage: audienti prospects add-profile <prsp_id> --url <profile_url|email|phone> [--json] [--account <acct_id>]";
|
|
30
|
+
const PROSPECTS_REPORT_BAD_PROFILE_USAGE = "Usage: audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json] [--account <acct_id>]";
|
|
29
31
|
const SEQUENCE_EXPORT_CSV_COLUMNS = [
|
|
30
32
|
"prospect_id",
|
|
31
33
|
"prospect_name",
|
|
@@ -114,6 +116,8 @@ async function dispatch(argv, context) {
|
|
|
114
116
|
if (normalizedResource === "prospects" && action === "write") return prospectsWrite(rest, context, { accountOverride });
|
|
115
117
|
if (normalizedResource === "prospects" && action === "add-note") return prospectsAddNote(rest, context, { accountOverride });
|
|
116
118
|
if (normalizedResource === "prospects" && action === "add-steer") return prospectsAddSteer(rest, context, { accountOverride });
|
|
119
|
+
if (normalizedResource === "prospects" && action === "add-profile") return prospectsAddProfile(rest, context, { accountOverride });
|
|
120
|
+
if (normalizedResource === "prospects" && action === "report-bad-profile") return prospectsReportBadProfile(rest, context, { accountOverride });
|
|
117
121
|
if (normalizedResource === "prospects" && action === "sequence-preview") return prospectsSequencePreview(rest, context, { accountOverride });
|
|
118
122
|
if (normalizedResource === "prospects" && action === "sequence-export") return prospectsSequenceExport(rest, context, { accountOverride });
|
|
119
123
|
if (normalizedResource === "prospects" && action === "import") return prospectsImport(rest, context, { accountOverride });
|
|
@@ -122,6 +126,9 @@ async function dispatch(argv, context) {
|
|
|
122
126
|
if (normalizedResource === "operator" && action === "queue") return operatorQueue(rest, context, { accountOverride });
|
|
123
127
|
if (normalizedResource === "operator" && action === "next") return operatorNext(rest, context, { accountOverride });
|
|
124
128
|
if (normalizedResource === "operator" && action === "outcome") return operatorOutcome(rest, context, { accountOverride });
|
|
129
|
+
if (normalizedResource === "analytics" && ["prospects", "prospect"].includes(action)) return analyticsProspects(rest, context, { accountOverride });
|
|
130
|
+
if (normalizedResource === "analytics" && ["visibility", "visops"].includes(action)) return analyticsVisibility(rest, context, { accountOverride });
|
|
131
|
+
if (normalizedResource === "analytics" && action === "content") return analyticsContent(rest, context, { accountOverride });
|
|
125
132
|
|
|
126
133
|
throw new CommandError(usage(), { exitCode: resource ? 1 : 0 });
|
|
127
134
|
}
|
|
@@ -858,6 +865,31 @@ async function prospectsAddSteer(args, context, { accountOverride } = {}) {
|
|
|
858
865
|
});
|
|
859
866
|
}
|
|
860
867
|
|
|
868
|
+
async function prospectsAddProfile(args, context, { accountOverride } = {}) {
|
|
869
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
870
|
+
...jsonOptions(),
|
|
871
|
+
url: { type: "string" }
|
|
872
|
+
});
|
|
873
|
+
if (positionals.length !== 1 || !values.url) throw new CommandError(PROSPECTS_ADD_PROFILE_USAGE);
|
|
874
|
+
|
|
875
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
876
|
+
const response = await client.addProspectProfile(accountId, positionals[0], { url: values.url });
|
|
877
|
+
if (values.json) return writeJson(context.stdout, response);
|
|
878
|
+
|
|
879
|
+
renderProspectProfileMutation(response, context, { action: "Added" });
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
async function prospectsReportBadProfile(args, context, { accountOverride } = {}) {
|
|
883
|
+
const { values, positionals } = parseCommandArgs(args, jsonOptions());
|
|
884
|
+
if (positionals.length !== 2) throw new CommandError(PROSPECTS_REPORT_BAD_PROFILE_USAGE);
|
|
885
|
+
|
|
886
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
887
|
+
const response = await client.reportBadProspectProfile(accountId, positionals[0], { profile_id: positionals[1] });
|
|
888
|
+
if (values.json) return writeJson(context.stdout, response);
|
|
889
|
+
|
|
890
|
+
renderProspectProfileMutation(response, context, { action: "Reported" });
|
|
891
|
+
}
|
|
892
|
+
|
|
861
893
|
async function prospectNoteCommand(args, context, { accountOverride, forcedType, usageText }) {
|
|
862
894
|
const { values, positionals } = parseCommandArgs(args, {
|
|
863
895
|
...jsonOptions(),
|
|
@@ -1010,7 +1042,7 @@ async function toolsGet(args, context, { accountOverride } = {}) {
|
|
|
1010
1042
|
}
|
|
1011
1043
|
|
|
1012
1044
|
async function operatorQueue(args, context, { accountOverride } = {}) {
|
|
1013
|
-
const { values, positionals } = parseCommandArgs(args,
|
|
1045
|
+
const { values, positionals } = parseCommandArgs(args, operatorFilterOptions());
|
|
1014
1046
|
if (positionals.length > 0) throw new CommandError("Usage: audienti operator queue [--json] [filters] [--account <acct_id>]");
|
|
1015
1047
|
|
|
1016
1048
|
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
@@ -1021,12 +1053,30 @@ async function operatorQueue(args, context, { accountOverride } = {}) {
|
|
|
1021
1053
|
}
|
|
1022
1054
|
|
|
1023
1055
|
async function operatorNext(args, context, { accountOverride } = {}) {
|
|
1024
|
-
const { values, positionals } = parseCommandArgs(args,
|
|
1025
|
-
if (positionals.length > 0) throw new CommandError("Usage: audienti operator next [--json] [filters] [--account <acct_id>]");
|
|
1056
|
+
const { values, positionals } = parseCommandArgs(args, operatorNextOptions());
|
|
1057
|
+
if (positionals.length > 0) throw new CommandError("Usage: audienti operator next [--json|--plan|--done|--skip|--fail|--return] [filters] [--note <text>] [--account <acct_id>]");
|
|
1058
|
+
if (values.json && values.plan) throw new CommandError("Choose one output format: use either --json or --plan.");
|
|
1059
|
+
const outcomeStatus = operatorNextOutcomeStatus(values);
|
|
1060
|
+
if (values.plan && outcomeStatus) throw new CommandError("Choose one mode: use either --plan or an outcome flag.");
|
|
1061
|
+
if (!outcomeStatus && (values.note !== undefined || values["occurred-at"] !== undefined)) {
|
|
1062
|
+
throw new CommandError("--note and --occurred-at require an outcome flag: --done, --skip, --fail, or --return.");
|
|
1063
|
+
}
|
|
1026
1064
|
|
|
1027
1065
|
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1028
1066
|
const payload = await client.operatorNext(accountId, operatorQuery(values));
|
|
1067
|
+
if (outcomeStatus) {
|
|
1068
|
+
const response = await client.operatorOutcome(accountId, operatorNextOutcomePayload(payload?.next_move, {
|
|
1069
|
+
status: outcomeStatus,
|
|
1070
|
+
note: values.note,
|
|
1071
|
+
occurredAt: values["occurred-at"],
|
|
1072
|
+
filters: payload?.filters
|
|
1073
|
+
}));
|
|
1074
|
+
if (values.json) return writeJson(context.stdout, response);
|
|
1075
|
+
|
|
1076
|
+
return renderOperatorOutcome(response, context);
|
|
1077
|
+
}
|
|
1029
1078
|
if (values.json) return writeJson(context.stdout, payload);
|
|
1079
|
+
if (values.plan) return renderOperatorPlan(payload?.next_move, context);
|
|
1030
1080
|
|
|
1031
1081
|
renderOperatorNext(payload?.next_move, context);
|
|
1032
1082
|
}
|
|
@@ -1051,6 +1101,39 @@ async function operatorOutcome(args, context, { accountOverride } = {}) {
|
|
|
1051
1101
|
renderOperatorOutcome(response, context);
|
|
1052
1102
|
}
|
|
1053
1103
|
|
|
1104
|
+
async function analyticsProspects(args, context, { accountOverride } = {}) {
|
|
1105
|
+
const { values, positionals } = parseCommandArgs(args, analyticsOptions());
|
|
1106
|
+
if (positionals.length > 0) throw new CommandError("Usage: audienti analytics prospects [--window 24h] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]");
|
|
1107
|
+
|
|
1108
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1109
|
+
const payload = await client.analyticsProspects(accountId, analyticsQuery(values));
|
|
1110
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1111
|
+
|
|
1112
|
+
renderAnalyticsProspects(payload, context);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
async function analyticsVisibility(args, context, { accountOverride } = {}) {
|
|
1116
|
+
const { values, positionals } = parseCommandArgs(args, analyticsOptions());
|
|
1117
|
+
if (positionals.length > 0) throw new CommandError("Usage: audienti analytics visibility [--window 24h] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]");
|
|
1118
|
+
|
|
1119
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1120
|
+
const payload = await client.analyticsVisibility(accountId, analyticsQuery(values));
|
|
1121
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1122
|
+
|
|
1123
|
+
renderAnalyticsVisibility(payload, context);
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
async function analyticsContent(args, context, { accountOverride } = {}) {
|
|
1127
|
+
const { values, positionals } = parseCommandArgs(args, analyticsOptions());
|
|
1128
|
+
if (positionals.length > 0) throw new CommandError("Usage: audienti analytics content [--window 24h] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]");
|
|
1129
|
+
|
|
1130
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1131
|
+
const payload = await client.analyticsContent(accountId, analyticsQuery(values));
|
|
1132
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1133
|
+
|
|
1134
|
+
renderAnalyticsContent(payload, context);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1054
1137
|
function parseCommandArgs(args, options) {
|
|
1055
1138
|
try {
|
|
1056
1139
|
return parseArgs({
|
|
@@ -1106,7 +1189,7 @@ function jsonOptions() {
|
|
|
1106
1189
|
};
|
|
1107
1190
|
}
|
|
1108
1191
|
|
|
1109
|
-
function
|
|
1192
|
+
function operatorFilterOptions(extra = {}) {
|
|
1110
1193
|
return {
|
|
1111
1194
|
...jsonOptions(),
|
|
1112
1195
|
principal: { type: "string" },
|
|
@@ -1114,10 +1197,23 @@ function operatorOptions() {
|
|
|
1114
1197
|
list: { type: "string" },
|
|
1115
1198
|
stage: { type: "string" },
|
|
1116
1199
|
"opportunity-kind": { type: "string" },
|
|
1117
|
-
"writing-status": { type: "string" }
|
|
1200
|
+
"writing-status": { type: "string" },
|
|
1201
|
+
...extra
|
|
1118
1202
|
};
|
|
1119
1203
|
}
|
|
1120
1204
|
|
|
1205
|
+
function operatorNextOptions() {
|
|
1206
|
+
return operatorFilterOptions({
|
|
1207
|
+
plan: { type: "boolean" },
|
|
1208
|
+
done: { type: "boolean" },
|
|
1209
|
+
skip: { type: "boolean" },
|
|
1210
|
+
fail: { type: "boolean" },
|
|
1211
|
+
return: { type: "boolean" },
|
|
1212
|
+
note: { type: "string" },
|
|
1213
|
+
"occurred-at": { type: "string" }
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1121
1217
|
function operatorQuery(values) {
|
|
1122
1218
|
return compactObject({
|
|
1123
1219
|
principal_account_user_id: values.principal,
|
|
@@ -1129,6 +1225,48 @@ function operatorQuery(values) {
|
|
|
1129
1225
|
});
|
|
1130
1226
|
}
|
|
1131
1227
|
|
|
1228
|
+
function operatorNextOutcomeStatus(values) {
|
|
1229
|
+
const selected = [
|
|
1230
|
+
values.done ? "done" : null,
|
|
1231
|
+
values.skip ? "skipped" : null,
|
|
1232
|
+
values.fail ? "failed" : null,
|
|
1233
|
+
values.return ? "returned" : null
|
|
1234
|
+
].filter(Boolean);
|
|
1235
|
+
if (selected.length > 1) throw new CommandError("Choose one outcome flag: --done, --skip, --fail, or --return.");
|
|
1236
|
+
|
|
1237
|
+
return selected[0];
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
function operatorNextOutcomePayload(row, { status, note, occurredAt, filters }) {
|
|
1241
|
+
if (!row) throw new CommandError("No operator moves found.");
|
|
1242
|
+
if (!row.id) throw new CommandError("The next operator move is missing a row id.");
|
|
1243
|
+
if (!row.fingerprint) throw new CommandError("The next operator move is missing a fingerprint; update the server before using outcome shortcuts.");
|
|
1244
|
+
|
|
1245
|
+
return compactObject({
|
|
1246
|
+
row_id: row.id,
|
|
1247
|
+
status,
|
|
1248
|
+
fingerprint: row.fingerprint,
|
|
1249
|
+
queue_filters: filters,
|
|
1250
|
+
note,
|
|
1251
|
+
occurred_at: occurredAt
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
function analyticsOptions() {
|
|
1256
|
+
return {
|
|
1257
|
+
...jsonOptions(),
|
|
1258
|
+
window: { type: "string" },
|
|
1259
|
+
user: { type: "string" }
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
function analyticsQuery(values) {
|
|
1264
|
+
return compactObject({
|
|
1265
|
+
window: values.window,
|
|
1266
|
+
account_user_id: values.user
|
|
1267
|
+
});
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1132
1270
|
function compactObject(object) {
|
|
1133
1271
|
return Object.fromEntries(
|
|
1134
1272
|
Object.entries(object).filter(([, value]) => value !== undefined && value !== null && String(value).trim() !== "")
|
|
@@ -1622,6 +1760,19 @@ function renderProspectNote(payload, context) {
|
|
|
1622
1760
|
}
|
|
1623
1761
|
}
|
|
1624
1762
|
|
|
1763
|
+
function renderProspectProfileMutation(payload, context, { action }) {
|
|
1764
|
+
const prospect = payload?.prospect || {};
|
|
1765
|
+
const profile = payload?.profile || {};
|
|
1766
|
+
const status = payload?.status ? ` (${payload.status})` : "";
|
|
1767
|
+
|
|
1768
|
+
writeLine(context.stdout, `${action} profile${status}.`);
|
|
1769
|
+
writeLine(context.stdout, `Prospect: ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)})`);
|
|
1770
|
+
writeLine(context.stdout, `Profile: ${display(profile.citation_id || profile.prefix_id)}`);
|
|
1771
|
+
if (profile.identifier) writeLine(context.stdout, `Type: ${profile.identifier}`);
|
|
1772
|
+
if (profile.username) writeLine(context.stdout, `Username: ${profile.username}`);
|
|
1773
|
+
if (profile.url) writeLine(context.stdout, `URL: ${profile.url}`);
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1625
1776
|
function renderProspectSequencePreview(payload, context) {
|
|
1626
1777
|
const prospect = payload?.prospect || {};
|
|
1627
1778
|
const report = payload?.report || {};
|
|
@@ -1761,6 +1912,60 @@ function renderOperatorNext(row, context) {
|
|
|
1761
1912
|
writeLine(context.stdout, operatorRowLine(row));
|
|
1762
1913
|
}
|
|
1763
1914
|
|
|
1915
|
+
function renderOperatorPlan(row, context) {
|
|
1916
|
+
if (!row) return writeLine(context.stdout, "No operator moves found.");
|
|
1917
|
+
|
|
1918
|
+
const nextAction = row.next_action || {};
|
|
1919
|
+
const cta = row.cta || {};
|
|
1920
|
+
const draft = row.operator_draft || {};
|
|
1921
|
+
|
|
1922
|
+
writeLine(context.stdout, "Static operator plan");
|
|
1923
|
+
writeLine(context.stdout, `Move: ${display(row.id)}`);
|
|
1924
|
+
writeLine(context.stdout, `Kind: ${display(row.opportunity_kind)}`);
|
|
1925
|
+
writeLine(context.stdout, `Prospect: ${entityLabel(row.prospect)}`);
|
|
1926
|
+
if (row.motion) writeLine(context.stdout, `Motion: ${entityLabel(row.motion)}`);
|
|
1927
|
+
if (row.pipeline_stage || row.plan_state || row.status_label) {
|
|
1928
|
+
writeLine(context.stdout, `State: ${compactText([row.pipeline_stage, row.plan_state, row.status_label]).join(", ")}`);
|
|
1929
|
+
}
|
|
1930
|
+
if (row.due_label) writeLine(context.stdout, `Due: ${row.due_label}`);
|
|
1931
|
+
|
|
1932
|
+
writeLine(context.stdout, "");
|
|
1933
|
+
writeLine(context.stdout, `Next action: ${display(nextActionLabel(row), "Unknown")} (${display(nextAction.type, "unknown")})`);
|
|
1934
|
+
if (nextAction.request_mode) writeLine(context.stdout, `Request mode: ${nextAction.request_mode}`);
|
|
1935
|
+
const timing = timingLabel(nextAction, row);
|
|
1936
|
+
if (timing) writeLine(context.stdout, `Timing: ${timing}`);
|
|
1937
|
+
const target = targetLabel(nextAction);
|
|
1938
|
+
if (target) writeLine(context.stdout, `Target: ${target}`);
|
|
1939
|
+
|
|
1940
|
+
if (Object.keys(cta).length > 0) {
|
|
1941
|
+
writeLine(context.stdout, "");
|
|
1942
|
+
writeLine(context.stdout, `CTA: ${ctaLabel(cta)}`);
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
if (Object.keys(draft).length > 0) {
|
|
1946
|
+
writeLine(context.stdout, "");
|
|
1947
|
+
writeLine(context.stdout, `Draft: ${draftLabel(draft)}`);
|
|
1948
|
+
if (draft.writer_path) writeLine(context.stdout, `Writer: ${draft.writer_path}`);
|
|
1949
|
+
if (draft.subject) writeLine(context.stdout, `Subject: ${draft.subject}`);
|
|
1950
|
+
const body = draft.body || draft.text;
|
|
1951
|
+
if (body) {
|
|
1952
|
+
writeLine(context.stdout, "Body:");
|
|
1953
|
+
writeLine(context.stdout, body);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
if (row.rationale) {
|
|
1958
|
+
writeLine(context.stdout, "");
|
|
1959
|
+
writeLine(context.stdout, "Rationale:");
|
|
1960
|
+
writeLine(context.stdout, row.rationale);
|
|
1961
|
+
}
|
|
1962
|
+
if (row.guidance) {
|
|
1963
|
+
writeLine(context.stdout, "");
|
|
1964
|
+
writeLine(context.stdout, "Guidance:");
|
|
1965
|
+
writeLine(context.stdout, row.guidance);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1764
1969
|
function renderOperatorOutcome(payload, context) {
|
|
1765
1970
|
const outcome = payload?.operator_outcome || {};
|
|
1766
1971
|
const rowId = payload?.row_id || outcome.row_id;
|
|
@@ -1774,6 +1979,84 @@ function renderOperatorOutcome(payload, context) {
|
|
|
1774
1979
|
}
|
|
1775
1980
|
}
|
|
1776
1981
|
|
|
1982
|
+
function renderAnalyticsProspects(payload, context) {
|
|
1983
|
+
writeLine(context.stdout, `Prospect analytics (${analyticsWindowLabel(payload)})`);
|
|
1984
|
+
writeAnalyticsScope(payload, context);
|
|
1985
|
+
writeLine(context.stdout, `Prospects added: ${display(payload?.prospects_added_count, 0)}`);
|
|
1986
|
+
writeAnalyticsActionSummary(payload?.actions, context, "Actions");
|
|
1987
|
+
writeCountTable(context, "Action breakdown", payload?.actions?.breakdown, ["ACTION", "COUNT", "AUTOMATED", "AUTO %"], actionBreakdownRow);
|
|
1988
|
+
writeCountTable(context, "Queue stages", payload?.queue_stages, ["STAGE", "COUNT"], countRow);
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
function renderAnalyticsVisibility(payload, context) {
|
|
1992
|
+
writeLine(context.stdout, `Visibility analytics (${analyticsWindowLabel(payload)})`);
|
|
1993
|
+
writeAnalyticsScope(payload, context);
|
|
1994
|
+
writeLine(context.stdout, `Unique people engaged: ${display(payload?.unique_people_engaged_count, 0)}`);
|
|
1995
|
+
writeAnalyticsActionSummary(payload?.engagements, context, "Engagements");
|
|
1996
|
+
writeCountTable(context, "Engagement breakdown", payload?.engagements?.breakdown, ["ACTION", "COUNT", "AUTOMATED", "AUTO %"], actionBreakdownRow);
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
function renderAnalyticsContent(payload, context) {
|
|
2000
|
+
writeLine(context.stdout, `Content analytics (${analyticsWindowLabel(payload)})`);
|
|
2001
|
+
writeAnalyticsScope(payload, context);
|
|
2002
|
+
writeLine(context.stdout, `Published posts: ${display(payload?.published_posts_count, 0)}`);
|
|
2003
|
+
writeCountTable(context, "Stages", payload?.stage_breakdown, ["STAGE", "COUNT"], countRow);
|
|
2004
|
+
writeCountTable(context, "Execution statuses", payload?.execution_status_breakdown, ["STATUS", "COUNT"], countRow);
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
function writeAnalyticsScope(payload, context) {
|
|
2008
|
+
if (payload?.account_user) {
|
|
2009
|
+
writeLine(context.stdout, `User: ${entityLabel(payload.account_user)}`);
|
|
2010
|
+
} else {
|
|
2011
|
+
writeLine(context.stdout, "User: all account users");
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
function writeAnalyticsActionSummary(actions, context, label) {
|
|
2016
|
+
const total = display(actions?.total_count, 0);
|
|
2017
|
+
const automated = display(actions?.automated_count, 0);
|
|
2018
|
+
const percentage = percentageLabel(actions?.automated_percentage);
|
|
2019
|
+
writeLine(context.stdout, `${label}: ${total} (automated ${automated}, ${percentage})`);
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
function writeCountTable(context, title, rows, headers, mapRow) {
|
|
2023
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
2024
|
+
writeLine(context.stdout, "");
|
|
2025
|
+
writeLine(context.stdout, title);
|
|
2026
|
+
if (list.length === 0) return writeLine(context.stdout, "None");
|
|
2027
|
+
|
|
2028
|
+
writeLine(context.stdout, headers.join("\t"));
|
|
2029
|
+
for (const row of list) writeLine(context.stdout, mapRow(row).join("\t"));
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
function actionBreakdownRow(row) {
|
|
2033
|
+
return [
|
|
2034
|
+
display(row?.label || row?.key),
|
|
2035
|
+
display(row?.count, 0),
|
|
2036
|
+
display(row?.automated_count, 0),
|
|
2037
|
+
percentageLabel(row?.automated_percentage)
|
|
2038
|
+
];
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
function countRow(row) {
|
|
2042
|
+
return [
|
|
2043
|
+
display(row?.label || row?.key),
|
|
2044
|
+
display(row?.count, 0)
|
|
2045
|
+
];
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2048
|
+
function analyticsWindowLabel(payload) {
|
|
2049
|
+
const window = payload?.window || {};
|
|
2050
|
+
const key = display(window.key, "24h");
|
|
2051
|
+
if (!window.started_at || !window.ended_at) return key;
|
|
2052
|
+
|
|
2053
|
+
return `${key}: ${window.started_at} to ${window.ended_at}`;
|
|
2054
|
+
}
|
|
2055
|
+
|
|
2056
|
+
function percentageLabel(value) {
|
|
2057
|
+
return value === undefined || value === null || value === "" ? "n/a" : `${value}%`;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
1777
2060
|
function operatorRowLine(row) {
|
|
1778
2061
|
return [
|
|
1779
2062
|
display(row?.id),
|
|
@@ -1788,6 +2071,53 @@ function nextActionLabel(source) {
|
|
|
1788
2071
|
return source?.recommended_action_label || source?.next_action?.label || source?.cta?.label;
|
|
1789
2072
|
}
|
|
1790
2073
|
|
|
2074
|
+
function entityLabel(entity) {
|
|
2075
|
+
if (!entity) return "";
|
|
2076
|
+
|
|
2077
|
+
const name = entity.display_name || entity.name || entity.prefix_id || entity.id;
|
|
2078
|
+
const id = entity.prefix_id || entity.id;
|
|
2079
|
+
return id && id !== name ? `${display(name)} (${display(id)})` : display(name);
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
function timingLabel(nextAction, row) {
|
|
2083
|
+
const timing = nextAction.timing || {};
|
|
2084
|
+
const mode = timing.mode || row.timing_mode;
|
|
2085
|
+
const scheduledFor = timing.scheduled_for || row.scheduled_for;
|
|
2086
|
+
const parts = compactText([
|
|
2087
|
+
mode,
|
|
2088
|
+
scheduledFor ? `scheduled for ${scheduledFor}` : null
|
|
2089
|
+
]);
|
|
2090
|
+
|
|
2091
|
+
return parts.join(", ");
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
function targetLabel(nextAction) {
|
|
2095
|
+
const target = nextAction.target || {};
|
|
2096
|
+
return compactText([
|
|
2097
|
+
target.platform,
|
|
2098
|
+
target.profile_url,
|
|
2099
|
+
target.post_url,
|
|
2100
|
+
target.message_event_id ? `message ${target.message_event_id}` : null,
|
|
2101
|
+
target.post_id ? `post ${target.post_id}` : null
|
|
2102
|
+
]).join(" | ");
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
function ctaLabel(cta) {
|
|
2106
|
+
const action = compactText([cta.action || cta.type, cta.platform ? `on ${cta.platform}` : null]).join(" ");
|
|
2107
|
+
const disabled = cta.disabled ? "disabled" : "enabled";
|
|
2108
|
+
return `${display(cta.label, "Unnamed CTA")}${action ? ` (${action})` : ""}${cta.disabled === undefined ? "" : `, ${disabled}`}`;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
function draftLabel(draft) {
|
|
2112
|
+
const required = draft.required === true ? "required" : draft.required === false ? "not required" : null;
|
|
2113
|
+
const ready = draft.ready === true ? "ready" : draft.ready === false ? "not ready" : null;
|
|
2114
|
+
return compactText([draft.state, ready, required]).join(", ") || "unknown";
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
function compactText(values) {
|
|
2118
|
+
return values.map((value) => String(value || "").trim()).filter(Boolean);
|
|
2119
|
+
}
|
|
2120
|
+
|
|
1791
2121
|
function successCount(payload) {
|
|
1792
2122
|
if (Array.isArray(payload?.added)) return payload.added.length;
|
|
1793
2123
|
if (Array.isArray(payload?.removed)) return payload.removed.length;
|
|
@@ -2036,14 +2366,19 @@ const HELP_TOPICS = new Map([
|
|
|
2036
2366
|
" audienti prospects write <prsp_id> --type <surface_key> [--json]",
|
|
2037
2367
|
" audienti prospects add-note <prsp_id> --message <text> [--json]",
|
|
2038
2368
|
" audienti prospects add-steer <prsp_id> --message <text> [--json]",
|
|
2369
|
+
" audienti prospects add-profile <prsp_id> --url <profile_url|email|phone> [--json]",
|
|
2370
|
+
" audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json]",
|
|
2039
2371
|
" audienti prospects sequence-preview <prsp_id> [--json]",
|
|
2040
2372
|
" audienti prospects sequence-export <prsp_id> [--csv]",
|
|
2041
2373
|
" audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--json]",
|
|
2042
2374
|
" audienti prospects import-status <primp_id> [--json]",
|
|
2043
2375
|
" audienti tools get <email|phone> --url <linkedin_url> [--json]",
|
|
2044
|
-
" audienti operator next [--json]",
|
|
2376
|
+
" audienti operator next [--json|--plan|--done|--skip|--fail|--return]",
|
|
2045
2377
|
" audienti operator queue [--json]",
|
|
2046
2378
|
" audienti operator outcome <row_id> --payload <file.json> [--json]",
|
|
2379
|
+
" audienti analytics prospects [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
|
|
2380
|
+
" audienti analytics visibility [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
|
|
2381
|
+
" audienti analytics content [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
|
|
2047
2382
|
"",
|
|
2048
2383
|
"Planned submit-shape help topics:",
|
|
2049
2384
|
" audienti prospects disposition help",
|
|
@@ -2734,6 +3069,8 @@ const HELP_TOPICS = new Map([
|
|
|
2734
3069
|
" audienti prospects write <prsp_id> --type <surface_key> [--json]",
|
|
2735
3070
|
" audienti prospects add-note <prsp_id> --message <text> [--json]",
|
|
2736
3071
|
" audienti prospects add-steer <prsp_id> --message <text> [--json]",
|
|
3072
|
+
" audienti prospects add-profile <prsp_id> --url <profile_url|email|phone> [--json]",
|
|
3073
|
+
" audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json]",
|
|
2737
3074
|
" audienti prospects sequence-preview <prsp_id> [--json]",
|
|
2738
3075
|
" audienti prospects sequence-export <prsp_id> [--csv]",
|
|
2739
3076
|
" audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--json]",
|
|
@@ -2945,6 +3282,60 @@ const HELP_TOPICS = new Map([
|
|
|
2945
3282
|
" }"
|
|
2946
3283
|
].join("\n")],
|
|
2947
3284
|
|
|
3285
|
+
["prospects add-profile", [
|
|
3286
|
+
"Usage:",
|
|
3287
|
+
` ${PROSPECTS_ADD_PROFILE_USAGE.slice("Usage: ".length)}`,
|
|
3288
|
+
"",
|
|
3289
|
+
"Status: implemented",
|
|
3290
|
+
"",
|
|
3291
|
+
"Purpose:",
|
|
3292
|
+
" Add a profile, email address, or phone number to an existing prospect through the same add-profile path used by the prospect show page.",
|
|
3293
|
+
"",
|
|
3294
|
+
"Input shape:",
|
|
3295
|
+
" prsp_id: prsp_ prospect prefix id",
|
|
3296
|
+
" url: supported profile URL, plain email address, mailto: URL, plain phone number, or tel: URL",
|
|
3297
|
+
"",
|
|
3298
|
+
"Output shape:",
|
|
3299
|
+
" prospect: prospect summary",
|
|
3300
|
+
" profile: attached profile with prefix_id, citation_id, identifier, username, url, and status",
|
|
3301
|
+
" status: attached | already_attached",
|
|
3302
|
+
"",
|
|
3303
|
+
"API:",
|
|
3304
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/profiles.json",
|
|
3305
|
+
"",
|
|
3306
|
+
"JSON body:",
|
|
3307
|
+
" {",
|
|
3308
|
+
" \"url\": \"prospect@example.com\"",
|
|
3309
|
+
" }"
|
|
3310
|
+
].join("\n")],
|
|
3311
|
+
|
|
3312
|
+
["prospects report-bad-profile", [
|
|
3313
|
+
"Usage:",
|
|
3314
|
+
` ${PROSPECTS_REPORT_BAD_PROFILE_USAGE.slice("Usage: ".length)}`,
|
|
3315
|
+
"",
|
|
3316
|
+
"Status: implemented",
|
|
3317
|
+
"",
|
|
3318
|
+
"Purpose:",
|
|
3319
|
+
" Report one of a prospect's attached profiles as bad through the same report action used by the prospect show page.",
|
|
3320
|
+
"",
|
|
3321
|
+
"Input shape:",
|
|
3322
|
+
" prsp_id: prsp_ prospect prefix id",
|
|
3323
|
+
" prof_id: prof_ prefix id or citation id such as email/profile:name@example.com",
|
|
3324
|
+
"",
|
|
3325
|
+
"Output shape:",
|
|
3326
|
+
" prospect: prospect summary",
|
|
3327
|
+
" profile: reported profile",
|
|
3328
|
+
" status: reported",
|
|
3329
|
+
"",
|
|
3330
|
+
"API:",
|
|
3331
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/report_bad_profile.json",
|
|
3332
|
+
"",
|
|
3333
|
+
"JSON body:",
|
|
3334
|
+
" {",
|
|
3335
|
+
" \"profile_id\": \"prof_abc123\"",
|
|
3336
|
+
" }"
|
|
3337
|
+
].join("\n")],
|
|
3338
|
+
|
|
2948
3339
|
["prospects sequence-preview", [
|
|
2949
3340
|
"Usage:",
|
|
2950
3341
|
" audienti prospects sequence-preview <prsp_id> [--json] [--connection-state <state>] [--account <acct_id>]",
|
|
@@ -3109,11 +3500,11 @@ const HELP_TOPICS = new Map([
|
|
|
3109
3500
|
|
|
3110
3501
|
["operator", [
|
|
3111
3502
|
"Usage:",
|
|
3112
|
-
" audienti operator next [--json]",
|
|
3503
|
+
" audienti operator next [--json|--plan|--done|--skip|--fail|--return]",
|
|
3113
3504
|
" audienti operator queue [--json]",
|
|
3114
3505
|
" audienti operator outcome <row_id> --payload <file.json>",
|
|
3115
3506
|
"",
|
|
3116
|
-
"Status: read commands and prospect
|
|
3507
|
+
"Status: read commands and prospect next-move writeback implemented",
|
|
3117
3508
|
"",
|
|
3118
3509
|
"Filters:",
|
|
3119
3510
|
" --principal <account_user_id>",
|
|
@@ -3126,10 +3517,19 @@ const HELP_TOPICS = new Map([
|
|
|
3126
3517
|
|
|
3127
3518
|
["operator next", [
|
|
3128
3519
|
"Usage:",
|
|
3129
|
-
" audienti operator next [--json] [filters] [--account <acct_id>]",
|
|
3520
|
+
" audienti operator next [--json|--plan|--done|--skip|--fail|--return] [filters] [--note <text>] [--account <acct_id>]",
|
|
3130
3521
|
"",
|
|
3131
3522
|
"Status: implemented",
|
|
3132
3523
|
"",
|
|
3524
|
+
"Options:",
|
|
3525
|
+
" --plan Render a deterministic static plan from the existing next-action coach payload, CTA, and operator draft state",
|
|
3526
|
+
" --done Mark the current next prospect move completed through the operator outcome API",
|
|
3527
|
+
" --skip Mark the current next prospect move skipped through the operator outcome API",
|
|
3528
|
+
" --fail Mark the current next prospect move failed through the operator outcome API",
|
|
3529
|
+
" --return Mark the current next prospect move returned through the operator outcome API",
|
|
3530
|
+
" --note <text> Optional outcome note used with --done, --skip, --fail, or --return",
|
|
3531
|
+
" --occurred-at <ISO8601> Optional completion timestamp used with an outcome flag",
|
|
3532
|
+
"",
|
|
3133
3533
|
"Output shape:",
|
|
3134
3534
|
" next_move.id: row id",
|
|
3135
3535
|
" next_move.prospect.prefix_id: prsp_ | null",
|
|
@@ -3141,7 +3541,8 @@ const HELP_TOPICS = new Map([
|
|
|
3141
3541
|
" metrics: queue-builder metrics",
|
|
3142
3542
|
"",
|
|
3143
3543
|
"API:",
|
|
3144
|
-
" GET /api/v1/accounts/:account_id/operator/next.json"
|
|
3544
|
+
" GET /api/v1/accounts/:account_id/operator/next.json",
|
|
3545
|
+
" POST /api/v1/accounts/:account_id/operator/outcome.json when an outcome flag is used"
|
|
3145
3546
|
].join("\n")],
|
|
3146
3547
|
|
|
3147
3548
|
["operator queue", [
|
|
@@ -3187,6 +3588,84 @@ const HELP_TOPICS = new Map([
|
|
|
3187
3588
|
" POST /api/v1/accounts/:account_id/operator/outcome.json"
|
|
3188
3589
|
].join("\n")],
|
|
3189
3590
|
|
|
3591
|
+
["analytics", [
|
|
3592
|
+
"Usage:",
|
|
3593
|
+
" audienti analytics prospects [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
|
|
3594
|
+
" audienti analytics visibility [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
|
|
3595
|
+
" audienti analytics visops [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
|
|
3596
|
+
" audienti analytics content [--window 24h] [--user <account_user_id|email|name|me>] [--json]",
|
|
3597
|
+
"",
|
|
3598
|
+
"Status: implemented",
|
|
3599
|
+
"",
|
|
3600
|
+
"Window:",
|
|
3601
|
+
" --window <24h|7d|1w|day|week>",
|
|
3602
|
+
" --user <account_user_id|email|name|me> Narrow analytics to one account user. Email/name partials are accepted when they match exactly one account user.",
|
|
3603
|
+
"",
|
|
3604
|
+
"Output:",
|
|
3605
|
+
" Account-scoped analytics for prospects, visibility engagement, and ContentOps publishing."
|
|
3606
|
+
].join("\n")],
|
|
3607
|
+
|
|
3608
|
+
["analytics prospects", [
|
|
3609
|
+
"Usage:",
|
|
3610
|
+
" audienti analytics prospects [--window 24h] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]",
|
|
3611
|
+
"",
|
|
3612
|
+
"Status: implemented",
|
|
3613
|
+
"",
|
|
3614
|
+
"Output shape:",
|
|
3615
|
+
" prospects_added_count: account prospects added in the window",
|
|
3616
|
+
" account_user: selected account user when --user is provided, otherwise null",
|
|
3617
|
+
" actions: outbound action totals, type breakdown, and automated percentage",
|
|
3618
|
+
" queue_stages[]: current account prospect stage counts",
|
|
3619
|
+
"",
|
|
3620
|
+
"API:",
|
|
3621
|
+
" GET /api/v1/accounts/:account_id/analytics/prospects.json"
|
|
3622
|
+
].join("\n")],
|
|
3623
|
+
|
|
3624
|
+
["analytics prospect", [
|
|
3625
|
+
"Usage:",
|
|
3626
|
+
" audienti analytics prospect [--window 24h] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]",
|
|
3627
|
+
"",
|
|
3628
|
+
"Alias for `audienti analytics prospects`."
|
|
3629
|
+
].join("\n")],
|
|
3630
|
+
|
|
3631
|
+
["analytics visibility", [
|
|
3632
|
+
"Usage:",
|
|
3633
|
+
" audienti analytics visibility [--window 24h] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]",
|
|
3634
|
+
"",
|
|
3635
|
+
"Status: implemented",
|
|
3636
|
+
"",
|
|
3637
|
+
"Output shape:",
|
|
3638
|
+
" unique_people_engaged_count: unique prospects or profiles touched by visibility actions in the window",
|
|
3639
|
+
" account_user: selected account user when --user is provided, otherwise null",
|
|
3640
|
+
" engagements: visibility action totals, type breakdown, and automated percentage",
|
|
3641
|
+
"",
|
|
3642
|
+
"API:",
|
|
3643
|
+
" GET /api/v1/accounts/:account_id/analytics/visibility.json"
|
|
3644
|
+
].join("\n")],
|
|
3645
|
+
|
|
3646
|
+
["analytics visops", [
|
|
3647
|
+
"Usage:",
|
|
3648
|
+
" audienti analytics visops [--window 24h] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]",
|
|
3649
|
+
"",
|
|
3650
|
+
"Alias for `audienti analytics visibility`."
|
|
3651
|
+
].join("\n")],
|
|
3652
|
+
|
|
3653
|
+
["analytics content", [
|
|
3654
|
+
"Usage:",
|
|
3655
|
+
" audienti analytics content [--window 24h] [--user <account_user_id|email|name|me>] [--json] [--account <acct_id>]",
|
|
3656
|
+
"",
|
|
3657
|
+
"Status: implemented",
|
|
3658
|
+
"",
|
|
3659
|
+
"Output shape:",
|
|
3660
|
+
" account_user: selected account user when --user is provided, otherwise null",
|
|
3661
|
+
" published_posts_count: ContentOps work items published in the window",
|
|
3662
|
+
" stage_breakdown[]: current ContentOps work item stage counts",
|
|
3663
|
+
" execution_status_breakdown[]: current ContentOps execution status counts",
|
|
3664
|
+
"",
|
|
3665
|
+
"API:",
|
|
3666
|
+
" GET /api/v1/accounts/:account_id/analytics/content.json"
|
|
3667
|
+
].join("\n")],
|
|
3668
|
+
|
|
3190
3669
|
["agent-workflows", [
|
|
3191
3670
|
"Usage:",
|
|
3192
3671
|
" audienti help agent-workflows",
|
|
@@ -3220,6 +3699,8 @@ const HELP_TOPICS = new Map([
|
|
|
3220
3699
|
" audienti prospects show <prsp_id>",
|
|
3221
3700
|
" audienti prospects timeline <prsp_id> --types post,comment,reaction --json",
|
|
3222
3701
|
" audienti prospects message-types <prsp_id>",
|
|
3702
|
+
" audienti prospects add-profile <prsp_id> --url prospect@example.com",
|
|
3703
|
+
" audienti prospects report-bad-profile <prsp_id> <prof_id>",
|
|
3223
3704
|
" audienti prospects add-note <prsp_id> --type steer --message \"Meeting will not happen\" --engagement-type action.meeting.canceled",
|
|
3224
3705
|
" audienti prospects sequence-preview <prsp_id>",
|
|
3225
3706
|
" audienti prospects sequence-export <prsp_id> --csv",
|
|
@@ -3230,9 +3711,15 @@ const HELP_TOPICS = new Map([
|
|
|
3230
3711
|
"",
|
|
3231
3712
|
"6. Work the operator queue",
|
|
3232
3713
|
" audienti operator next",
|
|
3714
|
+
" audienti operator next --plan",
|
|
3233
3715
|
" audienti operator queue --json",
|
|
3234
3716
|
" audienti operator outcome <row_id> --payload <file.json>",
|
|
3235
3717
|
"",
|
|
3718
|
+
"7. Inspect account analytics",
|
|
3719
|
+
" audienti analytics prospects --window 24h",
|
|
3720
|
+
" audienti analytics visibility --window 24h --user me",
|
|
3721
|
+
" audienti analytics content --window week",
|
|
3722
|
+
"",
|
|
3236
3723
|
"Good defaults:",
|
|
3237
3724
|
" Use --json when another tool or agent will parse the result.",
|
|
3238
3725
|
" Use --account <acct_id> to avoid mutating the saved account during one-off runs.",
|