@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.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ApiClient
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HBSCN3HV.mjs";
|
|
5
5
|
|
|
6
6
|
// src/index.ts
|
|
7
7
|
import { Command as Command8 } from "commander";
|
|
@@ -210,7 +210,9 @@ function configCommand() {
|
|
|
210
210
|
const cmd = new Command("config").description(
|
|
211
211
|
"Manage the CLI's ~/.openbatrc settings"
|
|
212
212
|
);
|
|
213
|
-
cmd.command("set-key").description(
|
|
213
|
+
cmd.command("set-key").description(
|
|
214
|
+
"Store your API key in ~/.openbatrc. Reads from stdin by default; use --value to pass inline (discouraged \u2014 leaks into shell history)."
|
|
215
|
+
).option(
|
|
214
216
|
"--value <key>",
|
|
215
217
|
"Pass the key inline. Discouraged \u2014 leaks into shell history."
|
|
216
218
|
).action(async (opts) => {
|
|
@@ -226,13 +228,13 @@ function configCommand() {
|
|
|
226
228
|
key = Buffer.concat(chunks).toString("utf8").trim();
|
|
227
229
|
if (!key) {
|
|
228
230
|
fatal(
|
|
229
|
-
"No key on stdin. Try: echo 'ob_read_...' | openbat config set-key
|
|
231
|
+
"No key on stdin. Try: echo 'ob_read_...' | openbat config set-key"
|
|
230
232
|
);
|
|
231
233
|
}
|
|
232
234
|
}
|
|
233
235
|
await setApiKey(key);
|
|
234
236
|
process.stdout.write(
|
|
235
|
-
`Saved
|
|
237
|
+
`Saved key to ${configPath()} (mode 0600).
|
|
236
238
|
`
|
|
237
239
|
);
|
|
238
240
|
} catch (err) {
|
|
@@ -351,7 +353,9 @@ async function resolveChatbotId(api, chatbotFlag) {
|
|
|
351
353
|
);
|
|
352
354
|
const chatbots = list.chatbots ?? [];
|
|
353
355
|
if (chatbots.length === 0) {
|
|
354
|
-
fatal(
|
|
356
|
+
fatal(
|
|
357
|
+
"No chatbots yet. Run `openbat chatbots create --name <name>`, or ask an org owner to invite you."
|
|
358
|
+
);
|
|
355
359
|
}
|
|
356
360
|
if (chatbotFlag) {
|
|
357
361
|
if (UUID_RE2.test(chatbotFlag)) {
|
|
@@ -536,18 +540,6 @@ function exportCommand() {
|
|
|
536
540
|
|
|
537
541
|
// src/commands/auth.ts
|
|
538
542
|
import { Command as Command3 } from "commander";
|
|
539
|
-
async function client2(globals) {
|
|
540
|
-
const cfg = await resolveConfig({
|
|
541
|
-
apiKeyFlag: globals.apiKey ?? null,
|
|
542
|
-
baseUrlFlag: globals.baseUrl ?? null
|
|
543
|
-
});
|
|
544
|
-
if (!cfg.apiKey) {
|
|
545
|
-
fatal(
|
|
546
|
-
"No API key configured. Run `openbat config set-key`, pass --api-key, or set OPENBAT_API_KEY."
|
|
547
|
-
);
|
|
548
|
-
}
|
|
549
|
-
return new ApiClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl });
|
|
550
|
-
}
|
|
551
543
|
function detectKind(apiKey) {
|
|
552
544
|
if (apiKey.startsWith("ob_read_")) return "read";
|
|
553
545
|
if (apiKey.startsWith("ob_admin_")) return "admin";
|
|
@@ -599,17 +591,6 @@ function authCommand() {
|
|
|
599
591
|
fatal(err instanceof Error ? err.message : String(err));
|
|
600
592
|
}
|
|
601
593
|
});
|
|
602
|
-
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() {
|
|
603
|
-
try {
|
|
604
|
-
process.stderr.write(
|
|
605
|
-
"audit-log: endpoint not yet exposed via HTTP \u2014 query `select * from api_audit_log` in Supabase Studio for now.\n"
|
|
606
|
-
);
|
|
607
|
-
const _c = await client2(this.optsWithGlobals());
|
|
608
|
-
void _c;
|
|
609
|
-
} catch (err) {
|
|
610
|
-
fatal(err instanceof Error ? err.message : String(err));
|
|
611
|
-
}
|
|
612
|
-
});
|
|
613
594
|
return cmd;
|
|
614
595
|
}
|
|
615
596
|
|
|
@@ -896,7 +877,15 @@ async function pickDefaultChatbot(token, baseUrl) {
|
|
|
896
877
|
return;
|
|
897
878
|
}
|
|
898
879
|
if (chatbots.length === 0) {
|
|
899
|
-
process.stdout.write(
|
|
880
|
+
process.stdout.write(
|
|
881
|
+
[
|
|
882
|
+
"",
|
|
883
|
+
"No chatbots yet. To get one:",
|
|
884
|
+
" \u2022 Create one: openbat chatbots create --name <name>",
|
|
885
|
+
" \u2022 Or ask an org owner to invite you, then run `openbat login` again",
|
|
886
|
+
""
|
|
887
|
+
].join("\n")
|
|
888
|
+
);
|
|
900
889
|
return;
|
|
901
890
|
}
|
|
902
891
|
if (chatbots.length === 1) {
|
|
@@ -964,7 +953,7 @@ function logoutCommand() {
|
|
|
964
953
|
}
|
|
965
954
|
} else {
|
|
966
955
|
process.stderr.write(
|
|
967
|
-
"Note: read/admin keys can't self-revoke.
|
|
956
|
+
"Note: read/admin keys can't self-revoke server-side. Revoke them in the dashboard if needed; clearing local config only.\n"
|
|
968
957
|
);
|
|
969
958
|
}
|
|
970
959
|
await clearApiKey();
|
|
@@ -977,7 +966,7 @@ function logoutCommand() {
|
|
|
977
966
|
|
|
978
967
|
// src/commands/org.ts
|
|
979
968
|
import { Command as Command6 } from "commander";
|
|
980
|
-
async function
|
|
969
|
+
async function client2(globals) {
|
|
981
970
|
const cfg = await resolveConfig({
|
|
982
971
|
apiKeyFlag: globals.apiKey ?? null,
|
|
983
972
|
baseUrlFlag: globals.baseUrl ?? null
|
|
@@ -997,7 +986,7 @@ function orgCommand() {
|
|
|
997
986
|
cmd.command("list").description("List orgs the current PAT's user belongs to").action(async function() {
|
|
998
987
|
try {
|
|
999
988
|
const globals = this.optsWithGlobals();
|
|
1000
|
-
const c = await
|
|
989
|
+
const c = await client2(globals);
|
|
1001
990
|
const result = await c.get("/api/v1/orgs");
|
|
1002
991
|
emit(result.orgs, { json: !!globals.json });
|
|
1003
992
|
} catch (err) {
|
|
@@ -1007,7 +996,7 @@ function orgCommand() {
|
|
|
1007
996
|
cmd.command("show").description("Show the active org (id, name, members)").action(async function() {
|
|
1008
997
|
try {
|
|
1009
998
|
const globals = this.optsWithGlobals();
|
|
1010
|
-
const c = await
|
|
999
|
+
const c = await client2(globals);
|
|
1011
1000
|
const result = await c.get(
|
|
1012
1001
|
"/api/v1/orgs/active"
|
|
1013
1002
|
);
|
|
@@ -1022,7 +1011,7 @@ function orgCommand() {
|
|
|
1022
1011
|
cmd.command("rename").description("Rename an org (owner only)").requiredOption("--id <orgId>", "Org id").requiredOption("--name <name>", "New name").action(async function(opts) {
|
|
1023
1012
|
try {
|
|
1024
1013
|
const globals = this.optsWithGlobals();
|
|
1025
|
-
const c = await
|
|
1014
|
+
const c = await client2(globals);
|
|
1026
1015
|
await c.patch(`/api/v1/orgs/${opts.id}`, { name: opts.name });
|
|
1027
1016
|
emit({ ok: true, renamed: opts.id }, { json: !!globals.json });
|
|
1028
1017
|
} catch (err) {
|
|
@@ -1033,7 +1022,7 @@ function orgCommand() {
|
|
|
1033
1022
|
members.command("list").requiredOption("--id <orgId>", "Org id").action(async function(opts) {
|
|
1034
1023
|
try {
|
|
1035
1024
|
const globals = this.optsWithGlobals();
|
|
1036
|
-
const c = await
|
|
1025
|
+
const c = await client2(globals);
|
|
1037
1026
|
const result = await c.get(
|
|
1038
1027
|
`/api/v1/orgs/${opts.id}/members`
|
|
1039
1028
|
);
|
|
@@ -1045,7 +1034,7 @@ function orgCommand() {
|
|
|
1045
1034
|
members.command("invite").requiredOption("--id <orgId>", "Org id").requiredOption("--email <email>", "Invitee email").option("--role <role>", "member | admin", "member").action(async function(opts) {
|
|
1046
1035
|
try {
|
|
1047
1036
|
const globals = this.optsWithGlobals();
|
|
1048
|
-
const c = await
|
|
1037
|
+
const c = await client2(globals);
|
|
1049
1038
|
const result = await c.post(
|
|
1050
1039
|
`/api/v1/orgs/${opts.id}/members`,
|
|
1051
1040
|
{ email: opts.email, role: opts.role }
|
|
@@ -1063,7 +1052,7 @@ function orgCommand() {
|
|
|
1063
1052
|
members.command("set-role").requiredOption("--id <orgId>", "Org id").requiredOption("--member <memberId>", "Member id").requiredOption("--role <role>", "admin | member").action(async function(opts) {
|
|
1064
1053
|
try {
|
|
1065
1054
|
const globals = this.optsWithGlobals();
|
|
1066
|
-
const c = await
|
|
1055
|
+
const c = await client2(globals);
|
|
1067
1056
|
await c.patch(`/api/v1/orgs/${opts.id}/members/${opts.member}`, {
|
|
1068
1057
|
role: opts.role
|
|
1069
1058
|
});
|
|
@@ -1075,7 +1064,7 @@ function orgCommand() {
|
|
|
1075
1064
|
members.command("remove").requiredOption("--id <orgId>", "Org id").requiredOption("--member <memberId>", "Member id").action(async function(opts) {
|
|
1076
1065
|
try {
|
|
1077
1066
|
const globals = this.optsWithGlobals();
|
|
1078
|
-
const c = await
|
|
1067
|
+
const c = await client2(globals);
|
|
1079
1068
|
await c.delete(`/api/v1/orgs/${opts.id}/members/${opts.member}`);
|
|
1080
1069
|
emit({ ok: true }, { json: !!globals.json });
|
|
1081
1070
|
} catch (err) {
|
|
@@ -1086,7 +1075,7 @@ function orgCommand() {
|
|
|
1086
1075
|
invitations.command("list").requiredOption("--id <orgId>", "Org id").action(async function(opts) {
|
|
1087
1076
|
try {
|
|
1088
1077
|
const globals = this.optsWithGlobals();
|
|
1089
|
-
const c = await
|
|
1078
|
+
const c = await client2(globals);
|
|
1090
1079
|
const result = await c.get(
|
|
1091
1080
|
`/api/v1/orgs/${opts.id}/invitations`
|
|
1092
1081
|
);
|
|
@@ -1100,7 +1089,7 @@ function orgCommand() {
|
|
|
1100
1089
|
|
|
1101
1090
|
// src/commands/write.ts
|
|
1102
1091
|
import { Command as Command7 } from "commander";
|
|
1103
|
-
async function
|
|
1092
|
+
async function client3(globals) {
|
|
1104
1093
|
const cfg = await resolveConfig({
|
|
1105
1094
|
apiKeyFlag: globals.apiKey ?? null,
|
|
1106
1095
|
baseUrlFlag: globals.baseUrl ?? null
|
|
@@ -1110,6 +1099,15 @@ async function client4(globals) {
|
|
|
1110
1099
|
}
|
|
1111
1100
|
return new ApiClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl });
|
|
1112
1101
|
}
|
|
1102
|
+
function requireChatbotId(cmd) {
|
|
1103
|
+
const globals = cmd.optsWithGlobals();
|
|
1104
|
+
if (!globals.chatbot) {
|
|
1105
|
+
fatal(
|
|
1106
|
+
"--chatbot <id> is required. Pass it inline or set a default with `openbat use <id>`."
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
return globals.chatbot;
|
|
1110
|
+
}
|
|
1113
1111
|
function surfacePlaintext(plaintext, label) {
|
|
1114
1112
|
process.stderr.write(
|
|
1115
1113
|
`
|
|
@@ -1129,7 +1127,7 @@ function chatbotsCommand() {
|
|
|
1129
1127
|
cmd.command("list").description("List every chatbot the credential can reach").action(async function() {
|
|
1130
1128
|
try {
|
|
1131
1129
|
const globals = this.optsWithGlobals();
|
|
1132
|
-
const c = await
|
|
1130
|
+
const c = await client3(globals);
|
|
1133
1131
|
const result = await c.get(
|
|
1134
1132
|
"/api/v1/chatbots"
|
|
1135
1133
|
);
|
|
@@ -1141,7 +1139,7 @@ function chatbotsCommand() {
|
|
|
1141
1139
|
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) {
|
|
1142
1140
|
try {
|
|
1143
1141
|
const globals = this.optsWithGlobals();
|
|
1144
|
-
const c = await
|
|
1142
|
+
const c = await client3(globals);
|
|
1145
1143
|
const result = await c.post("/api/v1/chatbots", {
|
|
1146
1144
|
name: opts.name,
|
|
1147
1145
|
websiteUrl: opts.website,
|
|
@@ -1161,7 +1159,7 @@ function chatbotsCommand() {
|
|
|
1161
1159
|
cmd.command("delete <chatbotId>").description("Delete a chatbot (irreversible \u2014 cascade-deletes everything)").action(async function(chatbotId) {
|
|
1162
1160
|
try {
|
|
1163
1161
|
const globals = this.optsWithGlobals();
|
|
1164
|
-
const c = await
|
|
1162
|
+
const c = await client3(globals);
|
|
1165
1163
|
await c.delete(`/api/v1/chatbots/${chatbotId}`);
|
|
1166
1164
|
emit({ ok: true, deleted: chatbotId }, { json: !!globals.json });
|
|
1167
1165
|
} catch (err) {
|
|
@@ -1172,23 +1170,25 @@ function chatbotsCommand() {
|
|
|
1172
1170
|
}
|
|
1173
1171
|
function webhooksCommand() {
|
|
1174
1172
|
const cmd = new Command7("webhooks").description("Manage webhooks for a chatbot");
|
|
1175
|
-
cmd.command("list").
|
|
1173
|
+
cmd.command("list").action(async function() {
|
|
1176
1174
|
try {
|
|
1175
|
+
const chatbotId = requireChatbotId(this);
|
|
1177
1176
|
const globals = this.optsWithGlobals();
|
|
1178
|
-
const c = await
|
|
1177
|
+
const c = await client3(globals);
|
|
1179
1178
|
const result = await c.get(
|
|
1180
|
-
`/api/v1/chatbots/${
|
|
1179
|
+
`/api/v1/chatbots/${chatbotId}/webhooks`
|
|
1181
1180
|
);
|
|
1182
1181
|
emit(result.webhooks, { json: !!globals.json });
|
|
1183
1182
|
} catch (err) {
|
|
1184
1183
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1185
1184
|
}
|
|
1186
1185
|
});
|
|
1187
|
-
cmd.command("create").requiredOption("--
|
|
1186
|
+
cmd.command("create").requiredOption("--name <name>").requiredOption("--url <url>").option("--type <type>", "discord | slack | custom", "custom").action(async function(opts) {
|
|
1188
1187
|
try {
|
|
1188
|
+
const chatbotId = requireChatbotId(this);
|
|
1189
1189
|
const globals = this.optsWithGlobals();
|
|
1190
|
-
const c = await
|
|
1191
|
-
const result = await c.post(`/api/v1/chatbots/${
|
|
1190
|
+
const c = await client3(globals);
|
|
1191
|
+
const result = await c.post(`/api/v1/chatbots/${chatbotId}/webhooks`, {
|
|
1192
1192
|
name: opts.name,
|
|
1193
1193
|
url: opts.url,
|
|
1194
1194
|
type: opts.type
|
|
@@ -1199,11 +1199,12 @@ function webhooksCommand() {
|
|
|
1199
1199
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1200
1200
|
}
|
|
1201
1201
|
});
|
|
1202
|
-
cmd.command("delete").requiredOption("--
|
|
1202
|
+
cmd.command("delete").requiredOption("--webhook <id>", "Webhook id").action(async function(opts) {
|
|
1203
1203
|
try {
|
|
1204
|
+
const chatbotId = requireChatbotId(this);
|
|
1204
1205
|
const globals = this.optsWithGlobals();
|
|
1205
|
-
const c = await
|
|
1206
|
-
await c.delete(`/api/v1/chatbots/${
|
|
1206
|
+
const c = await client3(globals);
|
|
1207
|
+
await c.delete(`/api/v1/chatbots/${chatbotId}/webhooks/${opts.webhook}`);
|
|
1207
1208
|
emit({ ok: true, deleted: opts.webhook }, { json: !!globals.json });
|
|
1208
1209
|
} catch (err) {
|
|
1209
1210
|
fatal(err instanceof Error ? err.message : String(err));
|
|
@@ -1216,12 +1217,13 @@ function settingsCommand() {
|
|
|
1216
1217
|
"Manage chatbot settings + per-chatbot keys"
|
|
1217
1218
|
);
|
|
1218
1219
|
const keys = cmd.command("keys").description("Manage API keys for a chatbot");
|
|
1219
|
-
keys.command("rotate-ingest").
|
|
1220
|
+
keys.command("rotate-ingest").action(async function() {
|
|
1220
1221
|
try {
|
|
1222
|
+
const chatbotId = requireChatbotId(this);
|
|
1221
1223
|
const globals = this.optsWithGlobals();
|
|
1222
|
-
const c = await
|
|
1224
|
+
const c = await client3(globals);
|
|
1223
1225
|
const result = await c.post(
|
|
1224
|
-
`/api/v1/chatbots/${
|
|
1226
|
+
`/api/v1/chatbots/${chatbotId}/keys/ingest/rotate`,
|
|
1225
1227
|
{}
|
|
1226
1228
|
);
|
|
1227
1229
|
surfacePlaintext(result.plaintext, "New ingest key (ob_live_*)");
|
|
@@ -1230,12 +1232,13 @@ function settingsCommand() {
|
|
|
1230
1232
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1231
1233
|
}
|
|
1232
1234
|
});
|
|
1233
|
-
keys.command("generate-read").
|
|
1235
|
+
keys.command("generate-read").action(async function() {
|
|
1234
1236
|
try {
|
|
1237
|
+
const chatbotId = requireChatbotId(this);
|
|
1235
1238
|
const globals = this.optsWithGlobals();
|
|
1236
|
-
const c = await
|
|
1239
|
+
const c = await client3(globals);
|
|
1237
1240
|
const result = await c.post(
|
|
1238
|
-
`/api/v1/chatbots/${
|
|
1241
|
+
`/api/v1/chatbots/${chatbotId}/keys/read`,
|
|
1239
1242
|
{}
|
|
1240
1243
|
);
|
|
1241
1244
|
surfacePlaintext(result.plaintext, "New read key (ob_read_*)");
|
|
@@ -1244,11 +1247,12 @@ function settingsCommand() {
|
|
|
1244
1247
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1245
1248
|
}
|
|
1246
1249
|
});
|
|
1247
|
-
keys.command("generate-admin").requiredOption("--
|
|
1250
|
+
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) {
|
|
1248
1251
|
try {
|
|
1252
|
+
const chatbotId = requireChatbotId(this);
|
|
1249
1253
|
const globals = this.optsWithGlobals();
|
|
1250
|
-
const c = await
|
|
1251
|
-
const result = await c.post(`/api/v1/chatbots/${
|
|
1254
|
+
const c = await client3(globals);
|
|
1255
|
+
const result = await c.post(`/api/v1/chatbots/${chatbotId}/admin-keys`, {
|
|
1252
1256
|
name: opts.name,
|
|
1253
1257
|
expiresInDays: opts.expiresInDays ? Number(opts.expiresInDays) : void 0
|
|
1254
1258
|
});
|
|
@@ -1258,30 +1262,33 @@ function settingsCommand() {
|
|
|
1258
1262
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1259
1263
|
}
|
|
1260
1264
|
});
|
|
1261
|
-
keys.command("list-admin").
|
|
1265
|
+
keys.command("list-admin").action(async function() {
|
|
1262
1266
|
try {
|
|
1267
|
+
const chatbotId = requireChatbotId(this);
|
|
1263
1268
|
const globals = this.optsWithGlobals();
|
|
1264
|
-
const c = await
|
|
1269
|
+
const c = await client3(globals);
|
|
1265
1270
|
const result = await c.get(
|
|
1266
|
-
`/api/v1/chatbots/${
|
|
1271
|
+
`/api/v1/chatbots/${chatbotId}/admin-keys`
|
|
1267
1272
|
);
|
|
1268
1273
|
emit(result.keys, { json: !!globals.json });
|
|
1269
1274
|
} catch (err) {
|
|
1270
1275
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1271
1276
|
}
|
|
1272
1277
|
});
|
|
1273
|
-
keys.command("revoke-admin").requiredOption("--
|
|
1278
|
+
keys.command("revoke-admin").requiredOption("--key <keyId>", "Admin key id").action(async function(opts) {
|
|
1274
1279
|
try {
|
|
1280
|
+
const chatbotId = requireChatbotId(this);
|
|
1275
1281
|
const globals = this.optsWithGlobals();
|
|
1276
|
-
const c = await
|
|
1277
|
-
await c.delete(`/api/v1/chatbots/${
|
|
1282
|
+
const c = await client3(globals);
|
|
1283
|
+
await c.delete(`/api/v1/chatbots/${chatbotId}/admin-keys/${opts.key}`);
|
|
1278
1284
|
emit({ ok: true, revoked: opts.key }, { json: !!globals.json });
|
|
1279
1285
|
} catch (err) {
|
|
1280
1286
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1281
1287
|
}
|
|
1282
1288
|
});
|
|
1283
|
-
cmd.command("update").description("Patch a chatbot's settings JSONB").
|
|
1289
|
+
cmd.command("update").description("Patch a chatbot's settings JSONB").option("--description <text>").option("--website-url <url>").option("--language <code>").action(async function(opts) {
|
|
1284
1290
|
try {
|
|
1291
|
+
const chatbotId = requireChatbotId(this);
|
|
1285
1292
|
const settings = {};
|
|
1286
1293
|
if (opts.description) settings.description = opts.description;
|
|
1287
1294
|
if (opts.websiteUrl) settings.website_url = opts.websiteUrl;
|
|
@@ -1290,8 +1297,8 @@ function settingsCommand() {
|
|
|
1290
1297
|
fatal("Provide at least one setting to update.");
|
|
1291
1298
|
}
|
|
1292
1299
|
const globals = this.optsWithGlobals();
|
|
1293
|
-
const c = await
|
|
1294
|
-
await c.patch(`/api/v1/chatbots/${
|
|
1300
|
+
const c = await client3(globals);
|
|
1301
|
+
await c.patch(`/api/v1/chatbots/${chatbotId}/settings`, { settings });
|
|
1295
1302
|
emit({ ok: true }, { json: !!globals.json });
|
|
1296
1303
|
} catch (err) {
|
|
1297
1304
|
fatal(err instanceof Error ? err.message : String(err));
|
|
@@ -1301,19 +1308,20 @@ function settingsCommand() {
|
|
|
1301
1308
|
}
|
|
1302
1309
|
function workflowsCommand() {
|
|
1303
1310
|
const cmd = new Command7("workflows").description("Manage workflows");
|
|
1304
|
-
cmd.command("list").
|
|
1311
|
+
cmd.command("list").action(async function() {
|
|
1305
1312
|
try {
|
|
1313
|
+
const chatbotId = requireChatbotId(this);
|
|
1306
1314
|
const globals = this.optsWithGlobals();
|
|
1307
|
-
const c = await
|
|
1315
|
+
const c = await client3(globals);
|
|
1308
1316
|
const result = await c.get(
|
|
1309
|
-
`/api/v1/chatbots/${
|
|
1317
|
+
`/api/v1/chatbots/${chatbotId}/workflows`
|
|
1310
1318
|
);
|
|
1311
1319
|
emit(result.workflows, { json: !!globals.json });
|
|
1312
1320
|
} catch (err) {
|
|
1313
1321
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1314
1322
|
}
|
|
1315
1323
|
});
|
|
1316
|
-
cmd.command("create").description("Create a workflow from a built-in template").requiredOption("--
|
|
1324
|
+
cmd.command("create").description("Create a workflow from a built-in template").requiredOption("--name <name>").requiredOption(
|
|
1317
1325
|
"--template <name>",
|
|
1318
1326
|
"flag-to-webhook | outcome-to-webhook | sentiment-drop-to-webhook"
|
|
1319
1327
|
).requiredOption(
|
|
@@ -1321,9 +1329,10 @@ function workflowsCommand() {
|
|
|
1321
1329
|
"Flag value / outcome value / sentiment threshold"
|
|
1322
1330
|
).requiredOption("--webhook <id>", "Webhook id to fire").option("--message <tpl>", "Message template (supports {{user.id}}, etc.)").action(async function(opts) {
|
|
1323
1331
|
try {
|
|
1332
|
+
const chatbotId = requireChatbotId(this);
|
|
1324
1333
|
const globals = this.optsWithGlobals();
|
|
1325
|
-
const c = await
|
|
1326
|
-
const result = await c.post(`/api/v1/chatbots/${
|
|
1334
|
+
const c = await client3(globals);
|
|
1335
|
+
const result = await c.post(`/api/v1/chatbots/${chatbotId}/workflows`, {
|
|
1327
1336
|
name: opts.name,
|
|
1328
1337
|
template: opts.template,
|
|
1329
1338
|
triggerValue: opts.triggerValue,
|
|
@@ -1339,23 +1348,25 @@ function workflowsCommand() {
|
|
|
1339
1348
|
}
|
|
1340
1349
|
function reportsCommand() {
|
|
1341
1350
|
const cmd = new Command7("reports").description("Manage AI reports");
|
|
1342
|
-
cmd.command("list").
|
|
1351
|
+
cmd.command("list").action(async function() {
|
|
1343
1352
|
try {
|
|
1353
|
+
const chatbotId = requireChatbotId(this);
|
|
1344
1354
|
const globals = this.optsWithGlobals();
|
|
1345
|
-
const c = await
|
|
1355
|
+
const c = await client3(globals);
|
|
1346
1356
|
const result = await c.get(
|
|
1347
|
-
`/api/v1/chatbots/${
|
|
1357
|
+
`/api/v1/chatbots/${chatbotId}/reports`
|
|
1348
1358
|
);
|
|
1349
1359
|
emit(result.reports, { json: !!globals.json });
|
|
1350
1360
|
} catch (err) {
|
|
1351
1361
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1352
1362
|
}
|
|
1353
1363
|
});
|
|
1354
|
-
cmd.command("create").description("Create a new AI report; returns the org-private dashboard URL").
|
|
1364
|
+
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) {
|
|
1355
1365
|
try {
|
|
1366
|
+
const chatbotId = requireChatbotId(this);
|
|
1356
1367
|
const globals = this.optsWithGlobals();
|
|
1357
|
-
const c = await
|
|
1358
|
-
const result = await c.post(`/api/v1/chatbots/${
|
|
1368
|
+
const c = await client3(globals);
|
|
1369
|
+
const result = await c.post(`/api/v1/chatbots/${chatbotId}/reports`, { name: opts.name });
|
|
1359
1370
|
process.stderr.write(
|
|
1360
1371
|
`
|
|
1361
1372
|
Created report. View it (org members only):
|
|
@@ -1375,30 +1386,32 @@ Created report. View it (org members only):
|
|
|
1375
1386
|
}
|
|
1376
1387
|
function analysisCommand() {
|
|
1377
1388
|
const cmd = new Command7("analysis").description("Manage analysis definitions");
|
|
1378
|
-
cmd.command("list").
|
|
1389
|
+
cmd.command("list").option("--type <t>", "intent | flag | assistant_outcome | assistant_issue").option("--pending", "Include pending suggestions").action(async function(opts) {
|
|
1379
1390
|
try {
|
|
1391
|
+
const chatbotId = requireChatbotId(this);
|
|
1380
1392
|
const globals = this.optsWithGlobals();
|
|
1381
|
-
const c = await
|
|
1393
|
+
const c = await client3(globals);
|
|
1382
1394
|
const qs = new URLSearchParams();
|
|
1383
1395
|
if (opts.type) qs.set("type", opts.type);
|
|
1384
1396
|
if (opts.pending) qs.set("pending", "true");
|
|
1385
1397
|
const result = await c.get(
|
|
1386
|
-
`/api/v1/chatbots/${
|
|
1398
|
+
`/api/v1/chatbots/${chatbotId}/analysis-definitions${qs.size ? `?${qs}` : ""}`
|
|
1387
1399
|
);
|
|
1388
1400
|
emit(result.definitions, { json: !!globals.json });
|
|
1389
1401
|
} catch (err) {
|
|
1390
1402
|
fatal(err instanceof Error ? err.message : String(err));
|
|
1391
1403
|
}
|
|
1392
1404
|
});
|
|
1393
|
-
cmd.command("add").requiredOption(
|
|
1405
|
+
cmd.command("add").requiredOption(
|
|
1394
1406
|
"--type <t>",
|
|
1395
1407
|
"intent | flag | assistant_outcome | assistant_issue"
|
|
1396
1408
|
).requiredOption("--name <slug>", "snake_case slug").requiredOption("--display-name <text>").requiredOption("--description <text>").action(async function(opts) {
|
|
1397
1409
|
try {
|
|
1410
|
+
const chatbotId = requireChatbotId(this);
|
|
1398
1411
|
const globals = this.optsWithGlobals();
|
|
1399
|
-
const c = await
|
|
1412
|
+
const c = await client3(globals);
|
|
1400
1413
|
const result = await c.post(
|
|
1401
|
-
`/api/v1/chatbots/${
|
|
1414
|
+
`/api/v1/chatbots/${chatbotId}/analysis-definitions`,
|
|
1402
1415
|
{
|
|
1403
1416
|
analysisType: opts.type,
|
|
1404
1417
|
name: opts.name,
|
|
@@ -1417,10 +1430,11 @@ function usersCommand() {
|
|
|
1417
1430
|
const cmd = new Command7("users").description(
|
|
1418
1431
|
"List external users (chatbot customers) with health metrics"
|
|
1419
1432
|
);
|
|
1420
|
-
cmd.command("list").
|
|
1433
|
+
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) {
|
|
1421
1434
|
try {
|
|
1435
|
+
const chatbotId = requireChatbotId(this);
|
|
1422
1436
|
const globals = this.optsWithGlobals();
|
|
1423
|
-
const c = await
|
|
1437
|
+
const c = await client3(globals);
|
|
1424
1438
|
const qs = new URLSearchParams();
|
|
1425
1439
|
let from = opts.from;
|
|
1426
1440
|
if (!from && opts.days) {
|
|
@@ -1433,7 +1447,7 @@ function usersCommand() {
|
|
|
1433
1447
|
if (opts.search) qs.set("search", opts.search);
|
|
1434
1448
|
qs.set("limit", opts.limit);
|
|
1435
1449
|
const result = await c.get(
|
|
1436
|
-
`/api/v1/chatbots/${
|
|
1450
|
+
`/api/v1/chatbots/${chatbotId}/external-users?${qs}`
|
|
1437
1451
|
);
|
|
1438
1452
|
emit(result.users, { json: !!globals.json });
|
|
1439
1453
|
process.stderr.write(`
|
|
@@ -1451,7 +1465,7 @@ function sdkCommand() {
|
|
|
1451
1465
|
);
|
|
1452
1466
|
cmd.command("install-instructions").description("Print markdown the calling agent can follow").option(
|
|
1453
1467
|
"--framework <name>",
|
|
1454
|
-
"next |
|
|
1468
|
+
"next | vercel-ai-sdk (default: next)",
|
|
1455
1469
|
"next"
|
|
1456
1470
|
).option("--chatbot <id>", "Chatbot id (for the example snippet)").action(async function(opts) {
|
|
1457
1471
|
const chatbotId = opts.chatbot ?? "<chatbotId>";
|
|
@@ -1508,27 +1522,43 @@ function sdkCommand() {
|
|
|
1508
1522
|
const out = opts.framework === "vercel-ai-sdk" ? snippetWrapper : snippetNext;
|
|
1509
1523
|
process.stdout.write(out);
|
|
1510
1524
|
});
|
|
1511
|
-
cmd.command("verify").description("Check whether any event has arrived for the chatbot yet").
|
|
1525
|
+
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) {
|
|
1512
1526
|
try {
|
|
1513
1527
|
const globals = this.optsWithGlobals();
|
|
1514
|
-
const
|
|
1515
|
-
|
|
1528
|
+
const chatbotId = globals.chatbot;
|
|
1529
|
+
if (!chatbotId) {
|
|
1530
|
+
fatal("--chatbot <id> is required (also accepts the persisted active chatbot).");
|
|
1531
|
+
}
|
|
1532
|
+
const c = await client3(globals);
|
|
1533
|
+
const timeoutSec = Number(opts.timeout);
|
|
1534
|
+
const deadline = Date.now() + timeoutSec * 1e3;
|
|
1535
|
+
const params = new URLSearchParams({
|
|
1536
|
+
chatbotId,
|
|
1537
|
+
limit: "1"
|
|
1538
|
+
});
|
|
1539
|
+
process.stderr.write(
|
|
1540
|
+
`Waiting for first event on chatbot ${chatbotId} (timeout ${timeoutSec}s)\u2026
|
|
1541
|
+
`
|
|
1542
|
+
);
|
|
1543
|
+
let lastTick = Date.now();
|
|
1516
1544
|
while (Date.now() < deadline) {
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
`\u2713 First event detected. ${result.total} conversation(s) ingested.
|
|
1545
|
+
const result = await c.get(`/api/v1/conversations?${params}`);
|
|
1546
|
+
if (result.total > 0) {
|
|
1547
|
+
process.stderr.write(
|
|
1548
|
+
`First event detected. ${result.total} conversation(s) ingested.
|
|
1522
1549
|
`
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1550
|
+
);
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
if (Date.now() - lastTick >= 5e3) {
|
|
1554
|
+
process.stderr.write(".");
|
|
1555
|
+
lastTick = Date.now();
|
|
1527
1556
|
}
|
|
1528
1557
|
await new Promise((r) => setTimeout(r, 2e3));
|
|
1529
1558
|
}
|
|
1530
1559
|
process.stderr.write(
|
|
1531
|
-
`
|
|
1560
|
+
`
|
|
1561
|
+
Timed out after ${timeoutSec}s \u2014 no events yet. Confirm OPENBAT_API_KEY and that recordMessages is being called.
|
|
1532
1562
|
`
|
|
1533
1563
|
);
|
|
1534
1564
|
process.exit(2);
|
|
@@ -1543,7 +1573,7 @@ function sdkCommand() {
|
|
|
1543
1573
|
var program = new Command8();
|
|
1544
1574
|
program.name("openbat").description(
|
|
1545
1575
|
"Query OpenBat chatbot data \u2014 conversations, sentiment, analytics, exports."
|
|
1546
|
-
).version("0.2.
|
|
1576
|
+
).version("0.2.3").option("--api-key <key>", "Override the stored Read API key (footgun \u2014 leaks into shell history)").option(
|
|
1547
1577
|
"--base-url <url>",
|
|
1548
1578
|
"Override the OpenBat API base URL (defaults to ~/.openbatrc or https://openbat.dev)"
|
|
1549
1579
|
).option(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openbat/cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Command-line tool for querying OpenBat chatbot data — conversations, sentiment, analytics, exports",
|
|
5
5
|
"bin": {
|
|
6
6
|
"openbat": "bin/openbat"
|
|
@@ -37,7 +37,10 @@
|
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "tsup",
|
|
39
39
|
"dev": "tsup --watch",
|
|
40
|
-
"prepublishOnly": "npm run build"
|
|
40
|
+
"prepublishOnly": "npm run build",
|
|
41
|
+
"pretest": "npm run build",
|
|
42
|
+
"test": "node --test --experimental-strip-types --no-warnings 'tests/**/*.test.ts'",
|
|
43
|
+
"test:integration": "node --test --experimental-strip-types --no-warnings 'tests/integration/**/*.test.ts'"
|
|
41
44
|
},
|
|
42
45
|
"keywords": [
|
|
43
46
|
"openbat",
|