@openbat/cli 0.2.1 → 0.2.3
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/dist/api-client.js +6 -6
- package/dist/api-client.mjs +1 -1
- package/dist/{chunk-NYKJTHHK.mjs → chunk-HBSCN3HV.mjs} +6 -6
- package/dist/index.js +141 -111
- package/dist/index.mjs +136 -106
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -163,7 +163,7 @@ function configPath() {
|
|
|
163
163
|
|
|
164
164
|
// src/api-client.ts
|
|
165
165
|
var import_node_url = require("url");
|
|
166
|
-
var CLI_VERSION = "0.
|
|
166
|
+
var CLI_VERSION = "0.2.3";
|
|
167
167
|
var KEY_REGEX = /ob_(?:live|read|admin|pat)_[0-9a-f]{32}/g;
|
|
168
168
|
function redact(s) {
|
|
169
169
|
return s.replace(KEY_REGEX, (k) => `${k.slice(0, 16)}\u2026<hidden>`);
|
|
@@ -213,7 +213,7 @@ var ApiClient = class {
|
|
|
213
213
|
const msg = err instanceof Error ? err.message : String(err);
|
|
214
214
|
throw new Error(`Request to ${redact(url)} failed: ${redact(msg)}`);
|
|
215
215
|
}
|
|
216
|
-
return parseResponse(res, url);
|
|
216
|
+
return parseResponse(res, url, "GET");
|
|
217
217
|
}
|
|
218
218
|
/** Issue a POST with a JSON body. */
|
|
219
219
|
async post(path, body) {
|
|
@@ -275,12 +275,12 @@ mutate_fn = async function(method, path, body) {
|
|
|
275
275
|
const msg = err instanceof Error ? err.message : String(err);
|
|
276
276
|
throw new Error(`Request to ${redact(url)} failed: ${redact(msg)}`);
|
|
277
277
|
}
|
|
278
|
-
return parseResponse(res, url);
|
|
278
|
+
return parseResponse(res, url, method);
|
|
279
279
|
};
|
|
280
|
-
async function parseResponse(res, url) {
|
|
280
|
+
async function parseResponse(res, url, method) {
|
|
281
281
|
if (res.status === 401) {
|
|
282
282
|
throw new Error(
|
|
283
|
-
"Unauthorized. The API key was rejected (invalid, wrong kind for this endpoint, expired, or revoked)."
|
|
283
|
+
"Unauthorized. The API key was rejected (invalid, wrong kind for this endpoint, expired, or revoked). Run `openbat login` to refresh credentials."
|
|
284
284
|
);
|
|
285
285
|
}
|
|
286
286
|
if (res.status === 403) {
|
|
@@ -301,7 +301,7 @@ async function parseResponse(res, url) {
|
|
|
301
301
|
} catch {
|
|
302
302
|
}
|
|
303
303
|
throw new Error(
|
|
304
|
-
|
|
304
|
+
`${method} ${redact(url)} \u2192 ${res.status} ${res.statusText}${errBody?.error ? `: ${redact(errBody.error)}` : ""}`
|
|
305
305
|
);
|
|
306
306
|
}
|
|
307
307
|
try {
|
|
@@ -388,7 +388,9 @@ function configCommand() {
|
|
|
388
388
|
const cmd = new import_commander.Command("config").description(
|
|
389
389
|
"Manage the CLI's ~/.openbatrc settings"
|
|
390
390
|
);
|
|
391
|
-
cmd.command("set-key").description(
|
|
391
|
+
cmd.command("set-key").description(
|
|
392
|
+
"Store your API key in ~/.openbatrc. Reads from stdin by default; use --value to pass inline (discouraged \u2014 leaks into shell history)."
|
|
393
|
+
).option(
|
|
392
394
|
"--value <key>",
|
|
393
395
|
"Pass the key inline. Discouraged \u2014 leaks into shell history."
|
|
394
396
|
).action(async (opts) => {
|
|
@@ -404,13 +406,13 @@ function configCommand() {
|
|
|
404
406
|
key = Buffer.concat(chunks).toString("utf8").trim();
|
|
405
407
|
if (!key) {
|
|
406
408
|
fatal(
|
|
407
|
-
"No key on stdin. Try: echo 'ob_read_...' | openbat config set-key
|
|
409
|
+
"No key on stdin. Try: echo 'ob_read_...' | openbat config set-key"
|
|
408
410
|
);
|
|
409
411
|
}
|
|
410
412
|
}
|
|
411
413
|
await setApiKey(key);
|
|
412
414
|
process.stdout.write(
|
|
413
|
-
`Saved
|
|
415
|
+
`Saved key to ${configPath()} (mode 0600).
|
|
414
416
|
`
|
|
415
417
|
);
|
|
416
418
|
} catch (err) {
|
|
@@ -529,7 +531,9 @@ async function resolveChatbotId(api, chatbotFlag) {
|
|
|
529
531
|
);
|
|
530
532
|
const chatbots = list.chatbots ?? [];
|
|
531
533
|
if (chatbots.length === 0) {
|
|
532
|
-
fatal(
|
|
534
|
+
fatal(
|
|
535
|
+
"No chatbots yet. Run `openbat chatbots create --name <name>`, or ask an org owner to invite you."
|
|
536
|
+
);
|
|
533
537
|
}
|
|
534
538
|
if (chatbotFlag) {
|
|
535
539
|
if (UUID_RE2.test(chatbotFlag)) {
|
|
@@ -714,18 +718,6 @@ function exportCommand() {
|
|
|
714
718
|
|
|
715
719
|
// src/commands/auth.ts
|
|
716
720
|
var import_commander3 = require("commander");
|
|
717
|
-
async function client2(globals) {
|
|
718
|
-
const cfg = await resolveConfig({
|
|
719
|
-
apiKeyFlag: globals.apiKey ?? null,
|
|
720
|
-
baseUrlFlag: globals.baseUrl ?? null
|
|
721
|
-
});
|
|
722
|
-
if (!cfg.apiKey) {
|
|
723
|
-
fatal(
|
|
724
|
-
"No API key configured. Run `openbat config set-key`, pass --api-key, or set OPENBAT_API_KEY."
|
|
725
|
-
);
|
|
726
|
-
}
|
|
727
|
-
return new ApiClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl });
|
|
728
|
-
}
|
|
729
721
|
function detectKind(apiKey) {
|
|
730
722
|
if (apiKey.startsWith("ob_read_")) return "read";
|
|
731
723
|
if (apiKey.startsWith("ob_admin_")) return "admin";
|
|
@@ -777,17 +769,6 @@ function authCommand() {
|
|
|
777
769
|
fatal(err instanceof Error ? err.message : String(err));
|
|
778
770
|
}
|
|
779
771
|
});
|
|
780
|
-
cmd.command("audit-log").description("Show recent audit-log entries for the current user").option("--days <n>", "Look-back window in days", "7").action(async function() {
|
|
781
|
-
try {
|
|
782
|
-
process.stderr.write(
|
|
783
|
-
"audit-log: endpoint not yet exposed via HTTP \u2014 query `select * from api_audit_log` in Supabase Studio for now.\n"
|
|
784
|
-
);
|
|
785
|
-
const _c = await client2(this.optsWithGlobals());
|
|
786
|
-
void _c;
|
|
787
|
-
} catch (err) {
|
|
788
|
-
fatal(err instanceof Error ? err.message : String(err));
|
|
789
|
-
}
|
|
790
|
-
});
|
|
791
772
|
return cmd;
|
|
792
773
|
}
|
|
793
774
|
|
|
@@ -1074,7 +1055,15 @@ async function pickDefaultChatbot(token, baseUrl) {
|
|
|
1074
1055
|
return;
|
|
1075
1056
|
}
|
|
1076
1057
|
if (chatbots.length === 0) {
|
|
1077
|
-
process.stdout.write(
|
|
1058
|
+
process.stdout.write(
|
|
1059
|
+
[
|
|
1060
|
+
"",
|
|
1061
|
+
"No chatbots yet. To get one:",
|
|
1062
|
+
" \u2022 Create one: openbat chatbots create --name <name>",
|
|
1063
|
+
" \u2022 Or ask an org owner to invite you, then run `openbat login` again",
|
|
1064
|
+
""
|
|
1065
|
+
].join("\n")
|
|
1066
|
+
);
|
|
1078
1067
|
return;
|
|
1079
1068
|
}
|
|
1080
1069
|
if (chatbots.length === 1) {
|
|
@@ -1142,7 +1131,7 @@ function logoutCommand() {
|
|
|
1142
1131
|
}
|
|
1143
1132
|
} else {
|
|
1144
1133
|
process.stderr.write(
|
|
1145
|
-
"Note: read/admin keys can't self-revoke.
|
|
1134
|
+
"Note: read/admin keys can't self-revoke server-side. Revoke them in the dashboard if needed; clearing local config only.\n"
|
|
1146
1135
|
);
|
|
1147
1136
|
}
|
|
1148
1137
|
await clearApiKey();
|
|
@@ -1155,7 +1144,7 @@ function logoutCommand() {
|
|
|
1155
1144
|
|
|
1156
1145
|
// src/commands/org.ts
|
|
1157
1146
|
var import_commander6 = require("commander");
|
|
1158
|
-
async function
|
|
1147
|
+
async function client2(globals) {
|
|
1159
1148
|
const cfg = await resolveConfig({
|
|
1160
1149
|
apiKeyFlag: globals.apiKey ?? null,
|
|
1161
1150
|
baseUrlFlag: globals.baseUrl ?? null
|
|
@@ -1175,7 +1164,7 @@ function orgCommand() {
|
|
|
1175
1164
|
cmd.command("list").description("List orgs the current PAT's user belongs to").action(async function() {
|
|
1176
1165
|
try {
|
|
1177
1166
|
const globals = this.optsWithGlobals();
|
|
1178
|
-
const c = await
|
|
1167
|
+
const c = await client2(globals);
|
|
1179
1168
|
const result = await c.get("/api/v1/orgs");
|
|
1180
1169
|
emit(result.orgs, { json: !!globals.json });
|
|
1181
1170
|
} catch (err) {
|
|
@@ -1185,7 +1174,7 @@ function orgCommand() {
|
|
|
1185
1174
|
cmd.command("show").description("Show the active org (id, name, members)").action(async function() {
|
|
1186
1175
|
try {
|
|
1187
1176
|
const globals = this.optsWithGlobals();
|
|
1188
|
-
const c = await
|
|
1177
|
+
const c = await client2(globals);
|
|
1189
1178
|
const result = await c.get(
|
|
1190
1179
|
"/api/v1/orgs/active"
|
|
1191
1180
|
);
|
|
@@ -1200,7 +1189,7 @@ function orgCommand() {
|
|
|
1200
1189
|
cmd.command("rename").description("Rename an org (owner only)").requiredOption("--id <orgId>", "Org id").requiredOption("--name <name>", "New name").action(async function(opts) {
|
|
1201
1190
|
try {
|
|
1202
1191
|
const globals = this.optsWithGlobals();
|
|
1203
|
-
const c = await
|
|
1192
|
+
const c = await client2(globals);
|
|
1204
1193
|
await c.patch(`/api/v1/orgs/${opts.id}`, { name: opts.name });
|
|
1205
1194
|
emit({ ok: true, renamed: opts.id }, { json: !!globals.json });
|
|
1206
1195
|
} catch (err) {
|
|
@@ -1211,7 +1200,7 @@ function orgCommand() {
|
|
|
1211
1200
|
members.command("list").requiredOption("--id <orgId>", "Org id").action(async function(opts) {
|
|
1212
1201
|
try {
|
|
1213
1202
|
const globals = this.optsWithGlobals();
|
|
1214
|
-
const c = await
|
|
1203
|
+
const c = await client2(globals);
|
|
1215
1204
|
const result = await c.get(
|
|
1216
1205
|
`/api/v1/orgs/${opts.id}/members`
|
|
1217
1206
|
);
|
|
@@ -1223,7 +1212,7 @@ function orgCommand() {
|
|
|
1223
1212
|
members.command("invite").requiredOption("--id <orgId>", "Org id").requiredOption("--email <email>", "Invitee email").option("--role <role>", "member | admin", "member").action(async function(opts) {
|
|
1224
1213
|
try {
|
|
1225
1214
|
const globals = this.optsWithGlobals();
|
|
1226
|
-
const c = await
|
|
1215
|
+
const c = await client2(globals);
|
|
1227
1216
|
const result = await c.post(
|
|
1228
1217
|
`/api/v1/orgs/${opts.id}/members`,
|
|
1229
1218
|
{ email: opts.email, role: opts.role }
|
|
@@ -1241,7 +1230,7 @@ function orgCommand() {
|
|
|
1241
1230
|
members.command("set-role").requiredOption("--id <orgId>", "Org id").requiredOption("--member <memberId>", "Member id").requiredOption("--role <role>", "admin | member").action(async function(opts) {
|
|
1242
1231
|
try {
|
|
1243
1232
|
const globals = this.optsWithGlobals();
|
|
1244
|
-
const c = await
|
|
1233
|
+
const c = await client2(globals);
|
|
1245
1234
|
await c.patch(`/api/v1/orgs/${opts.id}/members/${opts.member}`, {
|
|
1246
1235
|
role: opts.role
|
|
1247
1236
|
});
|
|
@@ -1253,7 +1242,7 @@ function orgCommand() {
|
|
|
1253
1242
|
members.command("remove").requiredOption("--id <orgId>", "Org id").requiredOption("--member <memberId>", "Member id").action(async function(opts) {
|
|
1254
1243
|
try {
|
|
1255
1244
|
const globals = this.optsWithGlobals();
|
|
1256
|
-
const c = await
|
|
1245
|
+
const c = await client2(globals);
|
|
1257
1246
|
await c.delete(`/api/v1/orgs/${opts.id}/members/${opts.member}`);
|
|
1258
1247
|
emit({ ok: true }, { json: !!globals.json });
|
|
1259
1248
|
} catch (err) {
|
|
@@ -1264,7 +1253,7 @@ function orgCommand() {
|
|
|
1264
1253
|
invitations.command("list").requiredOption("--id <orgId>", "Org id").action(async function(opts) {
|
|
1265
1254
|
try {
|
|
1266
1255
|
const globals = this.optsWithGlobals();
|
|
1267
|
-
const c = await
|
|
1256
|
+
const c = await client2(globals);
|
|
1268
1257
|
const result = await c.get(
|
|
1269
1258
|
`/api/v1/orgs/${opts.id}/invitations`
|
|
1270
1259
|
);
|
|
@@ -1278,7 +1267,7 @@ function orgCommand() {
|
|
|
1278
1267
|
|
|
1279
1268
|
// src/commands/write.ts
|
|
1280
1269
|
var import_commander7 = require("commander");
|
|
1281
|
-
async function
|
|
1270
|
+
async function client3(globals) {
|
|
1282
1271
|
const cfg = await resolveConfig({
|
|
1283
1272
|
apiKeyFlag: globals.apiKey ?? null,
|
|
1284
1273
|
baseUrlFlag: globals.baseUrl ?? null
|
|
@@ -1288,6 +1277,15 @@ async function client4(globals) {
|
|
|
1288
1277
|
}
|
|
1289
1278
|
return new ApiClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl });
|
|
1290
1279
|
}
|
|
1280
|
+
function requireChatbotId(cmd) {
|
|
1281
|
+
const globals = cmd.optsWithGlobals();
|
|
1282
|
+
if (!globals.chatbot) {
|
|
1283
|
+
fatal(
|
|
1284
|
+
"--chatbot <id> is required. Pass it inline or set a default with `openbat use <id>`."
|
|
1285
|
+
);
|
|
1286
|
+
}
|
|
1287
|
+
return globals.chatbot;
|
|
1288
|
+
}
|
|
1291
1289
|
function surfacePlaintext(plaintext, label) {
|
|
1292
1290
|
process.stderr.write(
|
|
1293
1291
|
`
|
|
@@ -1307,7 +1305,7 @@ function chatbotsCommand() {
|
|
|
1307
1305
|
cmd.command("list").description("List every chatbot the credential can reach").action(async function() {
|
|
1308
1306
|
try {
|
|
1309
1307
|
const globals = this.optsWithGlobals();
|
|
1310
|
-
const c = await
|
|
1308
|
+
const c = await client3(globals);
|
|
1311
1309
|
const result = await c.get(
|
|
1312
1310
|
"/api/v1/chatbots"
|
|
1313
1311
|
);
|
|
@@ -1319,7 +1317,7 @@ function chatbotsCommand() {
|
|
|
1319
1317
|
cmd.command("create").description("Create a new chatbot (PAT scope required)").requiredOption("--name <name>", "Chatbot name").option("--website <url>").option("--docs-url <url>").option("--mcp-url <url>").option("--language <code>", "Primary language code (default: en)", "en").action(async function(opts) {
|
|
1320
1318
|
try {
|
|
1321
1319
|
const globals = this.optsWithGlobals();
|
|
1322
|
-
const c = await
|
|
1320
|
+
const c = await client3(globals);
|
|
1323
1321
|
const result = await c.post("/api/v1/chatbots", {
|
|
1324
1322
|
name: opts.name,
|
|
1325
1323
|
websiteUrl: opts.website,
|
|
@@ -1339,7 +1337,7 @@ function chatbotsCommand() {
|
|
|
1339
1337
|
cmd.command("delete <chatbotId>").description("Delete a chatbot (irreversible \u2014 cascade-deletes everything)").action(async function(chatbotId) {
|
|
1340
1338
|
try {
|
|
1341
1339
|
const globals = this.optsWithGlobals();
|
|
1342
|
-
const c = await
|
|
1340
|
+
const c = await client3(globals);
|
|
1343
1341
|
await c.delete(`/api/v1/chatbots/${chatbotId}`);
|
|
1344
1342
|
emit({ ok: true, deleted: chatbotId }, { json: !!globals.json });
|
|
1345
1343
|
} catch (err) {
|
|
@@ -1350,23 +1348,25 @@ function chatbotsCommand() {
|
|
|
1350
1348
|
}
|
|
1351
1349
|
function webhooksCommand() {
|
|
1352
1350
|
const cmd = new import_commander7.Command("webhooks").description("Manage webhooks for a chatbot");
|
|
1353
|
-
cmd.command("list").
|
|
1351
|
+
cmd.command("list").action(async function() {
|
|
1354
1352
|
try {
|
|
1353
|
+
const chatbotId = requireChatbotId(this);
|
|
1355
1354
|
const globals = this.optsWithGlobals();
|
|
1356
|
-
const c = await
|
|
1355
|
+
const c = await client3(globals);
|
|
1357
1356
|
const result = await c.get(
|
|
1358
|
-
`/api/v1/chatbots/${
|
|
1357
|
+
`/api/v1/chatbots/${chatbotId}/webhooks`
|
|
1359
1358
|
);
|
|
1360
1359
|
emit(result.webhooks, { json: !!globals.json });
|
|
1361
1360
|
} catch (err) {
|
|
1362
1361
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1363
1362
|
}
|
|
1364
1363
|
});
|
|
1365
|
-
cmd.command("create").requiredOption("--
|
|
1364
|
+
cmd.command("create").requiredOption("--name <name>").requiredOption("--url <url>").option("--type <type>", "discord | slack | custom", "custom").action(async function(opts) {
|
|
1366
1365
|
try {
|
|
1366
|
+
const chatbotId = requireChatbotId(this);
|
|
1367
1367
|
const globals = this.optsWithGlobals();
|
|
1368
|
-
const c = await
|
|
1369
|
-
const result = await c.post(`/api/v1/chatbots/${
|
|
1368
|
+
const c = await client3(globals);
|
|
1369
|
+
const result = await c.post(`/api/v1/chatbots/${chatbotId}/webhooks`, {
|
|
1370
1370
|
name: opts.name,
|
|
1371
1371
|
url: opts.url,
|
|
1372
1372
|
type: opts.type
|
|
@@ -1377,11 +1377,12 @@ function webhooksCommand() {
|
|
|
1377
1377
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1378
1378
|
}
|
|
1379
1379
|
});
|
|
1380
|
-
cmd.command("delete").requiredOption("--
|
|
1380
|
+
cmd.command("delete").requiredOption("--webhook <id>", "Webhook id").action(async function(opts) {
|
|
1381
1381
|
try {
|
|
1382
|
+
const chatbotId = requireChatbotId(this);
|
|
1382
1383
|
const globals = this.optsWithGlobals();
|
|
1383
|
-
const c = await
|
|
1384
|
-
await c.delete(`/api/v1/chatbots/${
|
|
1384
|
+
const c = await client3(globals);
|
|
1385
|
+
await c.delete(`/api/v1/chatbots/${chatbotId}/webhooks/${opts.webhook}`);
|
|
1385
1386
|
emit({ ok: true, deleted: opts.webhook }, { json: !!globals.json });
|
|
1386
1387
|
} catch (err) {
|
|
1387
1388
|
fatal(err instanceof Error ? err.message : String(err));
|
|
@@ -1394,12 +1395,13 @@ function settingsCommand() {
|
|
|
1394
1395
|
"Manage chatbot settings + per-chatbot keys"
|
|
1395
1396
|
);
|
|
1396
1397
|
const keys = cmd.command("keys").description("Manage API keys for a chatbot");
|
|
1397
|
-
keys.command("rotate-ingest").
|
|
1398
|
+
keys.command("rotate-ingest").action(async function() {
|
|
1398
1399
|
try {
|
|
1400
|
+
const chatbotId = requireChatbotId(this);
|
|
1399
1401
|
const globals = this.optsWithGlobals();
|
|
1400
|
-
const c = await
|
|
1402
|
+
const c = await client3(globals);
|
|
1401
1403
|
const result = await c.post(
|
|
1402
|
-
`/api/v1/chatbots/${
|
|
1404
|
+
`/api/v1/chatbots/${chatbotId}/keys/ingest/rotate`,
|
|
1403
1405
|
{}
|
|
1404
1406
|
);
|
|
1405
1407
|
surfacePlaintext(result.plaintext, "New ingest key (ob_live_*)");
|
|
@@ -1408,12 +1410,13 @@ function settingsCommand() {
|
|
|
1408
1410
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1409
1411
|
}
|
|
1410
1412
|
});
|
|
1411
|
-
keys.command("generate-read").
|
|
1413
|
+
keys.command("generate-read").action(async function() {
|
|
1412
1414
|
try {
|
|
1415
|
+
const chatbotId = requireChatbotId(this);
|
|
1413
1416
|
const globals = this.optsWithGlobals();
|
|
1414
|
-
const c = await
|
|
1417
|
+
const c = await client3(globals);
|
|
1415
1418
|
const result = await c.post(
|
|
1416
|
-
`/api/v1/chatbots/${
|
|
1419
|
+
`/api/v1/chatbots/${chatbotId}/keys/read`,
|
|
1417
1420
|
{}
|
|
1418
1421
|
);
|
|
1419
1422
|
surfacePlaintext(result.plaintext, "New read key (ob_read_*)");
|
|
@@ -1422,11 +1425,12 @@ function settingsCommand() {
|
|
|
1422
1425
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1423
1426
|
}
|
|
1424
1427
|
});
|
|
1425
|
-
keys.command("generate-admin").requiredOption("--
|
|
1428
|
+
keys.command("generate-admin").requiredOption("--name <name>", "Human-friendly name (e.g. 'CI key')").option("--expires-in-days <n>", "Auto-expire after N days").action(async function(opts) {
|
|
1426
1429
|
try {
|
|
1430
|
+
const chatbotId = requireChatbotId(this);
|
|
1427
1431
|
const globals = this.optsWithGlobals();
|
|
1428
|
-
const c = await
|
|
1429
|
-
const result = await c.post(`/api/v1/chatbots/${
|
|
1432
|
+
const c = await client3(globals);
|
|
1433
|
+
const result = await c.post(`/api/v1/chatbots/${chatbotId}/admin-keys`, {
|
|
1430
1434
|
name: opts.name,
|
|
1431
1435
|
expiresInDays: opts.expiresInDays ? Number(opts.expiresInDays) : void 0
|
|
1432
1436
|
});
|
|
@@ -1436,30 +1440,33 @@ function settingsCommand() {
|
|
|
1436
1440
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1437
1441
|
}
|
|
1438
1442
|
});
|
|
1439
|
-
keys.command("list-admin").
|
|
1443
|
+
keys.command("list-admin").action(async function() {
|
|
1440
1444
|
try {
|
|
1445
|
+
const chatbotId = requireChatbotId(this);
|
|
1441
1446
|
const globals = this.optsWithGlobals();
|
|
1442
|
-
const c = await
|
|
1447
|
+
const c = await client3(globals);
|
|
1443
1448
|
const result = await c.get(
|
|
1444
|
-
`/api/v1/chatbots/${
|
|
1449
|
+
`/api/v1/chatbots/${chatbotId}/admin-keys`
|
|
1445
1450
|
);
|
|
1446
1451
|
emit(result.keys, { json: !!globals.json });
|
|
1447
1452
|
} catch (err) {
|
|
1448
1453
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1449
1454
|
}
|
|
1450
1455
|
});
|
|
1451
|
-
keys.command("revoke-admin").requiredOption("--
|
|
1456
|
+
keys.command("revoke-admin").requiredOption("--key <keyId>", "Admin key id").action(async function(opts) {
|
|
1452
1457
|
try {
|
|
1458
|
+
const chatbotId = requireChatbotId(this);
|
|
1453
1459
|
const globals = this.optsWithGlobals();
|
|
1454
|
-
const c = await
|
|
1455
|
-
await c.delete(`/api/v1/chatbots/${
|
|
1460
|
+
const c = await client3(globals);
|
|
1461
|
+
await c.delete(`/api/v1/chatbots/${chatbotId}/admin-keys/${opts.key}`);
|
|
1456
1462
|
emit({ ok: true, revoked: opts.key }, { json: !!globals.json });
|
|
1457
1463
|
} catch (err) {
|
|
1458
1464
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1459
1465
|
}
|
|
1460
1466
|
});
|
|
1461
|
-
cmd.command("update").description("Patch a chatbot's settings JSONB").
|
|
1467
|
+
cmd.command("update").description("Patch a chatbot's settings JSONB").option("--description <text>").option("--website-url <url>").option("--language <code>").action(async function(opts) {
|
|
1462
1468
|
try {
|
|
1469
|
+
const chatbotId = requireChatbotId(this);
|
|
1463
1470
|
const settings = {};
|
|
1464
1471
|
if (opts.description) settings.description = opts.description;
|
|
1465
1472
|
if (opts.websiteUrl) settings.website_url = opts.websiteUrl;
|
|
@@ -1468,8 +1475,8 @@ function settingsCommand() {
|
|
|
1468
1475
|
fatal("Provide at least one setting to update.");
|
|
1469
1476
|
}
|
|
1470
1477
|
const globals = this.optsWithGlobals();
|
|
1471
|
-
const c = await
|
|
1472
|
-
await c.patch(`/api/v1/chatbots/${
|
|
1478
|
+
const c = await client3(globals);
|
|
1479
|
+
await c.patch(`/api/v1/chatbots/${chatbotId}/settings`, { settings });
|
|
1473
1480
|
emit({ ok: true }, { json: !!globals.json });
|
|
1474
1481
|
} catch (err) {
|
|
1475
1482
|
fatal(err instanceof Error ? err.message : String(err));
|
|
@@ -1479,19 +1486,20 @@ function settingsCommand() {
|
|
|
1479
1486
|
}
|
|
1480
1487
|
function workflowsCommand() {
|
|
1481
1488
|
const cmd = new import_commander7.Command("workflows").description("Manage workflows");
|
|
1482
|
-
cmd.command("list").
|
|
1489
|
+
cmd.command("list").action(async function() {
|
|
1483
1490
|
try {
|
|
1491
|
+
const chatbotId = requireChatbotId(this);
|
|
1484
1492
|
const globals = this.optsWithGlobals();
|
|
1485
|
-
const c = await
|
|
1493
|
+
const c = await client3(globals);
|
|
1486
1494
|
const result = await c.get(
|
|
1487
|
-
`/api/v1/chatbots/${
|
|
1495
|
+
`/api/v1/chatbots/${chatbotId}/workflows`
|
|
1488
1496
|
);
|
|
1489
1497
|
emit(result.workflows, { json: !!globals.json });
|
|
1490
1498
|
} catch (err) {
|
|
1491
1499
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1492
1500
|
}
|
|
1493
1501
|
});
|
|
1494
|
-
cmd.command("create").description("Create a workflow from a built-in template").requiredOption("--
|
|
1502
|
+
cmd.command("create").description("Create a workflow from a built-in template").requiredOption("--name <name>").requiredOption(
|
|
1495
1503
|
"--template <name>",
|
|
1496
1504
|
"flag-to-webhook | outcome-to-webhook | sentiment-drop-to-webhook"
|
|
1497
1505
|
).requiredOption(
|
|
@@ -1499,9 +1507,10 @@ function workflowsCommand() {
|
|
|
1499
1507
|
"Flag value / outcome value / sentiment threshold"
|
|
1500
1508
|
).requiredOption("--webhook <id>", "Webhook id to fire").option("--message <tpl>", "Message template (supports {{user.id}}, etc.)").action(async function(opts) {
|
|
1501
1509
|
try {
|
|
1510
|
+
const chatbotId = requireChatbotId(this);
|
|
1502
1511
|
const globals = this.optsWithGlobals();
|
|
1503
|
-
const c = await
|
|
1504
|
-
const result = await c.post(`/api/v1/chatbots/${
|
|
1512
|
+
const c = await client3(globals);
|
|
1513
|
+
const result = await c.post(`/api/v1/chatbots/${chatbotId}/workflows`, {
|
|
1505
1514
|
name: opts.name,
|
|
1506
1515
|
template: opts.template,
|
|
1507
1516
|
triggerValue: opts.triggerValue,
|
|
@@ -1517,23 +1526,25 @@ function workflowsCommand() {
|
|
|
1517
1526
|
}
|
|
1518
1527
|
function reportsCommand() {
|
|
1519
1528
|
const cmd = new import_commander7.Command("reports").description("Manage AI reports");
|
|
1520
|
-
cmd.command("list").
|
|
1529
|
+
cmd.command("list").action(async function() {
|
|
1521
1530
|
try {
|
|
1531
|
+
const chatbotId = requireChatbotId(this);
|
|
1522
1532
|
const globals = this.optsWithGlobals();
|
|
1523
|
-
const c = await
|
|
1533
|
+
const c = await client3(globals);
|
|
1524
1534
|
const result = await c.get(
|
|
1525
|
-
`/api/v1/chatbots/${
|
|
1535
|
+
`/api/v1/chatbots/${chatbotId}/reports`
|
|
1526
1536
|
);
|
|
1527
1537
|
emit(result.reports, { json: !!globals.json });
|
|
1528
1538
|
} catch (err) {
|
|
1529
1539
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1530
1540
|
}
|
|
1531
1541
|
});
|
|
1532
|
-
cmd.command("create").description("Create a new AI report; returns the org-private dashboard URL").
|
|
1542
|
+
cmd.command("create").description("Create a new AI report; returns the org-private dashboard URL").option("--name <name>", "Report name", "Untitled Report").action(async function(opts) {
|
|
1533
1543
|
try {
|
|
1544
|
+
const chatbotId = requireChatbotId(this);
|
|
1534
1545
|
const globals = this.optsWithGlobals();
|
|
1535
|
-
const c = await
|
|
1536
|
-
const result = await c.post(`/api/v1/chatbots/${
|
|
1546
|
+
const c = await client3(globals);
|
|
1547
|
+
const result = await c.post(`/api/v1/chatbots/${chatbotId}/reports`, { name: opts.name });
|
|
1537
1548
|
process.stderr.write(
|
|
1538
1549
|
`
|
|
1539
1550
|
Created report. View it (org members only):
|
|
@@ -1553,30 +1564,32 @@ Created report. View it (org members only):
|
|
|
1553
1564
|
}
|
|
1554
1565
|
function analysisCommand() {
|
|
1555
1566
|
const cmd = new import_commander7.Command("analysis").description("Manage analysis definitions");
|
|
1556
|
-
cmd.command("list").
|
|
1567
|
+
cmd.command("list").option("--type <t>", "intent | flag | assistant_outcome | assistant_issue").option("--pending", "Include pending suggestions").action(async function(opts) {
|
|
1557
1568
|
try {
|
|
1569
|
+
const chatbotId = requireChatbotId(this);
|
|
1558
1570
|
const globals = this.optsWithGlobals();
|
|
1559
|
-
const c = await
|
|
1571
|
+
const c = await client3(globals);
|
|
1560
1572
|
const qs = new URLSearchParams();
|
|
1561
1573
|
if (opts.type) qs.set("type", opts.type);
|
|
1562
1574
|
if (opts.pending) qs.set("pending", "true");
|
|
1563
1575
|
const result = await c.get(
|
|
1564
|
-
`/api/v1/chatbots/${
|
|
1576
|
+
`/api/v1/chatbots/${chatbotId}/analysis-definitions${qs.size ? `?${qs}` : ""}`
|
|
1565
1577
|
);
|
|
1566
1578
|
emit(result.definitions, { json: !!globals.json });
|
|
1567
1579
|
} catch (err) {
|
|
1568
1580
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1569
1581
|
}
|
|
1570
1582
|
});
|
|
1571
|
-
cmd.command("add").requiredOption(
|
|
1583
|
+
cmd.command("add").requiredOption(
|
|
1572
1584
|
"--type <t>",
|
|
1573
1585
|
"intent | flag | assistant_outcome | assistant_issue"
|
|
1574
1586
|
).requiredOption("--name <slug>", "snake_case slug").requiredOption("--display-name <text>").requiredOption("--description <text>").action(async function(opts) {
|
|
1575
1587
|
try {
|
|
1588
|
+
const chatbotId = requireChatbotId(this);
|
|
1576
1589
|
const globals = this.optsWithGlobals();
|
|
1577
|
-
const c = await
|
|
1590
|
+
const c = await client3(globals);
|
|
1578
1591
|
const result = await c.post(
|
|
1579
|
-
`/api/v1/chatbots/${
|
|
1592
|
+
`/api/v1/chatbots/${chatbotId}/analysis-definitions`,
|
|
1580
1593
|
{
|
|
1581
1594
|
analysisType: opts.type,
|
|
1582
1595
|
name: opts.name,
|
|
@@ -1595,10 +1608,11 @@ function usersCommand() {
|
|
|
1595
1608
|
const cmd = new import_commander7.Command("users").description(
|
|
1596
1609
|
"List external users (chatbot customers) with health metrics"
|
|
1597
1610
|
);
|
|
1598
|
-
cmd.command("list").
|
|
1611
|
+
cmd.command("list").option("--from <iso>").option("--to <iso>").option("--days <n>", "Convenience: last N days").option("--search <q>").option("--limit <n>", "Page size", "20").action(async function(opts) {
|
|
1599
1612
|
try {
|
|
1613
|
+
const chatbotId = requireChatbotId(this);
|
|
1600
1614
|
const globals = this.optsWithGlobals();
|
|
1601
|
-
const c = await
|
|
1615
|
+
const c = await client3(globals);
|
|
1602
1616
|
const qs = new URLSearchParams();
|
|
1603
1617
|
let from = opts.from;
|
|
1604
1618
|
if (!from && opts.days) {
|
|
@@ -1611,7 +1625,7 @@ function usersCommand() {
|
|
|
1611
1625
|
if (opts.search) qs.set("search", opts.search);
|
|
1612
1626
|
qs.set("limit", opts.limit);
|
|
1613
1627
|
const result = await c.get(
|
|
1614
|
-
`/api/v1/chatbots/${
|
|
1628
|
+
`/api/v1/chatbots/${chatbotId}/external-users?${qs}`
|
|
1615
1629
|
);
|
|
1616
1630
|
emit(result.users, { json: !!globals.json });
|
|
1617
1631
|
process.stderr.write(`
|
|
@@ -1629,7 +1643,7 @@ function sdkCommand() {
|
|
|
1629
1643
|
);
|
|
1630
1644
|
cmd.command("install-instructions").description("Print markdown the calling agent can follow").option(
|
|
1631
1645
|
"--framework <name>",
|
|
1632
|
-
"next |
|
|
1646
|
+
"next | vercel-ai-sdk (default: next)",
|
|
1633
1647
|
"next"
|
|
1634
1648
|
).option("--chatbot <id>", "Chatbot id (for the example snippet)").action(async function(opts) {
|
|
1635
1649
|
const chatbotId = opts.chatbot ?? "<chatbotId>";
|
|
@@ -1686,27 +1700,43 @@ function sdkCommand() {
|
|
|
1686
1700
|
const out = opts.framework === "vercel-ai-sdk" ? snippetWrapper : snippetNext;
|
|
1687
1701
|
process.stdout.write(out);
|
|
1688
1702
|
});
|
|
1689
|
-
cmd.command("verify").description("Check whether any event has arrived for the chatbot yet").
|
|
1703
|
+
cmd.command("verify").description("Check whether any event has arrived for the chatbot yet").option("--timeout <n>", "Seconds to wait (default: 60)", "60").action(async function(opts) {
|
|
1690
1704
|
try {
|
|
1691
1705
|
const globals = this.optsWithGlobals();
|
|
1692
|
-
const
|
|
1693
|
-
|
|
1706
|
+
const chatbotId = globals.chatbot;
|
|
1707
|
+
if (!chatbotId) {
|
|
1708
|
+
fatal("--chatbot <id> is required (also accepts the persisted active chatbot).");
|
|
1709
|
+
}
|
|
1710
|
+
const c = await client3(globals);
|
|
1711
|
+
const timeoutSec = Number(opts.timeout);
|
|
1712
|
+
const deadline = Date.now() + timeoutSec * 1e3;
|
|
1713
|
+
const params = new URLSearchParams({
|
|
1714
|
+
chatbotId,
|
|
1715
|
+
limit: "1"
|
|
1716
|
+
});
|
|
1717
|
+
process.stderr.write(
|
|
1718
|
+
`Waiting for first event on chatbot ${chatbotId} (timeout ${timeoutSec}s)\u2026
|
|
1719
|
+
`
|
|
1720
|
+
);
|
|
1721
|
+
let lastTick = Date.now();
|
|
1694
1722
|
while (Date.now() < deadline) {
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
`\u2713 First event detected. ${result.total} conversation(s) ingested.
|
|
1723
|
+
const result = await c.get(`/api/v1/conversations?${params}`);
|
|
1724
|
+
if (result.total > 0) {
|
|
1725
|
+
process.stderr.write(
|
|
1726
|
+
`First event detected. ${result.total} conversation(s) ingested.
|
|
1700
1727
|
`
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1728
|
+
);
|
|
1729
|
+
return;
|
|
1730
|
+
}
|
|
1731
|
+
if (Date.now() - lastTick >= 5e3) {
|
|
1732
|
+
process.stderr.write(".");
|
|
1733
|
+
lastTick = Date.now();
|
|
1705
1734
|
}
|
|
1706
1735
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
1707
1736
|
}
|
|
1708
1737
|
process.stderr.write(
|
|
1709
|
-
`
|
|
1738
|
+
`
|
|
1739
|
+
Timed out after ${timeoutSec}s \u2014 no events yet. Confirm OPENBAT_API_KEY and that recordMessages is being called.
|
|
1710
1740
|
`
|
|
1711
1741
|
);
|
|
1712
1742
|
process.exit(2);
|
|
@@ -1721,7 +1751,7 @@ function sdkCommand() {
|
|
|
1721
1751
|
var program = new import_commander8.Command();
|
|
1722
1752
|
program.name("openbat").description(
|
|
1723
1753
|
"Query OpenBat chatbot data \u2014 conversations, sentiment, analytics, exports."
|
|
1724
|
-
).version("0.2.
|
|
1754
|
+
).version("0.2.3").option("--api-key <key>", "Override the stored Read API key (footgun \u2014 leaks into shell history)").option(
|
|
1725
1755
|
"--base-url <url>",
|
|
1726
1756
|
"Override the OpenBat API base URL (defaults to ~/.openbatrc or https://openbat.dev)"
|
|
1727
1757
|
).option(
|