@senticor/hive 1.87.2 → 1.88.1

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.
Files changed (2) hide show
  1. package/hive.cjs +173 -23
  2. package/package.json +1 -1
package/hive.cjs CHANGED
@@ -8630,6 +8630,21 @@ var ROLE_KEY_RE = /^[a-z0-9][a-z0-9._:-]{0,63}$/;
8630
8630
  function hasTenantAudienceDelimiter(displayKey) {
8631
8631
  return /[\s,]/.test(String(displayKey || "").trim());
8632
8632
  }
8633
+ var MAX_TENANT_DISPLAY_NAME_LENGTH = 200;
8634
+ var CONTROL_CHARS = new RegExp("\\p{Cc}", "u");
8635
+ function parseOptionalTenantDisplayName(value, field = "displayName") {
8636
+ if (value === void 0) return void 0;
8637
+ if (value === null) return null;
8638
+ if (typeof value !== "string") throw new Error(`${field} must be a string or null`);
8639
+ const name = value.trim();
8640
+ if (!name) throw new Error(`${field} must be a non-empty string (send null to clear it)`);
8641
+ if (CONTROL_CHARS.test(name)) throw new Error(`${field} must not contain control characters (line breaks, tabs, NUL)`);
8642
+ const length = [...name].length;
8643
+ if (length > MAX_TENANT_DISPLAY_NAME_LENGTH) {
8644
+ throw new Error(`${field} is too long (${length} characters); at most ${MAX_TENANT_DISPLAY_NAME_LENGTH}`);
8645
+ }
8646
+ return name;
8647
+ }
8633
8648
 
8634
8649
  // src/lib/client.ts
8635
8650
  init_cjs_shims();
@@ -8686,6 +8701,14 @@ function promptText(query) {
8686
8701
  });
8687
8702
  });
8688
8703
  }
