@audienti/cli 0.1.106 → 0.1.108

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,19 @@ All notable changes to the Audienti CLI are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.108] - 2026-10-08
8
+
9
+ ### Fixed
10
+
11
+ - Import receipts resolve to the surviving person after compatible LinkedIn duplicate reconciliation. Account and list records are preserved; conflicting records remain available for identity review.
12
+
13
+ ## [0.1.107] - 2026-10-08
14
+
15
+ ### Added
16
+
17
+ - `prospects import`, `prospects intake` and `prospects import-batch` can request a new list or system transition.
18
+ - Batch imports submit parsed rows and defaults to the account API in one request; the CLI renders the server response. Explicit invalid names are forwarded for API validation.
19
+
7
20
  ## [0.1.106] - 2026-10-08
8
21
 
9
22
  ### Added
package/README.md CHANGED
@@ -839,14 +839,22 @@ audienti company-rules create --domain example.com --disposition not_fit --user
839
839
  audienti company-rules apply --all
840
840
  ```
841
841
 
842
+ The direct intake action supports the same destination names and optional experiment:
843
+
844
+ ```bash
845
+ audienti prospects intake --url https://www.linkedin.com/in/example --new-list "Target list" --new-transition "Fit transition" --json
846
+ ```
847
+
848
+ Use `--motion <motn_id>` for an existing experiment. Explicit new names, including blank names, are sent to the API for validation.
849
+
842
850
  To import multiple LinkedIn people through the same per-prospect import path:
843
851
 
844
852
  ```bash
