@openbkn/bkn-sdk 0.1.1-alpha.9 → 0.1.2

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/cli.js CHANGED
@@ -6,8 +6,8 @@ import {
6
6
  HttpError,
7
7
  InputError,
8
8
  activePlatform,
9
- attachNoAuth,
10
9
  attachToken,
10
+ changePasswordSafe,
11
11
  createClient,
12
12
  credentialDeviceLogin,
13
13
  currentToken,
@@ -16,7 +16,6 @@ import {
16
16
  deletePlatform,
17
17
  deviceLogin,
18
18
  exportCreds,
19
- fetchAuthStatus,
20
19
  formatError,
21
20
  getUserSafe,
22
21
  isHeadless,
@@ -28,24 +27,24 @@ import {
28
27
  rawCall,
29
28
  readPlatformConfig,
30
29
  renderReportMarkdown,
31
- request,
32
30
  resolveContext,
33
31
  setActivePlatform,
34
32
  status,
35
33
  switchUser,
36
34
  toExitCode,
37
35
  use,
36
+ validateFixturePath,
38
37
  whoami,
39
38
  writePlatformConfig
40
- } from "./chunk-BFE4SU3V.js";
39
+ } from "./chunk-LH3ONZGQ.js";
41
40
 
42
41
  // src/cli.ts
43
- import { Command as Command16 } from "commander";
42
+ import { Command as Command17 } from "commander";
44
43
 
45
44
  // package.json
46
45
  var package_default = {
47
46
  name: "@openbkn/bkn-sdk",
48
- version: "0.1.1-alpha.9",
47
+ version: "0.1.2",
49
48
  description: "Unified TypeScript SDK + CLI for the BKN (Business Knowledge Network) platform.",
50
49
  type: "module",
51
50
  license: "Apache-2.0",
@@ -63,7 +62,7 @@ var package_default = {
63
62
  import: "./dist/index.js"
64
63
  }
65
64
  },
66
- files: ["dist", "README.md", "README.zh.md", "LICENSE"],
65
+ files: ["dist", "!dist/**/*.map", "README.md", "README.zh.md", "LICENSE", "NOTICE"],
67
66
  publishConfig: {
68
67
  access: "public"
69
68
  },
@@ -76,21 +75,23 @@ var package_default = {
76
75
  build: "tsup",
77
76
  dev: "tsup --watch",
78
77
  typecheck: "tsc --noEmit",
79
- lint: "biome check . && tsc --noEmit",
78
+ "check:deps": "node scripts/check-no-self-dep.mjs",
79
+ lint: "npm run check:deps && biome check . && tsc --noEmit",
80
80
  format: "biome format --write .",
81
81
  test: "vitest run",
82
+ "test:e2e:trace-business": "npm run build && node test/e2e/bkn-trace-business-interaction.mjs",
82
83
  "test:cover": "vitest run --coverage",
83
84
  ci: "npm run lint && npm test",
84
85
  prepublishOnly: "npm run ci && npm run build"
85
86
  },
86
87
  dependencies: {
87
88
  "@clack/prompts": "^0.9.1",
88
- "@openbkn/bkn-sdk": "^0.1.1-alpha.3",
89
89
  chalk: "^5.4.1",
90
90
  commander: "^13.1.0",
91
91
  "csv-parse": "^6.2.1",
92
92
  "js-yaml": "^4.2.0",
93
93
  jszip: "^3.10.1",
94
+ undici: "^8.7.0",
94
95
  zod: "^3.24.1"
95
96
  },
96
97
  devDependencies: {
@@ -104,6 +105,7 @@ var package_default = {
104
105
  };
105
106
 
106
107
  // src/commands/admin.ts
108
+ import { readFileSync as readFileSync2 } from "fs";
107
109
  import { Command as Command2 } from "commander";
108
110
 
109
111
  // src/help/grouped-help.ts
@@ -174,10 +176,15 @@ function renderOrgTree(nodes, prefix = "") {
174
176
  // src/utils/output.ts
175
177
  function printJson(value, opts = {}) {
176
178
  if (opts.json || opts.compact) {
177
- process.stdout.write(`${JSON.stringify(value, null, opts.compact ? 0 : 2)}
179
+ const json = JSON.stringify(value === void 0 ? null : value, null, opts.compact ? 0 : 2);
180
+ process.stdout.write(`${json}
178
181
  `);
179
182
  return;
180
183
  }
184
+ if (value === void 0) {
185
+ process.stdout.write("(ok)\n");
186
+ return;
187
+ }
181
188
  const rows = toRows(value);
182
189
  if (rows) {
183
190
  const fullColumns = columnsOf(rows).filter((c) => rows.some((r) => stringifyCell(r[c]) !== ""));
@@ -215,7 +222,8 @@ var ROW_ENVELOPES = [
215
222
  "users",
216
223
  "roles",
217
224
  "departments",
218
- "members"
225
+ "members",
226
+ "keys"
219
227
  ];
220
228
  function toRows(value) {
221
229
  const isRowArray = (v) => Array.isArray(v) && v.length > 0 && v.every((x) => x !== null && typeof x === "object" && !Array.isArray(x));
@@ -300,16 +308,46 @@ function stringifyCell(v) {
300
308
  return s.length > CELL_MAX ? `${s.slice(0, CELL_MAX - 1)}\u2026` : s;
301
309
  }
302
310
 
311
+ // src/utils/prompt.ts
312
+ import { createInterface } from "readline";
313
+ function promptLine(query, hidden = false) {
314
+ return new Promise((resolve2) => {
315
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
316
+ if (hidden) {
317
+ const mutable = rl;
318
+ mutable._writeToOutput = (s) => {
319
+ if (s.startsWith(query)) process.stdout.write(query);
320
+ };
321
+ }
322
+ rl.question(query, (answer) => {
323
+ rl.close();
324
+ if (hidden) process.stdout.write("\n");
325
+ resolve2(answer.trim());
326
+ });
327
+ });
328
+ }
329
+
303
330
  // src/commands/_shared.ts
304
331
  import { readFileSync } from "fs";
332
+ function traceOptionsFrom(o) {
333
+ const conversationId = (typeof o.conversationId === "string" ? o.conversationId : void 0) ?? process.env.BKN_CONVERSATION_ID;
334
+ const interactionId = (typeof o.interactionId === "string" ? o.interactionId : void 0) ?? process.env.BKN_INTERACTION_ID;
335
+ if (!conversationId && !interactionId) return void 0;
336
+ return {
337
+ ...conversationId ? { conversationId } : {},
338
+ ...interactionId ? { interactionId } : {}
339
+ };
340
+ }
305
341
  function clientFrom(cmd) {
306
342
  const o = cmd.optsWithGlobals();
343
+ const trace = traceOptionsFrom(o);
307
344
  return createClient({
308
345
  baseUrl: o.baseUrl,
309
346
  token: o.token,
310
347
  user: o.user,
311
348
  businessDomain: o.bizDomain,
312
- insecure: o.insecure
349
+ insecure: o.insecure,
350
+ ...trace ? { trace } : {}
313
351
  });
314
352
  }
315
353
  function outputOptions(cmd) {
@@ -331,27 +369,7 @@ function readBody(opts) {
331
369
  }
332
370
 
333
371
  // src/commands/auth.ts
334
- import { createInterface } from "readline";
335
372
  import { Command } from "commander";
336
-
337
- // src/api/eacp-crypto.ts
338
- import {
339
- constants,
340
- createPrivateKey,
341
- createPublicKey,
342
- publicEncrypt
343
- } from "crypto";
344
-
345
- // src/api/admin.ts
346
- async function changePasswordSafe(ctx, account, oldPassword, newPassword) {
347
- await request(ctx, "/api/safe/v1/auth/change-password", {
348
- method: "POST",
349
- body: { account, old_password: oldPassword, new_password: newPassword }
350
- });
351
- return { ok: true };
352
- }
353
-
354
- // src/commands/auth.ts
355
373
  async function resolveAccount(baseUrl, accessToken, insecure, idToken) {
356
374
  const sub = decodeJwt(idToken ?? accessToken)?.sub;
357
375
  if (!sub) return void 0;
@@ -365,22 +383,6 @@ async function resolveAccount(baseUrl, accessToken, insecure, idToken) {
365
383
  return void 0;
366
384
  }
367
385
  }
368
- function promptLine(query, hidden = false) {
369
- return new Promise((resolve2) => {
370
- const rl = createInterface({ input: process.stdin, output: process.stdout });
371
- if (hidden) {
372
- const mutable = rl;
373
- mutable._writeToOutput = (s) => {
374
- if (s.startsWith(query)) process.stdout.write(query);
375
- };
376
- }
377
- rl.question(query, (answer) => {
378
- rl.close();
379
- if (hidden) process.stdout.write("\n");
380
- resolve2(answer.trim());
381
- });
382
- });
383
- }
384
386
  function renderSessions(items) {
385
387
  const byPlatform = /* @__PURE__ */ new Map();
386
388
  for (const it of items) {
@@ -396,25 +398,17 @@ function renderSessions(items) {
396
398
  return lines.join("\n") || "(no saved sessions)";
397
399
  }
398
400
  function registerAuthLeaves(cmd) {
399
- cmd.command("login <url>").description("Log in to a platform (attach a token, or browser/password OAuth)").option("-u, --username <name>", "username for password signin").option("-p, --password <pwd>", "password for password signin").option("--token <token>", "provide a token directly (CI / headless)").option("--client-id <id>", "use a fixed OAuth2 client id (skip dynamic registration)").option("--client-secret <secret>", "OAuth2 client secret (omit for public/PKCE)").option(
400
- "--port <n>",
401
- "loopback redirect port for the auth_code flow",
402
- (v) => Number.parseInt(v, 10)
403
- ).option("--device", "headless device-code login (RFC 8628) \u2014 no callback server, no password").option("--audience <aud>", "device-code token audience", "bkn-safe").option(
401
+ cmd.command("login <url>").description("Log in to a platform (attach a token, or browser/password OAuth)").option("-u, --username <name>", "username for password signin").option("-p, --password <pwd>", "password for password signin").option("--token <token>", "provide a token directly (CI / headless)").option("--client-id <id>", "OAuth2 client id to authenticate as").option("--device", "headless device-code login (RFC 8628) \u2014 no callback server, no password").option("--audience <aud>", "device-code token audience", "bkn-safe").option(
404
402
  "--timeout <s>",
405
403
  "device-login wait before timing out",
406
404
  (v) => Number.parseInt(v, 10),
407
405
  120
408
- ).option("--no-browser", "(legacy) print the URL instead of opening a browser").option("--product <name>", "(legacy) ISF OAuth product query").option("--signin-public-key-file <path>", "(legacy) RSA public key for ISF /oauth2/signin").option("--no-auth", "register the platform with no authentication (no bkn-safe)").action(async (url, opts, cmd2) => {
406
+ ).option("--no-browser", "print the URL instead of opening a browser").action(async (url, opts, cmd2) => {
409
407
  const g = cmd2.optsWithGlobals();
410
- if (g.insecure) process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
411
408
  const out = outputOptions(cmd2);
412
409
  const report = (r) => {
413
410
  if (out.json || out.compact) {
414
411
  printJson({ loggedIn: true, ...r }, out);
415
- } else if (r.noAuth) {
416
- process.stdout.write(`Registered ${r.baseUrl ?? url} (no authentication)
417
- `);
418
412
  } else {
419
413
  process.stdout.write(`Logged in to ${r.baseUrl ?? url} as ${r.username ?? r.userId}
420
414
  `);
@@ -425,19 +419,6 @@ function registerAuthLeaves(cmd) {
425
419
  report(attachToken(url, token, { insecure: g.insecure }));
426
420
  return;
427
421
  }
428
- if (opts.auth === false) {
429
- report(attachNoAuth(url, { insecure: g.insecure }));
430
- return;
431
- }
432
- const authStatus = await fetchAuthStatus(url);
433
- if (authStatus && !authStatus.enabled) {
434
- process.stderr.write(
435
- `Platform auth is disabled (stack: ${authStatus.stack ?? "none"}) \u2014 registering without auth.
436
- `
437
- );
438
- report(attachNoAuth(url, { insecure: g.insecure }));
439
- return;
440
- }
441
422
  let tokens;
442
423
  let account;
443
424
  try {
@@ -448,7 +429,8 @@ function registerAuthLeaves(cmd) {
448
429
  tokens = await credentialDeviceLogin(url, username, password, {
449
430
  clientId: opts.clientId,
450
431
  audience: opts.audience,
451
- timeoutMs: opts.timeout * 1e3
432
+ timeoutMs: opts.timeout * 1e3,
433
+ insecure: g.insecure
452
434
  });
453
435
  } else {
454
436
  const headless = isHeadless();
@@ -457,6 +439,7 @@ function registerAuthLeaves(cmd) {
457
439
  clientId: opts.clientId,
458
440
  audience: opts.audience,
459
441
  timeoutMs: opts.timeout * 1e3,
442
+ insecure: g.insecure,
460
443
  onPrompt: ({ userCode, verificationUri, verificationUriComplete }) => {
461
444
  const target = verificationUriComplete ?? verificationUri;
462
445
  process.stderr.write(
@@ -475,9 +458,9 @@ User code: ${userCode}
475
458
  }
476
459
  } catch (e) {
477
460
  if (e instanceof Error && /Device auth failed \(404\)/.test(e.message)) {
478
- process.stderr.write("No auth endpoint found \u2014 registering platform without auth.\n");
479
- report(attachNoAuth(url, { insecure: g.insecure }));
480
- return;
461
+ throw new InputError(
462
+ `No auth endpoint on ${url} \u2014 the platform has no bkn-safe auth stack. Deploy bkn-safe, or log in elsewhere and pass the token with \`--token\`.`
463
+ );
481
464
  }
482
465
  throw e;
483
466
  }
@@ -493,29 +476,29 @@ User code: ${userCode}
493
476
  attachToken(url, tokens.accessToken, {
494
477
  refreshToken: tokens.refreshToken,
495
478
  idToken: tokens.idToken,
496
- insecure: g.insecure,
497
- username: account
479
+ username: account,
480
+ insecure: g.insecure
498
481
  })
499
482
  );
500
483
  });
