@audienti/cli 0.1.0
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 +11 -0
- package/LICENSE +19 -0
- package/README.md +62 -0
- package/bin/audienti.js +6 -0
- package/package.json +42 -0
- package/src/api-client.js +295 -0
- package/src/cli.js +3055 -0
- package/src/config.js +69 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2026 OMALab, Inc.
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
This repository and its original source code, documentation, workflows,
|
|
5
|
+
prompts, scripts, plugin metadata, and related materials are proprietary to
|
|
6
|
+
OMALab, Inc.
|
|
7
|
+
|
|
8
|
+
No permission is granted to use, copy, modify, merge, publish, distribute,
|
|
9
|
+
sublicense, sell, or publish substantial portions of this repository or its
|
|
10
|
+
contents without prior written permission from OMALab, Inc.
|
|
11
|
+
|
|
12
|
+
Nothing in this notice limits rights available under applicable law, including
|
|
13
|
+
fair use. Short quotations, references, summaries, links, commentary, and other
|
|
14
|
+
legally permitted uses are allowed under those rights. If you quote or reference
|
|
15
|
+
this work, attribution to OMALab, Inc. and a link to this repository are
|
|
16
|
+
requested.
|
|
17
|
+
|
|
18
|
+
Third-party content and dependencies remain owned by their respective owners
|
|
19
|
+
and are governed by their own licenses.
|
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Audienti CLI
|
|
2
|
+
|
|
3
|
+
Audienti CLI is the agent-first command-line client for the Audienti production
|
|
4
|
+
API. It lets local coding agents and operators inspect accounts, create and
|
|
5
|
+
manage plays, import prospects, build lists, and work supported operator flows.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Requires Node.js 20 or newer.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install --global @audienti/cli
|
|
13
|
+
audienti --help
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
For one-off use, run `npx @audienti/cli --help`.
|
|
17
|
+
|
|
18
|
+
## Authenticate
|
|
19
|
+
|
|
20
|
+
Create an Audienti API token through the product, then configure this machine:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
audienti auth token <token>
|
|
24
|
+
audienti accounts list --json
|
|
25
|
+
audienti accounts select <acct_id>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The CLI writes its local configuration to `~/.config/audienti/config.json` with
|
|
29
|
+
owner-only permissions. Do not place a production token in an agent prompt,
|
|
30
|
+
repository file, issue, or CI secret.
|
|
31
|
+
|
|
32
|
+
## Agent Workflows
|
|
33
|
+
|
|
34
|
+
Start with the built-in, production-safe workflow guide:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
audienti help agent-workflows
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use `--json` whenever another program or agent will consume the result. Inspect
|
|
41
|
+
the target state before mutations, and use the command-specific help before
|
|
42
|
+
creating, changing, or deleting data.
|
|
43
|
+
|
|
44
|
+
## Compatibility
|
|
45
|
+
|
|
46
|
+
The CLI talks to the versioned Audienti `/api/v1` contract at
|
|
47
|
+
`https://app.audienti.com` by default. A release occurs only after the matching
|
|
48
|
+
server deploy succeeds.
|
|
49
|
+
|
|
50
|
+
The canonical source lives with the Audienti application under
|
|
51
|
+
`packages/audienti-cli`. This public repository is a CI-managed mirror; direct
|
|
52
|
+
changes are unsupported and cause the next source release to fail safely.
|
|
53
|
+
|
|
54
|
+
## Plugins
|
|
55
|
+
|
|
56
|
+
This repository includes Codex and Claude Code plugin manifests plus an
|
|
57
|
+
`audienti` skill. The plugin provides workflow instructions; it does not grant
|
|
58
|
+
credentials or silently authenticate an agent.
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
Copyright (c) 2026 OMALab, Inc. All rights reserved. See [LICENSE](LICENSE).
|
package/bin/audienti.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@audienti/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent-first command-line client for Audienti.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"audienti": "./bin/audienti.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"src/",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"CHANGELOG.md"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "node --test test/*.test.js",
|
|
18
|
+
"verify": "node scripts/verify-package.mjs",
|
|
19
|
+
"check": "npm run verify && npm test"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=20"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/audienti/cli.git"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/audienti/cli#readme",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/audienti/cli/issues"
|
|
31
|
+
},
|
|
32
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
33
|
+
"keywords": [
|
|
34
|
+
"audienti",
|
|
35
|
+
"cli",
|
|
36
|
+
"agents",
|
|
37
|
+
"go-to-market"
|
|
38
|
+
],
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
export const DEFAULT_HOST = "https://app.audienti.com";
|
|
2
|
+
|
|
3
|
+
export class ApiError extends Error {
|
|
4
|
+
constructor(message, { status, body } = {}) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = "ApiError";
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.body = body;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function normalizeHost(host = DEFAULT_HOST) {
|
|
13
|
+
const trimmed = String(host || DEFAULT_HOST).trim();
|
|
14
|
+
const withProtocol = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
|
|
15
|
+
const url = new URL(withProtocol);
|
|
16
|
+
url.pathname = url.pathname.replace(/\/+$/, "");
|
|
17
|
+
url.search = "";
|
|
18
|
+
url.hash = "";
|
|
19
|
+
|
|
20
|
+
return url.toString().replace(/\/$/, "");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class AudientiClient {
|
|
24
|
+
constructor({ host = DEFAULT_HOST, token, fetchImpl = globalThis.fetch } = {}) {
|
|
25
|
+
if (!fetchImpl) {
|
|
26
|
+
throw new Error("This Node runtime does not provide fetch.");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
this.host = normalizeHost(host);
|
|
30
|
+
this.token = token;
|
|
31
|
+
this.fetchImpl = fetchImpl;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
me() {
|
|
35
|
+
return this.requestJson("/api/v1/me.json");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
accounts() {
|
|
39
|
+
return this.requestJson("/api/v1/accounts.json");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
users(accountId) {
|
|
43
|
+
return this.requestJson(accountPath(accountId, ["users"]));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
offers(accountId) {
|
|
47
|
+
return this.requestJson(accountPath(accountId, ["offers"]));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
createOffer(accountId, body) {
|
|
51
|
+
return this.requestJson(accountPath(accountId, ["offers"]), {
|
|
52
|
+
method: "POST",
|
|
53
|
+
body
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
icps(accountId) {
|
|
58
|
+
return this.requestJson(accountPath(accountId, ["icps"]));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
createIcp(accountId, body) {
|
|
62
|
+
return this.requestJson(accountPath(accountId, ["icps"]), {
|
|
63
|
+
method: "POST",
|
|
64
|
+
body
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
companies(accountId, query = {}) {
|
|
69
|
+
return this.requestJson(accountPath(accountId, ["companies"], query));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
lists(accountId) {
|
|
73
|
+
return this.requestJson(accountPath(accountId, ["lists"]));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
createList(accountId, body) {
|
|
77
|
+
return this.requestJson(accountPath(accountId, ["lists"]), {
|
|
78
|
+
method: "POST",
|
|
79
|
+
body
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
list(accountId, listId) {
|
|
84
|
+
return this.requestJson(accountPath(accountId, ["lists", listId]));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
updateList(accountId, listId, body) {
|
|
88
|
+
return this.requestJson(accountPath(accountId, ["lists", listId]), {
|
|
89
|
+
method: "PATCH",
|
|
90
|
+
body
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
deleteList(accountId, listId) {
|
|
95
|
+
return this.requestJson(accountPath(accountId, ["lists", listId]), {
|
|
96
|
+
method: "DELETE"
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
listProspects(accountId, listId, query = {}) {
|
|
101
|
+
return this.requestJson(accountPath(accountId, ["lists", listId, "prospects"], query));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
addListProspects(accountId, listId, body) {
|
|
105
|
+
return this.requestJson(accountPath(accountId, ["lists", listId, "prospects"]), {
|
|
106
|
+
method: "POST",
|
|
107
|
+
body
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
removeListProspects(accountId, listId, body) {
|
|
112
|
+
return this.requestJson(accountPath(accountId, ["lists", listId, "prospects"]), {
|
|
113
|
+
method: "DELETE",
|
|
114
|
+
body
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
motions(accountId) {
|
|
119
|
+
return this.requestJson(accountPath(accountId, ["motions"]));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
motion(accountId, motionId) {
|
|
123
|
+
return this.requestJson(accountPath(accountId, ["motions", motionId]));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
createMotion(accountId, body) {
|
|
127
|
+
return this.requestJson(accountPath(accountId, ["motions"]), {
|
|
128
|
+
method: "POST",
|
|
129
|
+
body
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
motionStatus(accountId, motionId) {
|
|
134
|
+
return this.requestJson(accountPath(accountId, ["motions", motionId, "status"]));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
motionProspects(accountId, motionId, query = {}) {
|
|
138
|
+
return this.requestJson(accountPath(accountId, ["motions", motionId, "prospects"], query));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
addMotionProspects(accountId, motionId, body) {
|
|
142
|
+
return this.requestJson(accountPath(accountId, ["motions", motionId, "prospects"]), {
|
|
143
|
+
method: "POST",
|
|
144
|
+
body
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
prospects(accountId, query = {}) {
|
|
149
|
+
return this.requestJson(accountPath(accountId, ["prospects"], query));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
prospect(accountId, prospectId) {
|
|
153
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId]));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
prospectMessageTypes(accountId, prospectId) {
|
|
157
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "message_types"]));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
writeProspectMessage(accountId, prospectId, body) {
|
|
161
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "write_message"]), {
|
|
162
|
+
method: "POST",
|
|
163
|
+
body
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
prospectSequencePreview(accountId, prospectId, body = {}) {
|
|
168
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "sequence_preview"]), {
|
|
169
|
+
method: "POST",
|
|
170
|
+
body
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
addProspectNote(accountId, prospectId, body) {
|
|
175
|
+
return this.requestJson(accountPath(accountId, ["prospects", prospectId, "add_note"]), {
|
|
176
|
+
method: "POST",
|
|
177
|
+
body
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
prospectImport(accountId, body) {
|
|
182
|
+
return this.requestJson(accountPath(accountId, ["prospect_imports"]), {
|
|
183
|
+
method: "POST",
|
|
184
|
+
body
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
prospectImportStatus(accountId, importId) {
|
|
189
|
+
return this.requestJson(accountPath(accountId, ["prospect_imports", importId]));
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
operatorQueue(accountId, query = {}) {
|
|
193
|
+
return this.requestJson(accountPath(accountId, ["operator"], query));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
operatorNext(accountId, query = {}) {
|
|
197
|
+
return this.requestJson(accountPath(accountId, ["operator", "next"], query));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
operatorOutcome(accountId, body) {
|
|
201
|
+
return this.requestJson(accountPath(accountId, ["operator", "outcome"]), {
|
|
202
|
+
method: "POST",
|
|
203
|
+
body
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async requestJson(path, { method = "GET", body } = {}) {
|
|
208
|
+
const response = await this.fetchImpl(new URL(path, `${this.host}/`), {
|
|
209
|
+
method,
|
|
210
|
+
headers: this.headers(body),
|
|
211
|
+
body: body === undefined ? undefined : JSON.stringify(body)
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
const responseBody = await parseBody(response);
|
|
215
|
+
|
|
216
|
+
if (!response.ok) {
|
|
217
|
+
throw new ApiError(errorMessage(response.status, responseBody), {
|
|
218
|
+
status: response.status,
|
|
219
|
+
body: responseBody
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return responseBody;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
headers(body) {
|
|
227
|
+
const headers = {
|
|
228
|
+
Accept: "application/json"
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
if (this.token) {
|
|
232
|
+
headers.Authorization = `Bearer ${this.token}`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (body !== undefined) {
|
|
236
|
+
headers["Content-Type"] = "application/json";
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return headers;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function accountPath(accountId, segments, query = {}) {
|
|
244
|
+
const encodedSegments = [
|
|
245
|
+
"api",
|
|
246
|
+
"v1",
|
|
247
|
+
"accounts",
|
|
248
|
+
accountId,
|
|
249
|
+
...segments
|
|
250
|
+
].map((segment) => encodeURIComponent(segment));
|
|
251
|
+
const searchParams = new URLSearchParams();
|
|
252
|
+
|
|
253
|
+
for (const [key, value] of Object.entries(query)) {
|
|
254
|
+
if (value !== undefined && value !== null && String(value).trim() !== "") {
|
|
255
|
+
searchParams.set(key, String(value));
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const path = `/${encodedSegments.join("/")}.json`;
|
|
260
|
+
const search = searchParams.toString();
|
|
261
|
+
return search ? `${path}?${search}` : path;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async function parseBody(response) {
|
|
265
|
+
const text = await response.text();
|
|
266
|
+
if (!text) return null;
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
return JSON.parse(text);
|
|
270
|
+
} catch {
|
|
271
|
+
return text;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function errorMessage(status, body) {
|
|
276
|
+
if (status === 401) {
|
|
277
|
+
return "Authentication failed. Run `audienti auth token <token>` with a valid API token.";
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (status === 403) {
|
|
281
|
+
return "The API token is not allowed to access that Audienti resource.";
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (status === 404) {
|
|
285
|
+
return "The requested Audienti resource was not found.";
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (status === 422) {
|
|
289
|
+
const reasons = [body?.errors, body?.details].find(Array.isArray);
|
|
290
|
+
const details = reasons?.length > 0 ? reasons.join(", ") : body?.error;
|
|
291
|
+
return details ? `Audienti rejected the request: ${details}` : "Audienti rejected the request.";
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return `Audienti API request failed with HTTP ${status}.`;
|
|
295
|
+
}
|