@audienti/cli 0.1.1 → 0.1.2

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,13 @@ All notable changes to the Audienti CLI are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.2] - 2026-07-10
8
+
9
+ ### Added
10
+
11
+ - Add `audienti prospects timeline` for filtered prospect timeline reads.
12
+ - Add `audienti prospects sequence-export` for spreadsheet-ready no-reply sequence previews.
13
+
7
14
  ## [0.1.1] - 2026-07-10
8
15
 
9
16
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audienti/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Agent-first command-line client for Audienti.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api-client.js CHANGED
@@ -153,6 +153,10 @@ export class AudientiClient {
153
153
  return this.requestJson(accountPath(accountId, ["prospects", prospectId]));
154
154
  }
155
155
 
156
+ prospectTimeline(accountId, prospectId, query = {}) {
157
+ return this.requestJson(accountPath(accountId, ["prospects", prospectId, "timeline"], query));
158
+ }
159
+
156
160
  prospectMessageTypes(accountId, prospectId) {
157
161
  return this.requestJson(accountPath(accountId, ["prospects", prospectId, "message_types"]));
158
162
  }
@@ -171,6 +175,13 @@ export class AudientiClient {
171
175
  });
172
176
  }
173
177
 
178
+ prospectSequenceExport(accountId, prospectId, body = {}) {
179
+ return this.requestJson(accountPath(accountId, ["prospects", prospectId, "sequence_export"]), {
180
+ method: "POST",
181
+ body
182
+ });
183
+ }
184
+
174
185
  addProspectNote(accountId, prospectId, body) {
175
186
  return this.requestJson(accountPath(accountId, ["prospects", prospectId, "add_note"]), {
176
187
  method: "POST",
package/src/cli.js CHANGED
@@ -26,6 +26,30 @@ 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 SEQUENCE_EXPORT_CSV_COLUMNS = [
30
+ "prospect_id",
31
+ "prospect_name",
32
+ "branch",
33
+ "branch_label",
34
+ "step_number",
35
+ "kind",
36
+ "key",
37
+ "stage",
38
+ "channel",
39
+ "scheduled_for",
40
+ "available",
41
+ "status",
42
+ "subject",
43
+ "body",
44
+ "warnings",
45
+ "writer_engine",
46
+ "rationale",
47
+ "guidance",
48
+ "transition_label",
49
+ "disposition",
50
+ "missing_reason",
51
+ "empty_body_reason"
52
+ ];
29
53
 
30
54
  export async function run(argv = process.argv.slice(2), deps = {}) {
31
55
  const context = {
@@ -85,11 +109,13 @@ async function dispatch(argv, context) {
85
109
  if (normalizedResource === "motions" && action === "create") return motionsCreate(rest, context, { accountOverride });
86
110
  if (normalizedResource === "prospects" && action === "list") return prospectsList(rest, context, { accountOverride });
87
111
  if (normalizedResource === "prospects" && action === "show") return prospectsShow(rest, context, { accountOverride });
112
+ if (normalizedResource === "prospects" && action === "timeline") return prospectsTimeline(rest, context, { accountOverride });
88
113
  if (normalizedResource === "prospects" && action === "message-types") return prospectsMessageTypes(rest, context, { accountOverride });
89
114
  if (normalizedResource === "prospects" && action === "write") return prospectsWrite(rest, context, { accountOverride });
90
115
  if (normalizedResource === "prospects" && action === "add-note") return prospectsAddNote(rest, context, { accountOverride });
91
116
  if (normalizedResource === "prospects" && action === "add-steer") return prospectsAddSteer(rest, context, { accountOverride });
92
117
  if (normalizedResource === "prospects" && action === "sequence-preview") return prospectsSequencePreview(rest, context, { accountOverride });
118
+ if (normalizedResource === "prospects" && action === "sequence-export") return prospectsSequenceExport(rest, context, { accountOverride });
93
119
  if (normalizedResource === "prospects" && action === "import") return prospectsImport(rest, context, { accountOverride });
94
120
  if (normalizedResource === "prospects" && action === "import-status") return prospectsImportStatus(rest, context, { accountOverride });
95
121
  if (normalizedResource === "tools" && action === "get") return toolsGet(rest, context, { accountOverride });
@@ -763,6 +789,28 @@ async function prospectsShow(args, context, { accountOverride } = {}) {
763
789
  renderProspect(prospect, context);
764
790
  }
765
791
 
792
+ async function prospectsTimeline(args, context, { accountOverride } = {}) {
793
+ const { values, positionals } = parseCommandArgs(args, {
794
+ ...jsonOptions(),
795
+ limit: { type: "string" },
796
+ type: { type: "string" },
797
+ types: { type: "string" }
798
+ });
799
+ if (positionals.length !== 1) {
800
+ throw new CommandError("Usage: audienti prospects timeline <prsp_id> [--json] [--types <post,comment,reaction>] [--limit <n>] [--account <acct_id>]");
801
+ }
802
+ if (values.type && values.types) throw new CommandError("Choose one type filter: use either --type or --types.");
803
+
804
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
805
+ const payload = await client.prospectTimeline(accountId, positionals[0], compactObject({
806
+ limit: values.limit,
807
+ types: values.types || values.type
808
+ }));
809
+ if (values.json) return writeJson(context.stdout, payload);
810
+
811
+ renderProspectTimeline(payload, context);
812
+ }
813
+
766
814
  async function prospectsMessageTypes(args, context, { accountOverride } = {}) {
767
815
  const { values, positionals } = parseCommandArgs(args, jsonOptions());
768
816
  if (positionals.length !== 1) {
@@ -852,6 +900,31 @@ async function prospectsSequencePreview(args, context, { accountOverride } = {})
852
900
  renderProspectSequencePreview(payload, context);
853
901
  }
854
902
 
903
+ async function prospectsSequenceExport(args, context, { accountOverride } = {}) {
904
+ const { values, positionals } = parseCommandArgs(args, {
905
+ ...jsonOptions(),
906
+ csv: { type: "boolean" },
907
+ branch: { type: "string" },
908
+ branches: { type: "string" },
909
+ "angle-index": { type: "string" }
910
+ });
911
+ if (positionals.length !== 1) {
912
+ throw new CommandError("Usage: audienti prospects sequence-export <prsp_id> [--json|--csv] [--branch <both|no-accept|accepted>] [--account <acct_id>]");
913
+ }
914
+ if (values.csv && values.json) throw new CommandError("Choose one output format: use either --csv or --json.");
915
+ if (values.branch && values.branches) throw new CommandError("Choose one branch filter: use either --branch or --branches.");
916
+
917
+ const { client, accountId } = await requireAccountContext(context, { accountOverride });
918
+ const payload = await client.prospectSequenceExport(accountId, positionals[0], compactObject({
919
+ branches: values.branches || values.branch,
920
+ angle_index: values["angle-index"]
921
+ }));
922
+ if (values.json) return writeJson(context.stdout, payload);
923
+ if (values.csv) return writeLine(context.stdout, sequenceExportRowsToCsv(payload?.rows || []));
924
+
925
+ renderProspectSequenceExport(payload, context);
926
+ }
927
+
855
928
  async function prospectsImport(args, context, { accountOverride } = {}) {
856
929
  const { values, positionals } = parseCommandArgs(args, {
857
930
  ...jsonOptions(),
@@ -1463,6 +1536,27 @@ function renderProspect(prospect, context) {
1463
1536
  if (nextActionLabel(prospect?.queue)) writeLine(context.stdout, `Next action: ${nextActionLabel(prospect.queue)}`);
1464
1537
  }
1465
1538
 
1539
+ function renderProspectTimeline(payload, context) {
1540
+ const prospect = payload?.prospect || {};
1541
+ const timeline = Array.isArray(payload?.timeline) ? payload.timeline : [];
1542
+
1543
+ writeLine(context.stdout, `Prospect: ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)})`);
1544
+ if (timeline.length === 0) {
1545
+ writeLine(context.stdout, "No timeline items found.");
1546
+ return;
1547
+ }
1548
+
1549
+ writeLine(context.stdout, "OCCURRED AT\tTYPE\tTEXT\tURL");
1550
+ for (const item of timeline) {
1551
+ writeLine(context.stdout, [
1552
+ display(item.occurred_at),
1553
+ display(item.type),
1554
+ display(item.text),
1555
+ display(item.url)
1556
+ ].join("\t"));
1557
+ }
1558
+ }
1559
+
1466
1560
  function renderProspectMessageTypes(payload, context) {
1467
1561
  const surfaces = Array.isArray(payload?.message_surfaces) ? payload.message_surfaces : [];
1468
1562
  const prospect = payload?.prospect || {};
@@ -1574,6 +1668,40 @@ function renderProspectSequencePreview(payload, context) {
1574
1668
  });
1575
1669
  }
1576
1670
 
1671
+ function renderProspectSequenceExport(payload, context) {
1672
+ const prospect = payload?.prospect || {};
1673
+ const branches = Array.isArray(payload?.branches) ? payload.branches : [];
1674
+
1675
+ writeLine(context.stdout, `Prospect: ${display(prospect.display_name || prospect.name)} (${display(prospect.prefix_id)})`);
1676
+ if (payload?.context?.source) writeLine(context.stdout, `Context: ${payload.context.source}`);
1677
+ if (branches.length === 0) {
1678
+ writeLine(context.stdout, "No sequence rows were generated.");
1679
+ return;
1680
+ }
1681
+
1682
+ for (const branch of branches) {
1683
+ writeLine(context.stdout, "");
1684
+ writeLine(context.stdout, `${display(branch.label)} (${display(branch.key)})`);
1685
+ const rows = Array.isArray(branch.rows) ? branch.rows : [];
1686
+ if (rows.length === 0) {
1687
+ writeLine(context.stdout, "No rows.");
1688
+ continue;
1689
+ }
1690
+
1691
+ writeLine(context.stdout, "STEP\tKIND\tSTAGE\tCHANNEL\tSCHEDULED FOR\tBODY");
1692
+ for (const row of rows) {
1693
+ writeLine(context.stdout, [
1694
+ display(row.step_number),
1695
+ display(row.kind),
1696
+ display(row.stage),
1697
+ display(row.channel),
1698
+ display(row.scheduled_for),
1699
+ display(row.body || row.disposition || row.missing_reason)
1700
+ ].join("\t"));
1701
+ }
1702
+ }
1703
+ }
1704
+
1577
1705
  function renderProspectImportStarted(payload, context) {
1578
1706
  writeLine(context.stdout, `Started prospect import ${display(payload?.prefix_id)}.`);
1579
1707
  writeLine(context.stdout, `Status: ${display(payload?.status)}`);
@@ -1782,6 +1910,13 @@ function prospectsToCsv(prospects) {
1782
1910
  ].join("\n");
1783
1911
  }
1784
1912
 
1913
+ function sequenceExportRowsToCsv(rows) {
1914
+ return [
1915
+ SEQUENCE_EXPORT_CSV_COLUMNS.join(","),
1916
+ ...rows.map((row) => SEQUENCE_EXPORT_CSV_COLUMNS.map((column) => csvField(row?.[column])).join(","))
1917
+ ].join("\n");
1918
+ }
1919
+
1785
1920
  function csvField(value) {
1786
1921
  const text = value === undefined || value === null ? "" : String(value);
1787
1922
  if (!/[",\n]/.test(text)) return text;
@@ -1896,11 +2031,13 @@ const HELP_TOPICS = new Map([
1896
2031
  " audienti motions create --payload <file.json> [--json]",
1897
2032
  " audienti prospects list [--json]",
1898
2033
  " audienti prospects show <prsp_id> [--json]",
2034
+ " audienti prospects timeline <prsp_id> [--json]",
1899
2035
  " audienti prospects message-types <prsp_id> [--json]",
1900
2036
  " audienti prospects write <prsp_id> --type <surface_key> [--json]",
1901
2037
  " audienti prospects add-note <prsp_id> --message <text> [--json]",
1902
2038
  " audienti prospects add-steer <prsp_id> --message <text> [--json]",
1903
2039
  " audienti prospects sequence-preview <prsp_id> [--json]",
2040
+ " audienti prospects sequence-export <prsp_id> [--csv]",
1904
2041
  " audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--json]",
1905
2042
  " audienti prospects import-status <primp_id> [--json]",
1906
2043
  " audienti tools get <email|phone> --url <linkedin_url> [--json]",
@@ -2592,11 +2729,13 @@ const HELP_TOPICS = new Map([
2592
2729
  "Usage:",
2593
2730
  " audienti prospects list [--json] [filters]",
2594
2731
  " audienti prospects show <prsp_id> [--json]",
2732
+ " audienti prospects timeline <prsp_id> [--json]",
2595
2733
  " audienti prospects message-types <prsp_id> [--json]",
2596
2734
  " audienti prospects write <prsp_id> --type <surface_key> [--json]",
2597
2735
  " audienti prospects add-note <prsp_id> --message <text> [--json]",
2598
2736
  " audienti prospects add-steer <prsp_id> --message <text> [--json]",
2599
2737
  " audienti prospects sequence-preview <prsp_id> [--json]",
2738
+ " audienti prospects sequence-export <prsp_id> [--csv]",
2600
2739
  " audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--json]",
2601
2740
  " audienti prospects import-status <primp_id> [--json]",
2602
2741
  "",
@@ -2681,6 +2820,31 @@ const HELP_TOPICS = new Map([
2681
2820
  " GET /api/v1/accounts/:account_id/prospects/:id.json"
2682
2821
  ].join("\n")],
2683
2822
 
2823
+ ["prospects timeline", [
2824
+ "Usage:",
2825
+ " audienti prospects timeline <prsp_id> [--json] [--types <post,comment,reaction>] [--limit <n>] [--account <acct_id>]",
2826
+ "",
2827
+ "Status: implemented",
2828
+ "",
2829
+ "Purpose:",
2830
+ " Read one prospect's visible timeline without running sequence preview or generation work.",
2831
+ "",
2832
+ "Input shape:",
2833
+ " prsp_id: prsp_ prefix id",
2834
+ " types: optional comma-separated filter. Supported: post, comment, action, message, reaction, provenance",
2835
+ " limit: optional max rows, capped by the API",
2836
+ "",
2837
+ "Output shape:",
2838
+ " timeline[].type: post | comment | action | message | reaction | provenance",
2839
+ " timeline[].occurred_at: ISO-8601 timestamp, newest first",
2840
+ " timeline[].url: source URL when available",
2841
+ " timeline[].text: normalized display text",
2842
+ " timeline[].profile.url: source profile URL when available",
2843
+ "",
2844
+ "API:",
2845
+ " GET /api/v1/accounts/:account_id/prospects/:id/timeline.json"
2846
+ ].join("\n")],
2847
+
2684
2848
  ["prospects message-types", [
2685
2849
  "Usage:",
2686
2850
  " audienti prospects message-types <prsp_id> [--json] [--account <acct_id>]",
@@ -2803,6 +2967,31 @@ const HELP_TOPICS = new Map([
2803
2967
  " POST /api/v1/accounts/:account_id/prospects/:id/sequence_preview.json"
2804
2968
  ].join("\n")],
2805
2969
 
2970
+ ["prospects sequence-export", [
2971
+ "Usage:",
2972
+ " audienti prospects sequence-export <prsp_id> [--json|--csv] [--branch <both|no-accept|accepted>] [--angle-index <n>] [--account <acct_id>]",
2973
+ "",
2974
+ "Status: implemented",
2975
+ "",
2976
+ "Purpose:",
2977
+ " Generate the full no-reply path for spreadsheet review without opening or updating a report workspace.",
2978
+ "",
2979
+ "Branches:",
2980
+ " both: default. Runs no_accept and accepted branches",
2981
+ " no-accept: no reply and no accepted connection request",
2982
+ " accepted: connection request accepted, then no reply otherwise",
2983
+ "",
2984
+ "Output shape:",
2985
+ " rows[].prospect_id: prsp_",
2986
+ " rows[].branch: no_accept | accepted",
2987
+ " rows[].step_number: spreadsheet row order within the branch",
2988
+ " rows[].kind: message | wait | action | terminal",
2989
+ " rows[].stage/channel/scheduled_for/body: sequence details for spreadsheet columns",
2990
+ "",
2991
+ "API:",
2992
+ " POST /api/v1/accounts/:account_id/prospects/:id/sequence_export.json"
2993
+ ].join("\n")],
2994
+
2806
2995
  ["prospects import", [
2807
2996
  "Usage:",
2808
2997
  " audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--assigned-user <id|me>] [--json] [--account <acct_id>]",
@@ -3029,9 +3218,11 @@ const HELP_TOPICS = new Map([
3029
3218
  " audienti companies search --query \"Honeywell\"",
3030
3219
  " audienti prospects list --company-profile <prof_id>",
3031
3220
  " audienti prospects show <prsp_id>",
3221
+ " audienti prospects timeline <prsp_id> --types post,comment,reaction --json",
3032
3222
  " audienti prospects message-types <prsp_id>",
3033
3223
  " audienti prospects add-note <prsp_id> --type steer --message \"Meeting will not happen\" --engagement-type action.meeting.canceled",
3034
3224
  " audienti prospects sequence-preview <prsp_id>",
3225
+ " audienti prospects sequence-export <prsp_id> --csv",
3035
3226
  "",
3036
3227
  "5. Attach existing prospects without re-importing",
3037
3228
  " audienti lists add-prospects <list_id> <prsp_id> [prsp_id...]",