@openbat/cli 0.2.2 → 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.
@@ -32,7 +32,7 @@ __export(api_client_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(api_client_exports);
34
34
  var import_node_url = require("url");
35
- var CLI_VERSION = "0.2.2";
35
+ var CLI_VERSION = "0.2.3";
36
36
  var KEY_REGEX = /ob_(?:live|read|admin|pat)_[0-9a-f]{32}/g;
37
37
  function redact(s) {
38
38
  return s.replace(KEY_REGEX, (k) => `${k.slice(0, 16)}\u2026<hidden>`);
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ApiClient
3
- } from "./chunk-MCDJLQI2.mjs";
3
+ } from "./chunk-HBSCN3HV.mjs";
4
4
  export {
5
5
  ApiClient
6
6
  };
@@ -9,7 +9,7 @@ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "acce
9
9
 
10
10
  // src/api-client.ts
11
11
  import { URL } from "url";
12
- var CLI_VERSION = "0.2.2";
12
+ var CLI_VERSION = "0.2.3";
13
13
  var KEY_REGEX = /ob_(?:live|read|admin|pat)_[0-9a-f]{32}/g;
14
14
  function redact(s) {
15
15
  return s.replace(KEY_REGEX, (k) => `${k.slice(0, 16)}\u2026<hidden>`);
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.2.2";
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>`);
@@ -1277,6 +1277,15 @@ async function client3(globals) {
1277
1277
  }
1278
1278
  return new ApiClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl });
1279
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
+ }
1280
1289
  function surfacePlaintext(plaintext, label) {
1281
1290
  process.stderr.write(
1282
1291
  `
@@ -1339,23 +1348,25 @@ function chatbotsCommand() {
1339
1348
  }
1340
1349
  function webhooksCommand() {
1341
1350
  const cmd = new import_commander7.Command("webhooks").description("Manage webhooks for a chatbot");
1342
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1351
+ cmd.command("list").action(async function() {
1343
1352
  try {
1353
+ const chatbotId = requireChatbotId(this);
1344
1354
  const globals = this.optsWithGlobals();
1345
1355
  const c = await client3(globals);
1346
1356
  const result = await c.get(
1347
- `/api/v1/chatbots/${opts.chatbot}/webhooks`
1357
+ `/api/v1/chatbots/${chatbotId}/webhooks`
1348
1358
  );
1349
1359
  emit(result.webhooks, { 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").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--name <name>").requiredOption("--url <url>").option("--type <type>", "discord | slack | custom", "custom").action(async function(opts) {
1364
+ cmd.command("create").requiredOption("--name <name>").requiredOption("--url <url>").option("--type <type>", "discord | slack | custom", "custom").action(async function(opts) {
1355
1365
  try {
1366
+ const chatbotId = requireChatbotId(this);
1356
1367
  const globals = this.optsWithGlobals();
1357
1368
  const c = await client3(globals);
1358
- const result = await c.post(`/api/v1/chatbots/${opts.chatbot}/webhooks`, {
1369
+ const result = await c.post(`/api/v1/chatbots/${chatbotId}/webhooks`, {
1359
1370
  name: opts.name,
1360
1371
  url: opts.url,
1361
1372
  type: opts.type
@@ -1366,11 +1377,12 @@ function webhooksCommand() {
1366
1377
  fatal(err instanceof Error ? err.message : String(err));
1367
1378
  }
1368
1379
  });
1369
- cmd.command("delete").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--webhook <id>", "Webhook id").action(async function(opts) {
1380
+ cmd.command("delete").requiredOption("--webhook <id>", "Webhook id").action(async function(opts) {
1370
1381
  try {
1382
+ const chatbotId = requireChatbotId(this);
1371
1383
  const globals = this.optsWithGlobals();
1372
1384
  const c = await client3(globals);
1373
- await c.delete(`/api/v1/chatbots/${opts.chatbot}/webhooks/${opts.webhook}`);
1385
+ await c.delete(`/api/v1/chatbots/${chatbotId}/webhooks/${opts.webhook}`);
1374
1386
  emit({ ok: true, deleted: opts.webhook }, { json: !!globals.json });
1375
1387
  } catch (err) {
1376
1388
  fatal(err instanceof Error ? err.message : String(err));
@@ -1383,12 +1395,13 @@ function settingsCommand() {
1383
1395
  "Manage chatbot settings + per-chatbot keys"
1384
1396
  );
1385
1397
  const keys = cmd.command("keys").description("Manage API keys for a chatbot");
1386
- keys.command("rotate-ingest").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1398
+ keys.command("rotate-ingest").action(async function() {
1387
1399
  try {
1400
+ const chatbotId = requireChatbotId(this);
1388
1401
  const globals = this.optsWithGlobals();
1389
1402
  const c = await client3(globals);
1390
1403
  const result = await c.post(
1391
- `/api/v1/chatbots/${opts.chatbot}/keys/ingest/rotate`,
1404
+ `/api/v1/chatbots/${chatbotId}/keys/ingest/rotate`,
1392
1405
  {}
1393
1406
  );
1394
1407
  surfacePlaintext(result.plaintext, "New ingest key (ob_live_*)");
@@ -1397,12 +1410,13 @@ function settingsCommand() {
1397
1410
  fatal(err instanceof Error ? err.message : String(err));
1398
1411
  }
1399
1412
  });
1400
- keys.command("generate-read").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1413
+ keys.command("generate-read").action(async function() {
1401
1414
  try {
1415
+ const chatbotId = requireChatbotId(this);
1402
1416
  const globals = this.optsWithGlobals();
1403
1417
  const c = await client3(globals);
1404
1418
  const result = await c.post(
1405
- `/api/v1/chatbots/${opts.chatbot}/keys/read`,
1419
+ `/api/v1/chatbots/${chatbotId}/keys/read`,
1406
1420
  {}
1407
1421
  );
1408
1422
  surfacePlaintext(result.plaintext, "New read key (ob_read_*)");
@@ -1411,11 +1425,12 @@ function settingsCommand() {
1411
1425
  fatal(err instanceof Error ? err.message : String(err));
1412
1426
  }
1413
1427
  });
1414
- keys.command("generate-admin").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--name <name>", "Human-friendly name (e.g. 'CI key')").option("--expires-in-days <n>", "Auto-expire after N days").action(async function(opts) {
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) {
1415
1429
  try {
1430
+ const chatbotId = requireChatbotId(this);
1416
1431
  const globals = this.optsWithGlobals();
1417
1432
  const c = await client3(globals);
1418
- const result = await c.post(`/api/v1/chatbots/${opts.chatbot}/admin-keys`, {
1433
+ const result = await c.post(`/api/v1/chatbots/${chatbotId}/admin-keys`, {
1419
1434
  name: opts.name,
1420
1435
  expiresInDays: opts.expiresInDays ? Number(opts.expiresInDays) : void 0
1421
1436
  });
@@ -1425,30 +1440,33 @@ function settingsCommand() {
1425
1440
  fatal(err instanceof Error ? err.message : String(err));
1426
1441
  }
1427
1442
  });
1428
- keys.command("list-admin").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1443
+ keys.command("list-admin").action(async function() {
1429
1444
  try {
1445
+ const chatbotId = requireChatbotId(this);
1430
1446
  const globals = this.optsWithGlobals();
1431
1447
  const c = await client3(globals);
1432
1448
  const result = await c.get(
1433
- `/api/v1/chatbots/${opts.chatbot}/admin-keys`
1449
+ `/api/v1/chatbots/${chatbotId}/admin-keys`
1434
1450
  );
1435
1451
  emit(result.keys, { json: !!globals.json });
1436
1452
  } catch (err) {
1437
1453
  fatal(err instanceof Error ? err.message : String(err));
1438
1454
  }
1439
1455
  });
1440
- keys.command("revoke-admin").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--key <keyId>", "Admin key id").action(async function(opts) {
1456
+ keys.command("revoke-admin").requiredOption("--key <keyId>", "Admin key id").action(async function(opts) {
1441
1457
  try {
1458
+ const chatbotId = requireChatbotId(this);
1442
1459
  const globals = this.optsWithGlobals();
1443
1460
  const c = await client3(globals);
1444
- await c.delete(`/api/v1/chatbots/${opts.chatbot}/admin-keys/${opts.key}`);
1461
+ await c.delete(`/api/v1/chatbots/${chatbotId}/admin-keys/${opts.key}`);
1445
1462
  emit({ ok: true, revoked: opts.key }, { json: !!globals.json });
1446
1463
  } catch (err) {
1447
1464
  fatal(err instanceof Error ? err.message : String(err));
1448
1465
  }
1449
1466
  });
1450
- cmd.command("update").description("Patch a chatbot's settings JSONB").requiredOption("--chatbot <id>", "Chatbot id").option("--description <text>").option("--website-url <url>").option("--language <code>").action(async function(opts) {
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) {
1451
1468
  try {
1469
+ const chatbotId = requireChatbotId(this);
1452
1470
  const settings = {};
1453
1471
  if (opts.description) settings.description = opts.description;
1454
1472
  if (opts.websiteUrl) settings.website_url = opts.websiteUrl;
@@ -1458,7 +1476,7 @@ function settingsCommand() {
1458
1476
  }
1459
1477
  const globals = this.optsWithGlobals();
1460
1478
  const c = await client3(globals);
1461
- await c.patch(`/api/v1/chatbots/${opts.chatbot}/settings`, { settings });
1479
+ await c.patch(`/api/v1/chatbots/${chatbotId}/settings`, { settings });
1462
1480
  emit({ ok: true }, { json: !!globals.json });
1463
1481
  } catch (err) {
1464
1482
  fatal(err instanceof Error ? err.message : String(err));
@@ -1468,19 +1486,20 @@ function settingsCommand() {
1468
1486
  }
1469
1487
  function workflowsCommand() {
1470
1488
  const cmd = new import_commander7.Command("workflows").description("Manage workflows");
1471
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1489
+ cmd.command("list").action(async function() {
1472
1490
  try {
1491
+ const chatbotId = requireChatbotId(this);
1473
1492
  const globals = this.optsWithGlobals();
1474
1493
  const c = await client3(globals);
1475
1494
  const result = await c.get(
1476
- `/api/v1/chatbots/${opts.chatbot}/workflows`
1495
+ `/api/v1/chatbots/${chatbotId}/workflows`
1477
1496
  );
1478
1497
  emit(result.workflows, { json: !!globals.json });
1479
1498
  } catch (err) {
1480
1499
  fatal(err instanceof Error ? err.message : String(err));
1481
1500
  }
1482
1501
  });
1483
- cmd.command("create").description("Create a workflow from a built-in template").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--name <name>").requiredOption(
1502
+ cmd.command("create").description("Create a workflow from a built-in template").requiredOption("--name <name>").requiredOption(
1484
1503
  "--template <name>",
1485
1504
  "flag-to-webhook | outcome-to-webhook | sentiment-drop-to-webhook"
1486
1505
  ).requiredOption(
@@ -1488,9 +1507,10 @@ function workflowsCommand() {
1488
1507
  "Flag value / outcome value / sentiment threshold"
1489
1508
  ).requiredOption("--webhook <id>", "Webhook id to fire").option("--message <tpl>", "Message template (supports {{user.id}}, etc.)").action(async function(opts) {
1490
1509
  try {
1510
+ const chatbotId = requireChatbotId(this);
1491
1511
  const globals = this.optsWithGlobals();
1492
1512
  const c = await client3(globals);
1493
- const result = await c.post(`/api/v1/chatbots/${opts.chatbot}/workflows`, {
1513
+ const result = await c.post(`/api/v1/chatbots/${chatbotId}/workflows`, {
1494
1514
  name: opts.name,
1495
1515
  template: opts.template,
1496
1516
  triggerValue: opts.triggerValue,
@@ -1506,23 +1526,25 @@ function workflowsCommand() {
1506
1526
  }
1507
1527
  function reportsCommand() {
1508
1528
  const cmd = new import_commander7.Command("reports").description("Manage AI reports");
1509
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1529
+ cmd.command("list").action(async function() {
1510
1530
  try {
1531
+ const chatbotId = requireChatbotId(this);
1511
1532
  const globals = this.optsWithGlobals();
1512
1533
  const c = await client3(globals);
1513
1534
  const result = await c.get(
1514
- `/api/v1/chatbots/${opts.chatbot}/reports`
1535
+ `/api/v1/chatbots/${chatbotId}/reports`
1515
1536
  );
1516
1537
  emit(result.reports, { json: !!globals.json });
1517
1538
  } catch (err) {
1518
1539
  fatal(err instanceof Error ? err.message : String(err));
1519
1540
  }
1520
1541
  });
1521
- cmd.command("create").description("Create a new AI report; returns the org-private dashboard URL").requiredOption("--chatbot <id>", "Chatbot id").option("--name <name>", "Report name", "Untitled Report").action(async function(opts) {
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) {
1522
1543
  try {
1544
+ const chatbotId = requireChatbotId(this);
1523
1545
  const globals = this.optsWithGlobals();
1524
1546
  const c = await client3(globals);
1525
- const result = await c.post(`/api/v1/chatbots/${opts.chatbot}/reports`, { name: opts.name });
1547
+ const result = await c.post(`/api/v1/chatbots/${chatbotId}/reports`, { name: opts.name });
1526
1548
  process.stderr.write(
1527
1549
  `
1528
1550
  Created report. View it (org members only):
@@ -1542,30 +1564,32 @@ Created report. View it (org members only):
1542
1564
  }
1543
1565
  function analysisCommand() {
1544
1566
  const cmd = new import_commander7.Command("analysis").description("Manage analysis definitions");
1545
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").option("--type <t>", "intent | flag | assistant_outcome | assistant_issue").option("--pending", "Include pending suggestions").action(async function(opts) {
1567
+ cmd.command("list").option("--type <t>", "intent | flag | assistant_outcome | assistant_issue").option("--pending", "Include pending suggestions").action(async function(opts) {
1546
1568
  try {
1569
+ const chatbotId = requireChatbotId(this);
1547
1570
  const globals = this.optsWithGlobals();
1548
1571
  const c = await client3(globals);
1549
1572
  const qs = new URLSearchParams();
1550
1573
  if (opts.type) qs.set("type", opts.type);
1551
1574
  if (opts.pending) qs.set("pending", "true");
1552
1575
  const result = await c.get(
1553
- `/api/v1/chatbots/${opts.chatbot}/analysis-definitions${qs.size ? `?${qs}` : ""}`
1576
+ `/api/v1/chatbots/${chatbotId}/analysis-definitions${qs.size ? `?${qs}` : ""}`
1554
1577
  );
1555
1578
  emit(result.definitions, { json: !!globals.json });
1556
1579
  } catch (err) {
1557
1580
  fatal(err instanceof Error ? err.message : String(err));
1558
1581
  }
1559
1582
  });
1560
- cmd.command("add").requiredOption("--chatbot <id>", "Chatbot id").requiredOption(
1583
+ cmd.command("add").requiredOption(
1561
1584
  "--type <t>",
1562
1585
  "intent | flag | assistant_outcome | assistant_issue"
1563
1586
  ).requiredOption("--name <slug>", "snake_case slug").requiredOption("--display-name <text>").requiredOption("--description <text>").action(async function(opts) {
1564
1587
  try {
1588
+ const chatbotId = requireChatbotId(this);
1565
1589
  const globals = this.optsWithGlobals();
1566
1590
  const c = await client3(globals);
1567
1591
  const result = await c.post(
1568
- `/api/v1/chatbots/${opts.chatbot}/analysis-definitions`,
1592
+ `/api/v1/chatbots/${chatbotId}/analysis-definitions`,
1569
1593
  {
1570
1594
  analysisType: opts.type,
1571
1595
  name: opts.name,
@@ -1584,8 +1608,9 @@ function usersCommand() {
1584
1608
  const cmd = new import_commander7.Command("users").description(
1585
1609
  "List external users (chatbot customers) with health metrics"
1586
1610
  );
1587
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").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) {
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) {
1588
1612
  try {
1613
+ const chatbotId = requireChatbotId(this);
1589
1614
  const globals = this.optsWithGlobals();
1590
1615
  const c = await client3(globals);
1591
1616
  const qs = new URLSearchParams();
@@ -1600,7 +1625,7 @@ function usersCommand() {
1600
1625
  if (opts.search) qs.set("search", opts.search);
1601
1626
  qs.set("limit", opts.limit);
1602
1627
  const result = await c.get(
1603
- `/api/v1/chatbots/${opts.chatbot}/external-users?${qs}`
1628
+ `/api/v1/chatbots/${chatbotId}/external-users?${qs}`
1604
1629
  );
1605
1630
  emit(result.users, { json: !!globals.json });
1606
1631
  process.stderr.write(`
@@ -1675,18 +1700,22 @@ function sdkCommand() {
1675
1700
  const out = opts.framework === "vercel-ai-sdk" ? snippetWrapper : snippetNext;
1676
1701
  process.stdout.write(out);
1677
1702
  });
1678
- cmd.command("verify").description("Check whether any event has arrived for the chatbot yet").requiredOption("--chatbot <id>", "Chatbot id").option("--timeout <n>", "Seconds to wait (default: 60)", "60").action(async function(opts) {
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) {
1679
1704
  try {
1680
1705
  const globals = this.optsWithGlobals();
1706
+ const chatbotId = globals.chatbot;
1707
+ if (!chatbotId) {
1708
+ fatal("--chatbot <id> is required (also accepts the persisted active chatbot).");
1709
+ }
1681
1710
  const c = await client3(globals);
1682
1711
  const timeoutSec = Number(opts.timeout);
1683
1712
  const deadline = Date.now() + timeoutSec * 1e3;
1684
1713
  const params = new URLSearchParams({
1685
- chatbotId: opts.chatbot,
1714
+ chatbotId,
1686
1715
  limit: "1"
1687
1716
  });
1688
1717
  process.stderr.write(
1689
- `Waiting for first event on chatbot ${opts.chatbot} (timeout ${timeoutSec}s)\u2026
1718
+ `Waiting for first event on chatbot ${chatbotId} (timeout ${timeoutSec}s)\u2026
1690
1719
  `
1691
1720
  );
1692
1721
  let lastTick = Date.now();
@@ -1722,7 +1751,7 @@ Timed out after ${timeoutSec}s \u2014 no events yet. Confirm OPENBAT_API_KEY and
1722
1751
  var program = new import_commander8.Command();
1723
1752
  program.name("openbat").description(
1724
1753
  "Query OpenBat chatbot data \u2014 conversations, sentiment, analytics, exports."
1725
- ).version("0.2.2").option("--api-key <key>", "Override the stored Read API key (footgun \u2014 leaks into shell history)").option(
1754
+ ).version("0.2.3").option("--api-key <key>", "Override the stored Read API key (footgun \u2014 leaks into shell history)").option(
1726
1755
  "--base-url <url>",
1727
1756
  "Override the OpenBat API base URL (defaults to ~/.openbatrc or https://openbat.dev)"
1728
1757
  ).option(
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ApiClient
4
- } from "./chunk-MCDJLQI2.mjs";
4
+ } from "./chunk-HBSCN3HV.mjs";
5
5
 
6
6
  // src/index.ts
7
7
  import { Command as Command8 } from "commander";
@@ -1099,6 +1099,15 @@ async function client3(globals) {
1099
1099
  }
1100
1100
  return new ApiClient({ apiKey: cfg.apiKey, baseUrl: cfg.baseUrl });
1101
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
+ }
1102
1111
  function surfacePlaintext(plaintext, label) {
1103
1112
  process.stderr.write(
1104
1113
  `
@@ -1161,23 +1170,25 @@ function chatbotsCommand() {
1161
1170
  }
1162
1171
  function webhooksCommand() {
1163
1172
  const cmd = new Command7("webhooks").description("Manage webhooks for a chatbot");
1164
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1173
+ cmd.command("list").action(async function() {
1165
1174
  try {
1175
+ const chatbotId = requireChatbotId(this);
1166
1176
  const globals = this.optsWithGlobals();
1167
1177
  const c = await client3(globals);
1168
1178
  const result = await c.get(
1169
- `/api/v1/chatbots/${opts.chatbot}/webhooks`
1179
+ `/api/v1/chatbots/${chatbotId}/webhooks`
1170
1180
  );
1171
1181
  emit(result.webhooks, { json: !!globals.json });
1172
1182
  } catch (err) {
1173
1183
  fatal(err instanceof Error ? err.message : String(err));
1174
1184
  }
1175
1185
  });
1176
- cmd.command("create").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--name <name>").requiredOption("--url <url>").option("--type <type>", "discord | slack | custom", "custom").action(async function(opts) {
1186
+ cmd.command("create").requiredOption("--name <name>").requiredOption("--url <url>").option("--type <type>", "discord | slack | custom", "custom").action(async function(opts) {
1177
1187
  try {
1188
+ const chatbotId = requireChatbotId(this);
1178
1189
  const globals = this.optsWithGlobals();
1179
1190
  const c = await client3(globals);
1180
- const result = await c.post(`/api/v1/chatbots/${opts.chatbot}/webhooks`, {
1191
+ const result = await c.post(`/api/v1/chatbots/${chatbotId}/webhooks`, {
1181
1192
  name: opts.name,
1182
1193
  url: opts.url,
1183
1194
  type: opts.type
@@ -1188,11 +1199,12 @@ function webhooksCommand() {
1188
1199
  fatal(err instanceof Error ? err.message : String(err));
1189
1200
  }
1190
1201
  });
1191
- cmd.command("delete").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--webhook <id>", "Webhook id").action(async function(opts) {
1202
+ cmd.command("delete").requiredOption("--webhook <id>", "Webhook id").action(async function(opts) {
1192
1203
  try {
1204
+ const chatbotId = requireChatbotId(this);
1193
1205
  const globals = this.optsWithGlobals();
1194
1206
  const c = await client3(globals);
1195
- await c.delete(`/api/v1/chatbots/${opts.chatbot}/webhooks/${opts.webhook}`);
1207
+ await c.delete(`/api/v1/chatbots/${chatbotId}/webhooks/${opts.webhook}`);
1196
1208
  emit({ ok: true, deleted: opts.webhook }, { json: !!globals.json });
1197
1209
  } catch (err) {
1198
1210
  fatal(err instanceof Error ? err.message : String(err));
@@ -1205,12 +1217,13 @@ function settingsCommand() {
1205
1217
  "Manage chatbot settings + per-chatbot keys"
1206
1218
  );
1207
1219
  const keys = cmd.command("keys").description("Manage API keys for a chatbot");
1208
- keys.command("rotate-ingest").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1220
+ keys.command("rotate-ingest").action(async function() {
1209
1221
  try {
1222
+ const chatbotId = requireChatbotId(this);
1210
1223
  const globals = this.optsWithGlobals();
1211
1224
  const c = await client3(globals);
1212
1225
  const result = await c.post(
1213
- `/api/v1/chatbots/${opts.chatbot}/keys/ingest/rotate`,
1226
+ `/api/v1/chatbots/${chatbotId}/keys/ingest/rotate`,
1214
1227
  {}
1215
1228
  );
1216
1229
  surfacePlaintext(result.plaintext, "New ingest key (ob_live_*)");
@@ -1219,12 +1232,13 @@ function settingsCommand() {
1219
1232
  fatal(err instanceof Error ? err.message : String(err));
1220
1233
  }
1221
1234
  });
1222
- keys.command("generate-read").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1235
+ keys.command("generate-read").action(async function() {
1223
1236
  try {
1237
+ const chatbotId = requireChatbotId(this);
1224
1238
  const globals = this.optsWithGlobals();
1225
1239
  const c = await client3(globals);
1226
1240
  const result = await c.post(
1227
- `/api/v1/chatbots/${opts.chatbot}/keys/read`,
1241
+ `/api/v1/chatbots/${chatbotId}/keys/read`,
1228
1242
  {}
1229
1243
  );
1230
1244
  surfacePlaintext(result.plaintext, "New read key (ob_read_*)");
@@ -1233,11 +1247,12 @@ function settingsCommand() {
1233
1247
  fatal(err instanceof Error ? err.message : String(err));
1234
1248
  }
1235
1249
  });
1236
- keys.command("generate-admin").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--name <name>", "Human-friendly name (e.g. 'CI key')").option("--expires-in-days <n>", "Auto-expire after N days").action(async function(opts) {
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) {
1237
1251
  try {
1252
+ const chatbotId = requireChatbotId(this);
1238
1253
  const globals = this.optsWithGlobals();
1239
1254
  const c = await client3(globals);
1240
- const result = await c.post(`/api/v1/chatbots/${opts.chatbot}/admin-keys`, {
1255
+ const result = await c.post(`/api/v1/chatbots/${chatbotId}/admin-keys`, {
1241
1256
  name: opts.name,
1242
1257
  expiresInDays: opts.expiresInDays ? Number(opts.expiresInDays) : void 0
1243
1258
  });
@@ -1247,30 +1262,33 @@ function settingsCommand() {
1247
1262
  fatal(err instanceof Error ? err.message : String(err));
1248
1263
  }
1249
1264
  });
1250
- keys.command("list-admin").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1265
+ keys.command("list-admin").action(async function() {
1251
1266
  try {
1267
+ const chatbotId = requireChatbotId(this);
1252
1268
  const globals = this.optsWithGlobals();
1253
1269
  const c = await client3(globals);
1254
1270
  const result = await c.get(
1255
- `/api/v1/chatbots/${opts.chatbot}/admin-keys`
1271
+ `/api/v1/chatbots/${chatbotId}/admin-keys`
1256
1272
  );
1257
1273
  emit(result.keys, { json: !!globals.json });
1258
1274
  } catch (err) {
1259
1275
  fatal(err instanceof Error ? err.message : String(err));
1260
1276
  }
1261
1277
  });
1262
- keys.command("revoke-admin").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--key <keyId>", "Admin key id").action(async function(opts) {
1278
+ keys.command("revoke-admin").requiredOption("--key <keyId>", "Admin key id").action(async function(opts) {
1263
1279
  try {
1280
+ const chatbotId = requireChatbotId(this);
1264
1281
  const globals = this.optsWithGlobals();
1265
1282
  const c = await client3(globals);
1266
- await c.delete(`/api/v1/chatbots/${opts.chatbot}/admin-keys/${opts.key}`);
1283
+ await c.delete(`/api/v1/chatbots/${chatbotId}/admin-keys/${opts.key}`);
1267
1284
  emit({ ok: true, revoked: opts.key }, { json: !!globals.json });
1268
1285
  } catch (err) {
1269
1286
  fatal(err instanceof Error ? err.message : String(err));
1270
1287
  }
1271
1288
  });
1272
- cmd.command("update").description("Patch a chatbot's settings JSONB").requiredOption("--chatbot <id>", "Chatbot id").option("--description <text>").option("--website-url <url>").option("--language <code>").action(async function(opts) {
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) {
1273
1290
  try {
1291
+ const chatbotId = requireChatbotId(this);
1274
1292
  const settings = {};
1275
1293
  if (opts.description) settings.description = opts.description;
1276
1294
  if (opts.websiteUrl) settings.website_url = opts.websiteUrl;
@@ -1280,7 +1298,7 @@ function settingsCommand() {
1280
1298
  }
1281
1299
  const globals = this.optsWithGlobals();
1282
1300
  const c = await client3(globals);
1283
- await c.patch(`/api/v1/chatbots/${opts.chatbot}/settings`, { settings });
1301
+ await c.patch(`/api/v1/chatbots/${chatbotId}/settings`, { settings });
1284
1302
  emit({ ok: true }, { json: !!globals.json });
1285
1303
  } catch (err) {
1286
1304
  fatal(err instanceof Error ? err.message : String(err));
@@ -1290,19 +1308,20 @@ function settingsCommand() {
1290
1308
  }
1291
1309
  function workflowsCommand() {
1292
1310
  const cmd = new Command7("workflows").description("Manage workflows");
1293
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1311
+ cmd.command("list").action(async function() {
1294
1312
  try {
1313
+ const chatbotId = requireChatbotId(this);
1295
1314
  const globals = this.optsWithGlobals();
1296
1315
  const c = await client3(globals);
1297
1316
  const result = await c.get(
1298
- `/api/v1/chatbots/${opts.chatbot}/workflows`
1317
+ `/api/v1/chatbots/${chatbotId}/workflows`
1299
1318
  );
1300
1319
  emit(result.workflows, { json: !!globals.json });
1301
1320
  } catch (err) {
1302
1321
  fatal(err instanceof Error ? err.message : String(err));
1303
1322
  }
1304
1323
  });
1305
- cmd.command("create").description("Create a workflow from a built-in template").requiredOption("--chatbot <id>", "Chatbot id").requiredOption("--name <name>").requiredOption(
1324
+ cmd.command("create").description("Create a workflow from a built-in template").requiredOption("--name <name>").requiredOption(
1306
1325
  "--template <name>",
1307
1326
  "flag-to-webhook | outcome-to-webhook | sentiment-drop-to-webhook"
1308
1327
  ).requiredOption(
@@ -1310,9 +1329,10 @@ function workflowsCommand() {
1310
1329
  "Flag value / outcome value / sentiment threshold"
1311
1330
  ).requiredOption("--webhook <id>", "Webhook id to fire").option("--message <tpl>", "Message template (supports {{user.id}}, etc.)").action(async function(opts) {
1312
1331
  try {
1332
+ const chatbotId = requireChatbotId(this);
1313
1333
  const globals = this.optsWithGlobals();
1314
1334
  const c = await client3(globals);
1315
- const result = await c.post(`/api/v1/chatbots/${opts.chatbot}/workflows`, {
1335
+ const result = await c.post(`/api/v1/chatbots/${chatbotId}/workflows`, {
1316
1336
  name: opts.name,
1317
1337
  template: opts.template,
1318
1338
  triggerValue: opts.triggerValue,
@@ -1328,23 +1348,25 @@ function workflowsCommand() {
1328
1348
  }
1329
1349
  function reportsCommand() {
1330
1350
  const cmd = new Command7("reports").description("Manage AI reports");
1331
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").action(async function(opts) {
1351
+ cmd.command("list").action(async function() {
1332
1352
  try {
1353
+ const chatbotId = requireChatbotId(this);
1333
1354
  const globals = this.optsWithGlobals();
1334
1355
  const c = await client3(globals);
1335
1356
  const result = await c.get(
1336
- `/api/v1/chatbots/${opts.chatbot}/reports`
1357
+ `/api/v1/chatbots/${chatbotId}/reports`
1337
1358
  );
1338
1359
  emit(result.reports, { json: !!globals.json });
1339
1360
  } catch (err) {
1340
1361
  fatal(err instanceof Error ? err.message : String(err));
1341
1362
  }
1342
1363
  });
1343
- cmd.command("create").description("Create a new AI report; returns the org-private dashboard URL").requiredOption("--chatbot <id>", "Chatbot id").option("--name <name>", "Report name", "Untitled Report").action(async function(opts) {
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) {
1344
1365
  try {
1366
+ const chatbotId = requireChatbotId(this);
1345
1367
  const globals = this.optsWithGlobals();
1346
1368
  const c = await client3(globals);
1347
- const result = await c.post(`/api/v1/chatbots/${opts.chatbot}/reports`, { name: opts.name });
1369
+ const result = await c.post(`/api/v1/chatbots/${chatbotId}/reports`, { name: opts.name });
1348
1370
  process.stderr.write(
1349
1371
  `
1350
1372
  Created report. View it (org members only):
@@ -1364,30 +1386,32 @@ Created report. View it (org members only):
1364
1386
  }
1365
1387
  function analysisCommand() {
1366
1388
  const cmd = new Command7("analysis").description("Manage analysis definitions");
1367
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").option("--type <t>", "intent | flag | assistant_outcome | assistant_issue").option("--pending", "Include pending suggestions").action(async function(opts) {
1389
+ cmd.command("list").option("--type <t>", "intent | flag | assistant_outcome | assistant_issue").option("--pending", "Include pending suggestions").action(async function(opts) {
1368
1390
  try {
1391
+ const chatbotId = requireChatbotId(this);
1369
1392
  const globals = this.optsWithGlobals();
1370
1393
  const c = await client3(globals);
1371
1394
  const qs = new URLSearchParams();
1372
1395
  if (opts.type) qs.set("type", opts.type);
1373
1396
  if (opts.pending) qs.set("pending", "true");
1374
1397
  const result = await c.get(
1375
- `/api/v1/chatbots/${opts.chatbot}/analysis-definitions${qs.size ? `?${qs}` : ""}`
1398
+ `/api/v1/chatbots/${chatbotId}/analysis-definitions${qs.size ? `?${qs}` : ""}`
1376
1399
  );
1377
1400
  emit(result.definitions, { json: !!globals.json });
1378
1401
  } catch (err) {
1379
1402
  fatal(err instanceof Error ? err.message : String(err));
1380
1403
  }
1381
1404
  });
1382
- cmd.command("add").requiredOption("--chatbot <id>", "Chatbot id").requiredOption(
1405
+ cmd.command("add").requiredOption(
1383
1406
  "--type <t>",
1384
1407
  "intent | flag | assistant_outcome | assistant_issue"
1385
1408
  ).requiredOption("--name <slug>", "snake_case slug").requiredOption("--display-name <text>").requiredOption("--description <text>").action(async function(opts) {
1386
1409
  try {
1410
+ const chatbotId = requireChatbotId(this);
1387
1411
  const globals = this.optsWithGlobals();
1388
1412
  const c = await client3(globals);
1389
1413
  const result = await c.post(
1390
- `/api/v1/chatbots/${opts.chatbot}/analysis-definitions`,
1414
+ `/api/v1/chatbots/${chatbotId}/analysis-definitions`,
1391
1415
  {
1392
1416
  analysisType: opts.type,
1393
1417
  name: opts.name,
@@ -1406,8 +1430,9 @@ function usersCommand() {
1406
1430
  const cmd = new Command7("users").description(
1407
1431
  "List external users (chatbot customers) with health metrics"
1408
1432
  );
1409
- cmd.command("list").requiredOption("--chatbot <id>", "Chatbot id").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) {
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) {
1410
1434
  try {
1435
+ const chatbotId = requireChatbotId(this);
1411
1436
  const globals = this.optsWithGlobals();
1412
1437
  const c = await client3(globals);
1413
1438
  const qs = new URLSearchParams();
@@ -1422,7 +1447,7 @@ function usersCommand() {
1422
1447
  if (opts.search) qs.set("search", opts.search);
1423
1448
  qs.set("limit", opts.limit);
1424
1449
  const result = await c.get(
1425
- `/api/v1/chatbots/${opts.chatbot}/external-users?${qs}`
1450
+ `/api/v1/chatbots/${chatbotId}/external-users?${qs}`
1426
1451
  );
1427
1452
  emit(result.users, { json: !!globals.json });
1428
1453
  process.stderr.write(`
@@ -1497,18 +1522,22 @@ function sdkCommand() {
1497
1522
  const out = opts.framework === "vercel-ai-sdk" ? snippetWrapper : snippetNext;
1498
1523
  process.stdout.write(out);
1499
1524
  });
1500
- cmd.command("verify").description("Check whether any event has arrived for the chatbot yet").requiredOption("--chatbot <id>", "Chatbot id").option("--timeout <n>", "Seconds to wait (default: 60)", "60").action(async function(opts) {
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) {
1501
1526
  try {
1502
1527
  const globals = this.optsWithGlobals();
1528
+ const chatbotId = globals.chatbot;
1529
+ if (!chatbotId) {
1530
+ fatal("--chatbot <id> is required (also accepts the persisted active chatbot).");
1531
+ }
1503
1532
  const c = await client3(globals);
1504
1533
  const timeoutSec = Number(opts.timeout);
1505
1534
  const deadline = Date.now() + timeoutSec * 1e3;
1506
1535
  const params = new URLSearchParams({
1507
- chatbotId: opts.chatbot,
1536
+ chatbotId,
1508
1537
  limit: "1"
1509
1538
  });
1510
1539
  process.stderr.write(
1511
- `Waiting for first event on chatbot ${opts.chatbot} (timeout ${timeoutSec}s)\u2026
1540
+ `Waiting for first event on chatbot ${chatbotId} (timeout ${timeoutSec}s)\u2026
1512
1541
  `
1513
1542
  );
1514
1543
  let lastTick = Date.now();
@@ -1544,7 +1573,7 @@ Timed out after ${timeoutSec}s \u2014 no events yet. Confirm OPENBAT_API_KEY and
1544
1573
  var program = new Command8();
1545
1574
  program.name("openbat").description(
1546
1575
  "Query OpenBat chatbot data \u2014 conversations, sentiment, analytics, exports."
1547
- ).version("0.2.2").option("--api-key <key>", "Override the stored Read API key (footgun \u2014 leaks into shell history)").option(
1576
+ ).version("0.2.3").option("--api-key <key>", "Override the stored Read API key (footgun \u2014 leaks into shell history)").option(
1548
1577
  "--base-url <url>",
1549
1578
  "Override the OpenBat API base URL (defaults to ~/.openbatrc or https://openbat.dev)"
1550
1579
  ).option(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openbat/cli",
3
- "version": "0.2.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",