@audienti/cli 0.1.24 → 0.1.27
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 +22 -0
- package/package.json +1 -1
- package/src/api-client.js +14 -0
- package/src/cli.js +283 -21
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to the Audienti CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.27] - 2026-07-22
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Add `audienti operator failed-drafts` and `audienti operator failed-drafts requeue` for listing failed prospect operator drafts and queueing async rewrites.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Show prospect replan coach errors as not persisted instead of displaying failed `--apply` runs as dry runs.
|
|
16
|
+
|
|
17
|
+
## [0.1.26] - 2026-07-22
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Add `audienti prospects replan <prsp_id> [--apply]` for dry-running or persisting refreshed next-action coach plans.
|
|
22
|
+
|
|
23
|
+
## [0.1.25] - 2026-07-22
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- Add `bad_data_404` support to prospect disposition commands.
|
|
28
|
+
|
|
7
29
|
## [0.1.24] - 2026-07-22
|
|
8
30
|
|
|
9
31
|
### Changed
|
package/package.json
CHANGED
package/src/api-client.js
CHANGED
|
@@ -366,6 +366,13 @@ export class AudientiClient {
|
|
|
366
366
|
return this.requestJson(accountPath(accountId, ["prospects", prospectId]));
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
+
replanProspect(accountId, prospectId, body = {}) {
|
|
370
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "replan"]), {
|
|
371
|
+
method: "POST",
|
|
372
|
+
body
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
369
376
|
assignProspects(accountId, body) {
|
|
370
377
|
return this.requestJson(accountPath(accountId, ["prospects", "assign"]), {
|
|
371
378
|
method: "POST",
|
|
@@ -500,6 +507,13 @@ export class AudientiClient {
|
|
|
500
507
|
return this.requestJson(accountPath(accountId, ["operator", "next"], query));
|
|
501
508
|
}
|
|
502
509
|
|
|
510
|
+
requeueOperatorFailedDrafts(accountId, body = {}) {
|
|
511
|
+
return this.requestJson(accountPath(accountId, ["operator", "failed_drafts", "requeue"]), {
|
|
512
|
+
method: "POST",
|
|
513
|
+
body
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
|
|
503
517
|
operatorOutcome(accountId, body) {
|
|
504
518
|
return this.requestJson(accountPath(accountId, ["operator", "outcome"]), {
|
|
505
519
|
method: "POST",
|
package/src/cli.js
CHANGED
|
@@ -30,20 +30,24 @@ const DEFAULT_PROFILE_IDENTIFIERS = [
|
|
|
30
30
|
];
|
|
31
31
|
const DELETE_CONFIRMATION_VALUES = new Set(["yes", "true", "y"]);
|
|
32
32
|
const MOTION_STATUS_VALUES = new Set(["draft", "preparing", "active", "paused", "archived"]);
|
|
33
|
-
const
|
|
33
|
+
const PROSPECT_INACTIVE_REASON_VALUES = new Set(["nurture", "non_responsive", "not_fit", "bad_data_404"]);
|
|
34
|
+
const PROSPECT_STATUS_VALUES = new Set(["active", ...PROSPECT_INACTIVE_REASON_VALUES, "rejected"]);
|
|
34
35
|
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>]";
|
|
35
36
|
const PROSPECTS_ADD_STEER_USAGE = "Usage: audienti prospects add-steer <prsp_id> (--message <text> [--engagement-type <key>] | --payload <file.json>) [--json] [--account <acct_id>]";
|
|
36
37
|
const PROSPECTS_ADD_PROFILE_USAGE = "Usage: audienti prospects add-profile <prsp_id> --url <profile_url|email|phone> [--json] [--account <acct_id>]";
|
|
37
38
|
const PROSPECTS_REPORT_BAD_PROFILE_USAGE = "Usage: audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json] [--account <acct_id>]";
|
|
38
39
|
const PROSPECTS_ASSIGN_USAGE = "Usage: audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json] [--account <acct_id>]";
|
|
39
|
-
const PROSPECTS_SET_STATUS_USAGE = "Usage: audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|rejected> [--json] [--account <acct_id>]";
|
|
40
|
+
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>]";
|
|
41
|
+
const PROSPECTS_REPLAN_USAGE = "Usage: audienti prospects replan <prsp_id> [--apply] [--json] [--account <acct_id>]";
|
|
40
42
|
const PROSPECTS_REJECT_USAGE = "Usage: audienti prospects reject <prsp_id> [--json] [--account <acct_id>]";
|
|
41
|
-
const PROSPECTS_NURTURE_USAGE = "Usage: audienti prospects nurture <prsp_id> [--reason <nurture|non_responsive|not_fit>] [--json] [--account <acct_id>]";
|
|
43
|
+
const PROSPECTS_NURTURE_USAGE = "Usage: audienti prospects nurture <prsp_id> [--reason <nurture|non_responsive|not_fit|bad_data_404>] [--json] [--account <acct_id>]";
|
|
42
44
|
const PROSPECTS_RESTORE_USAGE = "Usage: audienti prospects restore <prsp_id> [--json] [--account <acct_id>]";
|
|
43
45
|
const PROSPECTS_LOCK_USAGE = "Usage: audienti prospects lock <prsp_id> [--note <text>] [--kind <protected_relationship|company_policy>] [--json] [--account <acct_id>]";
|
|
44
46
|
const PROSPECTS_UNLOCK_USAGE = "Usage: audienti prospects unlock <prsp_id> [--json] [--account <acct_id>]";
|
|
45
47
|
const PROSPECTS_CHECK_USAGE = "Usage: audienti prospects check [--json|--csv] [filters] [--account <acct_id>]";
|
|
46
48
|
const PROSPECTS_IMPORT_BATCH_USAGE = "Usage: audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--assigned-user <id|me>] [--json] [--account <acct_id>]";
|
|
49
|
+
const OPERATOR_FAILED_DRAFTS_USAGE = "Usage: audienti operator failed-drafts [--json] [filters] [--account <acct_id>]";
|
|
50
|
+
const OPERATOR_FAILED_DRAFTS_REQUEUE_USAGE = "Usage: audienti operator failed-drafts requeue (--all | <row_id> [row_id...]) [--limit <n>] [--json] [filters] [--account <acct_id>]";
|
|
47
51
|
const DNC_ADD_USAGE = "Usage: audienti dnc add <email|citation_id|profile_url> [--json] [--account <acct_id>]";
|
|
48
52
|
const DNC_IMPORT_USAGE = "Usage: audienti dnc import --file <txt|csv> [--json] [--account <acct_id>]";
|
|
49
53
|
const DNC_REMOVE_USAGE = "Usage: audienti dnc remove <dnc_entry_id> [--json] [--account <acct_id>]";
|
|
@@ -242,6 +246,7 @@ async function dispatch(argv, context) {
|
|
|
242
246
|
if (normalizedResource === "prospects" && action === "show") return prospectsShow(rest, context, { accountOverride });
|
|
243
247
|
if (normalizedResource === "prospects" && action === "assign") return prospectsAssign(rest, context, { accountOverride });
|
|
244
248
|
if (normalizedResource === "prospects" && action === "set-status") return prospectsSetStatus(rest, context, { accountOverride });
|
|
249
|
+
if (normalizedResource === "prospects" && action === "replan") return prospectsReplan(rest, context, { accountOverride });
|
|
245
250
|
if (normalizedResource === "prospects" && action === "reject") return prospectsDisposition("reject", rest, context, { accountOverride });
|
|
246
251
|
if (normalizedResource === "prospects" && action === "nurture") return prospectsDisposition("nurture", rest, context, { accountOverride });
|
|
247
252
|
if (normalizedResource === "prospects" && action === "restore") return prospectsDisposition("restore", rest, context, { accountOverride });
|
|
@@ -263,6 +268,7 @@ async function dispatch(argv, context) {
|
|
|
263
268
|
if (normalizedResource === "tools" && action === "list") return toolsList(rest, context);
|
|
264
269
|
if (normalizedResource === "tools" && action === "get") return toolsGet(rest, context, { accountOverride });
|
|
265
270
|
if (normalizedResource === "tools" && action === "linkedin-review") return toolsLinkedinReview(rest, context, { accountOverride });
|
|
271
|
+
if (normalizedResource === "operator" && action === "failed-drafts") return operatorFailedDrafts(rest, context, { accountOverride });
|
|
266
272
|
if (normalizedResource === "operator" && action === "queue") return operatorQueue(rest, context, { accountOverride });
|
|
267
273
|
if (normalizedResource === "operator" && action === "next") return operatorNext(rest, context, { accountOverride });
|
|
268
274
|
if (normalizedResource === "operator" && action === "outcome") return operatorOutcome(rest, context, { accountOverride });
|
|
@@ -1839,6 +1845,22 @@ async function prospectsShow(args, context, { accountOverride } = {}) {
|
|
|
1839
1845
|
renderProspect(prospect, context);
|
|
1840
1846
|
}
|
|
1841
1847
|
|
|
1848
|
+
async function prospectsReplan(args, context, { accountOverride } = {}) {
|
|
1849
|
+
const { values, positionals } = parseCommandArgs(args, {
|
|
1850
|
+
...jsonOptions(),
|
|
1851
|
+
apply: { type: "boolean" }
|
|
1852
|
+
});
|
|
1853
|
+
if (positionals.length !== 1) throw new CommandError(PROSPECTS_REPLAN_USAGE);
|
|
1854
|
+
|
|
1855
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
1856
|
+
const payload = await client.replanProspect(accountId, positionals[0], compactObject({
|
|
1857
|
+
apply: values.apply
|
|
1858
|
+
}));
|
|
1859
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
1860
|
+
|
|
1861
|
+
renderProspectReplan(payload, context);
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1842
1864
|
async function prospectsDisposition(action, args, context, { accountOverride } = {}) {
|
|
1843
1865
|
const usageText = {
|
|
1844
1866
|
reject: PROSPECTS_REJECT_USAGE,
|
|
@@ -1849,7 +1871,12 @@ async function prospectsDisposition(action, args, context, { accountOverride } =
|
|
|
1849
1871
|
...jsonOptions(),
|
|
1850
1872
|
reason: { type: "string" }
|
|
1851
1873
|
});
|
|
1852
|
-
|
|
1874
|
+
const inactiveReason = values.reason ? String(values.reason).trim() : undefined;
|
|
1875
|
+
if (
|
|
1876
|
+
positionals.length !== 1 ||
|
|
1877
|
+
(action !== "nurture" && inactiveReason) ||
|
|
1878
|
+
(action === "nurture" && inactiveReason && !PROSPECT_INACTIVE_REASON_VALUES.has(inactiveReason))
|
|
1879
|
+
) {
|
|
1853
1880
|
throw new CommandError(usageText);
|
|
1854
1881
|
}
|
|
1855
1882
|
|
|
@@ -1859,7 +1886,7 @@ async function prospectsDisposition(action, args, context, { accountOverride } =
|
|
|
1859
1886
|
await client.rejectProspect(accountId, prospectId) :
|
|
1860
1887
|
action === "restore" ?
|
|
1861
1888
|
await client.restoreProspect(accountId, prospectId) :
|
|
1862
|
-
await client.nurtureProspect(accountId, prospectId, compactObject({ inactive_reason:
|
|
1889
|
+
await client.nurtureProspect(accountId, prospectId, compactObject({ inactive_reason: inactiveReason }));
|
|
1863
1890
|
if (values.json) return writeJson(context.stdout, payload);
|
|
1864
1891
|
|
|
1865
1892
|
renderProspectDisposition(payload, context, { action });
|
|
@@ -2438,6 +2465,41 @@ async function operatorQueue(args, context, { accountOverride } = {}) {
|
|
|
2438
2465
|
renderOperatorQueue(payload, context);
|
|
2439
2466
|
}
|
|
2440
2467
|
|
|
2468
|
+
async function operatorFailedDrafts(args, context, { accountOverride } = {}) {
|
|
2469
|
+
if (args[0] === "requeue") {
|
|
2470
|
+
return operatorFailedDraftsRequeue(args.slice(1), context, { accountOverride });
|
|
2471
|
+
}
|
|
2472
|
+
|
|
2473
|
+
const { values, positionals } = parseCommandArgs(args, operatorFailedDraftOptions());
|
|
2474
|
+
if (positionals.length > 0) throw new CommandError(OPERATOR_FAILED_DRAFTS_USAGE);
|
|
2475
|
+
|
|
2476
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
2477
|
+
const payload = await client.operatorQueue(accountId, operatorFailedDraftQuery(values));
|
|
2478
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
2479
|
+
|
|
2480
|
+
renderOperatorFailedDrafts(payload, context);
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
async function operatorFailedDraftsRequeue(args, context, { accountOverride } = {}) {
|
|
2484
|
+
const { values, positionals } = parseCommandArgs(args, operatorFailedDraftOptions({
|
|
2485
|
+
all: { type: "boolean" },
|
|
2486
|
+
limit: { type: "string" }
|
|
2487
|
+
}));
|
|
2488
|
+
if (values.all && positionals.length > 0) throw new CommandError("Choose either --all or row ids, not both.");
|
|
2489
|
+
if (!values.all && positionals.length === 0) throw new CommandError(OPERATOR_FAILED_DRAFTS_REQUEUE_USAGE);
|
|
2490
|
+
|
|
2491
|
+
const { client, accountId } = await requireAccountContext(context, { accountOverride });
|
|
2492
|
+
const payload = await client.requeueOperatorFailedDrafts(accountId, compactObject({
|
|
2493
|
+
...operatorFailedDraftQuery(values),
|
|
2494
|
+
all: values.all || undefined,
|
|
2495
|
+
limit: values.limit,
|
|
2496
|
+
row_ids: positionals.length > 0 ? positionals : undefined
|
|
2497
|
+
}));
|
|
2498
|
+
if (values.json) return writeJson(context.stdout, payload);
|
|
2499
|
+
|
|
2500
|
+
renderOperatorFailedDraftRequeue(payload, context);
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2441
2503
|
async function operatorNext(args, context, { accountOverride } = {}) {
|
|
2442
2504
|
const { values, positionals } = parseCommandArgs(args, operatorNextOptions());
|
|
2443
2505
|
if (positionals.length > 0) throw new CommandError("Usage: audienti operator next [--json|--plan|--done|--skip|--fail|--return] [filters] [--note <text>] [--account <acct_id>]");
|
|
@@ -2699,6 +2761,18 @@ function operatorNextOptions() {
|
|
|
2699
2761
|
});
|
|
2700
2762
|
}
|
|
2701
2763
|
|
|
2764
|
+
function operatorFailedDraftOptions(extra = {}) {
|
|
2765
|
+
return {
|
|
2766
|
+
...jsonOptions(),
|
|
2767
|
+
principal: { type: "string" },
|
|
2768
|
+
motion: { type: "string" },
|
|
2769
|
+
list: { type: "string" },
|
|
2770
|
+
stage: { type: "string" },
|
|
2771
|
+
query: { type: "string" },
|
|
2772
|
+
...extra
|
|
2773
|
+
};
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2702
2776
|
function operatorQuery(values) {
|
|
2703
2777
|
return compactObject({
|
|
2704
2778
|
principal_account_user_id: values.principal,
|
|
@@ -2710,6 +2784,18 @@ function operatorQuery(values) {
|
|
|
2710
2784
|
});
|
|
2711
2785
|
}
|
|
2712
2786
|
|
|
2787
|
+
function operatorFailedDraftQuery(values) {
|
|
2788
|
+
return compactObject({
|
|
2789
|
+
principal_account_user_id: values.principal,
|
|
2790
|
+
motion_id: values.motion,
|
|
2791
|
+
list_id: values.list,
|
|
2792
|
+
stage: values.stage,
|
|
2793
|
+
query: values.query,
|
|
2794
|
+
opportunity_kind: "prospect",
|
|
2795
|
+
writing_status: "draft_failed"
|
|
2796
|
+
});
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2713
2799
|
function operatorNextOutcomeStatus(values) {
|
|
2714
2800
|
const selected = [
|
|
2715
2801
|
values.done ? "done" : null,
|
|
@@ -3895,6 +3981,40 @@ function renderProspect(prospect, context) {
|
|
|
3895
3981
|
if (nextActionLabel(prospect?.queue)) writeLine(context.stdout, `Next action: ${nextActionLabel(prospect.queue)}`);
|
|
3896
3982
|
}
|
|
3897
3983
|
|
|
3984
|
+
function renderProspectReplan(payload, context) {
|
|
3985
|
+
const prospect = payload?.prospect || {};
|
|
3986
|
+
const current = payload?.current || {};
|
|
3987
|
+
const replanned = payload?.replanned || {};
|
|
3988
|
+
const status = replanStatusLabel(payload);
|
|
3989
|
+
|
|
3990
|
+
writeLine(context.stdout, `Replan ${status} for ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)}).`);
|
|
3991
|
+
writeLine(context.stdout, `Changed: ${payload?.changed ? "yes" : "no"}`);
|
|
3992
|
+
if (payload?.reason_code) writeLine(context.stdout, `Reason: ${payload.reason_code}`);
|
|
3993
|
+
writeLine(context.stdout, `Current: ${formatCoachAction(current.next_action)}`);
|
|
3994
|
+
writeLine(context.stdout, `Replanned: ${formatCoachAction(replanned.next_action)}`);
|
|
3995
|
+
if (replanned.rationale) writeLine(context.stdout, `Rationale: ${replanned.rationale}`);
|
|
3996
|
+
if (replanned.guidance) writeLine(context.stdout, `Guidance: ${replanned.guidance}`);
|
|
3997
|
+
if (payload?.status === "dry_run") writeLine(context.stdout, "Run again with --apply to persist this plan.");
|
|
3998
|
+
if (payload?.status === "coach_error") writeLine(context.stdout, "The plan was not persisted. Fix the coach error and rerun with --apply.");
|
|
3999
|
+
}
|
|
4000
|
+
|
|
4001
|
+
function replanStatusLabel(payload) {
|
|
4002
|
+
if (payload?.status === "dry_run") return "dry run";
|
|
4003
|
+
if (payload?.status === "coach_error") return "coach error";
|
|
4004
|
+
if (payload?.status === "not_applied") return "not applied";
|
|
4005
|
+
|
|
4006
|
+
return payload?.applied ? "applied" : "dry run";
|
|
4007
|
+
}
|
|
4008
|
+
|
|
4009
|
+
function formatCoachAction(nextAction = {}) {
|
|
4010
|
+
const action = nextAction?.label || nextAction?.type || "none";
|
|
4011
|
+
const mode = nextAction?.request_mode || nextAction?.mode;
|
|
4012
|
+
const timing = nextAction?.timing?.mode;
|
|
4013
|
+
const details = compactText([mode, timing]).join(", ");
|
|
4014
|
+
|
|
4015
|
+
return details ? `${action} (${details})` : action;
|
|
4016
|
+
}
|
|
4017
|
+
|
|
3898
4018
|
function renderProspectDisposition(payload, context, { action }) {
|
|
3899
4019
|
const prospect = payload?.prospect || {};
|
|
3900
4020
|
const accountProspect = payload?.account_prospect || {};
|
|
@@ -4591,6 +4711,87 @@ function renderOperatorOutcome(payload, context) {
|
|
|
4591
4711
|
}
|
|
4592
4712
|
}
|
|
4593
4713
|
|
|
4714
|
+
function renderOperatorFailedDrafts(payload, context) {
|
|
4715
|
+
const rows = Array.isArray(payload?.decision_queue) ? payload.decision_queue : [];
|
|
4716
|
+
if (rows.length === 0) {
|
|
4717
|
+
writeLine(context.stdout, "No failed operator drafts found.");
|
|
4718
|
+
return;
|
|
4719
|
+
}
|
|
4720
|
+
|
|
4721
|
+
writeLine(context.stdout, "Failed operator drafts");
|
|
4722
|
+
writeAlignedTable(context, ["ROW ID", "PROSPECT", "MOTION", "STATUS", "REASON", "DRAFT"], rows.map(operatorFailedDraftTableRow));
|
|
4723
|
+
writeLine(context.stdout, "");
|
|
4724
|
+
writeLine(context.stdout, `Shown: ${rows.length}`);
|
|
4725
|
+
writeLine(context.stdout, "Requeue: audienti operator failed-drafts requeue <row_id> [row_id...]");
|
|
4726
|
+
writeLine(context.stdout, "If a rewrite fails again, it remains in this list with the latest failure reason.");
|
|
4727
|
+
}
|
|
4728
|
+
|
|
4729
|
+
function renderOperatorFailedDraftRequeue(payload, context) {
|
|
4730
|
+
const metrics = payload?.metrics || {};
|
|
4731
|
+
const queued = Number(metrics.queued_count || 0);
|
|
4732
|
+
const skipped = Number(metrics.skipped_count || 0);
|
|
4733
|
+
const failed = Number(metrics.failed_count || 0);
|
|
4734
|
+
writeLine(context.stdout, `Queued draft rewrites: ${queued}`);
|
|
4735
|
+
if (skipped > 0) writeLine(context.stdout, `Skipped: ${skipped}`);
|
|
4736
|
+
if (failed > 0) writeLine(context.stdout, `Failed: ${failed}`);
|
|
4737
|
+
|
|
4738
|
+
writeOperatorFailedDraftRequeueDetails(context, "Queued", payload?.queued);
|
|
4739
|
+
writeOperatorFailedDraftRequeueDetails(context, "Skipped", payload?.skipped);
|
|
4740
|
+
writeOperatorFailedDraftRequeueDetails(context, "Failed", payload?.failed);
|
|
4741
|
+
|
|
4742
|
+
const message = payload?.message ||
|
|
4743
|
+
"Rewrites run asynchronously. Re-run `audienti operator failed-drafts` with the same filters to see drafts that still fail after rewriting.";
|
|
4744
|
+
writeLine(context.stdout, "");
|
|
4745
|
+
writeLine(context.stdout, message);
|
|
4746
|
+
}
|
|
4747
|
+
|
|
4748
|
+
function writeOperatorFailedDraftRequeueDetails(context, label, rows) {
|
|
4749
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
4750
|
+
if (list.length === 0) return;
|
|
4751
|
+
|
|
4752
|
+
writeLine(context.stdout, "");
|
|
4753
|
+
writeLine(context.stdout, label);
|
|
4754
|
+
writeAlignedTable(context, ["ROW ID", "PROSPECT", "REASON", "DRAFT ID", "JOB ID"], list.map((row) => [
|
|
4755
|
+
display(row.row_id),
|
|
4756
|
+
display(row.prospect_name || row.prospect_id),
|
|
4757
|
+
display(row.reason),
|
|
4758
|
+
display(row.draft_id || row.source_draft_id),
|
|
4759
|
+
display(row.job_id)
|
|
4760
|
+
]));
|
|
4761
|
+
}
|
|
4762
|
+
|
|
4763
|
+
function operatorFailedDraftTableRow(row) {
|
|
4764
|
+
const draft = row?.operator_draft || {};
|
|
4765
|
+
return [
|
|
4766
|
+
display(row?.id),
|
|
4767
|
+
operatorSubjectLabel(row),
|
|
4768
|
+
operatorMotionLabel(row),
|
|
4769
|
+
display(draft.status || draft.state),
|
|
4770
|
+
operatorFailedDraftReason(draft),
|
|
4771
|
+
operatorFailedDraftSnippet(draft)
|
|
4772
|
+
];
|
|
4773
|
+
}
|
|
4774
|
+
|
|
4775
|
+
function operatorFailedDraftReason(draft) {
|
|
4776
|
+
const payload = draft?.payload || {};
|
|
4777
|
+
const codes = Array.isArray(payload.quality_codes) ? payload.quality_codes.filter(Boolean).join(",") : "";
|
|
4778
|
+
return display(
|
|
4779
|
+
codes ||
|
|
4780
|
+
payload.blank_reason ||
|
|
4781
|
+
payload.error ||
|
|
4782
|
+
payload.message ||
|
|
4783
|
+
payload.status ||
|
|
4784
|
+
draft?.status ||
|
|
4785
|
+
draft?.state,
|
|
4786
|
+
"-"
|
|
4787
|
+
);
|
|
4788
|
+
}
|
|
4789
|
+
|
|
4790
|
+
function operatorFailedDraftSnippet(draft) {
|
|
4791
|
+
const payload = draft?.payload || {};
|
|
4792
|
+
return truncateCliText(payload.subject || payload.body || payload.text || "", 64) || "-";
|
|
4793
|
+
}
|
|
4794
|
+
|
|
4594
4795
|
function renderAnalyticsProspects(payload, context) {
|
|
4595
4796
|
writeLine(context.stdout, `Prospect analytics (${analyticsWindowLabel(payload)})`);
|
|
4596
4797
|
writeAnalyticsCohort(payload, context);
|
|
@@ -5372,7 +5573,8 @@ const HELP_TOPICS = new Map([
|
|
|
5372
5573
|
" audienti prospects check [filters]",
|
|
5373
5574
|
" audienti prospects show <prsp_id>",
|
|
5374
5575
|
" audienti prospects assign <prsp_id> --assigned-user <id|me|unassign>",
|
|
5375
|
-
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|rejected>",
|
|
5576
|
+
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected>",
|
|
5577
|
+
" audienti prospects replan <prsp_id> [--apply]",
|
|
5376
5578
|
" audienti prospects lock <prsp_id> [--note <text>]",
|
|
5377
5579
|
" audienti prospects reject <prsp_id>",
|
|
5378
5580
|
" audienti prospects nurture <prsp_id> [--reason <reason>]",
|
|
@@ -5411,11 +5613,13 @@ const HELP_TOPICS = new Map([
|
|
|
5411
5613
|
" audienti prospects write <prsp_id> --type <surface_key>",
|
|
5412
5614
|
" audienti prospects sequence-export <prsp_id>",
|
|
5413
5615
|
"",
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
"
|
|
5616
|
+
" Operator queue",
|
|
5617
|
+
" audienti operator next --plan",
|
|
5618
|
+
" audienti operator next --done --note <text>",
|
|
5619
|
+
" audienti operator queue",
|
|
5620
|
+
" audienti operator failed-drafts",
|
|
5621
|
+
" audienti operator failed-drafts requeue <row_id>",
|
|
5622
|
+
"",
|
|
5419
5623
|
" Analytics",
|
|
5420
5624
|
" audienti analytics prospects --window 24h",
|
|
5421
5625
|
" audienti analytics dashboard --play-tag <tag>",
|
|
@@ -6874,7 +7078,8 @@ const HELP_TOPICS = new Map([
|
|
|
6874
7078
|
" audienti prospects check [--json|--csv] [filters]",
|
|
6875
7079
|
" audienti prospects show <prsp_id> [--json]",
|
|
6876
7080
|
" audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json]",
|
|
6877
|
-
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|rejected> [--json]",
|
|
7081
|
+
" audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected> [--json]",
|
|
7082
|
+
" audienti prospects replan <prsp_id> [--apply] [--json]",
|
|
6878
7083
|
" audienti prospects reject <prsp_id> [--json]",
|
|
6879
7084
|
" audienti prospects nurture <prsp_id> [--reason <reason>] [--json]",
|
|
6880
7085
|
" audienti prospects restore <prsp_id> [--json]",
|
|
@@ -7032,10 +7237,10 @@ const HELP_TOPICS = new Map([
|
|
|
7032
7237
|
" Set the account-scoped prospect disposition directly, without routing through a motion.",
|
|
7033
7238
|
"",
|
|
7034
7239
|
"Input shape:",
|
|
7035
|
-
" status: active | nurture | non_responsive | not_fit | rejected",
|
|
7240
|
+
" status: active | nurture | non_responsive | not_fit | bad_data_404 | rejected",
|
|
7036
7241
|
"",
|
|
7037
7242
|
"Behavior:",
|
|
7038
|
-
" active restores the prospect, rejected uses the rejection/DNC path, and nurture/non_responsive/not_fit use the shared inactive disposition path.",
|
|
7243
|
+
" active restores the prospect, rejected uses the rejection/DNC path, and nurture/non_responsive/not_fit/bad_data_404 use the shared inactive disposition path.",
|
|
7039
7244
|
"",
|
|
7040
7245
|
"API:",
|
|
7041
7246
|
" POST /api/v1/accounts/:account_id/prospects/:id/restore.json",
|
|
@@ -7056,6 +7261,28 @@ const HELP_TOPICS = new Map([
|
|
|
7056
7261
|
" GET /api/v1/accounts/:account_id/prospects/:id.json"
|
|
7057
7262
|
].join("\n")],
|
|
7058
7263
|
|
|
7264
|
+
["prospects replan", [
|
|
7265
|
+
"Usage:",
|
|
7266
|
+
` ${PROSPECTS_REPLAN_USAGE.slice("Usage: ".length)}`,
|
|
7267
|
+
"",
|
|
7268
|
+
"Status: implemented",
|
|
7269
|
+
"",
|
|
7270
|
+
"Purpose:",
|
|
7271
|
+
" Re-run the next-action coach for one account prospect from the CLI without adding a product UI button.",
|
|
7272
|
+
"",
|
|
7273
|
+
"Behavior:",
|
|
7274
|
+
" Defaults to a dry-run so operators can compare the cached plan with the current planner output.",
|
|
7275
|
+
" Pass --apply to persist the replanned AccountProspect coach payload.",
|
|
7276
|
+
"",
|
|
7277
|
+
"API:",
|
|
7278
|
+
" POST /api/v1/accounts/:account_id/prospects/:id/replan.json",
|
|
7279
|
+
"",
|
|
7280
|
+
"JSON body:",
|
|
7281
|
+
" {",
|
|
7282
|
+
" \"apply\": true",
|
|
7283
|
+
" }"
|
|
7284
|
+
].join("\n")],
|
|
7285
|
+
|
|
7059
7286
|
["prospects reject", [
|
|
7060
7287
|
"Usage:",
|
|
7061
7288
|
` ${PROSPECTS_REJECT_USAGE.slice("Usage: ".length)}`,
|
|
@@ -7079,7 +7306,7 @@ const HELP_TOPICS = new Map([
|
|
|
7079
7306
|
" Move one prospect to an inactive nurture disposition through the shared disposition path.",
|
|
7080
7307
|
"",
|
|
7081
7308
|
"Input shape:",
|
|
7082
|
-
" reason: nurture | non_responsive | not_fit. Defaults to nurture.",
|
|
7309
|
+
" reason: nurture | non_responsive | not_fit | bad_data_404. Defaults to nurture.",
|
|
7083
7310
|
"",
|
|
7084
7311
|
"API:",
|
|
7085
7312
|
" POST /api/v1/accounts/:account_id/prospects/:id/nurture.json"
|
|
@@ -7676,9 +7903,11 @@ const HELP_TOPICS = new Map([
|
|
|
7676
7903
|
"Usage:",
|
|
7677
7904
|
" audienti operator next [--json|--plan|--done|--skip|--fail|--return]",
|
|
7678
7905
|
" audienti operator queue [--json]",
|
|
7906
|
+
" audienti operator failed-drafts [--json]",
|
|
7907
|
+
" audienti operator failed-drafts requeue (--all | <row_id> [row_id...])",
|
|
7679
7908
|
" audienti operator outcome <row_id> --payload <file.json>",
|
|
7680
7909
|
"",
|
|
7681
|
-
"Status: read commands and prospect next-move writeback implemented",
|
|
7910
|
+
"Status: read commands, failed draft requeue, and prospect next-move writeback implemented",
|
|
7682
7911
|
"",
|
|
7683
7912
|
"Filters:",
|
|
7684
7913
|
" --principal <account_user_id>",
|
|
@@ -7736,6 +7965,37 @@ const HELP_TOPICS = new Map([
|
|
|
7736
7965
|
" GET /api/v1/accounts/:account_id/operator.json"
|
|
7737
7966
|
].join("\n")],
|
|
7738
7967
|
|
|
7968
|
+
["operator failed-drafts", [
|
|
7969
|
+
"Usage:",
|
|
7970
|
+
" audienti operator failed-drafts [--json] [filters] [--account <acct_id>]",
|
|
7971
|
+
" audienti operator failed-drafts requeue (--all | <row_id> [row_id...]) [--limit <n>] [--json] [filters] [--account <acct_id>]",
|
|
7972
|
+
"",
|
|
7973
|
+
"Status: implemented",
|
|
7974
|
+
"",
|
|
7975
|
+
"Purpose:",
|
|
7976
|
+
" Lists failed prospect operator drafts and queues selected drafts for rewriting.",
|
|
7977
|
+
"",
|
|
7978
|
+
"Filters:",
|
|
7979
|
+
" --principal <account_user_id>",
|
|
7980
|
+
" --motion <motn_id>",
|
|
7981
|
+
" --list <list_id>",
|
|
7982
|
+
" --stage <stage>",
|
|
7983
|
+
" --query <text>",
|
|
7984
|
+
"",
|
|
7985
|
+
"Output:",
|
|
7986
|
+
" Plain text: failed draft rows with status, reason, and draft snippet",
|
|
7987
|
+
" JSON list: standard operator queue payload forced to prospect draft_failed rows",
|
|
7988
|
+
" JSON requeue: { status, queued[], skipped[], failed[], metrics, message }",
|
|
7989
|
+
"",
|
|
7990
|
+
"Notes:",
|
|
7991
|
+
" Requeue is async. A queued response means the rewrite job was accepted, not that the draft passed.",
|
|
7992
|
+
" If a rewrite fails again, rerun the list command with the same filters to see the latest failure reason.",
|
|
7993
|
+
"",
|
|
7994
|
+
"API:",
|
|
7995
|
+
" GET /api/v1/accounts/:account_id/operator.json?opportunity_kind=prospect&writing_status=draft_failed",
|
|
7996
|
+
" POST /api/v1/accounts/:account_id/operator/failed_drafts/requeue.json"
|
|
7997
|
+
].join("\n")],
|
|
7998
|
+
|
|
7739
7999
|
["operator outcome", [
|
|
7740
8000
|
"Usage:",
|
|
7741
8001
|
" audienti operator outcome <row_id> --payload <file.json> [--json] [--account <acct_id>]",
|
|
@@ -8002,11 +8262,13 @@ const HELP_TOPICS = new Map([
|
|
|
8002
8262
|
" audienti lists add-prospects <list_id> <prsp_id> [prsp_id...]",
|
|
8003
8263
|
" audienti motions add-prospects <motn_id> <prsp_id> [prsp_id...]",
|
|
8004
8264
|
"",
|
|
8005
|
-
|
|
8006
|
-
|
|
8007
|
-
|
|
8008
|
-
|
|
8009
|
-
|
|
8265
|
+
"6. Work the operator queue",
|
|
8266
|
+
" audienti operator next",
|
|
8267
|
+
" audienti operator next --plan",
|
|
8268
|
+
" audienti operator queue --json",
|
|
8269
|
+
" audienti operator failed-drafts",
|
|
8270
|
+
" audienti operator failed-drafts requeue <row_id>",
|
|
8271
|
+
" audienti operator outcome <row_id> --payload <file.json>",
|
|
8010
8272
|
"",
|
|
8011
8273
|
"7. Inspect account analytics",
|
|
8012
8274
|
" audienti users activity me --window 7d",
|