@senticor/hive 1.80.2 → 1.82.0

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 +167 -26
  2. package/package.json +1 -1
package/hive.cjs CHANGED
@@ -10376,22 +10376,22 @@ var artifactName = injectedString(
10376
10376
  true ? "hive-cli" : void 0
10377
10377
  ) || String(process.env.HIVE_CLI_ARTIFACT_NAME || "hive-cli").trim() || "hive-cli";
10378
10378
  var packageVersion = injectedString(
10379
- true ? "1.80.2" : void 0
10379
+ true ? "1.82.0" : void 0
10380
10380
  ) || String(process.env.HIVE_CLI_PACKAGE_VERSION || "").trim() || readPackageVersion();
10381
10381
  var releaseVersion = injectedString(
10382
- true ? "1.80.2" : void 0
10382
+ true ? "1.82.0" : void 0
10383
10383
  ) || String(process.env.HIVE_CLI_RELEASE_VERSION || "").trim() || packageVersion || "dev";
10384
10384
  var releaseChannel = injectedString(
10385
10385
  true ? "final" : void 0
10386
10386
  ) || String(process.env.HIVE_CLI_RELEASE_CHANNEL || "").trim() || (releaseVersion.includes("-rc.") ? "rc" : releaseVersion === "dev" ? "dev" : "final");
10387
10387
  var buildCommit = injectedString(
10388
- true ? "85fa5397b257276d240289d501c571f329a3402a" : void 0
10388
+ true ? "2f846d7d534f6f999f7f38cdd33899cc544a2d4d" : void 0
10389
10389
  ) || String(process.env.HIVE_CLI_BUILD_COMMIT || "").trim() || "unknown";
10390
10390
  var buildTimestamp = injectedString(
10391
- true ? "2026-10-28T20:25:06Z" : void 0
10391
+ true ? "2026-10-28T23:24:20Z" : void 0
10392
10392
  ) || String(process.env.HIVE_CLI_BUILD_TIMESTAMP || "").trim() || "unknown";
10393
10393
  var ociRef = injectedString(
10394
- true ? "registry.onstackit.cloud/senticor/hive-cli:1.80.2" : void 0
10394
+ true ? "registry.onstackit.cloud/senticor/hive-cli:1.82.0" : void 0
10395
10395
  ) || String(process.env.HIVE_CLI_OCI_REF || "").trim() || `registry.onstackit.cloud/senticor/${artifactName}:${releaseVersion}`;
