@audienti/cli 0.1.122 → 0.1.129
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 +42 -0
- package/package.json +1 -1
- package/src/api-client.js +35 -5
- package/src/cli.js +96 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,48 @@ All notable changes to the Audienti CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.129] - 2026-10-21
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- `browser-repair` hosted-test responses take `remaining_rounds` from the hosted-rounds cap in the repair skill file instead of a fixed constant (#2147).
|
|
12
|
+
|
|
13
|
+
## [0.1.128] - 2026-10-21
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `browser-repair computer <observe|navigate|click|scroll|type|responses>` commands for task-bound live browser sessions in the bounded repair loop (#2147).
|
|
18
|
+
|
|
19
|
+
## [0.1.127] - 2026-10-21
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Browser repair patch, hosted-test and no-change commands for the bounded repair loop (#2147).
|
|
24
|
+
|
|
25
|
+
## [0.1.126] - 2026-10-20
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- `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).
|
|
30
|
+
|
|
31
|
+
## [0.1.125] - 2026-10-20
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- `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).
|
|
36
|
+
|
|
37
|
+
## [0.1.124] - 2026-10-20
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- 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).
|
|
42
|
+
|
|
43
|
+
## [0.1.123] - 2026-10-20
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- `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).
|
|
48
|
+
|
|
7
49
|
## [0.1.122] - 2026-10-19
|
|
8
50
|
|
|
9
51
|
### Added
|
package/package.json
CHANGED
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 (
|
|
1462
|
-
headers.Authorization = `Bearer ${
|
|
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>]",
|