@audienti/cli 0.1.25 → 0.1.28

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 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.28] - 2026-07-23
8
+
9
+ ### Added
10
+
11
+ - Add `audienti prospects reenrich` for dry-running or queueing one forced LinkedIn person profile re-enrichment.
12
+ - Add `audienti prospects refresh-queue` for dry-running or applying account-scoped next-action and operator draft cache repair for one prospect.
13
+
14
+ ## [0.1.27] - 2026-07-22
15
+
16
+ ### Added
17
+
18
+ - Add `audienti operator failed-drafts` and `audienti operator failed-drafts requeue` for listing failed prospect operator drafts and queueing async rewrites.
19
+
20
+ ### Fixed
21
+
22
+ - Show prospect replan coach errors as not persisted instead of displaying failed `--apply` runs as dry runs.
23
+
24
+ ## [0.1.26] - 2026-07-22
25
+
26
+ ### Added
27
+
28
+ - Add `audienti prospects replan <prsp_id> [--apply]` for dry-running or persisting refreshed next-action coach plans.
29
+
7
30
  ## [0.1.25] - 2026-07-22
8
31
 
9
32
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audienti/cli",
3
- "version": "0.1.25",
3
+ "version": "0.1.28",
4
4
  "description": "Agent-first command-line client for Audienti.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api-client.js CHANGED