10396
10396
  var RELEASE_INFO = Object.freeze({
10397
10397
  packageVersion,
@@ -32580,6 +32580,127 @@ function canonicalPinKey(tenant) {
32580
32580
  function rolesFromArgs(args) {
32581
32581
  return [.../* @__PURE__ */ new Set([...normalizeCliList(args.roles), ...normalizeCliList(args.role)])];
32582
32582
  }
32583
+ async function listMembers(client, tenantId) {
32584
+ const res = await client.get(`/api/admin/orgs/${enc(tenantId)}/members`);
32585
+ ensureOk(res.status, res.data, "list tenant members");
32586
+ const rows = recordOf2(res.data).memberships;
32587
+ return (Array.isArray(rows) ? rows : []).map((row) => {
32588
+ const m = recordOf2(row);
32589
+ const principal = recordOf2(m.principal);
32590
+ return {
32591
+ membershipId: String(m.membershipId ?? ""),
32592
+ membershipStatus: String(m.membershipStatus ?? ""),
32593
+ roles: Array.isArray(m.roles) ? m.roles.map(String).sort() : [],
32594
+ principalId: String(principal.principalId ?? ""),
32595
+ email: String(principal.email ?? "").toLowerCase()
32596
+ };
32597
+ });
32598
+ }
32599
+ function findMember(members2, by) {
32600
+ if (by.principalId) return members2.find((m) => m.principalId === by.principalId);
32601
+ return members2.find((m) => m.email === by.email);
32602
+ }
32603
+ function memberSelector(args) {
32604
+ const principalId = String(args.principalId || "").trim();
32605
+ const email3 = String(args.email || "").trim().toLowerCase();
32606
+ if (principalId && email3) {
32607
+ throw commandError("CONFLICTING_ARGS", EXIT_GUARDRAIL, "Pass --principal-id or --email, not both.");
32608
+ }
32609
+ if (!principalId && !email3) {
32610
+ throw commandError("MEMBER_REQUIRED", 1, "Pass --email <address> or --principal-id <uuid>.");
32611
+ }
32612
+ return principalId ? { principalId } : { email: email3 };
32613
+ }
32614
+ async function requireMember(client, tenantId, args) {
32615
+ const by = memberSelector(args);
32616
+ const member = findMember(await listMembers(client, tenantId), by);
32617
+ if (!member) {
32618
+ throw commandError(
32619
+ "MEMBER_NOT_FOUND",
32620
+ 1,
32621
+ `${by.email ?? by.principalId} is not a member of tenant ${tenantId}. Run 'hive org members list'.`
32622
+ );
32623
+ }
32624
+ return member;
32625
+ }
32626
+ var without = (a, b) => a.filter((x) => !b.includes(x));
32627
+ async function forEachRole(roles, action, call) {
32628
+ const done = [];
32629
+ for (const role of roles) {
32630
+ const res = await call(role);
32631
+ if (!isHttpOk(res.status)) {
32632
+ if (done.length) {
32633
+ throw commandError(
32634
+ "PARTIAL_ROLE_CHANGE",
32635
+ 3,
32636
+ `${action} '${role}' failed (HTTP ${res.status}) after ${done.join(", ")} succeeded. Re-run with the remaining roles.`
32637
+ );
32638
+ }
32639
+ ensureOk(res.status, res.data, `${action} '${role}'`);
32640
+ }
32641
+ done.push(role);
32642
+ }
32643
+ }
32644
+ async function changeRoles(args, action) {
32645
+ printContextNotice(args, { adminScope: true });
32646
+ const { tenantId } = await resolveTenantId(args);
32647
+ const roles = rolesFromArgs(args);
32648
+ if (!roles.length) throw commandError("ROLE_REQUIRED", 1, "Pass --roles <role-a,role-b> or --role <role-key>.");
32649
+ const { client } = adminCtx(args);
32650
+ const before = await requireMember(client, tenantId, args);
32651
+ const base = `/api/admin/orgs/${enc(tenantId)}/members/${enc(before.principalId)}/roles`;
32652
+ await forEachRole(
32653
+ roles,
32654
+ `${action} tenant role`,
32655
+ (role) => action === "grant" ? client.put(base, { roleKey: role }) : client.del(`${base}/${enc(role)}`)
32656
+ );
32657
+ const after = findMember(await listMembers(client, tenantId), { principalId: before.principalId });
32658
+ const rolesAfter = after?.roles ?? [];
32659
+ const changed = action === "grant" ? without(rolesAfter, before.roles) : without(before.roles, rolesAfter);
32660
+ return {
32661
+ ok: true,
32662
+ tenantId,
32663
+ principalId: before.principalId,
32664
+ // The single-role answer's field, kept for scripts that read it.
32665
+ ...roles.length === 1 ? { roleKey: roles[0] } : {},
32666
+ roles,
32667
+ rolesBefore: before.roles,
32668
+ rolesAfter,
32669
+ [action === "grant" ? "rolesAdded" : "rolesRemoved"]: changed,
32670
+ idempotent: changed.length === 0
32671
+ };
32672
+ }
32673
+ async function changeMembership(args, target) {
32674
+ printContextNotice(args, { adminScope: true });
32675
+ const { tenantId } = await resolveTenantId(args);
32676
+ const { client } = adminCtx(args);
32677
+ const before = await requireMember(client, tenantId, args);
32678
+ const path10 = `/api/admin/orgs/${enc(tenantId)}/members`;
32679
+ let res;
32680
+ if (target === "suspended") {
32681
+ res = await client.patch(`${path10}/${enc(before.membershipId)}`, { status: "suspended" });
32682
+ } else if (target === "revoked") {
32683
+ res = await client.del(`${path10}/${enc(before.membershipId)}`);
32684
+ } else {
32685
+ if (!before.email) {
32686
+ throw commandError("EMAIL_UNKNOWN", 1, `Member ${before.principalId} has no email, which re-admission needs.`);
32687
+ }
32688
+ res = await client.post(path10, { email: before.email, roles: [] });
32689
+ }
32690
+ ensureOk(res.status, res.data, `${target === "active" ? "reactivate" : target === "revoked" ? "revoke" : "suspend"} membership`);
32691
+ const after = findMember(await listMembers(client, tenantId), { principalId: before.principalId });
32692
+ return {
32693
+ ok: true,
32694
+ tenantId,
32695
+ principalId: before.principalId,
32696
+ email: before.email || null,
32697
+ membershipId: before.membershipId,
32698
+ membershipStatusBefore: before.membershipStatus,
32699
+ membershipStatus: after?.membershipStatus ?? target,
32700
+ rolesAfter: after?.roles ?? [],
32701
+ idempotent: before.membershipStatus === target
32702
+ };
32703
+ }
32583
32704
  function ensureAuthorized(status2, action) {
32584
32705
  if (status2 === 401 || status2 === 403) {
32585
32706
  throw commandError(
@@ -32689,9 +32810,45 @@ var org = defineCommand({
32689
32810
  if (args.displayName) body.displayName = args.displayName;
32690
32811
  if (args.kind) body.kind = args.kind;
32691
32812
  const { client, fmt } = adminCtx(args);
32813
+ const email3 = String(args.email).trim().toLowerCase();
32814
+ const before = findMember(await listMembers(client, tenantId), { email: email3 });
32692
32815
  const res = await client.post(`/api/admin/orgs/${enc(tenantId)}/members`, body);
32693
32816
  ensureOk(res.status, res.data, "admit tenant member");
32694
- return output({ ...recordOf2(res.data), idempotent: true }, fmt);
32817
+ const after = findMember(await listMembers(client, tenantId), { email: email3 });
32818
+ const rolesBefore = before?.roles ?? [];
32819
+ const rolesAfter = after?.roles ?? [];
32820
+ const rolesAdded = without(rolesAfter, rolesBefore);
32821
+ return output({
32822
+ ...recordOf2(res.data),
32823
+ created: !before,
32824
+ membershipStatusBefore: before?.membershipStatus ?? null,
32825
+ membershipStatus: after?.membershipStatus ?? null,
32826
+ rolesBefore,
32827
+ rolesAfter,
32828
+ rolesAdded,
32829
+ idempotent: Boolean(before) && before?.membershipStatus === "active" && rolesAdded.length === 0
32830
+ }, fmt);
32831
+ }
32832
+ }),
32833
+ suspend: defineCommand({
32834
+ meta: { name: "suspend", description: "Suspend a membership (--email or --principal-id); reactivate undoes it" },
32835
+ args: orgArgs,
32836
+ async run({ args }) {
32837
+ return output(await changeMembership(args, "suspended"), adminCtx(args).fmt);
32838
+ }
32839
+ }),
32840
+ revoke: defineCommand({
32841
+ meta: { name: "revoke", description: "Remove a person from the tenant (--email or --principal-id); their roles go too" },
32842
+ args: orgArgs,
32843
+ async run({ args }) {
32844
+ return output(await changeMembership(args, "revoked"), adminCtx(args).fmt);
32845
+ }
32846
+ }),
32847
+ reactivate: defineCommand({
32848
+ meta: { name: "reactivate", description: "Make a suspended or revoked membership active again (--email or --principal-id)" },
32849
+ args: orgArgs,
32850
+ async run({ args }) {
32851
+ return output(await changeMembership(args, "active"), adminCtx(args).fmt);
32695
32852
  }
32696
32853
  })
32697
32854
  }
@@ -32701,33 +32858,17 @@ var org = defineCommand({
32701
32858
  args: orgArgs,
32702
32859
  subCommands: {
32703
32860
  grant: defineCommand({
32704
- meta: { name: "grant", description: "Grant a tenant role to a principal" },
32861
+ meta: { name: "grant", description: "Grant tenant roles to a member (--roles a,b; --email or --principal-id)" },
32705
32862
  args: orgArgs,
32706
32863
  async run({ args }) {
32707
- printContextNotice(args, { adminScope: true });
32708
- const { tenantId } = await resolveTenantId(args);
32709
- req(args, "principalId");
32710
- const role = rolesFromArgs(args)[0];
32711
- if (!role) throw commandError("ROLE_REQUIRED", 1, "Pass --role <role-key>.");
32712
- const { client, fmt } = adminCtx(args);
32713
- const res = await client.put(`/api/admin/orgs/${enc(tenantId)}/members/${enc(args.principalId)}/roles`, { roleKey: role });
32714
- ensureOk(res.status, res.data, "grant tenant role");
32715
- return output({ ...recordOf2(res.data), idempotent: true }, fmt);
32864
+ return output(await changeRoles(args, "grant"), adminCtx(args).fmt);
32716
32865
  }
32717
32866
  }),
32718
32867
  revoke: defineCommand({
32719
- meta: { name: "revoke", description: "Revoke a tenant role from a principal" },
32868
+ meta: { name: "revoke", description: "Revoke tenant roles from a member (--roles a,b; --email or --principal-id)" },
32720
32869
  args: orgArgs,
32721
32870
  async run({ args }) {
32722
- printContextNotice(args, { adminScope: true });
32723
- const { tenantId } = await resolveTenantId(args);
32724
- req(args, "principalId");
32725
- const role = rolesFromArgs(args)[0];
32726
- if (!role) throw commandError("ROLE_REQUIRED", 1, "Pass --role <role-key>.");
32727
- const { client, fmt } = adminCtx(args);
32728
- const res = await client.del(`/api/admin/orgs/${enc(tenantId)}/members/${enc(args.principalId)}/roles/${enc(role)}`);
32729
- ensureOk(res.status, res.data, "revoke tenant role");
32730
- return output(res.data, fmt);
32871
+ return output(await changeRoles(args, "revoke"), adminCtx(args).fmt);
32731
32872
  }
32732
32873
  })
32733
32874
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@senticor/hive",
3
- "version": "1.80.2",
3
+ "version": "1.82.0",
4
4
  "description": "Cognitive Hive OS — unified CLI",
5
5
  "type": "commonjs",
6
6
  "bin": {