501
- cmd.command("status").description("Show base URL and whether a token is configured").action((_opts, cmd2) => printJson(status(), outputOptions(cmd2)));
484
+ cmd.command("status").description("Show base URL and whether a token is configured").action(
485
+ (_opts, cmd2) => printJson(status({ user: cmd2.optsWithGlobals().user }), outputOptions(cmd2))
486
+ );
502
487
  cmd.command("token").description("Print the current access token, refreshing it if expired (keep secret)").option("--no-refresh", "print the stored token as-is, without refreshing").action(async (opts, cmd2) => {
503
488
  const g = cmd2.optsWithGlobals();
504
- if (g.insecure) process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
505
- const token = opts.refresh === false ? currentToken() : await currentTokenFresh();
489
+ const token = opts.refresh === false ? currentToken({ user: g.user }) : await currentTokenFresh({ insecure: g.insecure, user: g.user });
506
490
  process.stdout.write(`${token}
507
491
  `);
508
492
  });
509
493
  cmd.command("whoami [url]").description("Show current user identity (from the token)").option("--no-lookup", "skip the backend identity fallback (eacp/user/get)").action(async (_url, opts, cmd2) => {
510
494
  const g = cmd2.optsWithGlobals();
511
- if (g.insecure) process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
512
- const me = whoami();
495
+ const me = whoami({ user: g.user });
513
496
  if (opts.lookup !== false && me.baseUrl && me.sub) {
514
497
  try {
515
498
  const u = await getUserSafe(
516
499
  {
517
500
  baseUrl: me.baseUrl,
518
- token: currentToken(),
501
+ token: currentToken({ user: g.user }),
519
502
  businessDomain: DEFAULT_BUSINESS_DOMAIN,
520
503
  insecure: Boolean(g.insecure)
521
504
  },
@@ -580,9 +563,8 @@ User code: ${userCode}
580
563
  cmd.command("export").description("Export the active session's tokens (for a headless host)").action((_opts, cmd2) => {
581
564
  printJson(exportCreds(), outputOptions(cmd2));
582
565
  });
583
- cmd.command("change-password [url]").description("Change your account password (bkn-safe self-service; no browser)").option("-a, --account <name>", "account / login name (the login column, e.g. admin)").option("--old-password <pwd>", "current password").option("--new-password <pwd>", "new password").option("--public-key-file <path>", "(legacy) RSA public key for ISF password encryption").action(async (url, opts, cmd2) => {
566
+ cmd.command("change-password [url]").description("Change your account password (bkn-safe self-service; no browser)").option("-a, --account <name>", "account / login name (the login column, e.g. admin)").option("--old-password <pwd>", "current password").option("--new-password <pwd>", "new password").action(async (url, opts, cmd2) => {
584
567
  const g = cmd2.optsWithGlobals();
585
- if (g.insecure) process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
586
568
  const ctx = resolveContext({
587
569
  baseUrl: url ?? g.baseUrl,
588
570
  token: g.token,
@@ -623,10 +605,14 @@ function authCommand() {
623
605
  // src/commands/admin.ts
624
606
  var int = (v) => Number.parseInt(v, 10);
625
607
  var DEFAULT_RESET_PASSWORD = "openbkn";
608
+ async function importLicenseFile(cmd, file, receipt) {
609
+ const text = readFileSync2(file, "utf8");
610
+ const res = await clientFrom(cmd).admin.licenseImport(text, { receipt });
611
+ printJson(res, outputOptions(cmd));
612
+ if ("stored" in res && res.stored) process.exitCode = 1;
613
+ }
626
614
  function adminCommand() {
627
- const admin = new Command2("admin").description(
628
- "Operator CLI (kweaver-admin): org, user, role, models, audit"
629
- );
615
+ const admin = new Command2("admin").description("Operator CLI: org, user, role, models, audit");
630
616
  registerAuthLeaves(admin.command("auth").description("Operator authentication"));
631
617
  const org = admin.command("org").description("Departments and org structure");
632
618
  org.command("list").description("List departments").option("--role <r>", "role qualifier", "super_admin").option("--name <s>", "filter by name").option("--limit <n>", "page size", int, 100).option("--offset <n>", "page offset", int, 0).action(async (opts, cmd) => {
@@ -755,15 +741,19 @@ function adminCommand() {
755
741
  user.command("delete <id>").description("Delete a user").action(async (id, _opts, cmd) => {
756
742
  printJson(await clientFrom(cmd).admin.userDelete(id), outputOptions(cmd));
757
743
  });
758
- user.command("reset-password [id]").description("Reset a user's password (defaults to the platform initial password)").option("--id <userId>", "explicit user UUID (alt to the positional id)").option("--user <account>", "resolve the user by account / login name").option("--password <s>", "the new password (default: platform initial 'openbkn')").option("--new-password <s>", "the new password (alias of --password)").option("-y, --yes", "skip confirmation").action(async (id, opts, cmd) => {
744
+ user.command("reset-password [id]").description("Reset a user's password (defaults to the platform initial password)").option("--id <userId>", "explicit user UUID (alt to the positional id)").option("--user <account>", "resolve the user by account / login name").option("--password <s>", "the new password (default: platform initial 'openbkn')").option("--new-password <s>", "the new password (alias of --password)").option("--prompt-password", "type the new password interactively (input hidden)").option("-y, --yes", "skip confirmation").action(async (id, opts, cmd) => {
759
745
  const userId = id ?? opts.id ?? opts.user;
760
746
  if (!userId) throw new Error("Provide a user id (positional or --id).");
761
- const pwd = opts.password ?? opts.newPassword ?? DEFAULT_RESET_PASSWORD;
747
+ let explicit = opts.password ?? opts.newPassword;
748
+ if (!explicit && opts.promptPassword) {
749
+ explicit = await promptLine("New password: ", true);
750
+ if (!explicit) throw new InputError("No password entered.");
751
+ }
752
+ const pwd = explicit ?? DEFAULT_RESET_PASSWORD;
762
753
  const r = await clientFrom(cmd).admin.userResetPassword(userId, pwd);
763
754
  const out = outputOptions(cmd);
764
755
  if (out.json || out.compact) printJson(r, out);
765
- else if (opts.password || opts.newPassword)
766
- process.stdout.write(`Password reset for ${userId}.
756
+ else if (explicit) process.stdout.write(`Password reset for ${userId}.
767
757
  `);
768
758
  else
769
759
  process.stdout.write(
@@ -906,6 +896,27 @@ function adminCommand() {
906
896
  );
907
897
  });
908
898
  }
899
+ const license = admin.command("license").description("Cluster license management");
900
+ license.command("show").description("Current license detail (state/edition/expiry/features)").action(async (_opts, cmd) => {
901
+ printJson(await clientFrom(cmd).admin.licenseGet(), outputOptions(cmd));
902
+ });
903
+ license.command("import <file>").description("Import a .lic license file (online deployments auto-activate)").action(async (file, _opts, cmd) => {
904
+ await importLicenseFile(cmd, file, false);
905
+ });
906
+ license.command("receipt <file>").description("Import an offline activation receipt (.lic from the license portal)").action(async (file, _opts, cmd) => {
907
+ await importLicenseFile(cmd, file, true);
908
+ });
909
+ license.command("activate").description("Report the installed license to the issuer (online deployments)").action(async (_opts, cmd) => {
910
+ printJson(await clientFrom(cmd).admin.licenseActivate(), outputOptions(cmd));
911
+ });
912
+ license.command("remove").description("Remove the installed license (back to unactivated)").action(async (_opts, cmd) => {
913
+ printJson(await clientFrom(cmd).admin.licenseRemove(), outputOptions(cmd));
914
+ });
915
+ license.command("fingerprint").description(
916
+ "This cluster's machine code (paste into the license portal for offline activation)"
917
+ ).action(async (_opts, cmd) => {
918
+ printJson(await clientFrom(cmd).admin.licenseFingerprint(), outputOptions(cmd));
919
+ });
909
920
  admin.command("audit").description("Audit log queries").command("list").description("List login audit events").option("--user <name>", "filter by user").option("--start <time>", "start time").option("--end <time>", "end time").option("--page <n>", "page", int, 1).option("--size <n>", "page size", int, 30).action(async (opts, cmd) => {
910
921
  printJson(
911
922
  await clientFrom(cmd).admin.auditList({
@@ -966,7 +977,14 @@ function adminCommand() {
966
977
  import { Command as Command3 } from "commander";
967
978
  var int2 = (v) => Number.parseInt(v, 10);
968
979
  function agentCommand() {
969
- const cmd = new Command3("agent").description("Agent CRUD, chat, sessions, publish");
980
+ const cmd = new Command3("agent").description(
981
+ "[DEPRECATED] Decision Agent \u2014 CRUD, chat, sessions, publish (being phased out)"
982
+ );
983
+ cmd.hook("preAction", () => {
984
+ process.stderr.write(
985
+ "\u26A0\uFE0F `openbkn agent` is deprecated and may be removed in a future release.\n"
986
+ );
987
+ });
970
988
  cmd.command("list").description("List published agents").option("--name <s>", "filter by name").option("--limit <n>", "page size", int2, DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", int2, 0).option("--category-id <id>", "filter by category").action(async (opts, cmd2) => {
971
989
  const data = await clientFrom(cmd2).agents.list({
972
990
  name: opts.name,
@@ -1068,11 +1086,78 @@ function agentCommand() {
1068
1086
  return group(cmd, "DECISION AGENT");
1069
1087
  }
1070
1088
 
1071
- // src/commands/bkn.ts
1089
+ // src/commands/appkey.ts
1072
1090
  import { Command as Command4 } from "commander";
1091
+ var int3 = (v) => Number.parseInt(v, 10);
1092
+ var DAY_MS = 864e5;
1093
+ function printNewKey(created, out) {
1094
+ if (out.json || out.compact) {
1095
+ printJson(created, out);
1096
+ return;
1097
+ }
1098
+ process.stderr.write(
1099
+ "\u26A0\uFE0F Copy this key now \u2014 the plaintext is shown only once and cannot be retrieved again.\n\n"
1100
+ );
1101
+ const fields = [
1102
+ ["key", created.key],
1103
+ ["name", created.name],
1104
+ ["id", `${created.id} (use this to revoke/regenerate)`],
1105
+ ["key_id", created.key_id],
1106
+ ["expires_at", created.expires_at ?? "never"]
1107
+ ];
1108
+ const w = Math.max(...fields.map(([k]) => k.length));
1109
+ for (const [k, v] of fields) process.stdout.write(` ${k.padEnd(w)} ${v}
1110
+ `);
1111
+ }
1112
+ function appkeyCommand() {
1113
+ const appkey = new Command4("appkey").description(
1114
+ "AppKeys \u2014 user-issued long-lived credentials (bak_) for the Context Loader"
1115
+ );
1116
+ appkey.command("list").description("List your own AppKeys (no secrets)").action(async (_opts, cmd) => {
1117
+ printJson(await clientFrom(cmd).appKeys.list(), outputOptions(cmd));
1118
+ });
1119
+ appkey.command("create").description("Issue an AppKey \u2014 the plaintext key is shown ONCE, on create").requiredOption("--name <s>", "display name (to tell keys apart)").option("--expires-at <rfc3339>", "expiry as RFC3339 (e.g. 2027-01-01T00:00:00Z)").option("--expire-days <n>", "expiry in N days from now (alternative to --expires-at)", int3).option("--never-expire", "never expire (wins over --expires-at/--expire-days)").action(async (opts, cmd) => {
1120
+ let expiresAt = opts.expiresAt;
1121
+ if (opts.expireDays !== void 0) {
1122
+ if (!Number.isFinite(opts.expireDays) || opts.expireDays <= 0) {
1123
+ throw new InputError("--expire-days must be a positive integer.");
1124
+ }
1125
+ if (expiresAt) {
1126
+ throw new InputError("Use either --expires-at or --expire-days, not both.");
1127
+ }
1128
+ expiresAt = new Date(Date.now() + opts.expireDays * DAY_MS).toISOString();
1129
+ }
1130
+ const created = await clientFrom(cmd).appKeys.create({
1131
+ name: opts.name,
1132
+ expiresAt,
1133
+ neverExpire: Boolean(opts.neverExpire)
1134
+ });
1135
+ printNewKey(created, outputOptions(cmd));
1136
+ });
1137
+ appkey.command("regenerate <id>").alias("rotate").description("Rotate a key in place \u2014 mints a new plaintext; the old bak_ dies immediately").action(async (id, _opts, cmd) => {
1138
+ const created = await clientFrom(cmd).appKeys.regenerate(id);
1139
+ printNewKey(created, outputOptions(cmd));
1140
+ });
1141
+ appkey.command("revoke <id>").alias("delete").alias("rm").description("Revoke one of your AppKeys (immediate; use the `id`, not `key_id`)").action(async (id, _opts, cmd) => {
1142
+ await clientFrom(cmd).appKeys.revoke(id);
1143
+ printJson({ revoked: id }, outputOptions(cmd));
1144
+ });
1145
+ const admin = appkey.command("admin").description("Admin governance over all AppKeys");
1146
+ admin.command("list").description("List all AppKeys, or one owner's (adds owner_user_id)").option("--owner-id <id>", "filter to a single owner").action(async (opts, cmd) => {
1147
+ printJson(await clientFrom(cmd).appKeys.adminList(opts.ownerId), outputOptions(cmd));
1148
+ });
1149
+ admin.command("revoke <id>").alias("delete").alias("rm").description("Revoke any AppKey by id").action(async (id, _opts, cmd) => {
1150
+ await clientFrom(cmd).appKeys.adminRevoke(id);
1151
+ printJson({ revoked: id }, outputOptions(cmd));
1152
+ });
1153
+ return group(appkey, "AUTHENTICATION & CONFIG");
1154
+ }
1155
+
1156
+ // src/commands/bkn.ts
1157
+ import { Command as Command5 } from "commander";
1073
1158
 
1074
1159
  // src/utils/bkn-validate.ts
1075
- import { existsSync, readFileSync as readFileSync2, readdirSync, statSync } from "fs";
1160
+ import { existsSync, readFileSync as readFileSync3, readdirSync, statSync } from "fs";
1076
1161
  import { join, resolve } from "path";
1077
1162
  var BKN_OBJECT_NAME_MAX_LENGTH = 40;
1078
1163
  function parseFrontmatter(text) {
@@ -1125,7 +1210,7 @@ function validateBknDirectory(dirPath) {
1125
1210
  if (!existsSync(networkPath)) {
1126
1211
  errors.push("Missing network.bkn at the BKN root.");
1127
1212
  } else {
1128
- const fm = parseFrontmatter(readFileSync2(networkPath, "utf8"));
1213
+ const fm = parseFrontmatter(readFileSync3(networkPath, "utf8"));
1129
1214
  if (!fm) errors.push("network.bkn has no frontmatter block.");
1130
1215
  else {
1131
1216
  if (fm.type !== "knowledge_network")
@@ -1137,7 +1222,7 @@ function validateBknDirectory(dirPath) {
1137
1222
  const otIds = /* @__PURE__ */ new Set();
1138
1223
  const otFiles = bknFiles(join(dir, "object_types"));
1139
1224
  for (const file of otFiles) {
1140
- const fm = parseFrontmatter(readFileSync2(file, "utf8"));
1225
+ const fm = parseFrontmatter(readFileSync3(file, "utf8"));
1141
1226
  const rel = file.slice(dir.length + 1);
1142
1227
  if (!fm || fm.type !== "object_type") {
1143
1228
  errors.push(`${rel}: not a valid object_type (missing/wrong frontmatter type).`);
@@ -1157,7 +1242,7 @@ function validateBknDirectory(dirPath) {
1157
1242
  }
1158
1243
  const rtFiles = bknFiles(join(dir, "relation_types"));
1159
1244
  for (const file of rtFiles) {
1160
- const text = readFileSync2(file, "utf8");
1245
+ const text = readFileSync3(file, "utf8");
1161
1246
  const fm = parseFrontmatter(text);
1162
1247
  const rel = file.slice(dir.length + 1);
1163
1248
  if (!fm || fm.type !== "relation_type") {
@@ -1187,10 +1272,10 @@ function validateBknDirectory(dirPath) {
1187
1272
  }
1188
1273
 
1189
1274
  // src/commands/bkn.ts
1190
- var int3 = (v) => Number.parseInt(v, 10);
1275
+ var int4 = (v) => Number.parseInt(v, 10);
1191
1276
  function bknCommand() {
1192
- const bkn = new Command4("bkn").description("Knowledge networks \u2014 list, query, schema, instances");
1193
- bkn.command("list").description("List knowledge networks").option("--limit <n>", "page size", int3, DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", int3, 0).option("--name-pattern <s>", "filter by name pattern").option("--tag <s>", "filter by tag").option("--sort <field>", "sort field", "update_time").option("--direction <dir>", "asc | desc", "desc").action(async (_opts, cmd) => {
1277
+ const bkn = new Command5("bkn").description("Knowledge networks \u2014 list, query, schema, instances");
1278
+ bkn.command("list").description("List knowledge networks").option("--limit <n>", "page size", int4, DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", int4, 0).option("--name-pattern <s>", "filter by name pattern").option("--tag <s>", "filter by tag").option("--sort <field>", "sort field", "update_time").option("--direction <dir>", "asc | desc", "desc").action(async (_opts, cmd) => {
1194
1279
  const o = cmd.optsWithGlobals();
1195
1280
  const data = await clientFrom(cmd).kn.list({
1196
1281
  limit: o.limit,
@@ -1209,7 +1294,7 @@ function bknCommand() {
1209
1294
  });
1210
1295
  printJson(data, outputOptions(cmd));
1211
1296
  });
1212
- bkn.command("search <kn-id> <query>").description("Semantic search within a knowledge network").option("--max-concepts <n>", "max concepts to return", int3, 10).option("--mode <mode>", "retrieval mode", "keyword_vector_retrieval").action(async (knId, query, opts, cmd) => {
1297
+ bkn.command("search <kn-id> <query>").description("Semantic search within a knowledge network").option("--max-concepts <n>", "max concepts to return", int4, 10).option("--mode <mode>", "retrieval mode", "keyword_vector_retrieval").action(async (knId, query, opts, cmd) => {
1213
1298
  const data = await clientFrom(cmd).kn.search(knId, query, {
1214
1299
  maxConcepts: opts.maxConcepts,
1215
1300
  mode: opts.mode
@@ -1282,9 +1367,6 @@ function bknCommand() {
1282
1367
  outputOptions(cmd)
1283
1368
  );
1284
1369
  });
1285
- objectType?.command("properties <kn-id> <ot-id>").description("Get an object type's calculated properties").action(async (knId, otId, _opts, cmd) => {
1286
- printJson(await clientFrom(cmd).kn.objectTypeProperties(knId, otId), outputOptions(cmd));
1287
- });
1288
1370
  bkn.command("create <name>").description("Create an (empty) knowledge network").option("--branch <b>", "branch", "main").action(async (name, opts, cmd) => {
1289
1371
  printJson(await clientFrom(cmd).kn.create({ name, branch: opts.branch }), outputOptions(cmd));
1290
1372
  });
@@ -1298,7 +1380,7 @@ function bknCommand() {
1298
1380
  printJson(await clientFrom(cmd).kn.subgraph(knId, readBody(opts)), outputOptions(cmd));
1299
1381
  });
1300
1382
  const actionLog = bkn.command("action-log").description("Action logs \u2014 list/get/cancel");
1301
- actionLog.command("list <kn-id>").description("List action logs").option("--status <s>", "filter by status").option("--action-type-id <id>", "filter by action type").option("--limit <n>", "page size", int3, DEFAULT_LIST_LIMIT).action(async (knId, opts, cmd) => {
1383
+ actionLog.command("list <kn-id>").description("List action logs").option("--status <s>", "filter by status").option("--action-type-id <id>", "filter by action type").option("--limit <n>", "page size", int4, DEFAULT_LIST_LIMIT).action(async (knId, opts, cmd) => {
1302
1384
  printJson(
1303
1385
  await clientFrom(cmd).kn.actionLogs(knId, {
1304
1386
  status: opts.status,
@@ -1413,19 +1495,6 @@ function bknCommand() {
1413
1495
  sched.command("delete <kn-id> <schedule-ids>").description("Delete action schedule(s) (comma-joined ids)").action(async (knId, ids, _o, cmd) => {
1414
1496
  printJson(await clientFrom(cmd).kn.actionScheduleDelete(knId, ids), outputOptions(cmd));
1415
1497
  });
1416
- const job = bkn.command("job").description("Build jobs \u2014 list/get/tasks");
1417
- job.command("list <kn-id>").description("List jobs").action(async (knId, _o, cmd) => {
1418
- printJson(await clientFrom(cmd).kn.jobs(knId), outputOptions(cmd));
1419
- });
1420
- job.command("get <kn-id> <job-id>").description("Get a job").action(async (knId, jobId, _o, cmd) => {
1421
- printJson(await clientFrom(cmd).kn.job(knId, jobId), outputOptions(cmd));
1422
- });
1423
- job.command("tasks <kn-id> <job-id>").description("List a job's tasks").action(async (knId, jobId, _o, cmd) => {
1424
- printJson(await clientFrom(cmd).kn.jobTasks(knId, jobId), outputOptions(cmd));
1425
- });
1426
- job.command("delete <kn-id> <job-ids>").description("Delete job(s) (comma-joined ids)").action(async (knId, ids, _o, cmd) => {
1427
- printJson(await clientFrom(cmd).kn.jobDelete(knId, ids), outputOptions(cmd));
1428
- });
1429
1498
  bkn.command("push <directory>").description("Pack a BKN directory into a tar and import it as a knowledge network").option("--branch <name>", "target branch", "main").option("--build", "submit a Vega build task for each object type declaring a vector index").option(
1430
1499
  "--embedding-model <id>",
1431
1500
  "embedding model id for declared vector indexes (with --build)"
@@ -1478,7 +1547,7 @@ function bknCommand() {
1478
1547
  printJson(result, outputOptions(cmd));
1479
1548
  if (!result.valid) process.exitCode = 1;
1480
1549
  });
1481
- bkn.command("create-from-csv <catalog-id>").description("Import CSV files into a Vega catalog, then build a KN from them").requiredOption("--files <glob>", "CSV paths (comma-separated or glob)").requiredOption("--name <name>", "knowledge network name").option("--table-prefix <s>", "prefix for derived table names", "").option("--batch-size <n>", "rows per insert batch", int3, 500).option("--tables <list>", "subset of imported tables to include in the KN").option("--pk-map <map>", "explicit primary keys: '<table>:<col>[,...]'").option("--build", "submit a Vega build task per resource after creation").option(
1550
+ bkn.command("create-from-csv <catalog-id>").description("Import CSV files into a Vega catalog, then build a KN from them").requiredOption("--files <glob>", "CSV paths (comma-separated or glob)").requiredOption("--name <name>", "knowledge network name").option("--table-prefix <s>", "prefix for derived table names", "").option("--batch-size <n>", "rows per insert batch", int4, 500).option("--tables <list>", "subset of imported tables to include in the KN").option("--pk-map <map>", "explicit primary keys: '<table>:<col>[,...]'").option("--build", "submit a Vega build task per resource after creation").option(
1482
1551
  "--embedding-fields <map>",
1483
1552
  "columns to vectorize per table (with --build): '<table>:<col>[+<col>...][,...]'"
1484
1553
  ).option("--embedding-model <id>", "embedding model id for the vector index (with --build)").option("--no-rollback", "keep a partially-created KN on failure").action(async (catalogId, opts, cmd) => {
@@ -1504,25 +1573,27 @@ function bknCommand() {
1504
1573
  }
1505
1574
 
1506
1575
  // src/commands/call.ts
1507
- import { Command as Command5 } from "commander";
1576
+ import { Command as Command6 } from "commander";
1508
1577
  function collect(value, prev) {
1509
1578
  prev.push(value);
1510
1579
  return prev;
1511
1580
  }
1512
1581
  function callCommand() {
1513
- const cmd = new Command5("call").alias("curl").description("Call an API with curl-style flags and auto-injected auth headers").argument("<url>", "API path (e.g. /api/...) or absolute URL").option("-X, --request <method>", "HTTP method").option("-H, --header <header>", 'extra header "Name: value" (repeatable)', collect, []).option("-d, --data <body>", "request body (sets JSON content-type if unset)").option("--data-raw <body>", "alias for --data").option(
1582
+ const cmd = new Command6("call").alias("curl").description("Call an API with curl-style flags and auto-injected auth headers").argument("<url>", "API path (e.g. /api/...) or absolute URL").option("-X, --request <method>", "HTTP method").option("-H, --header <header>", 'extra header "Name: value" (repeatable)', collect, []).option("-d, --data <body>", "request body (sets JSON content-type if unset)").option("--data-raw <body>", "alias for --data").option(
1514
1583
  "-F, --form <field>",
1515
1584
  "multipart field key=value or key=@file (repeatable)",
1516
1585
  collect,
1517
1586
  []
1518
1587
  ).option("-v, --verbose", "print request line to stderr").action(async (url, opts, cmd2) => {
1519
1588
  const g = cmd2.optsWithGlobals();
1589
+ const trace = traceOptionsFrom(g);
1520
1590
  const ctx = resolveContext({
1521
1591
  baseUrl: g.baseUrl,
1522
1592
  token: g.token,
1523
1593
  user: g.user,
1524
1594
  businessDomain: g.bizDomain,
1525
- insecure: g.insecure
1595
+ insecure: g.insecure,
1596
+ ...trace ? { trace } : {}
1526
1597
  });
1527
1598
  const res = await rawCall(ctx, url, {
1528
1599
  method: opts.request,
@@ -1545,14 +1616,14 @@ function callCommand() {
1545
1616
  }
1546
1617
 
1547
1618
  // src/commands/config.ts
1548
- import { Command as Command6 } from "commander";
1619
+ import { Command as Command7 } from "commander";
1549
1620
  function requireActive() {
1550
1621
  const baseUrl = activePlatform();
1551
1622
  if (!baseUrl) throw new InputError("No active platform. Run `openbkn auth login <url>` first.");
1552
1623
  return baseUrl;
1553
1624
  }
1554
1625
  function configCommand() {
1555
- const config = new Command6("config").description("Per-platform CLI configuration");
1626
+ const config = new Command7("config").description("Per-platform CLI configuration");
1556
1627
  config.command("show").description("Show the active platform and business domain").action((_opts, cmd) => {
1557
1628
  const baseUrl = activePlatform();
1558
1629
  printJson(
@@ -1585,13 +1656,56 @@ function configCommand() {
1585
1656
  }
1586
1657
 
1587
1658
  // src/commands/context.ts
1588
- import { Command as Command7 } from "commander";
1589
- var int4 = (v) => Number.parseInt(v, 10);
1659
+ import { Command as Command8 } from "commander";
1660
+ var int5 = (v) => Number.parseInt(v, 10);
1661
+ var collectArg = (v, prev) => {
1662
+ prev.push(v);
1663
+ return prev;
1664
+ };
1665
+ function buildArgs(opts) {
1666
+ let out = {};
1667
+ if (opts.args) {
1668
+ try {
1669
+ out = JSON.parse(opts.args);
1670
+ } catch {
1671
+ throw new InputError("--args must be valid JSON");
1672
+ }
1673
+ }
1674
+ for (const pair of opts.arg ?? []) {
1675
+ const idx = pair.indexOf("=");
1676
+ if (idx <= 0) throw new InputError(`--arg must be key=value (got: ${pair})`);
1677
+ const key = pair.slice(0, idx);
1678
+ const raw = pair.slice(idx + 1);
1679
+ try {
1680
+ out[key] = JSON.parse(raw);
1681
+ } catch {
1682
+ out[key] = raw;
1683
+ }
1684
+ }
1685
+ return out;
1686
+ }
1687
+ function printToolList(res, out) {
1688
+ if (out.json || out.compact) {
1689
+ printJson(res, out);
1690
+ return;
1691
+ }
1692
+ const r = res ?? {};
1693
+ const arr = [res, r.tools, r.result?.tools, r.data].find(Array.isArray);
1694
+ if (!arr) {
1695
+ printJson(res, out);
1696
+ return;
1697
+ }
1698
+ const rows = arr.map((t) => ({
1699
+ name: t.name ?? t.tool_name ?? t.key ?? "",
1700
+ description: typeof t.description === "string" ? t.description : ""
1701
+ }));
1702
+ printJson(rows, out);
1703
+ }
1590
1704
  function contextCommand() {
1591
- const cmd = new Command7("context").description(
1705
+ const cmd = new Command8("context").description(
1592
1706
  "Context loader (MCP) \u2014 schema discovery, instance query, skill recall"
1593
1707
  );
1594
- cmd.command("search-schema <kn-id> <query>").description("Search object/relation/action/metric schemas").option("--scope <list>", "comma-separated scopes (object,relation,action,metric)").option("--max <n>", "max concepts", int4).action(async (knId, query, opts, cmd2) => {
1708
+ cmd.command("search-schema <kn-id> <query>").description("Search object/relation/action/metric schemas").option("--scope <list>", "comma-separated scopes (object,relation,action,metric)").option("--max <n>", "max concepts", int5).action(async (knId, query, opts, cmd2) => {
1595
1709
  const data = await clientFrom(cmd2).context.searchSchema(knId, query, {
1596
1710
  searchScope: opts.scope ? String(opts.scope).split(",") : void 0,
1597
1711
  maxConcepts: opts.max
@@ -1607,23 +1721,51 @@ function contextCommand() {
1607
1721
  }
1608
1722
  printJson(await clientFrom(cmd2).context.queryObjectInstance(knId, args), outputOptions(cmd2));
1609
1723
  });
1610
- cmd.command("find-skills <kn-id> <object-type-id>").description("Recall skills for an object type").option("--top-k <n>", "max skills (1-20)", int4).action(async (knId, otId, opts, cmd2) => {
1724
+ cmd.command("find-skills <kn-id> <object-type-id>").description("Recall skills for an object type").option("--top-k <n>", "max skills (1-20)", int5).action(async (knId, otId, opts, cmd2) => {
1611
1725
  printJson(
1612
1726
  await clientFrom(cmd2).context.findSkills(knId, otId, opts.topK),
1613
1727
  outputOptions(cmd2)
1614
1728
  );
1615
1729
  });
1616
- cmd.command("tools <kn-id>").description("List MCP tools").action(async (knId, _opts, cmd2) => {
1617
- printJson(await clientFrom(cmd2).context.tools(knId), outputOptions(cmd2));
1730
+ cmd.command("kn-detail <kn-id>").description("Get a KN's schema at a detail level (progressive: summary skeleton \u2192 drill down)").option("--detail-level <level>", "summary (default) | full", "summary").action(async (knId, opts, cmd2) => {
1731
+ const level = opts.detailLevel === "full" ? "full" : "summary";
1732
+ printJson(await clientFrom(cmd2).context.knDetail(knId, level), outputOptions(cmd2));
1618
1733
  });
1619
- cmd.command("tool-call <kn-id> <name>").description("Call any MCP tool directly (--args JSON)").requiredOption("--args <json>", "tool arguments as JSON").action(async (knId, name, opts, cmd2) => {
1620
- let args;
1621
- try {
1622
- args = JSON.parse(opts.args);
1623
- } catch {
1624
- throw new InputError("--args must be valid JSON");
1625
- }
1626
- printJson(await clientFrom(cmd2).context.toolCall(knId, name, args), outputOptions(cmd2));
1734
+ cmd.command("object-types <kn-id> <ids...>").description("Full definitions for the given object-type ids (unmatched \u2192 `missing`)").action(async (knId, ids, _opts, cmd2) => {
1735
+ printJson(await clientFrom(cmd2).context.objectTypes(knId, ids), outputOptions(cmd2));
1736
+ });
1737
+ cmd.command("relation-types <kn-id> <ids...>").description("Full definitions for the given relation-type ids (unmatched \u2192 `missing`)").action(async (knId, ids, _opts, cmd2) => {
1738
+ printJson(await clientFrom(cmd2).context.relationTypes(knId, ids), outputOptions(cmd2));
1739
+ });
1740
+ cmd.command("info").description("List the deploy's MCP tool catalog (global \u2014 no KN needed)").action(async (_opts, cmd2) => {
1741
+ printToolList(await clientFrom(cmd2).context.info(), outputOptions(cmd2));
1742
+ });
1743
+ cmd.command("tools <kn-id>").description("List MCP tools advertised for a KN session").action(async (knId, _opts, cmd2) => {
1744
+ printToolList(await clientFrom(cmd2).context.tools(knId), outputOptions(cmd2));
1745
+ });
1746
+ cmd.command("tool-call <kn-id> <name>").description("Call any MCP tool by name \u2014 current or future (use `tools` to discover)").option("--args <json>", "tool arguments as JSON").option(
1747
+ "--arg <key=value>",
1748
+ "one argument (repeatable; value parsed as JSON, else string)",
1749
+ collectArg,
1750
+ []
1751
+ ).action(async (knId, name, opts, cmd2) => {
1752
+ printJson(
1753
+ await clientFrom(cmd2).context.toolCall(knId, name, buildArgs(opts)),
1754
+ outputOptions(cmd2)
1755
+ );
1756
+ });
1757
+ cmd.command("call-method <kn-id> <method>").description(
1758
+ "Call any MCP method by name (e.g. tools/list, resources/read) \u2014 current or future"
1759
+ ).option("--args <json>", "method params as JSON").option(
1760
+ "--arg <key=value>",
1761
+ "one param (repeatable; value parsed as JSON, else string)",
1762
+ collectArg,
1763
+ []
1764
+ ).action(async (knId, method, opts, cmd2) => {
1765
+ printJson(
1766
+ await clientFrom(cmd2).context.callMethod(knId, method, buildArgs(opts)),
1767
+ outputOptions(cmd2)
1768
+ );
1627
1769
  });
1628
1770
  cmd.command("resources <kn-id>").description("List MCP resources").action(async (knId, _opts, cmd2) => {
1629
1771
  printJson(await clientFrom(cmd2).context.resources(knId), outputOptions(cmd2));
@@ -1655,19 +1797,19 @@ function contextCommand() {
1655
1797
  throw new InputError("--args must be valid JSON");
1656
1798
  }
1657
1799
  };
1658
- cmd.command("query-instance-subgraph <kn-id>").description("Layer-2: query an instance subgraph across relation-type paths").requiredOption("--args <json>", "tool arguments as JSON").action(async (knId, opts, cmd2) => {
1800
+ cmd.command("query-instance-subgraph <kn-id>").description("Query an instance subgraph across relation-type paths").requiredOption("--args <json>", "tool arguments as JSON").action(async (knId, opts, cmd2) => {
1659
1801
  printJson(
1660
1802
  await clientFrom(cmd2).context.queryInstanceSubgraph(knId, jsonArgs(opts.args)),
1661
1803
  outputOptions(cmd2)
1662
1804
  );
1663
1805
  });
1664
- cmd.command("get-logic-properties <kn-id>").description("Layer-3: compute logic-property values for instances").requiredOption("--args <json>", "tool arguments as JSON").action(async (knId, opts, cmd2) => {
1806
+ cmd.command("get-logic-properties <kn-id>").description("Compute logic-property values for instances").requiredOption("--args <json>", "tool arguments as JSON").action(async (knId, opts, cmd2) => {
1665
1807
  printJson(
1666
1808
  await clientFrom(cmd2).context.logicProperties(knId, jsonArgs(opts.args)),
1667
1809
  outputOptions(cmd2)
1668
1810
  );
1669
1811
  });
1670
- cmd.command("get-action-info <kn-id>").description("Layer-3: fetch action info / dynamic tools for an instance").requiredOption("--args <json>", "tool arguments as JSON").action(async (knId, opts, cmd2) => {
1812
+ cmd.command("get-action-info <kn-id>").description("Fetch action info / dynamic tools for an instance").requiredOption("--args <json>", "tool arguments as JSON").action(async (knId, opts, cmd2) => {
1671
1813
  printJson(
1672
1814
  await clientFrom(cmd2).context.actionInfo(knId, jsonArgs(opts.args)),
1673
1815
  outputOptions(cmd2)
@@ -1677,20 +1819,24 @@ function contextCommand() {
1677
1819
  }
1678
1820
 
1679
1821
  // src/commands/dataflow.ts
1680
- import { Command as Command8 } from "commander";
1681
- var int5 = (v) => Number.parseInt(v, 10);
1822
+ import { Command as Command9 } from "commander";
1823
+ var int6 = (v) => Number.parseInt(v, 10);
1682
1824
  function dataflowCommand() {
1683
- const cmd = new Command8("dataflow").description("Dataflow document workflows \u2014 list, runs, logs");
1825
+ const cmd = new Command9("dataflow").description("Dataflow document workflows \u2014 list, runs, logs");
1684
1826
  cmd.command("list").description("List all dataflows").action(async (_opts, cmd2) => {
1685
1827
  printJson(await clientFrom(cmd2).dataflows.list(), outputOptions(cmd2));
1686
1828
  });
1687
- cmd.command("runs <dagId>").description("List run records for one dataflow").option("--since <date>", "filter runs since a date").action(async (dagId, opts, cmd2) => {
1829
+ cmd.command("runs <dagId>").description("List run records for one dataflow").option("--since <date>", "filter runs since a date").option("--limit <n>", "page size (backend default 20)", int6).option("--page <n>", "page (0-based; backend default 0)", int6).action(async (dagId, opts, cmd2) => {
1688
1830
  printJson(
1689
- await clientFrom(cmd2).dataflows.runs(dagId, { since: opts.since }),
1831
+ await clientFrom(cmd2).dataflows.runs(dagId, {
1832
+ since: opts.since,
1833
+ page: opts.page,
1834
+ limit: opts.limit
1835
+ }),
1690
1836
  outputOptions(cmd2)
1691
1837
  );
1692
1838
  });
1693
- cmd.command("logs <dagId> <instanceId>").description("Show logs for one run").option("--page <n>", "page", int5, 0).option("--limit <n>", "page size", int5, DEFAULT_LIST_LIMIT).action(async (dagId, instanceId, opts, cmd2) => {
1839
+ cmd.command("logs <dagId> <instanceId>").description("Show logs for one run").option("--page <n>", "page", int6, 0).option("--limit <n>", "page size", int6, DEFAULT_LIST_LIMIT).action(async (dagId, instanceId, opts, cmd2) => {
1694
1840
  printJson(
1695
1841
  await clientFrom(cmd2).dataflows.logs(dagId, instanceId, {
1696
1842
  page: opts.page,
@@ -1752,8 +1898,8 @@ function dataflowCommand() {
1752
1898
 
1753
1899
  // src/commands/explore.ts
1754
1900
  import { createServer } from "http";
1755
- import { Command as Command9 } from "commander";
1756
- var int6 = (v) => Number.parseInt(v, 10);
1901
+ import { Command as Command10 } from "commander";
1902
+ var int7 = (v) => Number.parseInt(v, 10);
1757
1903
  var ROUTES = {
1758
1904
  "GET /api/bkn/meta": (c, q) => c.kn.get(req(q, "knId")),
1759
1905
  "POST /api/bkn/search": (c, _q, b) => c.kn.search(str(b.knId), str(b.query), {
@@ -1761,7 +1907,6 @@ var ROUTES = {
1761
1907
  }),
1762
1908
  "POST /api/bkn/instances": (c, _q, b) => c.kn.objectTypeQuery(str(b.knId), str(b.objectTypeId), b.body ?? {}),
1763
1909
  "POST /api/bkn/subgraph": (c, _q, b) => c.kn.subgraph(str(b.knId), b.body ?? b),
1764
- "POST /api/bkn/properties": (c, _q, b) => c.kn.objectTypeProperties(str(b.knId), str(b.objectTypeId)),
1765
1910
  "GET /api/vega/catalogs": (c) => c.vega.catalogs(),
1766
1911
  "GET /api/vega/catalog": (c, q) => c.vega.getCatalog(req(q, "catalogId")),
1767
1912
  "GET /api/vega/catalog-resources": (c, q) => c.vega.catalogResources(req(q, "catalogId"), q.get("category") ?? void 0),
@@ -1798,10 +1943,10 @@ var INDEX = `<!doctype html><meta charset="utf-8"><title>openbkn explore</title>
1798
1943
  <p>Read-only JSON endpoints for bkn + vega:</p>
1799
1944
  <ul>${Object.keys(ROUTES).map((r) => `<li><code>${r}</code></li>`).join("")}</ul>`;
1800
1945
  function exploreCommand() {
1801
- const cmd = new Command9("explore").description(
1946
+ const cmd = new Command10("explore").description(
1802
1947
  "Start a local web server with read-only bkn + vega JSON endpoints"
1803
1948
  );
1804
- cmd.option("--port <n>", "port to listen on", int6, 7777).option("--host <h>", "host to bind", "127.0.0.1").action(async (opts, command) => {
1949
+ cmd.option("--port <n>", "port to listen on", int7, 7777).option("--host <h>", "host to bind", "127.0.0.1").action(async (opts, command) => {
1805
1950
  const client = clientFrom(command);
1806
1951
  const server = createServer((reqMsg, res) => {
1807
1952
  void handle(client, reqMsg, res);
@@ -1839,8 +1984,14 @@ async function handle(client, reqMsg, res) {
1839
1984
  }
1840
1985
 
1841
1986
  // src/commands/model.ts
1842
- import { Command as Command10 } from "commander";
1843
- var int7 = (v) => Number.parseInt(v, 10);
1987
+ import { Command as Command11 } from "commander";
1988
+ var int8 = (v) => Number.parseInt(v, 10);
1989
+ async function resolveLlmModelName(client, model) {
1990
+ if (!/^\d+$/.test(model)) return model;
1991
+ const detail = await client.models.llm.get(model);
1992
+ if (!detail?.model_name) throw new InputError(`No LLM found with id ${model}.`);
1993
+ return detail.model_name;
1994
+ }
1844
1995
  function addManagementCommands(parent, kind) {
1845
1996
  parent.command("add").description("Register a model (definition JSON via --body / --body-file)").option("--body <json>", "model definition JSON").option("--body-file <path>", "read model definition JSON from a file").action(async (opts, cmd) => {
1846
1997
  printJson(await clientFrom(cmd).models[kind].add(readBody(opts)), outputOptions(cmd));
@@ -1856,9 +2007,11 @@ function addManagementCommands(parent, kind) {
1856
2007
  });
1857
2008
  }
1858
2009
  function modelCommand() {
1859
- const model = new Command10("model").description("Model factory \u2014 LLM / small-model CRUD + chat");
2010
+ const model = new Command11("model").description(
2011
+ "Model factory \u2014 LLM / small-model CRUD, chat / embeddings / rerank, default selection"
2012
+ );
1860
2013
  const llm = model.command("llm").description("Large language models");
1861
- llm.command("list").description("List LLM models").option("--name <s>", "filter by name").option("--type <t>", "model type filter").option("--limit <n>", "page size", int7, DEFAULT_LIST_LIMIT).option("--page <n>", "page", int7, 1).action(async (opts, cmd) => {
2014
+ llm.command("list").description("List LLM models").option("--name <s>", "filter by name").option("--type <t>", "model type filter").option("--limit <n>", "page size", int8, DEFAULT_LIST_LIMIT).option("--page <n>", "page", int8, 1).action(async (opts, cmd) => {
1862
2015
  printJson(
1863
2016
  await clientFrom(cmd).models.llm.list({
1864
2017
  name: opts.name,
@@ -1872,18 +2025,26 @@ function modelCommand() {
1872
2025
  llm.command("get <modelId>").description("Get an LLM model").action(async (id, _opts, cmd) => {
1873
2026
  printJson(await clientFrom(cmd).models.llm.get(id), outputOptions(cmd));
1874
2027
  });
1875
- llm.command("chat <modelId>").description("OpenAI-compatible chat completion").requiredOption("-m, --message <text>", "user message").option("--stream", "stream the reply token-by-token to stdout").action(async (id, opts, cmd) => {
2028
+ llm.command("chat <model>").description("OpenAI-compatible chat completion (<model> = model name or numeric id)").requiredOption("-m, --message <text>", "user message").option("--stream", "stream the reply token-by-token to stdout").action(async (model2, opts, cmd) => {
2029
+ const client = clientFrom(cmd);
2030
+ const name = await resolveLlmModelName(client, model2);
1876
2031
  const messages = [{ role: "user", content: opts.message }];
1877
2032
  if (opts.stream) {
1878
- await clientFrom(cmd).models.llm.chatStream(id, messages, (t) => process.stdout.write(t));
2033
+ await client.models.llm.chatStream(name, messages, (t) => process.stdout.write(t));
1879
2034
  process.stdout.write("\n");
1880
2035
  return;
1881
2036
  }
1882
- printJson(await clientFrom(cmd).models.llm.chat(id, messages), outputOptions(cmd));
2037
+ printJson(await client.models.llm.chat(name, messages), outputOptions(cmd));
2038
+ });
2039
+ llm.command("set-default <modelId>").description("Set this LLM as the system default (admin)").action(async (id, _opts, cmd) => {
2040
+ printJson(await clientFrom(cmd).models.llm.setDefault(id, true), outputOptions(cmd));
2041
+ });
2042
+ llm.command("unset-default <modelId>").description("Clear this LLM as the system default (admin)").action(async (id, _opts, cmd) => {
2043
+ printJson(await clientFrom(cmd).models.llm.setDefault(id, false), outputOptions(cmd));
1883
2044
  });
1884
2045
  addManagementCommands(llm, "llm");
1885
2046
  const small = model.command("small").description("Small models (embedding / reranker)");
1886
- small.command("list").description("List small models").option("--name <s>", "filter by name").option("--type <t>", "model type filter").option("--limit <n>", "page size", int7, DEFAULT_LIST_LIMIT).option("--page <n>", "page", int7, 1).action(async (opts, cmd) => {
2047
+ small.command("list").description("List small models").option("--name <s>", "filter by name").option("--type <t>", "model type filter").option("--limit <n>", "page size", int8, DEFAULT_LIST_LIMIT).option("--page <n>", "page", int8, 1).action(async (opts, cmd) => {
1887
2048
  printJson(
1888
2049
  await clientFrom(cmd).models.small.list({
1889
2050
  name: opts.name,
@@ -1909,37 +2070,81 @@ function modelCommand() {
1909
2070
  outputOptions(cmd)
1910
2071
  );
1911
2072
  });
2073
+ small.command("get-default").description("Show the system default small model for a type").option("--type <t>", "model type: embedding | reranker", "embedding").action(async (opts, cmd) => {
2074
+ printJson(await clientFrom(cmd).models.small.getDefault(opts.type), outputOptions(cmd));
2075
+ });
2076
+ small.command("set-default <modelId>").description("Set this small model as the system default for its type (admin)").action(async (id, _opts, cmd) => {
2077
+ printJson(await clientFrom(cmd).models.small.setDefault(id, true), outputOptions(cmd));
2078
+ });
2079
+ small.command("unset-default <modelId>").description("Clear this small model as the system default (admin)").action(async (id, _opts, cmd) => {
2080
+ printJson(await clientFrom(cmd).models.small.setDefault(id, false), outputOptions(cmd));
2081
+ });
1912
2082
  addManagementCommands(small, "small");
2083
+ model.addHelpText(
2084
+ "after",
2085
+ `
2086
+ Identifiers:
2087
+ \u2022 get / set-default / delete take the numeric model id (e.g. 2071747547839467520).
2088
+ \u2022 chat takes a model NAME, but also accepts a numeric id (resolved to its name).
2089
+
2090
+ Examples:
2091
+ $ openbkn model llm list # ids + the 'default' flag
2092
+ $ openbkn model llm chat deepseek_v4_flash -m hi # by name
2093
+ $ openbkn model llm chat 2071747547839467520 -m hi --stream # by id, streamed
2094
+ $ openbkn model llm set-default 2071747547839467520 # system default LLM
2095
+ $ openbkn model small get-default --type embedding # current default
2096
+ $ openbkn model small set-default <id> # default embedding/reranker`
2097
+ );
1913
2098
  return group(model, "MODELS & SKILLS");
1914
2099
  }
1915
2100
 
1916
2101
  // src/commands/resource.ts
1917
- import { Command as Command11 } from "commander";
1918
- var int8 = (v) => Number.parseInt(v, 10);
2102
+ import { Command as Command12 } from "commander";
2103
+ var int9 = (v) => Number.parseInt(v, 10);
2104
+ var parsePairs = (raw) => {
2105
+ if (!raw) return void 0;
2106
+ return raw.split(",").map((part) => {
2107
+ const idx = part.indexOf("=");
2108
+ if (idx < 1) throw new Error("--extension must be key=value[,key=value]");
2109
+ return { key: part.slice(0, idx).trim(), value: part.slice(idx + 1).trim() };
2110
+ }).filter((p) => p.key.length > 0);
2111
+ };
1919
2112
  function resourceCommand() {
1920
- const cmd = new Command11("resource").alias("res").description("Resources \u2014 list, find, get, query, delete");
1921
- cmd.command("list").description("List resources under a catalog").option("--catalog-id <id>", "filter by catalog id").option("--datasource-id <id>", "alias of --catalog-id").option("--category <c>", "resource category (table | logicview | dataset)").option("--type <c>", "alias of --category").option("--limit <n>", "page size", int8, DEFAULT_LIST_LIMIT).action(async (opts, cmd2) => {
2113
+ const cmd = new Command12("resource").alias("res").description("Resources \u2014 list, find, get, query, delete");
2114
+ cmd.command("list").description("List resources under a catalog").option("--catalog-id <id>", "filter by catalog id").option("--datasource-id <id>", "alias of --catalog-id").option("--category <c>", "resource category (table | logicview | dataset)").option("--type <c>", "alias of --category").option("--status <status>", "filter by status").option("--database <name>", "filter by database").option("--limit <n>", "page size", int9, DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", int9, 0).option("--include-extensions", "include all extension key/value pairs").option("--include-extension-keys <keys>", "include selected extension keys").option("--extension <k=v,...>", "filter by extension key/value pairs").option("--sort <field>", "sort field: name | create_time | update_time").option("--direction <dir>", "sort direction: asc | desc").action(async (opts, cmd2) => {
1922
2115
  const data = await clientFrom(cmd2).resource.list({
1923
2116
  datasourceId: opts.catalogId ?? opts.datasourceId,
1924
2117
  category: opts.category ?? opts.type,
1925
- limit: opts.limit
2118
+ status: opts.status,
2119
+ database: opts.database,
2120
+ limit: opts.limit,
2121
+ offset: opts.offset,
2122
+ includeExtensions: opts.includeExtensions,
2123
+ includeExtensionKeys: opts.includeExtensionKeys,
2124
+ extensionPairs: parsePairs(opts.extension),
2125
+ sort: opts.sort,
2126
+ direction: opts.direction
1926
2127
  });
1927
2128
  printJson(data, outputOptions(cmd2));
1928
2129
  });
1929
- cmd.command("find").description("Search resources by name (fuzzy; --exact for strict)").requiredOption("--name <name>", "resource name to search").option("--exact", "exact name match").option("--catalog-id <id>", "limit to a catalog").option("--datasource-id <id>", "alias of --catalog-id").action(async (opts, cmd2) => {
2130
+ cmd.command("find").description("Search resources by name (fuzzy; --exact for strict)").requiredOption("--name <name>", "resource name to search").option("--exact", "exact name match").option("--catalog-id <id>", "limit to a catalog").option("--datasource-id <id>", "alias of --catalog-id").option("--limit <n>", "rows to scan before filtering", int9, DEFAULT_LIST_LIMIT).action(async (opts, cmd2) => {
1930
2131
  const data = await clientFrom(cmd2).resource.find(opts.name, {
1931
2132
  exact: opts.exact,
1932
- datasourceId: opts.catalogId ?? opts.datasourceId
2133
+ datasourceId: opts.catalogId ?? opts.datasourceId,
2134
+ limit: opts.limit
1933
2135
  });
1934
2136
  printJson(data, outputOptions(cmd2));
1935
2137
  });
1936
2138
  cmd.command("get <id>").description("Get resource details").action(async (id, _opts, cmd2) => {
1937
2139
  printJson(await clientFrom(cmd2).resource.get(id), outputOptions(cmd2));
1938
2140
  });
1939
- cmd.command("query <id>").description("Fetch data rows from a resource").option("--limit <n>", "row limit", int8, DEFAULT_QUERY_LIMIT).option("--offset <n>", "row offset", int8, 0).option("--need-total", "include total count").action(async (id, opts, cmd2) => {
2141
+ cmd.command("query <id>").description("Fetch data rows from a resource").option("--limit <n>", "row limit", int9, DEFAULT_QUERY_LIMIT).option("--offset <n>", "row offset", int9, 0).option("--paging-mode <mode>", "paging mode: single | cursor").option("--keep-alive-sec <s>", "cursor keep-alive in seconds (60\u20133600)", int9).option("--cursor <cursor>", "opaque cursor returned by the previous page").option("--need-total", "include total count").action(async (id, opts, cmd2) => {
1940
2142
  const data = await clientFrom(cmd2).resource.query(id, {
1941
2143
  limit: opts.limit,
1942
2144
  offset: opts.offset,
2145
+ pagingMode: opts.pagingMode,
2146
+ keepAliveSec: opts.keepAliveSec,
2147
+ cursor: opts.cursor,
1943
2148
  needTotal: opts.needTotal
1944
2149
  });
1945
2150
  printJson(data, outputOptions(cmd2));
@@ -1951,11 +2156,11 @@ function resourceCommand() {
1951
2156
  }
1952
2157
 
1953
2158
  // src/commands/skill.ts
1954
- import { Command as Command12 } from "commander";
1955
- var int9 = (v) => Number.parseInt(v, 10);
2159
+ import { Command as Command13 } from "commander";
2160
+ var int10 = (v) => Number.parseInt(v, 10);
1956
2161
  function skillCommand() {
1957
- const cmd = new Command12("skill").description("Skill registry and market");
1958
- const listOpts = (c) => c.option("--name <s>", "filter by name").option("--source <s>", "filter by source").option("--status <s>", "filter by status").option("--limit <n>", "page size", int9, DEFAULT_LIST_LIMIT).option("--page <n>", "page", int9, 1);
2162
+ const cmd = new Command13("skill").description("Skill registry and market");
2163
+ const listOpts = (c) => c.option("--name <s>", "filter by name").option("--source <s>", "filter by source").option("--status <s>", "filter by status").option("--limit <n>", "page size", int10, DEFAULT_LIST_LIMIT).option("--page <n>", "page", int10, 1);
1959
2164
  listOpts(cmd.command("list").description("List skills")).option("--create-user <s>", "filter by creator").action(async (opts, cmd2) => {
1960
2165
  printJson(
1961
2166
  await clientFrom(cmd2).skills.list({
@@ -2041,11 +2246,11 @@ function skillCommand() {
2041
2246
  }
2042
2247
 
2043
2248
  // src/commands/toolbox.ts
2044
- import { Command as Command13 } from "commander";
2045
- var int10 = (v) => Number.parseInt(v, 10);
2249
+ import { Command as Command14 } from "commander";
2250
+ var int11 = (v) => Number.parseInt(v, 10);
2046
2251
  function toolboxCommand() {
2047
- const cmd = new Command13("toolbox").description("Agent toolbox lifecycle");
2048
- cmd.command("list").description("List toolboxes").option("--keyword <s>", "filter by keyword").option("--limit <n>", "page size", int10, DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", int10, 0).action(async (opts, cmd2) => {
2252
+ const cmd = new Command14("toolbox").description("Agent toolbox lifecycle");
2253
+ cmd.command("list").description("List toolboxes").option("--keyword <s>", "filter by keyword").option("--limit <n>", "page size", int11, DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", int11, 0).action(async (opts, cmd2) => {
2049
2254
  printJson(
2050
2255
  await clientFrom(cmd2).toolboxes.list({
2051
2256
  keyword: opts.keyword,
@@ -2086,9 +2291,16 @@ function toolboxCommand() {
2086
2291
  return group(cmd, "DECISION AGENT");
2087
2292
  }
2088
2293
  function toolCommand() {
2089
- const cmd = new Command13("tool").description("Tools inside a toolbox");
2090
- cmd.command("list").description("List tools in a toolbox").requiredOption("--toolbox <box-id>", "toolbox id").action(async (opts, cmd2) => {
2091
- printJson(await clientFrom(cmd2).toolboxes.tools(opts.toolbox), outputOptions(cmd2));
2294
+ const cmd = new Command14("tool").description("Tools inside a toolbox");
2295
+ cmd.command("list").description("List tools in a toolbox").requiredOption("--toolbox <box-id>", "toolbox id").option("--limit <n>", "page size (backend default 10, max 100)", int11).option("--page <n>", "page (1-based; backend default 1)", int11).option("--all", "return every tool, ignoring page size").action(async (opts, cmd2) => {
2296
+ printJson(
2297
+ await clientFrom(cmd2).toolboxes.tools(opts.toolbox, {
2298
+ page: opts.page,
2299
+ pageSize: opts.limit,
2300
+ all: opts.all
2301
+ }),
2302
+ outputOptions(cmd2)
2303
+ );
2092
2304
  });
2093
2305
  cmd.command("enable <tool-ids...>").description("Enable one or more tools").requiredOption("--toolbox <box-id>", "toolbox id").action(async (toolIds, opts, cmd2) => {
2094
2306
  printJson(
@@ -2102,7 +2314,7 @@ function toolCommand() {
2102
2314
  outputOptions(cmd2)
2103
2315
  );
2104
2316
  });
2105
- const invokeOpts = (c) => c.requiredOption("--toolbox <box-id>", "toolbox id").option("--body <json>", "request body JSON").option("--header <json>", "headers map JSON").option("--query <json>", "query params JSON").option("--path <json>", "path params JSON").option("--timeout <s>", "per-call timeout seconds", int10);
2317
+ const invokeOpts = (c) => c.requiredOption("--toolbox <box-id>", "toolbox id").option("--body <json>", "request body JSON").option("--header <json>", "headers map JSON").option("--query <json>", "query params JSON").option("--path <json>", "path params JSON").option("--timeout <s>", "per-call timeout seconds", int11);
2106
2318
  const parseJson = (s, label) => {
2107
2319
  if (!s) return void 0;
2108
2320
  try {
@@ -2144,11 +2356,11 @@ function toolCommand() {
2144
2356
  }
2145
2357
 
2146
2358
  // src/commands/trace.ts
2147
- import { readFileSync as readFileSync4, writeFileSync } from "fs";
2148
- import { Command as Command14 } from "commander";
2359
+ import { readFileSync as readFileSync5, writeFileSync } from "fs";
2360
+ import { Command as Command15 } from "commander";
2149
2361
 
2150
- // src/trace-ai/schema-validate.ts
2151
- import { readFileSync as readFileSync3 } from "fs";
2362
+ // src/bkn-trace/schema-validate.ts
2363
+ import { readFileSync as readFileSync4 } from "fs";
2152
2364
  import { extname } from "path";
2153
2365
  import yaml from "js-yaml";
2154
2366
  import { z } from "zod";
@@ -2185,7 +2397,7 @@ var DiagnosisRule = z.object({
2185
2397
  params: z.record(z.string(), z.unknown()).optional()
2186
2398
  });
2187
2399
  function parseFile(file) {
2188
- const text = readFileSync3(file, "utf8");
2400
+ const text = readFileSync4(file, "utf8");
2189
2401
  const ext = extname(file).toLowerCase();
2190
2402
  if (ext === ".yaml" || ext === ".yml") return yaml.load(text);
2191
2403
  return JSON.parse(text);
@@ -2223,9 +2435,36 @@ function validateSchemaFile(file, kind) {
2223
2435
 
2224
2436
  // src/commands/trace.ts
2225
2437
  function traceCommand() {
2226
- const cmd = new Command14("trace").description(
2227
- "Trace AI \u2014 fetch spans, diagnose (symbolic + LLM rubric), scan, eval-set, schema validate"
2438
+ const cmd = new Command15("trace").description(
2439
+ "BKN Trace \u2014 fetch spans, diagnose (symbolic + LLM rubric), scan, eval-set, schema validate"
2228
2440
  );
2441
+ cmd.command("graph <trace-id>").description("Fetch normalized trace graph by trace id").action(async (traceId, _opts, cmd2) => {
2442
+ printJson(await clientFrom(cmd2).trace.graph(traceId), outputOptions(cmd2));
2443
+ });
2444
+ cmd.command("evidence-chain [trace-id]").description("Fetch BKN Trace evidence chain by trace id or --request-id").option("--request-id <id>", "BKN request id scope").option("--limit <n>", "maximum evidence trace batches", (v) => Number.parseInt(v, 10)).action(async (traceId, opts, cmd2) => {
2445
+ printJson(
2446
+ await clientFrom(cmd2).trace.evidenceChain(traceScope(traceId, opts.requestId), {
2447
+ limit: opts.limit
2448
+ }),
2449
+ outputOptions(cmd2)
2450
+ );
2451
+ });
2452
+ cmd.command("business-graph [trace-id]").description("Fetch BKN Trace business semantic graph by trace id or --request-id").option("--request-id <id>", "BKN request id scope").option("--limit <n>", "maximum evidence trace batches", (v) => Number.parseInt(v, 10)).action(async (traceId, opts, cmd2) => {
2453
+ printJson(
2454
+ await clientFrom(cmd2).trace.businessGraph(traceScope(traceId, opts.requestId), {
2455
+ limit: opts.limit
2456
+ }),
2457
+ outputOptions(cmd2)
2458
+ );
2459
+ });
2460
+ cmd.command("snapshot-preview [trace-id]").description("Fetch metadata-only evidence snapshot preview by trace id or --request-id").option("--request-id <id>", "BKN request id scope").option("--limit <n>", "maximum evidence trace batches", (v) => Number.parseInt(v, 10)).action(async (traceId, opts, cmd2) => {
2461
+ printJson(
2462
+ await clientFrom(cmd2).trace.snapshotPreview(traceScope(traceId, opts.requestId), {
2463
+ limit: opts.limit
2464
+ }),
2465
+ outputOptions(cmd2)
2466
+ );
2467
+ });
2229
2468
  cmd.command("get <conversation-id>").description("Fetch all trace spans for a conversation").option("--max-spans <n>", "max spans", (v) => Number.parseInt(v, 10)).action(async (conversationId, opts, cmd2) => {
2230
2469
  printJson(
2231
2470
  await clientFrom(cmd2).trace.spans(conversationId, { maxSpans: opts.maxSpans }),
@@ -2252,7 +2491,7 @@ function traceCommand() {
2252
2491
  });
2253
2492
  const evalSet = cmd.command("eval-set").description("Build + run trace eval sets");
2254
2493
  evalSet.command("build <queries-file>").description("Build eval cases from a queries JSON file").option("--out <file>", "write the cases JSON here (default: stdout)").action(async (queriesFile, opts, cmd2) => {
2255
- const raw = JSON.parse(readFileSync4(queriesFile, "utf8"));
2494
+ const raw = JSON.parse(readFileSync5(queriesFile, "utf8"));
2256
2495
  const cases = clientFrom(cmd2).trace.evalSetBuild(raw);
2257
2496
  if (opts.out) {
2258
2497
  writeFileSync(opts.out, JSON.stringify({ cases }, null, 2));
@@ -2262,7 +2501,7 @@ function traceCommand() {
2262
2501
  }
2263
2502
  });
2264
2503
  evalSet.command("test <cases-file>").description("Run an eval set against an agent (--llm enables semantic_match)").requiredOption("--agent <id>", "agent id to run the queries against").option("--version <v>", "agent version", "v0").option("--llm", "enable semantic_match assertions via the local `claude` CLI").action(async (casesFile, opts, cmd2) => {
2265
- const raw = JSON.parse(readFileSync4(casesFile, "utf8"));
2504
+ const raw = JSON.parse(readFileSync5(casesFile, "utf8"));
2266
2505
  const cases = clientFrom(cmd2).trace.evalSetBuild(raw);
2267
2506
  const result = await clientFrom(cmd2).trace.evalSetTest(opts.agent, cases, {
2268
2507
  version: opts.version,
@@ -2277,45 +2516,108 @@ function traceCommand() {
2277
2516
  printJson(result, outputOptions(cmd2));
2278
2517
  if (!result.valid) process.exitCode = 1;
2279
2518
  });
2519
+ cmd.command("validate-fixture <path>").description("Validate BKN Trace 1.0/2.0/2.1 fixture JSON files").action(async (path, _opts, cmd2) => {
2520
+ const result = validateFixturePath(path);
2521
+ printJson(result, outputOptions(cmd2));
2522
+ if (!result.ok) process.exitCode = 1;
2523
+ });
2524
+ const evidence = cmd.command("evidence").description("Submit BKN Trace 2.x business evidence events");
2525
+ evidence.command("emit <file>").description("Submit a BKN Trace 2.0/2.1 event batch JSON file").action(async (file, _opts, cmd2) => {
2526
+ const body = JSON.parse(readFileSync5(file, "utf8"));
2527
+ printJson(await clientFrom(cmd2).trace.emitEvidenceEvents(body), outputOptions(cmd2));
2528
+ });
2280
2529
  return group(cmd, "TRACE AI");
2281
2530
  }
2531
+ function traceScope(traceId, requestId) {
2532
+ if (traceId && requestId) {
2533
+ throw new InputError("Provide either trace id or --request-id, not both.");
2534
+ }
2535
+ if (requestId) return { requestId };
2536
+ if (traceId) return traceId;
2537
+ throw new InputError("Provide a trace id or --request-id.");
2538
+ }
2282
2539
 
2283
2540
  // src/commands/vega.ts
2284
- import { Command as Command15 } from "commander";
2541
+ import { Command as Command16 } from "commander";
2542
+ var int12 = (v) => Number.parseInt(v, 10);
2543
+ var parsePairs2 = (raw) => {
2544
+ if (!raw) return void 0;
2545
+ return raw.split(",").map((part) => {
2546
+ const idx = part.indexOf("=");
2547
+ if (idx < 1) throw new InputError("--extension must be key=value[,key=value]");
2548
+ return { key: part.slice(0, idx).trim(), value: part.slice(idx + 1).trim() };
2549
+ }).filter((p) => p.key.length > 0);
2550
+ };
2285
2551
  function vegaCommand() {
2286
- const vega = new Command15("vega").description(
2552
+ const vega = new Command16("vega").description(
2287
2553
  "Vega observability \u2014 catalog, resources, index build tasks"
2288
2554
  );
2289
2555
  const catalog = vega.command("catalog").description("Catalog entries");
2290
- catalog.command("list").description("List catalog entries").option("--limit <n>", "page size", (v) => Number.parseInt(v, 10), DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", (v) => Number.parseInt(v, 10), 0).action(async (_opts, cmd) => {
2556
+ catalog.command("list").description("List catalog entries").option("--limit <n>", "page size", (v) => Number.parseInt(v, 10), DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", (v) => Number.parseInt(v, 10), 0).option("--name <s>", "filter by name").option("--tag <s>", "filter by tag").option("--type <type>", "filter by catalog type: physical | logical").option("--enabled <bool>", "filter by enabled state").option("--health-check-status <s>", "filter by health status").option("--include-extensions", "include all extension key/value pairs").option("--include-extension-keys <keys>", "include selected extension keys").option("--extension <k=v,...>", "filter by extension key/value pairs").option("--sort <field>", "sort field: name | create_time | update_time").option("--direction <dir>", "sort direction: asc | desc").action(async (_opts, cmd) => {
2291
2557
  const o = cmd.optsWithGlobals();
2292
- const data = await clientFrom(cmd).vega.catalogs({ limit: o.limit, offset: o.offset });
2558
+ const data = await clientFrom(cmd).vega.catalogs({
2559
+ limit: o.limit,
2560
+ offset: o.offset,
2561
+ name: o.name,
2562
+ tag: o.tag,
2563
+ type: o.type,
2564
+ enabled: o.enabled === void 0 ? void 0 : o.enabled === "true",
2565
+ healthCheckStatus: o.healthCheckStatus,
2566
+ includeExtensions: o.includeExtensions,
2567
+ includeExtensionKeys: o.includeExtensionKeys,
2568
+ extensionPairs: parsePairs2(o.extension),
2569
+ sort: o.sort,
2570
+ direction: o.direction
2571
+ });
2293
2572
  printJson(data, outputOptions(cmd));
2294
2573
  });
2295
2574
  catalog.command("get <id>").description("Get a catalog by id").action(async (id, _opts, cmd) => {
2296
2575
  printJson(await clientFrom(cmd).vega.getCatalog(id), outputOptions(cmd));
2297
2576
  });
2298
- catalog.command("resources <id>").description("List resources under a catalog").option("--category <c>", "filter by category (e.g. table)").action(async (id, opts, cmd) => {
2299
- printJson(await clientFrom(cmd).vega.catalogResources(id, opts.category), outputOptions(cmd));
2577
+ catalog.command("resources <id>").description("List resources under a catalog").option("--category <c>", "filter by category (e.g. table)").option("--limit <n>", "page size (backend default 20, max 1000; -1 = all)", int12).option("--offset <n>", "page offset", int12, 0).action(async (id, opts, cmd) => {
2578
+ printJson(
2579
+ await clientFrom(cmd).vega.catalogResources(id, opts.category, opts.limit, opts.offset),
2580
+ outputOptions(cmd)
2581
+ );
2300
2582
  });
2301
2583
  catalog.command("health <ids...>").description("Health-status for one or more catalogs").action(async (ids, _opts, cmd) => {
2302
2584
  printJson(await clientFrom(cmd).vega.catalogHealth(ids), outputOptions(cmd));
2303
2585
  });
2304
- catalog.command("create").description("Create a catalog (data source)").requiredOption("--name <s>", "catalog name").requiredOption("--connector-type <s>", "connector type (e.g. mysql)").requiredOption("--connector-config <json>", "connector config JSON").option("--tags <t1,t2>", "comma-separated tags").option("--description <s>", "description").option("--enabled", "create enabled (default: disabled)").action(async (opts, cmd) => {
2586
+ catalog.command("create").description("Create a catalog (data source)").requiredOption("--name <s>", "catalog name").requiredOption("--connector-type <s>", "connector type (e.g. mysql)").requiredOption("--connector-config <json>", "connector config JSON").option("--id <id>", "explicit catalog id").option("--tags <t1,t2>", "comma-separated tags").option("--description <s>", "description").option("--enabled", "create enabled (default: disabled)").option("--internal", "create an internal catalog").option("--extensions <json>", "extension key/value JSON object").action(async (opts, cmd) => {
2305
2587
  let connectorConfig;
2306
2588
  try {
2307
2589
  connectorConfig = JSON.parse(opts.connectorConfig);
2308
2590
  } catch {
2309
2591
  throw new Error("--connector-config must be valid JSON");
2310
2592
  }
2593
+ const extensions = opts.extensions ? JSON.parse(opts.extensions) : void 0;
2311
2594
  printJson(
2312
2595
  await clientFrom(cmd).vega.createCatalog({
2596
+ id: opts.id,
2313
2597
  name: opts.name,
2314
2598
  connectorType: opts.connectorType,
2315
2599
  connectorConfig,
2316
2600
  tags: opts.tags ? String(opts.tags).split(",").map((t) => t.trim()).filter(Boolean) : void 0,
2317
2601
  description: opts.description,
2318
- enabled: opts.enabled ? true : void 0
2602
+ enabled: opts.enabled ? true : void 0,
2603
+ internal: opts.internal ? true : void 0,
2604
+ extensions
2605
+ }),
2606
+ outputOptions(cmd)
2607
+ );
2608
+ });
2609
+ catalog.command("update <id>").description("Update a catalog").option("--name <s>", "catalog name").option("--connector-type <s>", "connector type").option("--connector-config <json>", "connector config JSON").option("--tags <t1,t2>", "comma-separated tags").option("--description <s>", "description").option("--enabled <bool>", "enabled state").option("--extensions <json>", "extension key/value JSON object").action(async (id, opts, cmd) => {
2610
+ const connectorConfig = opts.connectorConfig ? JSON.parse(opts.connectorConfig) : void 0;
2611
+ const extensions = opts.extensions ? JSON.parse(opts.extensions) : void 0;
2612
+ printJson(
2613
+ await clientFrom(cmd).vega.updateCatalog(id, {
2614
+ name: opts.name,
2615
+ connectorType: opts.connectorType,
2616
+ connectorConfig,
2617
+ tags: opts.tags ? String(opts.tags).split(",").map((t) => t.trim()).filter(Boolean) : void 0,
2618
+ description: opts.description,
2619
+ enabled: opts.enabled === void 0 ? void 0 : opts.enabled === "true",
2620
+ extensions
2319
2621
  }),
2320
2622
  outputOptions(cmd)
2321
2623
  );
@@ -2323,6 +2625,15 @@ function vegaCommand() {
2323
2625
  catalog.command("enable <id>").description("Enable a catalog (required before discovery)").action(async (id, _opts, cmd) => {
2324
2626
  printJson(await clientFrom(cmd).vega.enableCatalog(id), outputOptions(cmd));
2325
2627
  });
2628
+ catalog.command("disable <id>").description("Disable a catalog").action(async (id, _opts, cmd) => {
2629
+ printJson(await clientFrom(cmd).vega.disableCatalog(id), outputOptions(cmd));
2630
+ });
2631
+ catalog.command("delete <id>").description("Delete a catalog").action(async (id, _opts, cmd) => {
2632
+ printJson(await clientFrom(cmd).vega.deleteCatalog(id), outputOptions(cmd));
2633
+ });
2634
+ catalog.command("test-connection <id>").description("Test a catalog connection").action(async (id, _opts, cmd) => {
2635
+ printJson(await clientFrom(cmd).vega.testCatalogConnection(id), outputOptions(cmd));
2636
+ });
2326
2637
  catalog.command("discover <id>").description("Trigger catalog resource discovery").option("--wait", "wait for discovery to complete").action(async (id, opts, cmd) => {
2327
2638
  printJson(
2328
2639
  await clientFrom(cmd).vega.discoverCatalog(id, Boolean(opts.wait)),
@@ -2336,13 +2647,67 @@ function vegaCommand() {
2336
2647
  connector.command("get <type>").description("Get a connector type").action(async (type, _opts, cmd) => {
2337
2648
  printJson(await clientFrom(cmd).vega.connectorType(type), outputOptions(cmd));
2338
2649
  });
2650
+ vega.command("sql").description("Run SQL / OpenSearch DSL directly against a vega-backend data source").option(
2651
+ "--query <sql>",
2652
+ "SQL string; reference a resource with a {{<resource-id>}} placeholder"
2653
+ ).option("--input-dialect <dialect>", "SQL input dialect: postgres | mysql | trino | duckdb").option("--paging-mode <mode>", "paging mode: single | cursor").option("--limit <n>", "page size (cursor mode requires it)", int12).option("--offset <n>", "first-page offset", int12).option("--keep-alive-sec <s>", "cursor keep-alive in seconds (60\u20133600)", int12).option("--cursor <cursor>", "opaque cursor returned by the previous page").option("--need-total", "include the complete total count").option("--query-timeout-sec <s>", "query timeout in seconds (1\u20133600)", int12).option(
2654
+ "-d, --data <json>",
2655
+ "full request body as JSON (advanced; wins over individual query flags)"
2656
+ ).action(async (opts, cmd) => {
2657
+ let body;
2658
+ if (opts.data) {
2659
+ try {
2660
+ body = JSON.parse(opts.data);
2661
+ } catch {
2662
+ throw new InputError("--data must be valid JSON");
2663
+ }
2664
+ } else if (opts.cursor) {
2665
+ if (opts.query || opts.inputDialect || opts.pagingMode || opts.limit !== void 0 || opts.offset !== void 0 || opts.keepAliveSec !== void 0 || opts.queryTimeoutSec !== void 0) {
2666
+ throw new InputError("--cursor cannot be combined with initial-query options");
2667
+ }
2668
+ body = {
2669
+ paging: { cursor: opts.cursor },
2670
+ ...opts.needTotal ? { need_total: true } : {}
2671
+ };
2672
+ } else {
2673
+ if (!opts.query) {
2674
+ throw new InputError("Provide --query, --cursor, or --data.");
2675
+ }
2676
+ if (opts.pagingMode === "cursor" && opts.limit === void 0) {
2677
+ throw new InputError("--limit is required when --paging-mode cursor");
2678
+ }
2679
+ const paging = {
2680
+ ...opts.pagingMode ? { mode: opts.pagingMode } : {},
2681
+ ...opts.limit !== void 0 ? { limit: opts.limit } : {},
2682
+ ...opts.offset !== void 0 ? { offset: opts.offset } : {},
2683
+ ...opts.keepAliveSec !== void 0 ? { keep_alive_sec: opts.keepAliveSec } : {}
2684
+ };
2685
+ body = {
2686
+ query: opts.query,
2687
+ query_format: "sql",
2688
+ ...opts.inputDialect ? { input_dialect: opts.inputDialect } : {},
2689
+ ...Object.keys(paging).length ? { paging } : {},
2690
+ ...opts.needTotal ? { need_total: true } : {},
2691
+ ...opts.queryTimeoutSec !== void 0 ? { query_timeout_sec: opts.queryTimeoutSec } : {}
2692
+ };
2693
+ }
2694
+ printJson(await clientFrom(cmd).vega.sql(body), outputOptions(cmd));
2695
+ });
2339
2696
  const resource = vega.command("resource").description("Vega-backend resources");
2340
- resource.command("list").description("List resources").option("--datasource-id <id>", "filter by catalog/datasource id").option("--catalog-id <id>", "alias of --datasource-id").option("--type <category>", "resource category").option("--category <category>", "alias of --type").option("--limit <n>", "page size", (v) => Number.parseInt(v, 10), DEFAULT_LIST_LIMIT).action(async (opts, cmd) => {
2697
+ resource.command("list").description("List resources").option("--datasource-id <id>", "filter by catalog/datasource id").option("--catalog-id <id>", "alias of --datasource-id").option("--type <category>", "resource category").option("--category <category>", "alias of --type").option("--status <status>", "filter by status").option("--database <name>", "filter by database").option("--limit <n>", "page size", (v) => Number.parseInt(v, 10), DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", int12, 0).option("--include-extensions", "include all extension key/value pairs").option("--include-extension-keys <keys>", "include selected extension keys").option("--extension <k=v,...>", "filter by extension key/value pairs").option("--sort <field>", "sort field: name | create_time | update_time").option("--direction <dir>", "sort direction: asc | desc").action(async (opts, cmd) => {
2341
2698
  printJson(
2342
2699
  await clientFrom(cmd).resource.list({
2343
2700
  datasourceId: opts.datasourceId ?? opts.catalogId,
2344
2701
  category: opts.type ?? opts.category,
2345
- limit: opts.limit
2702
+ status: opts.status,
2703
+ database: opts.database,
2704
+ limit: opts.limit,
2705
+ offset: opts.offset,
2706
+ includeExtensions: opts.includeExtensions,
2707
+ includeExtensionKeys: opts.includeExtensionKeys,
2708
+ extensionPairs: parsePairs2(opts.extension),
2709
+ sort: opts.sort,
2710
+ direction: opts.direction
2346
2711
  }),
2347
2712
  outputOptions(cmd)
2348
2713
  );
@@ -2360,16 +2725,25 @@ function vegaCommand() {
2360
2725
  dataset.command("build <resource-id>").description("Build a resource's index (creates a BuildTask)").requiredOption("--mode <mode>", "build mode: batch | streaming").option("--embedding-fields <list>", "comma-separated fields to vectorize").option(
2361
2726
  "--build-key-fields <list>",
2362
2727
  "comma-separated key fields (batch: time; streaming: row id)"
2363
- ).option("--embedding-model <id>", "embedding model id (default if omitted)").option("--model-dimensions <n>", "vector dimensions", (v) => Number.parseInt(v, 10)).option("--wait", "poll until the build reaches a terminal state").option("--timeout <s>", "wait timeout in seconds", (v) => Number.parseInt(v, 10), 300).action(async (resourceId, _opts, cmd) => {
2728
+ ).option("--embedding-model <id>", "default embedding model name/id").option("--fulltext-fields <list>", "comma-separated fields for fulltext index").option("--fulltext-analyzer <name>", "fulltext analyzer").option("--execute-type <type>", "batch execution type: incremental | full").option("--wait", "poll until the build reaches a terminal state").option("--timeout <s>", "wait timeout in seconds", (v) => Number.parseInt(v, 10), 300).action(async (resourceId, _opts, cmd) => {
2364
2729
  const o = cmd.optsWithGlobals();
2730
+ const embeddingFields = csv(o.embeddingFields);
2731
+ const buildKeyFields = csv(o.buildKeyFields);
2732
+ const fulltextFields = csv(o.fulltextFields);
2733
+ if (embeddingFields || buildKeyFields || o.embeddingModel || fulltextFields || o.fulltextAnalyzer) {
2734
+ await clientFrom(cmd).resource.configureIndex(resourceId, {
2735
+ embeddingFields,
2736
+ buildKeyFields,
2737
+ embeddingModel: o.embeddingModel,
2738
+ fulltextFields,
2739
+ fulltextAnalyzer: o.fulltextAnalyzer
2740
+ });
2741
+ }
2365
2742
  const task = await clientFrom(cmd).vega.build(
2366
2743
  {
2367
2744
  resource_id: resourceId,
2368
2745
  mode: o.mode,
2369
- embedding_fields: csv(o.embeddingFields),
2370
- build_key_fields: csv(o.buildKeyFields),
2371
- embedding_model: o.embeddingModel,
2372
- model_dimensions: o.modelDimensions
2746
+ execute_type: o.executeType
2373
2747
  },
2374
2748
  { wait: Boolean(o.wait), timeoutMs: o.timeout * 1e3 }
2375
2749
  );
@@ -2379,15 +2753,50 @@ function vegaCommand() {
2379
2753
  const task = await clientFrom(cmd).vega.buildStatus(taskId);
2380
2754
  printJson(task, outputOptions(cmd));
2381
2755
  });
2756
+ dataset.command("build-list").description("List BuildTasks").option("--limit <n>", "page size", int12, DEFAULT_LIST_LIMIT).option("--offset <n>", "page offset", int12, 0).option("--resource-id <id>", "filter by resource id").option("--catalog-id <id>", "filter by catalog id").option("--status <status>", "comma-separated statuses").option("--active", "only running/init tasks").option("--mode <mode>", "filter by mode: batch | streaming").option("--order-by <field>", "default | created_at | updated_at | status | mode").option("--order <dir>", "asc | desc").action(async (opts, cmd) => {
2757
+ printJson(
2758
+ await clientFrom(cmd).vega.buildTasks({
2759
+ limit: opts.limit,
2760
+ offset: opts.offset,
2761
+ resourceId: opts.resourceId,
2762
+ catalogId: opts.catalogId,
2763
+ status: opts.status,
2764
+ active: opts.active,
2765
+ mode: opts.mode,
2766
+ orderBy: opts.orderBy,
2767
+ order: opts.order
2768
+ }),
2769
+ outputOptions(cmd)
2770
+ );
2771
+ });
2772
+ dataset.command("build-start <task-id>").description("Start a BuildTask").option("--reset", "restart from the beginning").action(async (taskId, opts, cmd) => {
2773
+ printJson(
2774
+ await clientFrom(cmd).vega.startBuildTask(taskId, { reset: opts.reset }),
2775
+ outputOptions(cmd)
2776
+ );
2777
+ });
2778
+ dataset.command("build-stop <task-id>").description("Stop a BuildTask").action(async (taskId, _opts, cmd) => {
2779
+ printJson(await clientFrom(cmd).vega.stopBuildTask(taskId), outputOptions(cmd));
2780
+ });
2781
+ dataset.command("build-delete <ids...>").description("Delete one or more BuildTasks").option("--ignore-missing", "ignore missing task ids").option("--delete-active-index", "delete active indexes too").action(async (ids, opts, cmd) => {
2782
+ printJson(
2783
+ await clientFrom(cmd).vega.deleteBuildTasks(ids, {
2784
+ ignoreMissing: opts.ignoreMissing,
2785
+ deleteActiveIndex: opts.deleteActiveIndex
2786
+ }),
2787
+ outputOptions(cmd)
2788
+ );
2789
+ });
2382
2790
  return group(vega, "AI DATA PLATFORM");
2383
2791
  }
2384
2792
 
2385
2793
  // src/cli.ts
2386
- var program = new Command16();
2387
- program.name("openbkn").description("Operate the BKN platform from the CLI").version(package_default.version, "-V, --version", "output the version number").option("--base-url <url>", "platform base URL (env: BKN_BASE_URL)").option("--token <value>", "access token (env: BKN_TOKEN)").option("--user <id|name>", "use specific user credentials (env: BKN_USER)").option("--json", "machine-readable JSON output").option("--compact", "single-line JSON output").option("--full", "human view: show all columns (default trims to the key ones)").option("--biz-domain <s>", "business domain (alias: -bd)").option("-k, --insecure", "skip TLS verification (dev / self-signed only)").showHelpAfterError();
2794
+ var program = new Command17();
2795
+ program.name("openbkn").description("Operate the BKN platform from the CLI").version(package_default.version, "-V, --version", "output the version number").option("--base-url <url>", "platform base URL (env: BKN_BASE_URL)").option("--token <value>", "access token (env: BKN_TOKEN)").option("--user <id|name>", "use specific user credentials (env: BKN_USER)").option("--json", "machine-readable JSON output").option("--compact", "single-line JSON output").option("--full", "human view: show all columns (default trims to the key ones)").option("--biz-domain <s>", "business domain (alias: -bd)").option("--conversation-id <id>", "BKN Trace conversation id (env: BKN_CONVERSATION_ID)").option("--interaction-id <id>", "BKN Trace interaction id (env: BKN_INTERACTION_ID)").option("-k, --insecure", "skip TLS verification (dev / self-signed only)").showHelpAfterError();
2388
2796
  program.addCommand(authCommand());
2389
2797
  program.addCommand(callCommand());
2390
2798
  program.addCommand(configCommand());
2799
+ program.addCommand(appkeyCommand());
2391
2800
  program.addCommand(vegaCommand());
2392
2801
  program.addCommand(bknCommand());
2393
2802
  program.addCommand(resourceCommand());