845
- audienti prospects import-batch --file prospects.csv --motion <motn_id> --assigned-user me
853
+ audienti prospects import-batch --file prospects.csv --new-list "Target list" --new-transition "Fit transition" --assigned-user me
846
854
  ```
847
855
 
848
856
  CSV files should include a `linkedin_url` or `url` header. Optional row columns
849
- `list_id`, `motion_id`, and `assigned_user_id` override command defaults.
857
+ `list_id`, `motion_id`, `new_list_name`, `new_transition_name`, and `assigned_user_id` override command defaults. The command parses the file and sends one batch request; the API owns validation, destination creation, row outcomes, and queueing.
850
858
 
851
859
  ## Compatibility
852
860
 
@@ -867,3 +875,5 @@ credentials or silently authenticate an agent.
867
875
  ## License
868
876
 
869
877
  Copyright (c) 2026 OMALab, Inc. All rights reserved. See [LICENSE](LICENSE).
878
+
879
+ Batch import accepts up to 50 rows per API request. Split larger files before importing. Row destination IDs or new names override batch defaults; failed rows stay visible in the response.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audienti/cli",
3
- "version": "0.1.106",
3
+ "version": "0.1.108",
4
4
  "description": "Agent-first command-line client for Audienti.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api-client.js CHANGED
@@ -1210,6 +1210,13 @@ export class AudientiClient {
1210
1210
  });
1211
1211
  }
1212
1212
 
1213
+ prospectImportBatch(accountId, body) {
1214
+ return this.requestJson(accountPath(accountId, ["prospect_imports", "batch"]), {
1215
+ method: "POST",
1216
+ body
1217
+ });
1218
+ }
1219
+
1213
1220
  prospectImportStatus(accountId, importId) {
1214
1221
  return this.requestJson(accountPath(accountId, ["prospect_imports", importId]));
1215
1222
  }
package/src/cli.js CHANGED
@@ -77,7 +77,7 @@ const PROSPECTS_RESTORE_USAGE = "Usage: audienti prospects restore <prsp_id> [--
77
77
  const PROSPECTS_LOCK_USAGE = "Usage: audienti prospects lock <prsp_id> [--note <text>] [--kind <protected_relationship|company_policy>] [--json] [--account <acct_id>]";
78
78
  const PROSPECTS_UNLOCK_USAGE = "Usage: audienti prospects unlock <prsp_id> [--json] [--account <acct_id>]";
79
79
  const PROSPECTS_CHECK_USAGE = "Usage: audienti prospects check [--json|--csv] [filters] [--account <acct_id>]";
80
- 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>]";
80
+ const PROSPECTS_IMPORT_BATCH_USAGE = "Usage: audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--new-list <name>] [--new-transition <name>] [--assigned-user <id|me>] [--json] [--account <acct_id>]";
81
81
  const OPERATOR_FAILED_DRAFTS_USAGE = "Usage: audienti operator failed-drafts [--json] [filters] [--account <acct_id>]";
82
82
  const OPERATOR_FAILED_DRAFTS_REQUEUE_USAGE = "Usage: audienti operator failed-drafts requeue (--all | <row_id> [row_id...]) [--limit <n>] [--json] [filters] [--account <acct_id>]";
83
83
  const INBOX_OPS_QUEUE_USAGE = "Usage: audienti inbox-ops queue [--page <n>] [--offset <n>|--cursor <token>] [--group-by domain] [--json] [--account <acct_id>]";
@@ -5077,19 +5077,23 @@ async function prospectsImport(args, context, { accountOverride } = {}) {
5077
5077
  ...jsonOptions(),
5078
5078
  list: { type: "string" },
5079
5079
  motion: { type: "string" },
5080
+ "new-list": { type: "string" },
5081
+ "new-transition": { type: "string" },
5080
5082
  "assigned-user": { type: "string" }
5081
5083
  });
5082
5084
  if (positionals.length !== 1) {
5083
- throw new CommandError("Usage: audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--assigned-user <id|me>] [--json] [--account <acct_id>]");
5085
+ throw new CommandError("Usage: audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--new-list <name>] [--new-transition <name>] [--assigned-user <id|me>] [--json] [--account <acct_id>]");
5084
5086
  }
5085
5087
 
5086
5088
  const { client, accountId, config } = await requireAccountContext(context, { accountOverride });
5087
- const payload = await client.prospectImport(accountId, compactObject({
5089
+ const payload = await client.prospectImport(accountId, compactObjectPreservingFields({
5088
5090
  linkedin_url: positionals[0],
5089
5091
  list_id: values.list,
5090
5092
  motion_id: values.motion,
5093
+ new_list_name: values["new-list"],
5094
+ new_transition_name: values["new-transition"],
5091
5095
  assigned_user_id: resolveAccountUserId(values["assigned-user"], config, { accountOverride })
5092
- }));
5096
+ }, ["new_list_name", "new_transition_name"]));
5093
5097
  if (values.json) return writeJson(context.stdout, payload);
5094
5098
 
5095
5099
  renderProspectImportStarted(payload, context);
@@ -5101,7 +5105,9 @@ async function prospectsImportBatch(args, context, { accountOverride } = {}) {
5101
5105
  file: { type: "string" },
5102
5106
  list: { type: "string" },
5103
5107
  motion: { type: "string" },
5104
- "assigned-user": { type: "string" }
5108
+ "assigned-user": { type: "string" },
5109
+ "new-list": { type: "string" },
5110
+ "new-transition": { type: "string" }
5105
5111
  });
5106
5112
  if (positionals.length > 0 || !values.file) {
5107
5113
  throw new CommandError(PROSPECTS_IMPORT_BATCH_USAGE);
@@ -5111,40 +5117,16 @@ async function prospectsImportBatch(args, context, { accountOverride } = {}) {
5111
5117
  if (rows.length === 0) throw new CommandError("Import batch file did not contain any prospects.");
5112
5118
 
5113
5119
  const { client, accountId, config } = await requireAccountContext(context, { accountOverride });
5114
- const result = {
5115
- summary: {
5116
- total: rows.length,
5117
- started: 0,
5118
- failed: 0
5119
- },
5120
- imports: [],
5121
- failed: []
5122
- };
5123
-
5124
- for (const row of rows) {
5125
- const body = compactObject({
5126
- linkedin_url: row.linkedin_url,
5127
- list_id: row.list_id || values.list,
5128
- motion_id: row.motion_id || values.motion,
5129
- assigned_user_id: resolveAccountUserId(row.assigned_user_id || values["assigned-user"], config, { accountOverride })
5130
- });
5131
-
5132
- try {
5133
- const payload = await client.prospectImport(accountId, body);
5134
- result.imports.push(payload);
5135
- result.summary.started += 1;
5136
- } catch (error) {
5137
- if (!(error instanceof ApiError)) throw error;
5138
-
5139
- result.failed.push({
5140
- row: row.row,
5141
- linkedin_url: row.linkedin_url,
5142
- status: error.status,
5143
- error: error.body?.error || error.message
5144
- });
5145
- result.summary.failed += 1;
5146
- }
5147
- }
5120
+ const result = await client.prospectImportBatch(accountId, {
5121
+ rows,
5122
+ defaults: compactObjectPreservingFields({
5123
+ list_id: values.list,
5124
+ motion_id: values.motion,
5125
+ new_list_name: values["new-list"],
5126
+ new_transition_name: values["new-transition"],
5127
+ assigned_user_id: resolveAccountUserId(values["assigned-user"], config, { accountOverride })
5128
+ }, ["new_list_name", "new_transition_name"])
5129
+ });
5148
5130
 
5149
5131
  if (values.json) {
5150
5132
  writeJson(context.stdout, result);
@@ -6714,6 +6696,16 @@ function compactObject(object) {
6714
6696
  );
6715
6697
  }
6716
6698
 
6699
+ function compactObjectPreservingFields(object, fields) {
6700
+ const compacted = compactObject(object);
6701
+ for (const field of fields) {
6702
+ if (Object.prototype.hasOwnProperty.call(object, field) && object[field] !== undefined) {
6703
+ compacted[field] = object[field];
6704
+ }
6705
+ }
6706
+ return compacted;
6707
+ }
6708
+
6717
6709
  async function readLocalPackageMetadata() {
6718
6710
  const packageJson = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
6719
6711
  return {
@@ -7256,13 +7248,21 @@ function normalizeImportBatchRows(rows, filePath) {
7256
7248
  const linkedinUrl = normalized?.linkedin_url || normalized?.url;
7257
7249
  if (!linkedinUrl) throw new CommandError(`Missing linkedin_url on row ${rowNumber} in ${filePath}.`);
7258
7250
 
7259
- return compactObject({
7251
+ const result = compactObject({
7260
7252
  row: rowNumber,
7261
7253
  linkedin_url: linkedinUrl,
7262
7254
  list_id: normalized.list_id,
7263
7255
  motion_id: normalized.motion_id,
7256
+ new_list_name: normalized.new_list_name,
7257
+ new_transition_name: normalized.new_transition_name,
7264
7258
  assigned_user_id: normalized.assigned_user_id || normalized.assigned_user
7265
7259
  });
7260
+
7261
+ for (const field of ["new_list_name", "new_transition_name"]) {
7262
+ if (Object.prototype.hasOwnProperty.call(normalized, field)) result[field] = normalized[field];
7263
+ }
7264
+
7265
+ return result;
7266
7266
  });
7267
7267
  }
7268
7268
 
@@ -13637,8 +13637,8 @@ const HELP_TOPICS = new Map([
13637
13637
  " audienti prospects report-bad-profile <prsp_id> <prof_id|citation_id> [--json]",
13638
13638
  " audienti prospects sequence-preview <prsp_id> [--json]",
13639
13639
  " audienti prospects sequence-export <prsp_id> [--csv]",
13640
- " audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--json]",
13641
- " audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--json]",
13640
+ " audienti prospects import <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--new-list <name>] [--new-transition <name>] [--json]",
13641
+ " audienti prospects import-batch --file <csv|jsonl|json> [--list <list_id>] [--motion <motn_id>] [--new-list <name>] [--new-transition <name>] [--json]",
13642
13642
  " audienti prospects import-status <primp_id> [--json]",
13643
13643
  "",
13644
13644
  "Status: read commands, assignment, disposition, lock/unlock, per-prospect draft preview, sequence preview, and import implemented",
@@ -14324,13 +14324,15 @@ const HELP_TOPICS = new Map([
14324
14324
  " file: CSV with linkedin_url/url header, JSON array, JSONL objects, or newline-delimited LinkedIn URLs",
14325
14325
  " list_id: list_ prefix id | optional default for every row",
14326
14326
  " motn_id: motn_ prefix id | optional default for every row",
14327
+ " new_list_name: list name | a row value creates that row's list; command default applies to rows without one",
14328
+ " new_transition_name: system transition name | a row value creates that row's transition; command default applies to rows without one",
14327
14329
  " assigned_user_id: account user id or me | optional default for every row",
14328
14330
  "",
14329
14331
  "CSV columns:",
14330
- " linkedin_url or url, list_id, motion_id, assigned_user_id",
14332
+ " linkedin_url or url, list_id, motion_id, new_list_name, new_transition_name, assigned_user_id",
14331
14333
  "",
14332
14334
  "Behavior:",
14333
- " Starts one normal prospect import per row. Row-level list_id, motion_id, and assigned_user_id override command defaults.",
14335
+ " Starts one normal prospect import per row. Row-level destination names or IDs and assigned_user_id override command defaults.",
14334
14336
  "",
14335
14337
  "API:",
14336
14338
  " POST /api/v1/accounts/:account_id/prospect_imports.json"
@@ -15650,19 +15652,30 @@ const PARITY_ACTION_COMMANDS = new Map([
15650
15652
  done: (_positionals, payload) => `Rejected ${payload?.rejected?.length ?? 0}; failed ${payload?.failed?.length ?? 0}.`
15651
15653
  }],
15652
15654
  ["prospects intake", {
15653
- usage: "audienti prospects intake --url <linkedin_url> [--list <list_id>] [--assign <account_user_id>] [--signal <custom_signal_id>]",
15655
+ usage: "audienti prospects intake --url <linkedin_url> [--list <list_id>] [--motion <motn_id>] [--new-list <name>] [--new-transition <name>] [--assign <account_user_id>] [--signal <custom_signal_id>]",
15654
15656
  minPositionals: 0,
15655
15657
  maxPositionals: 0,
15656
15658
  purpose: "Add one LinkedIn person by URL, like Add prospect on the web.",
15657
15659
  api: "POST /api/v1/accounts/:account_id/prospects/intake.json",
15658
- options: { url: { type: "string" }, list: { type: "string" }, assign: { type: "string" }, signal: { type: "string" } },
15660
+ options: {
15661
+ url: { type: "string" },
15662
+ list: { type: "string" },
15663
+ motion: { type: "string" },
15664
+ "new-list": { type: "string" },
15665
+ "new-transition": { type: "string" },
15666
+ assign: { type: "string" },
15667
+ signal: { type: "string" }
15668
+ },
15659
15669
  required: ["url"],
15660
- run: (client, accountId, _positionals, values) => client.intakeProspect(accountId, compactObject({
15670
+ run: (client, accountId, _positionals, values) => client.intakeProspect(accountId, compactObjectPreservingFields({
15661
15671
  url: values.url,
15662
15672
  list_id: values.list,
15673
+ motion_id: values.motion,
15674
+ new_list_name: values["new-list"],
15675
+ new_transition_name: values["new-transition"],
15663
15676
  assigned_to_account_user_id: values.assign,
15664
15677
  custom_signal_id: values.signal
15665
- })),
15678
+ }, ["new_list_name", "new_transition_name"])),
15666
15679
  done: () => "Prospect intake queued."
15667
15680
  }],
15668
15681
  ["events retry", {