8704
+ var TOKEN_ENV_VARS = ["HIVE_TOKEN", "HIVE_TEST_TOKEN", "HIVE_BEARER_TOKEN"];
8705
+ function envToken(env = process.env) {
8706
+ for (const variable of TOKEN_ENV_VARS) {
8707
+ const token = env[variable];
8708
+ if (token) return { token, variable };
8709
+ }
8710
+ return null;
8711
+ }
8689
8712
  function parseJwt(token) {
8690
8713
  try {
8691
8714
  const parts = token.split(".");
@@ -9375,7 +9398,7 @@ var HiveClient = class {
9375
9398
  const headers = { accept };
9376
9399
  if (this.tenant) headers["x-hive-tenant"] = this.tenant;
9377
9400
  try {
9378
- const token = process.env.HIVE_TOKEN || process.env.HIVE_TEST_TOKEN || process.env.HIVE_BEARER_TOKEN || await getValidToken();
9401
+ const token = envToken()?.token || await getValidToken();
9379
9402
  if (token) headers["authorization"] = `Bearer ${token}`;
9380
9403
  } catch (e) {
9381
9404
  if (this.verbose) console.error("Warning: Could not fetch auth token", e.message);
@@ -9654,6 +9677,7 @@ var CliCommandError = class extends Error {
9654
9677
  remediation;
9655
9678
  tenant;
9656
9679
  problemType;
9680
+ details;
9657
9681
  constructor(symbolicCode, exitCode, message, options) {
9658
9682
  super(message, options);
9659
9683
  this.name = "CliCommandError";
@@ -9662,6 +9686,7 @@ var CliCommandError = class extends Error {
9662
9686
  this.remediation = options?.remediation;
9663
9687
  this.tenant = options?.tenant;
9664
9688
  this.problemType = options?.problemType;
9689
+ this.details = options?.details;
9665
9690
  }
9666
9691
  };
9667
9692
  function commandError(symbolicCode, exitCode, message, options) {
@@ -9693,6 +9718,16 @@ function remoteProblemType(data) {
9693
9718
  const body = data;
9694
9719
  return typeof body.type === "string" && typeof body.title === "string" && typeof body.status === "number" ? body.type : void 0;
9695
9720
  }
9721
+ function remoteProblemDetails(data) {
9722
+ if (!remoteProblemType(data)) return void 0;
9723
+ const raw = data.details;
9724
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
9725
+ const out = {};
9726
+ for (const [name, value] of Object.entries(raw)) {
9727
+ if (value === null || ["string", "number", "boolean"].includes(typeof value)) out[name] = value;
9728
+ }
9729
+ return Object.keys(out).length ? out : void 0;
9730
+ }
9696
9731
  function fieldText(value) {
9697
9732
  if (value === null || value === void 0) return "";
9698
9733
  if (typeof value === "object") {
@@ -9737,11 +9772,17 @@ function remoteFailureError(status2, data, action, exitCode = exitCodeForStatus(
9737
9772
  const remediation = remoteFailureRemediation(data);
9738
9773
  const tenant = remoteFailureTenant(data);
9739
9774
  const problemType = remoteProblemType(data);
9775
+ const details = remoteProblemDetails(data);
9740
9776
  return commandError(
9741
9777
  "REMOTE_FAILED",
9742
9778
  exitCode,
9743
9779
  `${action} failed${status2 ? ` (HTTP ${status2})` : ""}: ${remoteFailureText(data)}${remediation ? ` \u2014 ${remediation}` : ""}`,
9744
- remediation || tenant || problemType ? { ...remediation ? { remediation } : {}, ...tenant ? { tenant } : {}, ...problemType ? { problemType } : {} } : void 0
9780
+ remediation || tenant || problemType || details ? {
9781
+ ...remediation ? { remediation } : {},
9782
+ ...tenant ? { tenant } : {},
9783
+ ...problemType ? { problemType } : {},
9784
+ ...details ? { details } : {}
9785
+ } : void 0
9745
9786
  );
9746
9787
  }
9747
9788
  function remoteFailureText(data) {
@@ -9751,7 +9792,10 @@ function remoteFailureText(data) {
9751
9792
  const parts = [code, message, ...isProblem ? [] : [fieldText(body?.detail)]].filter(Boolean);
9752
9793
  const fields = isProblem ? [] : schemaErrorFields(data);
9753
9794
  if (fields.length) parts.push(`(offending field${fields.length > 1 ? "s" : ""}: ${fields.join(", ")})`);
9754
- return [...new Set(parts)].join(": ") || "unexpected response";
9795
+ const text = [...new Set(parts)].join(": ") || "unexpected response";
9796
+ const details = remoteProblemDetails(data);
9797
+ if (!details) return text;
9798
+ return `${text} (${Object.entries(details).map(([name, value]) => `${name}: ${JSON.stringify(value)}`).join(", ")})`;
9755
9799
  }
9756
9800
  function toStructuredError(err) {
9757
9801
  const e = err;
@@ -9764,7 +9808,8 @@ function toStructuredError(err) {
9764
9808
  message,
9765
9809
  ...e?.remediation ? { remediation: e.remediation } : {},
9766
9810
  ...e?.problemType ? { type: e.problemType } : {},
9767
- ...e?.tenant ? { tenant: e.tenant } : {}
9811
+ ...e?.tenant ? { tenant: e.tenant } : {},
9812
+ ...e?.details ? { details: e.details } : {}
9768
9813
  }
9769
9814
  };
9770
9815
  }
@@ -9815,11 +9860,19 @@ function installRemoteFailureExit() {
9815
9860
  const remediation = remoteFailureRemediation(failure2.body) ?? (failure2.status === 401 ? "Run 'hive login' to authenticate, or set HIVE_TOKEN." : void 0);
9816
9861
  const tenant = remoteFailureTenant(failure2.body);
9817
9862
  const problemType = remoteProblemType(failure2.body);
9863
+ const details = remoteProblemDetails(failure2.body);
9818
9864
  const message = `${failure2.method} ${failure2.path} failed${failure2.status ? ` (HTTP ${failure2.status})` : ""}: ${remoteFailureText(failure2.body)}`;
9819
9865
  if (isJsonMode()) {
9820
9866
  console.error(JSON.stringify({
9821
9867
  ok: false,
9822
- error: { code: symbolic, message, ...problemType ? { type: problemType } : {}, ...remediation ? { remediation } : {}, ...tenant ? { tenant } : {} }
9868
+ error: {
9869
+ code: symbolic,
9870
+ message,
9871
+ ...problemType ? { type: problemType } : {},
9872
+ ...remediation ? { remediation } : {},
9873
+ ...tenant ? { tenant } : {},
9874
+ ...details ? { details } : {}
9875
+ }
9823
9876
  }));
9824
9877
  } else {
9825
9878
  console.error(`\x1B[31mError:\x1B[0m ${symbolic}: ${message}`);
@@ -10376,22 +10429,22 @@ var artifactName = injectedString(
10376
10429
  true ? "hive-cli" : void 0
10377
10430
  ) || String(process.env.HIVE_CLI_ARTIFACT_NAME || "hive-cli").trim() || "hive-cli";
10378
10431
  var packageVersion = injectedString(
10379
- true ? "1.87.2" : void 0
10432
+ true ? "1.88.1" : void 0
10380
10433
  ) || String(process.env.HIVE_CLI_PACKAGE_VERSION || "").trim() || readPackageVersion();
10381
10434
  var releaseVersion = injectedString(
10382
- true ? "1.87.2" : void 0
10435
+ true ? "1.88.1" : void 0
10383
10436
  ) || String(process.env.HIVE_CLI_RELEASE_VERSION || "").trim() || packageVersion || "dev";
10384
10437
  var releaseChannel = injectedString(
10385
10438
  true ? "final" : void 0
10386
10439
  ) || String(process.env.HIVE_CLI_RELEASE_CHANNEL || "").trim() || (releaseVersion.includes("-rc.") ? "rc" : releaseVersion === "dev" ? "dev" : "final");
10387
10440
  var buildCommit = injectedString(
10388
- true ? "a96123fb3acccd513fb8e7aa2acd3767c46e56a2" : void 0
10441
+ true ? "0389229ca319d58530b1a250cc0eaed6c50ab3e2" : void 0
10389
10442
  ) || String(process.env.HIVE_CLI_BUILD_COMMIT || "").trim() || "unknown";
10390
10443
  var buildTimestamp = injectedString(
10391
- true ? "2026-10-29T21:57:37Z" : void 0
10444
+ true ? "2026-10-30T08:47:32Z" : void 0
10392
10445
  ) || String(process.env.HIVE_CLI_BUILD_TIMESTAMP || "").trim() || "unknown";
10393
10446
  var ociRef = injectedString(
10394
- true ? "registry.onstackit.cloud/senticor/hive-cli:1.87.2" : void 0
10447
+ true ? "registry.onstackit.cloud/senticor/hive-cli:1.88.1" : void 0
10395
10448
  ) || String(process.env.HIVE_CLI_OCI_REF || "").trim() || `registry.onstackit.cloud/senticor/${artifactName}:${releaseVersion}`;
10396
10449
  var RELEASE_INFO = Object.freeze({
10397
10450
  packageVersion,
@@ -11386,21 +11439,64 @@ var logout = defineCommand({
11386
11439
  console.log("Signed out. Local tokens deleted.");
11387
11440
  }
11388
11441
  });
11442
+ var claimText = (v) => typeof v === "string" && v ? v : null;
11443
+ function currentSession() {
11444
+ const env = envToken();
11445
+ if (env) {
11446
+ const claims2 = parseJwt(env.token);
11447
+ const exp = typeof claims2?.exp === "number" ? claims2.exp * 1e3 : null;
11448
+ return {
11449
+ loggedIn: true,
11450
+ source: "env",
11451
+ variable: env.variable,
11452
+ verified: false,
11453
+ subject: claimText(claims2?.sub),
11454
+ user: claimText(claims2?.preferred_username) ?? claimText(claims2?.email),
11455
+ issuer: claimText(claims2?.iss),
11456
+ expiresAt: exp === null ? null : new Date(exp).toISOString(),
11457
+ expired: exp === null ? null : exp <= Date.now()
11458
+ };
11459
+ }
11460
+ const creds = getStoredCredentials();
11461
+ if (!creds || !creds.access_token) return null;
11462
+ const expiresAt = Number.isFinite(creds.expires_at) ? creds.expires_at : null;
11463
+ return {
11464
+ loggedIn: true,
11465
+ source: "stored",
11466
+ variable: null,
11467
+ verified: false,
11468
+ subject: claimText(parseJwt(creds.access_token)?.sub),
11469
+ user: creds.user ?? null,
11470
+ issuer: creds.issuer ?? null,
11471
+ expiresAt: expiresAt === null ? null : new Date(expiresAt).toISOString(),
11472
+ expired: expiresAt === null ? null : expiresAt <= Date.now()
11473
+ };
11474
+ }
11389
11475
  var whoami = defineCommand({
11390
- meta: { name: "whoami", description: "Show active session info" },
11476
+ meta: { name: "whoami", description: "Show the session the next command uses (HIVE_TOKEN or the stored login)" },
11391
11477
  args: { ...globalArgs },
11392
- run() {
11393
- const creds = getStoredCredentials();
11394
- if (!creds || !creds.access_token) {
11395
- console.log("\x1B[33mNot logged in. Run 'hive login' to authenticate.\x1B[0m");
11478
+ run({ args }) {
11479
+ const asJson = args.json === true || String(args.format ?? "").toLowerCase() === "json";
11480
+ const session = currentSession();
11481
+ if (!session) {
11482
+ if (asJson) console.log(JSON.stringify({ loggedIn: false }, null, 2));
11483
+ else console.log("\x1B[33mNot logged in. Run 'hive login' to authenticate, or set HIVE_TOKEN.\x1B[0m");
11396
11484
  process.exit(1);
11397
11485
  }
11398
- const left = Math.floor((creds.expires_at - Date.now()) / 1e3);
11399
- console.log(`User: \x1B[36m${creds.user}\x1B[0m`);
11400
- console.log(`Issuer: ${creds.issuer}`);
11401
- console.log(
11402
- `Status: ${left > 0 ? `\x1B[32mActive\x1B[0m (expires in ${Math.floor(left / 60)} min)` : "\x1B[31mExpired\x1B[0m"}`
11403
- );
11486
+ if (asJson) {
11487
+ console.log(JSON.stringify(session, null, 2));
11488
+ } else {
11489
+ const unknown2 = "(not in token)";
11490
+ const left = session.expiresAt === null ? null : Math.floor((Date.parse(session.expiresAt) - Date.now()) / 1e3);
11491
+ console.log(`User: \x1B[36m${session.user ?? unknown2}\x1B[0m`);
11492
+ if (session.subject) console.log(`Subject: ${session.subject}`);
11493
+ console.log(`Issuer: ${session.issuer ?? unknown2}`);
11494
+ console.log(
11495
+ `Status: ${left === null ? "Expiry unknown" : left > 0 ? `\x1B[32mActive\x1B[0m (expires in ${Math.floor(left / 60)} min)` : "\x1B[31mExpired\x1B[0m"}`
11496
+ );
11497
+ console.log(session.source === "env" ? `Source: env (${session.variable}); claims read from the token, not verified` : "Source: stored login (hive login)");
11498
+ }
11499
+ if (session.source === "env" && session.expired === true) process.exit(1);
11404
11500
  }
11405
11501
  });
11406
11502
 
@@ -32465,8 +32561,27 @@ var orgArgs = withArgs({
32465
32561
  role: { type: "string", description: "Role key (repeat as comma-separated values where supported)" },
32466
32562
  roles: { type: "string", description: "Comma-separated role keys" },
32467
32563
  reuse: { type: "boolean", description: "On already-exists, reuse the existing tenant" },
32468
- pin: { type: "boolean", description: "Pin created/reused tenant display key in ~/.hive/config.json" }
32564
+ pin: { type: "boolean", description: "Pin created/reused tenant display key in ~/.hive/config.json" },
32565
+ orgName: { type: "string", description: "The organisation's display name for choosers (a label; --display-key stays the selector)" },
32566
+ clearOrgName: { type: "boolean", description: "rename: clear the organisation's display name, so clients show the key" },
32567
+ expectOrgName: { type: "string", description: "rename: change only if the stored name is this one ('' = no name yet)" }
32469
32568
  });
32569
+ function orgNameArg(args) {
32570
+ if (args.orgName === void 0) return void 0;
32571
+ try {
32572
+ return parseOptionalTenantDisplayName(String(args.orgName), "--org-name") ?? void 0;
32573
+ } catch (err) {
32574
+ throw commandError("INVALID_ORG_NAME", 1, err.message);
32575
+ }
32576
+ }
32577
+ function orgNameApplied(tenant, requested, reused) {
32578
+ if (!reused || tenant.displayName === requested) return true;
32579
+ const key = String(tenant.displayKey || "");
32580
+ console.error(
32581
+ `Note: tenant '${key}' already exists; its display name was not changed. Run: hive org rename --tenant-key ${key} --org-name ${JSON.stringify(requested)}`
32582
+ );
32583
+ return false;
32584
+ }
32470
32585
  function ensureOk(status2, data, action) {
32471
32586
  if (isHttpOk(status2)) return;
32472
32587
  throw remoteFailureError(status2, data, action);
@@ -32733,10 +32848,12 @@ var org = defineCommand({
32733
32848
  printContextNotice(args, { adminScope: true });
32734
32849
  req(args, "displayKey");
32735
32850
  assertCanonicalTenantSelector(String(args.displayKey), "--display-key");
32851
+ const orgName = orgNameArg(args);
32736
32852
  const body = {
32737
32853
  kind: args.kind || "organization",
32738
32854
  displayKey: args.displayKey
32739
32855
  };
32856
+ if (orgName !== void 0) body.displayName = orgName;
32740
32857
  applyRuntimeConfig(args, body);
32741
32858
  if (args.ownerPrincipalId) body.ownerPrincipalId = args.ownerPrincipalId;
32742
32859
  const requestedKind = String(body.kind || "organization").trim();
@@ -32777,7 +32894,37 @@ var org = defineCommand({
32777
32894
  const pinKey = canonicalPinKey(tenant);
32778
32895
  const pinnable = Boolean(args.pin && pinKey);
32779
32896
  if (pinnable && pinKey) saveConfig({ tenant: pinKey });
32780
- return output({ ...recordOf2(res.data), reused, pinned: pinnable }, fmt);
32897
+ const named = orgName === void 0 ? {} : { orgNameApplied: orgNameApplied(tenant, orgName, reused) };
32898
+ return output({ ...recordOf2(res.data), reused, pinned: pinnable, ...named }, fmt);
32899
+ }
32900
+ }),
32901
+ rename: defineCommand({
32902
+ meta: {
32903
+ name: "rename",
32904
+ description: "Set or clear an organisation's display name (--org-name or --clear-org-name; [--expect-org-name])"
32905
+ },
32906
+ args: orgArgs,
32907
+ async run({ args }) {
32908
+ printContextNotice(args, { adminScope: true });
32909
+ const name = orgNameArg(args);
32910
+ if (args.clearOrgName && name !== void 0) {
32911
+ throw commandError("CONFLICTING_ARGS", EXIT_GUARDRAIL, "Pass --org-name or --clear-org-name, not both.");
32912
+ }
32913
+ if (!args.clearOrgName && name === void 0) {
32914
+ throw commandError("ORG_NAME_REQUIRED", 1, "Pass --org-name <name>, or --clear-org-name to remove the name.");
32915
+ }
32916
+ const body = { displayName: args.clearOrgName ? null : name };
32917
+ if (args.expectOrgName !== void 0) {
32918
+ const expected = String(args.expectOrgName).trim();
32919
+ body.expectedDisplayName = expected || null;
32920
+ }
32921
+ const { tenantId } = await resolveTenantId(args);
32922
+ const { client, fmt } = adminCtx(args);
32923
+ const res = await client.patch(`/api/admin/orgs/${enc(tenantId)}`, body);
32924
+ ensureAuthorized(res.status, "Renaming an organisation");
32925
+ ensureOk(res.status, res.data, "rename organisation");
32926
+ const data = recordOf2(res.data);
32927
+ return output({ ...data, idempotent: data.changed === false }, fmt);
32781
32928
  }
32782
32929
  }),
32783
32930
  members: defineCommand({
@@ -32898,7 +33045,9 @@ var org = defineCommand({
32898
33045
  }
32899
33046
  const kind = String(args.kind || "organization").trim();
32900
33047
  const { client, fmt } = adminCtx(args);
33048
+ const orgName = orgNameArg(args);
32901
33049
  const createBody = { kind, displayKey: args.displayKey };
33050
+ if (orgName !== void 0) createBody.displayName = orgName;
32902
33051
  applyRuntimeConfig(args, createBody);
32903
33052
  if (args.ownerPrincipalId) createBody.ownerPrincipalId = args.ownerPrincipalId;
32904
33053
  let reusedTenant = false;
@@ -32947,6 +33096,7 @@ var org = defineCommand({
32947
33096
  if (!tenantId) {
32948
33097
  throw commandError("TENANT_NOT_FOUND", 1, "Tenant was created/reused but no id was returned.");
32949
33098
  }
33099
+ if (orgName !== void 0) orgNameApplied(tenant, orgName, reusedTenant);
32950
33100
  const admitBody = { email: email3, roles };
32951
33101
  if (args.displayName) admitBody.displayName = args.displayName;
32952
33102
  const admitRes = await client.post(`/api/admin/orgs/${enc(tenantId)}/members`, admitBody);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@senticor/hive",
3
- "version": "1.87.2",
3
+ "version": "1.88.1",
4
4
  "description": "Cognitive Hive OS — unified CLI",
5
5
  "type": "commonjs",
6
6
  "bin": {