@@ -366,6 +366,27 @@ 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
+
376
+ reenrichProspect(accountId, prospectId, body = {}) {
377
+ return this.requestJson(accountPath(accountId, ["prospects", prospectId, "reenrich"]), {
378
+ method: "POST",
379
+ body
380
+ });
381
+ }
382
+
383
+ refreshProspectQueue(accountId, prospectId, body = {}) {
384
+ return this.requestJson(accountPath(accountId, ["prospects", prospectId, "refresh_queue"]), {
385
+ method: "POST",
386
+ body
387
+ });
388
+ }
389
+
369
390
  assignProspects(accountId, body) {
370
391
  return this.requestJson(accountPath(accountId, ["prospects", "assign"]), {
371
392
  method: "POST",
@@ -500,6 +521,13 @@ export class AudientiClient {
500
521
  return this.requestJson(accountPath(accountId, ["operator", "next"], query));
501
522
  }
502
523
 
524
+ requeueOperatorFailedDrafts(accountId, body = {}) {
525
+ return this.requestJson(accountPath(accountId, ["operator", "failed_drafts", "requeue"]), {
526
+ method: "POST",
527
+ body
528
+ });
529
+ }
530
+
503
531
  operatorOutcome(accountId, body) {
504
532
  return this.requestJson(accountPath(accountId, ["operator", "outcome"]), {
505
533
  method: "POST",
package/src/cli.js CHANGED
@@ -38,6 +38,9 @@ const PROSPECTS_ADD_PROFILE_USAGE = "Usage: audienti prospects add-profile <prsp
38
38
  const PROSPECTS_REPORT_BAD_PROFILE_USAGE = "Usage: audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json] [--account <acct_id>]";
39
39
  const PROSPECTS_ASSIGN_USAGE = "Usage: audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json] [--account <acct_id>]";
40
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>]";
42
+ const PROSPECTS_REENRICH_USAGE = "Usage: audienti prospects reenrich <prsp_id> [--profile <prof_id|citation_id>] [--apply] [--json] [--account <acct_id>]";
43
+ const PROSPECTS_REFRESH_QUEUE_USAGE = "Usage: audienti prospects refresh-queue <prsp_id> [--apply] [--json] [--account <acct_id>]";
41
44
  const PROSPECTS_REJECT_USAGE = "Usage: audienti prospects reject <prsp_id> [--json] [--account <acct_id>]";
42
45
  const PROSPECTS_NURTURE_USAGE = "Usage: audienti prospects nurture <prsp_id> [--reason <nurture|non_responsive|not_fit|bad_data_404>] [--json] [--account <acct_id>]";
43
46
  const PROSPECTS_RESTORE_USAGE = "Usage: audienti prospects restore <prsp_id> [--json] [--account <acct_id>]";
@@ -45,6 +48,8 @@ const PROSPECTS_LOCK_USAGE = "Usage: audienti prospects lock <prsp_id> [--note <
45
48
  const PROSPECTS_UNLOCK_USAGE = "Usage: audienti prospects unlock <prsp_id> [--json] [--account <acct_id>]";
46
49
  const PROSPECTS_CHECK_USAGE = "Usage: audienti prospects check [--json|--csv] [filters] [--account <acct_id>]";
47
50
  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>]";
51
+ const OPERATOR_FAILED_DRAFTS_USAGE = "Usage: audienti operator failed-drafts [--json] [filters] [--account <acct_id>]";
52
+ const OPERATOR_FAILED_DRAFTS_REQUEUE_USAGE = "Usage: audienti operator failed-drafts requeue (--all | <row_id> [row_id...]) [--limit <n>] [--json] [filters] [--account <acct_id>]";
48
53
  const DNC_ADD_USAGE = "Usage: audienti dnc add <email|citation_id|profile_url> [--json] [--account <acct_id>]";
49
54
  const DNC_IMPORT_USAGE = "Usage: audienti dnc import --file <txt|csv> [--json] [--account <acct_id>]";
50
55
  const DNC_REMOVE_USAGE = "Usage: audienti dnc remove <dnc_entry_id> [--json] [--account <acct_id>]";
@@ -243,6 +248,9 @@ async function dispatch(argv, context) {
243
248
  if (normalizedResource === "prospects" && action === "show") return prospectsShow(rest, context, { accountOverride });
244
249
  if (normalizedResource === "prospects" && action === "assign") return prospectsAssign(rest, context, { accountOverride });
245
250
  if (normalizedResource === "prospects" && action === "set-status") return prospectsSetStatus(rest, context, { accountOverride });
251
+ if (normalizedResource === "prospects" && action === "replan") return prospectsReplan(rest, context, { accountOverride });
252
+ if (normalizedResource === "prospects" && action === "reenrich") return prospectsReenrich(rest, context, { accountOverride });
253
+ if (normalizedResource === "prospects" && action === "refresh-queue") return prospectsRefreshQueue(rest, context, { accountOverride });
246
254
  if (normalizedResource === "prospects" && action === "reject") return prospectsDisposition("reject", rest, context, { accountOverride });
247
255
  if (normalizedResource === "prospects" && action === "nurture") return prospectsDisposition("nurture", rest, context, { accountOverride });
248
256
  if (normalizedResource === "prospects" && action === "restore") return prospectsDisposition("restore", rest, context, { accountOverride });
@@ -264,6 +272,7 @@ async function dispatch(argv, context) {
264
272
  if (normalizedResource === "tools" && action === "list") return toolsList(rest, context);
265
273
  if (normalizedResource === "tools" && action === "get") return toolsGet(rest, context, { accountOverride });
266
274
  if (normalizedResource === "tools" && action === "linkedin-review") return toolsLinkedinReview(rest, context, { accountOverride });
275
+ if (normalizedResource === "operator" && action === "failed-drafts") return operatorFailedDrafts(rest, context, { accountOverride });
267
276
  if (normalizedResource === "operator" && action === "queue") return operatorQueue(rest, context, { accountOverride });
268
277
  if (normalizedResource === "operator" && action === "next") return operatorNext(rest, context, { accountOverride });
269
278
  if (normalizedResource === "operator" && action === "outcome") return operatorOutcome(rest, context, { accountOverride });
@@ -1840,6 +1849,56 @@ async function prospectsShow(args, context, { accountOverride } = {}) {
1840
1849
  renderProspect(prospect, context);
1841
1850
  }
1842
1851
 
1852
+ async function prospectsReplan(args, context, { accountOverride } = {}) {
1853
+ const { values, positionals } = parseCommandArgs(args, {
1854
+ ...jsonOptions(),
1855
+ apply: { type: "boolean" }
1856
+ });
1857
+ if (positionals.length !== 1) throw new CommandError(PROSPECTS_REPLAN_USAGE);
1858
+
1859
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
1860
+ const payload = await client.replanProspect(accountId, positionals[0], compactObject({
1861
+ apply: values.apply
1862
+ }));
1863
+ if (values.json) return writeJson(context.stdout, payload);
1864
+
1865
+ renderProspectReplan(payload, context);
1866
+ }
1867
+
1868
+ async function prospectsReenrich(args, context, { accountOverride } = {}) {
1869
+ const { values, positionals } = parseCommandArgs(args, {
1870
+ ...jsonOptions(),
1871
+ apply: { type: "boolean" },
1872
+ profile: { type: "string" }
1873
+ });
1874
+ if (positionals.length !== 1) throw new CommandError(PROSPECTS_REENRICH_USAGE);
1875
+
1876
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
1877
+ const payload = await client.reenrichProspect(accountId, positionals[0], compactObject({
1878
+ apply: values.apply,
1879
+ profile_id: values.profile
1880
+ }));
1881
+ if (values.json) return writeJson(context.stdout, payload);
1882
+
1883
+ renderProspectReenrich(payload, context);
1884
+ }
1885
+
1886
+ async function prospectsRefreshQueue(args, context, { accountOverride } = {}) {
1887
+ const { values, positionals } = parseCommandArgs(args, {
1888
+ ...jsonOptions(),
1889
+ apply: { type: "boolean" }
1890
+ });
1891
+ if (positionals.length !== 1) throw new CommandError(PROSPECTS_REFRESH_QUEUE_USAGE);
1892
+
1893
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
1894
+ const payload = await client.refreshProspectQueue(accountId, positionals[0], compactObject({
1895
+ apply: values.apply
1896
+ }));
1897
+ if (values.json) return writeJson(context.stdout, payload);
1898
+
1899
+ renderProspectRefreshQueue(payload, context);
1900
+ }
1901
+
1843
1902
  async function prospectsDisposition(action, args, context, { accountOverride } = {}) {
1844
1903
  const usageText = {
1845
1904
  reject: PROSPECTS_REJECT_USAGE,
@@ -2444,6 +2503,41 @@ async function operatorQueue(args, context, { accountOverride } = {}) {
2444
2503
  renderOperatorQueue(payload, context);
2445
2504
  }
2446
2505
 
2506
+ async function operatorFailedDrafts(args, context, { accountOverride } = {}) {
2507
+ if (args[0] === "requeue") {
2508
+ return operatorFailedDraftsRequeue(args.slice(1), context, { accountOverride });
2509
+ }
2510
+
2511
+ const { values, positionals } = parseCommandArgs(args, operatorFailedDraftOptions());
2512
+ if (positionals.length > 0) throw new CommandError(OPERATOR_FAILED_DRAFTS_USAGE);
2513
+
2514
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
2515
+ const payload = await client.operatorQueue(accountId, operatorFailedDraftQuery(values));
2516
+ if (values.json) return writeJson(context.stdout, payload);
2517
+
2518
+ renderOperatorFailedDrafts(payload, context);
2519
+ }
2520
+
2521
+ async function operatorFailedDraftsRequeue(args, context, { accountOverride } = {}) {
2522
+ const { values, positionals } = parseCommandArgs(args, operatorFailedDraftOptions({
2523
+ all: { type: "boolean" },
2524
+ limit: { type: "string" }
2525
+ }));
2526
+ if (values.all && positionals.length > 0) throw new CommandError("Choose either --all or row ids, not both.");
2527
+ if (!values.all && positionals.length === 0) throw new CommandError(OPERATOR_FAILED_DRAFTS_REQUEUE_USAGE);
2528
+
2529
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
2530
+ const payload = await client.requeueOperatorFailedDrafts(accountId, compactObject({
2531
+ ...operatorFailedDraftQuery(values),
2532
+ all: values.all || undefined,
2533
+ limit: values.limit,
2534
+ row_ids: positionals.length > 0 ? positionals : undefined
2535
+ }));
2536
+ if (values.json) return writeJson(context.stdout, payload);
2537
+
2538
+ renderOperatorFailedDraftRequeue(payload, context);
2539
+ }
2540
+
2447
2541
  async function operatorNext(args, context, { accountOverride } = {}) {
2448
2542
  const { values, positionals } = parseCommandArgs(args, operatorNextOptions());
2449
2543
  if (positionals.length > 0) throw new CommandError("Usage: audienti operator next [--json|--plan|--done|--skip|--fail|--return] [filters] [--note <text>] [--account <acct_id>]");
@@ -2705,6 +2799,18 @@ function operatorNextOptions() {
2705
2799
  });
2706
2800
  }
2707
2801
 
2802
+ function operatorFailedDraftOptions(extra = {}) {
2803
+ return {
2804
+ ...jsonOptions(),
2805
+ principal: { type: "string" },
2806
+ motion: { type: "string" },
2807
+ list: { type: "string" },
2808
+ stage: { type: "string" },
2809
+ query: { type: "string" },
2810
+ ...extra
2811
+ };
2812
+ }
2813
+
2708
2814
  function operatorQuery(values) {
2709
2815
  return compactObject({
2710
2816
  principal_account_user_id: values.principal,
@@ -2716,6 +2822,18 @@ function operatorQuery(values) {
2716
2822
  });
2717
2823
  }
2718
2824
 
2825
+ function operatorFailedDraftQuery(values) {
2826
+ return compactObject({
2827
+ principal_account_user_id: values.principal,
2828
+ motion_id: values.motion,
2829
+ list_id: values.list,
2830
+ stage: values.stage,
2831
+ query: values.query,
2832
+ opportunity_kind: "prospect",
2833
+ writing_status: "draft_failed"
2834
+ });
2835
+ }
2836
+
2719
2837
  function operatorNextOutcomeStatus(values) {
2720
2838
  const selected = [
2721
2839
  values.done ? "done" : null,
@@ -3901,6 +4019,95 @@ function renderProspect(prospect, context) {
3901
4019
  if (nextActionLabel(prospect?.queue)) writeLine(context.stdout, `Next action: ${nextActionLabel(prospect.queue)}`);
3902
4020
  }
3903
4021
 
4022
+ function renderProspectReplan(payload, context) {
4023
+ const prospect = payload?.prospect || {};
4024
+ const current = payload?.current || {};
4025
+ const replanned = payload?.replanned || {};
4026
+ const status = replanStatusLabel(payload);
4027
+
4028
+ writeLine(context.stdout, `Replan ${status} for ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)}).`);
4029
+ writeLine(context.stdout, `Changed: ${payload?.changed ? "yes" : "no"}`);
4030
+ if (payload?.reason_code) writeLine(context.stdout, `Reason: ${payload.reason_code}`);
4031
+ writeLine(context.stdout, `Current: ${formatCoachAction(current.next_action)}`);
4032
+ writeLine(context.stdout, `Replanned: ${formatCoachAction(replanned.next_action)}`);
4033
+ if (replanned.rationale) writeLine(context.stdout, `Rationale: ${replanned.rationale}`);
4034
+ if (replanned.guidance) writeLine(context.stdout, `Guidance: ${replanned.guidance}`);
4035
+ if (payload?.status === "dry_run") writeLine(context.stdout, "Run again with --apply to persist this plan.");
4036
+ if (payload?.status === "coach_error") writeLine(context.stdout, "The plan was not persisted. Fix the coach error and rerun with --apply.");
4037
+ }
4038
+
4039
+ function renderProspectReenrich(payload, context) {
4040
+ const prospect = payload?.prospect || {};
4041
+ const profile = payload?.profile || {};
4042
+ const completeness = payload?.completeness || {};
4043
+ const enrichment = payload?.enrichment || {};
4044
+ const status = payload?.status === "queued" ? "queued" : (payload?.status === "not_queued" ? "not queued" : "dry run");
4045
+
4046
+ writeLine(context.stdout, `Re-enrich ${status} for ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)}).`);
4047
+ writeLine(context.stdout, `Profile: ${display(profile.prefix_id)} ${display(profile.identifier)} ${display(profile.url)}`);
4048
+ writeLine(context.stdout, `Profile status: ${display(profile.status)}`);
4049
+ writeLine(context.stdout, `Thin profile signals: ${completeness.thin_profile_signals ? "yes" : "no"}`);
4050
+ writeLine(context.stdout, `Experience entries: ${sumObjectValues(completeness.experience_counts)}`);
4051
+ writeLine(context.stdout, `Substantive bio length: ${display(completeness.substantive_bio_length, 0)}`);
4052
+ if (profile.invalid_reason) writeLine(context.stdout, `Invalid reason: ${profile.invalid_reason}`);
4053
+ if (enrichment.retry_counter_reset) writeLine(context.stdout, "A stale enrichment retry counter will be cleared.");
4054
+ if (enrichment.next_enrichment_at) writeLine(context.stdout, `Next enrichment at: ${enrichment.next_enrichment_at}`);
4055
+ if (payload?.status === "dry_run") writeLine(context.stdout, "Run again with --apply to queue full enrichment.");
4056
+ if (payload?.status === "not_queued") writeLine(context.stdout, "The profile was not queued, usually because an active enrichment is already running.");
4057
+ }
4058
+
4059
+ function renderProspectRefreshQueue(payload, context) {
4060
+ const prospect = payload?.prospect || {};
4061
+ const draftCache = payload?.draft_cache || {};
4062
+ const coachCache = payload?.coach_cache || {};
4063
+ const refresh = payload?.queue_refresh || {};
4064
+ const status = payload?.status === "applied" ? "applied" : "dry run";
4065
+
4066
+ writeLine(context.stdout, `Refresh queue ${status} for ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)}).`);
4067
+ writeLine(context.stdout, `Coach cache: ${coachCache.present ? "present" : "empty"}`);
4068
+ if (coachCache.evaluated_at) writeLine(context.stdout, `Coach evaluated at: ${coachCache.evaluated_at}`);
4069
+ writeLine(context.stdout, `Draft cache rows: ${display(draftCache.count, 0)}`);
4070
+ writeLine(context.stdout, `Draft statuses: ${formatObjectCounts(draftCache.by_status)}`);
4071
+ writeLine(context.stdout, `Action types: ${Array.isArray(draftCache.action_types) && draftCache.action_types.length > 0 ? draftCache.action_types.join(", ") : "none"}`);
4072
+ if (payload?.applied) {
4073
+ writeLine(context.stdout, `Deleted draft rows: ${display(draftCache.deleted_count, 0)}`);
4074
+ writeLine(context.stdout, `Draft prewarm queued: ${display(refresh?.draft_prewarm?.enqueued_rows, 0)}`);
4075
+ } else {
4076
+ writeLine(context.stdout, "Run again with --apply to clear coach/draft cache and rebuild the queue row.");
4077
+ }
4078
+ }
4079
+
4080
+ function sumObjectValues(value) {
4081
+ if (!value || typeof value !== "object") return 0;
4082
+
4083
+ return Object.values(value).reduce((sum, item) => sum + Number(item || 0), 0);
4084
+ }
4085
+
4086
+ function formatObjectCounts(value) {
4087
+ if (!value || typeof value !== "object" || Object.keys(value).length === 0) return "none";
4088
+
4089
+ return Object.entries(value)
4090
+ .map(([key, count]) => `${key}:${count}`)
4091
+ .join(", ");
4092
+ }
4093
+
4094
+ function replanStatusLabel(payload) {
4095
+ if (payload?.status === "dry_run") return "dry run";
4096
+ if (payload?.status === "coach_error") return "coach error";
4097
+ if (payload?.status === "not_applied") return "not applied";
4098
+
4099
+ return payload?.applied ? "applied" : "dry run";
4100
+ }
4101
+
4102
+ function formatCoachAction(nextAction = {}) {
4103
+ const action = nextAction?.label || nextAction?.type || "none";
4104
+ const mode = nextAction?.request_mode || nextAction?.mode;
4105
+ const timing = nextAction?.timing?.mode;
4106
+ const details = compactText([mode, timing]).join(", ");
4107
+
4108
+ return details ? `${action} (${details})` : action;
4109
+ }
4110
+
3904
4111
  function renderProspectDisposition(payload, context, { action }) {
3905
4112
  const prospect = payload?.prospect || {};
3906
4113
  const accountProspect = payload?.account_prospect || {};
@@ -4597,6 +4804,87 @@ function renderOperatorOutcome(payload, context) {
4597
4804
  }
4598
4805
  }
4599
4806
 
4807
+ function renderOperatorFailedDrafts(payload, context) {
4808
+ const rows = Array.isArray(payload?.decision_queue) ? payload.decision_queue : [];
4809
+ if (rows.length === 0) {
4810
+ writeLine(context.stdout, "No failed operator drafts found.");
4811
+ return;
4812
+ }
4813
+
4814
+ writeLine(context.stdout, "Failed operator drafts");
4815
+ writeAlignedTable(context, ["ROW ID", "PROSPECT", "MOTION", "STATUS", "REASON", "DRAFT"], rows.map(operatorFailedDraftTableRow));
4816
+ writeLine(context.stdout, "");
4817
+ writeLine(context.stdout, `Shown: ${rows.length}`);
4818
+ writeLine(context.stdout, "Requeue: audienti operator failed-drafts requeue <row_id> [row_id...]");
4819
+ writeLine(context.stdout, "If a rewrite fails again, it remains in this list with the latest failure reason.");
4820
+ }
4821
+
4822
+ function renderOperatorFailedDraftRequeue(payload, context) {
4823
+ const metrics = payload?.metrics || {};
4824
+ const queued = Number(metrics.queued_count || 0);
4825
+ const skipped = Number(metrics.skipped_count || 0);
4826
+ const failed = Number(metrics.failed_count || 0);
4827
+ writeLine(context.stdout, `Queued draft rewrites: ${queued}`);
4828
+ if (skipped > 0) writeLine(context.stdout, `Skipped: ${skipped}`);
4829
+ if (failed > 0) writeLine(context.stdout, `Failed: ${failed}`);
4830
+
4831
+ writeOperatorFailedDraftRequeueDetails(context, "Queued", payload?.queued);
4832
+ writeOperatorFailedDraftRequeueDetails(context, "Skipped", payload?.skipped);
4833
+ writeOperatorFailedDraftRequeueDetails(context, "Failed", payload?.failed);
4834
+
4835
+ const message = payload?.message ||
4836
+ "Rewrites run asynchronously. Re-run `audienti operator failed-drafts` with the same filters to see drafts that still fail after rewriting.";
4837
+ writeLine(context.stdout, "");
4838
+ writeLine(context.stdout, message);
4839
+ }
4840
+
4841
+ function writeOperatorFailedDraftRequeueDetails(context, label, rows) {
4842
+ const list = Array.isArray(rows) ? rows : [];
4843
+ if (list.length === 0) return;
4844
+
4845
+ writeLine(context.stdout, "");
4846
+ writeLine(context.stdout, label);
4847
+ writeAlignedTable(context, ["ROW ID", "PROSPECT", "REASON", "DRAFT ID", "JOB ID"], list.map((row) => [
4848
+ display(row.row_id),
4849
+ display(row.prospect_name || row.prospect_id),
4850
+ display(row.reason),
4851
+ display(row.draft_id || row.source_draft_id),
4852
+ display(row.job_id)
4853
+ ]));
4854
+ }
4855
+
4856
+ function operatorFailedDraftTableRow(row) {
4857
+ const draft = row?.operator_draft || {};
4858
+ return [
4859
+ display(row?.id),
4860
+ operatorSubjectLabel(row),
4861
+ operatorMotionLabel(row),
4862
+ display(draft.status || draft.state),
4863
+ operatorFailedDraftReason(draft),
4864
+ operatorFailedDraftSnippet(draft)
4865
+ ];
4866
+ }
4867
+
4868
+ function operatorFailedDraftReason(draft) {
4869
+ const payload = draft?.payload || {};
4870
+ const codes = Array.isArray(payload.quality_codes) ? payload.quality_codes.filter(Boolean).join(",") : "";
4871
+ return display(
4872
+ codes ||
4873
+ payload.blank_reason ||
4874
+ payload.error ||
4875
+ payload.message ||
4876
+ payload.status ||
4877
+ draft?.status ||
4878
+ draft?.state,
4879
+ "-"
4880
+ );
4881
+ }
4882
+
4883
+ function operatorFailedDraftSnippet(draft) {
4884
+ const payload = draft?.payload || {};
4885
+ return truncateCliText(payload.subject || payload.body || payload.text || "", 64) || "-";
4886
+ }
4887
+
4600
4888
  function renderAnalyticsProspects(payload, context) {
4601
4889
  writeLine(context.stdout, `Prospect analytics (${analyticsWindowLabel(payload)})`);
4602
4890
  writeAnalyticsCohort(payload, context);
@@ -5379,6 +5667,9 @@ const HELP_TOPICS = new Map([
5379
5667
  " audienti prospects show <prsp_id>",
5380
5668
  " audienti prospects assign <prsp_id> --assigned-user <id|me|unassign>",
5381
5669
  " audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected>",
5670
+ " audienti prospects replan <prsp_id> [--apply]",
5671
+ " audienti prospects reenrich <prsp_id> [--apply]",
5672
+ " audienti prospects refresh-queue <prsp_id> [--apply]",
5382
5673
  " audienti prospects lock <prsp_id> [--note <text>]",
5383
5674
  " audienti prospects reject <prsp_id>",
5384
5675
  " audienti prospects nurture <prsp_id> [--reason <reason>]",
@@ -5417,11 +5708,13 @@ const HELP_TOPICS = new Map([
5417
5708
  " audienti prospects write <prsp_id> --type <surface_key>",
5418
5709
  " audienti prospects sequence-export <prsp_id>",
5419
5710
  "",
5420
- " Operator queue",
5421
- " audienti operator next --plan",
5422
- " audienti operator next --done --note <text>",
5423
- " audienti operator queue",
5424
- "",
5711
+ " Operator queue",
5712
+ " audienti operator next --plan",
5713
+ " audienti operator next --done --note <text>",
5714
+ " audienti operator queue",
5715
+ " audienti operator failed-drafts",
5716
+ " audienti operator failed-drafts requeue <row_id>",
5717
+ "",
5425
5718
  " Analytics",
5426
5719
  " audienti analytics prospects --window 24h",
5427
5720
  " audienti analytics dashboard --play-tag <tag>",
@@ -6881,6 +7174,9 @@ const HELP_TOPICS = new Map([
6881
7174
  " audienti prospects show <prsp_id> [--json]",
6882
7175
  " audienti prospects assign <prsp_id> [prsp_id...] --assigned-user <id|me|unassign> [--json]",
6883
7176
  " audienti prospects set-status <prsp_id> --status <active|nurture|non_responsive|not_fit|bad_data_404|rejected> [--json]",
7177
+ " audienti prospects replan <prsp_id> [--apply] [--json]",
7178
+ " audienti prospects reenrich <prsp_id> [--profile <prof_id|citation_id>] [--apply] [--json]",
7179
+ " audienti prospects refresh-queue <prsp_id> [--apply] [--json]",
6884
7180
  " audienti prospects reject <prsp_id> [--json]",
6885
7181
  " audienti prospects nurture <prsp_id> [--reason <reason>] [--json]",
6886
7182
  " audienti prospects restore <prsp_id> [--json]",
@@ -7062,6 +7358,73 @@ const HELP_TOPICS = new Map([
7062
7358
  " GET /api/v1/accounts/:account_id/prospects/:id.json"
7063
7359
  ].join("\n")],
7064
7360
 
7361
+ ["prospects replan", [
7362
+ "Usage:",
7363
+ ` ${PROSPECTS_REPLAN_USAGE.slice("Usage: ".length)}`,
7364
+ "",
7365
+ "Status: implemented",
7366
+ "",
7367
+ "Purpose:",
7368
+ " Re-run the next-action coach for one account prospect from the CLI without adding a product UI button.",
7369
+ "",
7370
+ "Behavior:",
7371
+ " Defaults to a dry-run so operators can compare the cached plan with the current planner output.",
7372
+ " Pass --apply to persist the replanned AccountProspect coach payload.",
7373
+ "",
7374
+ "API:",
7375
+ " POST /api/v1/accounts/:account_id/prospects/:id/replan.json",
7376
+ "",
7377
+ "JSON body:",
7378
+ " {",
7379
+ " \"apply\": true",
7380
+ " }"
7381
+ ].join("\n")],
7382
+
7383
+ ["prospects reenrich", [
7384
+ "Usage:",
7385
+ ` ${PROSPECTS_REENRICH_USAGE.slice("Usage: ".length)}`,
7386
+ "",
7387
+ "Status: implemented",
7388
+ "",
7389
+ "Purpose:",
7390
+ " Force a full LinkedIn person profile enrichment for one prospect from the CLI.",
7391
+ "",
7392
+ "Behavior:",
7393
+ " Defaults to a dry-run showing the selected profile, completeness signals, and whether a stale retry counter would be cleared.",
7394
+ " Pass --apply to queue ProfileEnrichJob with a maintenance origin and schedule expansion after enrichment.",
7395
+ "",
7396
+ "API:",
7397
+ " POST /api/v1/accounts/:account_id/prospects/:id/reenrich.json",
7398
+ "",
7399
+ "JSON body:",
7400
+ " {",
7401
+ " \"apply\": true,",
7402
+ " \"profile_id\": \"prof_abc123\"",
7403
+ " }"
7404
+ ].join("\n")],
7405
+
7406
+ ["prospects refresh-queue", [
7407
+ "Usage:",
7408
+ ` ${PROSPECTS_REFRESH_QUEUE_USAGE.slice("Usage: ".length)}`,
7409
+ "",
7410
+ "Status: implemented",
7411
+ "",
7412
+ "Purpose:",
7413
+ " Clear stale next-action coach and operator draft cache for one account prospect, then rebuild the queue row.",
7414
+ "",
7415
+ "Behavior:",
7416
+ " Defaults to a dry-run showing coach-cache and draft-cache state.",
7417
+ " Pass --apply to delete this prospect's account-scoped ProspectDraft rows, clear AccountProspect coach cache, and force the queue refresher.",
7418
+ "",
7419
+ "API:",
7420
+ " POST /api/v1/accounts/:account_id/prospects/:id/refresh_queue.json",
7421
+ "",
7422
+ "JSON body:",
7423
+ " {",
7424
+ " \"apply\": true",
7425
+ " }"
7426
+ ].join("\n")],
7427
+
7065
7428
  ["prospects reject", [
7066
7429
  "Usage:",
7067
7430
  ` ${PROSPECTS_REJECT_USAGE.slice("Usage: ".length)}`,
@@ -7682,9 +8045,11 @@ const HELP_TOPICS = new Map([
7682
8045
  "Usage:",
7683
8046
  " audienti operator next [--json|--plan|--done|--skip|--fail|--return]",
7684
8047
  " audienti operator queue [--json]",
8048
+ " audienti operator failed-drafts [--json]",
8049
+ " audienti operator failed-drafts requeue (--all | <row_id> [row_id...])",
7685
8050
  " audienti operator outcome <row_id> --payload <file.json>",
7686
8051
  "",
7687
- "Status: read commands and prospect next-move writeback implemented",
8052
+ "Status: read commands, failed draft requeue, and prospect next-move writeback implemented",
7688
8053
  "",
7689
8054
  "Filters:",
7690
8055
  " --principal <account_user_id>",
@@ -7742,6 +8107,37 @@ const HELP_TOPICS = new Map([
7742
8107
  " GET /api/v1/accounts/:account_id/operator.json"
7743
8108
  ].join("\n")],
7744
8109
 
8110
+ ["operator failed-drafts", [
8111
+ "Usage:",
8112
+ " audienti operator failed-drafts [--json] [filters] [--account <acct_id>]",
8113
+ " audienti operator failed-drafts requeue (--all | <row_id> [row_id...]) [--limit <n>] [--json] [filters] [--account <acct_id>]",
8114
+ "",
8115
+ "Status: implemented",
8116
+ "",
8117
+ "Purpose:",
8118
+ " Lists failed prospect operator drafts and queues selected drafts for rewriting.",
8119
+ "",
8120
+ "Filters:",
8121
+ " --principal <account_user_id>",
8122
+ " --motion <motn_id>",
8123
+ " --list <list_id>",
8124
+ " --stage <stage>",
8125
+ " --query <text>",
8126
+ "",
8127
+ "Output:",
8128
+ " Plain text: failed draft rows with status, reason, and draft snippet",
8129
+ " JSON list: standard operator queue payload forced to prospect draft_failed rows",
8130
+ " JSON requeue: { status, queued[], skipped[], failed[], metrics, message }",
8131
+ "",
8132
+ "Notes:",
8133
+ " Requeue is async. A queued response means the rewrite job was accepted, not that the draft passed.",
8134
+ " If a rewrite fails again, rerun the list command with the same filters to see the latest failure reason.",
8135
+ "",
8136
+ "API:",
8137
+ " GET /api/v1/accounts/:account_id/operator.json?opportunity_kind=prospect&writing_status=draft_failed",
8138
+ " POST /api/v1/accounts/:account_id/operator/failed_drafts/requeue.json"
8139
+ ].join("\n")],
8140
+
7745
8141
  ["operator outcome", [
7746
8142
  "Usage:",
7747
8143
  " audienti operator outcome <row_id> --payload <file.json> [--json] [--account <acct_id>]",
@@ -8008,11 +8404,13 @@ const HELP_TOPICS = new Map([
8008
8404
  " audienti lists add-prospects <list_id> <prsp_id> [prsp_id...]",
8009
8405
  " audienti motions add-prospects <motn_id> <prsp_id> [prsp_id...]",
8010
8406
  "",
8011
- "6. Work the operator queue",
8012
- " audienti operator next",
8013
- " audienti operator next --plan",
8014
- " audienti operator queue --json",
8015
- " audienti operator outcome <row_id> --payload <file.json>",
8407
+ "6. Work the operator queue",
8408
+ " audienti operator next",
8409
+ " audienti operator next --plan",
8410
+ " audienti operator queue --json",
8411
+ " audienti operator failed-drafts",
8412
+ " audienti operator failed-drafts requeue <row_id>",
8413
+ " audienti operator outcome <row_id> --payload <file.json>",
8016
8414
  "",
8017
8415
  "7. Inspect account analytics",
8018
8416
  " audienti users activity me --window 7d",