@audienti/cli 0.1.122 → 0.1.128

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,42 @@ All notable changes to the Audienti CLI are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.128] - 2026-10-21
8
+
9
+ ### Added
10
+
11
+ - `browser-repair computer <observe|navigate|click|scroll|type|responses>` commands for task-bound live browser sessions in the bounded repair loop (#2147).
12
+
13
+ ## [0.1.127] - 2026-10-21
14
+
15
+ ### Added
16
+
17
+ - Browser repair patch, hosted-test and no-change commands for the bounded repair loop (#2147).
18
+
19
+ ## [0.1.126] - 2026-10-20
20
+
21
+ ### Added
22
+
23
+ - `audienti social-tools list` and `audienti social-tools show <name>` show the social tool catalog (name, kind, description and inputs) from the read-only catalog API (#2147).
24
+
25
+ ## [0.1.125] - 2026-10-20
26
+
27
+ ### Changed
28
+
29
+ - `audienti motions update` now says when a newly attached backing list does not add the people already on it, and how many of them are not in the experiment yet. The API returns the same notice as `list_attachment` (#2945).
30
+
31
+ ## [0.1.124] - 2026-10-20
32
+
33
+ ### Fixed
34
+
35
+ - Motion status and discovery history no longer count completed visibility records as in-progress people. Status omits expired eligibility dates and reports discovery-history reconciliation holds instead of stale success or retry timers (#2944).
36
+
37
+ ## [0.1.123] - 2026-10-20
38
+
39
+ ### Fixed
40
+
41
+ - `audienti prospects replan <prsp> --apply` now admits a prospect that was never admitted to the Planner. When it cannot, it reports `not admitted` with the reason instead of `legacy`. Members of an active transition motion are no longer blocked from admission (#2945).
42
+
7
43
  ## [0.1.122] - 2026-10-19
8
44
 
9
45
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@audienti/cli",
3
- "version": "0.1.122",
3
+ "version": "0.1.128",
4
4
  "description": "Agent-first command-line client for Audienti.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api-client.js CHANGED
@@ -40,6 +40,14 @@ export class AudientiClient {
40
40
  return this.requestJson("/api/v1/accounts.json");
41
41
  }
42
42
 
43
+ socialTools() {
44
+ return this.requestJson("/api/v1/social_tools.json");
45
+ }
46
+
47
+ socialTool(name) {
48
+ return this.requestJson(`/api/v1/social_tools/${encodeURIComponent(name)}.json`);
49
+ }
50
+
43
51
  createAccount(body) {
44
52
  return this.requestJson("/api/v1/accounts.json", { method: "POST", body });
45
53
  }
@@ -59,6 +67,28 @@ export class AudientiClient {
59
67
  });
60
68
  }
61
69
 
70
+ browserRepairPatch(attemptId, { path, content }, token) {
71
+ return this.requestJson(`/api/v1/browser_repair_attempts/${encodeURIComponent(attemptId)}/patch.json`, {
72
+ method: "POST", body: { path, content }, token
73
+ });
74
+ }
75
+
76
+ browserRepairHostedTest(attemptId, token) {
77
+ return this.requestJson(`/api/v1/browser_repair_attempts/${encodeURIComponent(attemptId)}/hosted_test.json`, {method: "POST", body: {}, token});
78
+ }
79
+
80
+ browserRepairNoChange(attemptId, reason, token) {
81
+ return this.requestJson(`/api/v1/browser_repair_attempts/${encodeURIComponent(attemptId)}/no_change.json`, {
82
+ method: "POST", body: {reason}, token
83
+ });
84
+ }
85
+
86
+ browserRepairComputer(attemptId, tool, body = {}, token) {
87
+ return this.requestJson(apiPath(["browser_repair_attempts", attemptId, "computer", tool]), {
88
+ method: "POST", body, token
89
+ });
90
+ }
91
+
62
92
  users(accountId) {
63
93
  return this.requestJson(accountPath(accountId, ["users"]));
64
94
  }
@@ -1426,14 +1456,14 @@ export class AudientiClient {
1426
1456
  });
1427
1457
  }
1428
1458
 
1429
- async requestJson(path, { method = "GET", body } = {}) {
1459
+ async requestJson(path, { method = "GET", body, token } = {}) {
1430
1460
  const url = new URL(path, `${this.host}/`);
1431
1461
  let response;
1432
1462
 
1433
1463
  try {
1434
1464
  response = await this.fetchImpl(url, {
1435
1465
  method,
1436
- headers: this.headers(body),
1466
+ headers: this.headers(body, token === undefined ? this.token : token),
1437
1467
  body: body === undefined ? undefined : JSON.stringify(body)
1438
1468
  });
1439
1469
  } catch (error) {
@@ -1452,14 +1482,14 @@ export class AudientiClient {
1452
1482
  return responseBody;
1453
1483
  }
1454
1484
 
1455
- headers(body) {
1485
+ headers(body, token = this.token) {
1456
1486
  const headers = {
1457
1487
  Accept: "application/json",
1458
1488
  "X-Audienti-Client": "cli"
1459
1489
  };
1460
1490
 
1461
- if (this.token) {
1462
- headers.Authorization = `Bearer ${this.token}`;
1491
+ if (token) {
1492
+ headers.Authorization = `Bearer ${token}`;
1463
1493
  }
1464
1494
 
1465
1495
  if (body !== undefined) {
package/src/cli.js CHANGED
@@ -372,6 +372,9 @@ async function dispatch(argv, context) {
372
372
  if (normalizedResource === "accounts" && action === "create") return accountsCreate(rest, context);
373
373
  if (normalizedResource === "accounts" && action === "select") return accountsSelect(rest, context);
374
374
  if (normalizedResource === "accounts" && action === "show") return accountsShow(rest, context, { accountOverride });
375
+ if (normalizedResource === "social-tools" && action === "list") return socialToolsList(rest, context);
376
+ if (normalizedResource === "social-tools" && action === "show") return socialToolsShow(rest, context);
377
+ if (normalizedResource === "browser-repair") return browserRepair(action, rest, context);
375
378
  if (normalizedResource === "linkedin-lookups") return linkedinLookups(action, rest, context, { accountOverride });
376
379
  if (normalizedResource === "users" && action === "list") return usersList(rest, context, { accountOverride });
377
380
  if (normalizedResource === "users" && action === "select") return usersSelect(rest, context, { accountOverride });
@@ -1757,6 +1760,84 @@ async function accountsCreate(args, context) {
1757
1760
  writeLine(context.stdout, `Created account: ${account.name} (${account.prefix_id})`);
1758
1761
  }
1759
1762
 
1763
+ async function socialToolsList(args, context) {
1764
+ const {values, positionals} = parseCommandArgs(args, {json: {type: "boolean"}});
1765
+ if (positionals.length > 0) throw new CommandError("Usage: audienti social-tools list [--json]");
1766
+
1767
+ const config = await requireAuthenticatedConfig(context);
1768
+ const tools = await clientFromConfig(config, context).socialTools();
1769
+ if (values.json) {
1770
+ writeLine(context.stdout, JSON.stringify(tools, null, 2));
1771
+ return;
1772
+ }
1773
+
1774
+ writeLine(context.stdout, " NAME\tKIND\tWRITER\tEFFECT");
1775
+ for (const tool of tools) writeLine(context.stdout, ` ${tool.name}\t${tool.kind}\t${tool.writer}\t${tool.effect}`);
1776
+ }
1777
+
1778
+ async function socialToolsShow(args, context) {
1779
+ const {values, positionals} = parseCommandArgs(args, {json: {type: "boolean"}});
1780
+ if (positionals.length !== 1) throw new CommandError("Usage: audienti social-tools show <name> [--json]");
1781
+
1782
+ const config = await requireAuthenticatedConfig(context);
1783
+ const tool = await clientFromConfig(config, context).socialTool(positionals[0]);
1784
+ writeLine(context.stdout, JSON.stringify(tool, null, 2));
1785
+ }
1786
+
1787
+ async function browserRepair(action, args, context) {
1788
+ if (action === "computer") return browserRepairComputer(args, context);
1789
+ const config = await requireAuthenticatedConfig(context);
1790
+ const client = clientFromConfig(config, context);
1791
+ const {values, positionals} = parseCommandArgs(args, {
1792
+ attempt: {type: "string"}, path: {type: "string"}, "content-file": {type: "string"},
1793
+ reason: {type: "string"}, token: {type: "string"}, json: {type: "boolean"}
1794
+ });
1795
+ if (positionals.length || !values.attempt || !values.token) {
1796
+ throw new CommandError("Usage: audienti browser-repair <patch|hosted-test|no-change> --attempt <id> --token <token> ...");
1797
+ }
1798
+ let result;
1799
+ if (action === "patch") {
1800
+ if (!values.path || !values["content-file"]) throw new CommandError("Usage: audienti browser-repair patch --attempt <id> --path <p> --content-file <file>");
1801
+ result = await client.browserRepairPatch(values.attempt, {path: values.path, content: await readFile(values["content-file"], "utf8")}, values.token);
1802
+ } else if (action === "hosted-test") {
1803
+ result = await client.browserRepairHostedTest(values.attempt, values.token);
1804
+ } else if (action === "no-change") {
1805
+ if (!values.reason) throw new CommandError("Usage: audienti browser-repair no-change --attempt <id> --reason <text>");
1806
+ result = await client.browserRepairNoChange(values.attempt, values.reason, values.token);
1807
+ } else {
1808
+ throw new CommandError("Usage: audienti browser-repair <patch|hosted-test|no-change>");
1809
+ }
1810
+ if (values.json) writeJson(context.stdout, result);
1811
+ else writeLine(context.stdout, JSON.stringify(result));
1812
+ }
1813
+
1814
+ async function browserRepairComputer(args, context) {
1815
+ const config = await requireAuthenticatedConfig(context);
1816
+ const client = clientFromConfig(config, context);
1817
+ const {values, positionals} = parseCommandArgs(args, {
1818
+ attempt: {type: "string"}, token: {type: "string"}, selector: {type: "string"}, url: {type: "string"},
1819
+ ref: {type: "string"}, text: {type: "string"}, "expected-target": {type: "string"}, target: {type: "string"},
1820
+ offset: {type: "string"}, x: {type: "string"}, y: {type: "string"}, "delta-x": {type: "string"},
1821
+ "delta-y": {type: "string"}, mutating: {type: "boolean"}, submit: {type: "boolean"}, json: {type: "boolean"}
1822
+ });
1823
+ const tool = positionals.shift();
1824
+ if (!tool || positionals.length || !values.attempt || !values.token || !["observe", "navigate", "click", "scroll", "type", "responses"].includes(tool)) {
1825
+ throw new CommandError("Usage: audienti browser-repair computer <observe|navigate|click|scroll|type|responses> --attempt <id> --token <token>");
1826
+ }
1827
+ const body = {};
1828
+ for (const [key, value] of Object.entries({selector: values.selector, url: values.url, ref: values.ref, text: values.text,
1829
+ offset: values.offset === undefined ? undefined : Number(values.offset), x: values.x === undefined ? undefined : Number(values.x),
1830
+ y: values.y === undefined ? undefined : Number(values.y), delta_x: values["delta-x"] === undefined ? undefined : Number(values["delta-x"]),
1831
+ delta_y: values["delta-y"] === undefined ? undefined : Number(values["delta-y"]), mutating: values.mutating, submit: values.submit})) {
1832
+ if (value !== undefined) body[key] = value;
1833
+ }
1834
+ if (values["expected-target"] !== undefined) body.expected_target = parseJsonObjectOption(values["expected-target"], "--expected-target");
1835
+ if (values.target !== undefined) body.target = parseJsonObjectOption(values.target, "--target");
1836
+ const result = await client.browserRepairComputer(values.attempt, tool, body, values.token);
1837
+ if (values.json) return writeJson(context.stdout, result);
1838
+ writeLine(context.stdout, JSON.stringify(result));
1839
+ }
1840
+
1760
1841
  async function accountsShow(args, context, { accountOverride } = {}) {
1761
1842
  const { values, positionals } = parseCommandArgs(args, jsonOptions());
1762
1843
  if (positionals.length > 1) throw new CommandError(ACCOUNTS_SHOW_USAGE);
@@ -4061,6 +4142,7 @@ async function motionsUpdate(args, context, { accountOverride } = {}) {
4061
4142
 
4062
4143
  writeLine(context.stdout, `Updated motion ${display(motion?.name)} (${display(motion?.prefix_id)}).`);
4063
4144
  renderMotion(motion, context);
4145
+ if (motion?.list_attachment?.message) writeLine(context.stdout, `List: ${motion.list_attachment.message}`);
4064
4146
  if (!statusBlocked) return undefined;
4065
4147
 
4066
4148
  writeLine(
@@ -8394,6 +8476,8 @@ function renderProspectReplan(payload, context) {
8394
8476
  writeLine(context.stdout, "The request was recorded, but the Planner could not apply it. Review the reason before retrying.");
8395
8477
  } else if (payload?.status === "evaluation_error") {
8396
8478
  writeLine(context.stdout, "Planner evaluation failed. Fix the evaluation error and rerun with --apply.");
8479
+ } else if (payload?.status === "not_admitted") {
8480
+ writeLine(context.stdout, "This prospect is not admitted to the Planner, so nothing was planned. Fix the reason above and rerun with --apply.");
8397
8481
  } else if (payload?.status === "not_applied") {
8398
8482
  writeLine(context.stdout, "The plan was not persisted. Review the reason before retrying.");
8399
8483
  }
@@ -8458,6 +8542,7 @@ const REPLAN_STATUS_LABELS = Object.freeze({
8458
8542
  dry_run: "dry run",
8459
8543
  coach_error: "coach error",
8460
8544
  not_applied: "not applied",
8545
+ not_admitted: "not admitted",
8461
8546
  pending: "pending",
8462
8547
  busy: "busy",
8463
8548
  failed: "failed",
@@ -11039,6 +11124,17 @@ const HELP_TOPICS = new Map([
11039
11124
  " acct_id: string Account prefix id, for example acct_abc123"
11040
11125
  ].join("\n")],
11041
11126
 
11127
+ ["social-tools", [
11128
+ "Usage:",
11129
+ " audienti social-tools list [--json]",
11130
+ " audienti social-tools show <name> [--json]",
11131
+ "",
11132
+ "Status: implemented",
11133
+ "",
11134
+ "Purpose:",
11135
+ " List the server's social tool catalog or inspect one tool's public metadata."
11136
+ ].join("\n")],
11137
+
11042
11138
  ["social-cookies", [
11043
11139
  "Usage:",
11044
11140
  " audienti social-cookies sync-messages <scok_id> [--folder <folder>] [--retry] [--json] [--account <acct_id>]",