@aiaiai-pt/martha-cli 0.48.0 → 0.50.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ All notable changes to `@aiaiai-pt/martha-cli`. Format: [Keep a Changelog](https
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.49.0] — 2026-07-15
8
+
9
+ ### Added — UMS-gated second-party approval governance (#583 G1+G2)
10
+
11
+ - `martha approvals` now surfaces the server-computed requester, required-group
12
+ snapshot, and whether the current viewer can resolve the case. Resolution
13
+ remains server-authoritative and reports typed group/self-approval failures.
14
+ - `martha policy` and `martha approvals` consistently honor `--api-url`, including
15
+ machine-readable `--json` workflows against non-default Martha deployments.
16
+
7
17
  ## [0.48.0] — 2026-07-13
8
18
 
9
19
  ### Changed — BREAKING: `martha runner` means ONE thing (#714 runner-journey unification)
package/dist/index.js CHANGED
@@ -11119,7 +11119,7 @@ init_config();
11119
11119
  init_errors();
11120
11120
 
11121
11121
  // src/version.ts
11122
- var CLI_VERSION = "0.48.0";
11122
+ var CLI_VERSION = "0.50.0";
11123
11123
 
11124
11124
  // src/commands/sessions.ts
11125
11125
  function relativeTime(iso) {
@@ -16983,13 +16983,11 @@ init_errors();
16983
16983
  function registerApprovalCommands(program2) {
16984
16984
  const cmd = program2.command("approvals").description("Manage approval cases");
16985
16985
  function getCtx() {
16986
- const ctx = createContext({
16986
+ return createContext({
16987
16987
  profileOverride: program2.opts().profile,
16988
+ apiUrlOverride: program2.opts().apiUrl,
16988
16989
  verbose: program2.opts().verbose
16989
16990
  });
16990
- if (program2.opts().apiUrl)
16991
- ctx.profile.api_url = program2.opts().apiUrl;
16992
- return ctx;
16993
16991
  }
16994
16992
  function isJson() {
16995
16993
  return !!program2.opts().json;
@@ -20916,13 +20914,11 @@ function assertOneOf(value, allowed, flag) {
20916
20914
  function registerPolicyCommands(program2) {
20917
20915
  const cmd = program2.command("policy").description("Manage the tenant's invoke-time capability policy");
20918
20916
  function getCtx() {
20919
- const ctx = createContext({
20917
+ return createContext({
20920
20918
  profileOverride: program2.opts().profile,
20919
+ apiUrlOverride: program2.opts().apiUrl,
20921
20920
  verbose: program2.opts().verbose
20922
20921
  });
20923
- if (program2.opts().apiUrl)
20924
- ctx.profile.api_url = program2.opts().apiUrl;
20925
- return ctx;
20926
20922
  }
20927
20923
  const isJson = () => !!program2.opts().json;
20928
20924
  cmd.command("show").description("Show the current policy: settings + rules").action(async () => {
@@ -21208,6 +21204,8 @@ ${typed.hint}
21208
21204
  // src/commands/authz.ts
21209
21205
  var DEFAULT_ENTITY = "document_collection";
21210
21206
  var DEFAULT_ACTION = "read";
21207
+ var APPROVAL_ENTITY = "approval";
21208
+ var RESOLVE_ACTION = "resolve";
21211
21209
  function registerAuthzCommands(program2) {
21212
21210
  function getCtx() {
21213
21211
  const ctx = createContext({
@@ -21222,6 +21220,7 @@ function registerAuthzCommands(program2) {
21222
21220
  registerCollections(program2, getCtx, isJson);
21223
21221
  registerAccess(program2, getCtx, isJson);
21224
21222
  registerGroups(program2, getCtx, isJson);
21223
+ registerApprovers(program2, getCtx, isJson);
21225
21224
  }
21226
21225
  function renderGrantsTable(resp) {
21227
21226
  if (resp.grants.length === 0) {
@@ -21479,6 +21478,71 @@ function registerGroups(program2, getCtx, isJson) {
21479
21478
  }
21480
21479
  });
21481
21480
  }
21481
+ function registerApprovers(program2, getCtx, isJson) {
21482
+ const cmd = program2.command("approvers").description("Manage who may resolve approval cases in the tenant (UMS approval/resolve). " + "Noun-first sugar over `access` on the approval entity.");
21483
+ cmd.command("add <group>").description("Make a group a tenant approver (its members can resolve approvals)").option("--tenant <tenant>", "Target tenant (super-admin only)").action(async (group, opts) => {
21484
+ const ctx = getCtx();
21485
+ const json = isJson();
21486
+ try {
21487
+ await grant(ctx, {
21488
+ granteeType: "group",
21489
+ granteeId: group,
21490
+ entityType: APPROVAL_ENTITY,
21491
+ action: RESOLVE_ACTION,
21492
+ objectId: null,
21493
+ tenant: opts.tenant
21494
+ });
21495
+ emitOk(json, {
21496
+ status: "approver_added",
21497
+ entity_type: APPROVAL_ENTITY,
21498
+ action: RESOLVE_ACTION,
21499
+ grantee: `group:${group}`,
21500
+ text: `Group ${group} can now resolve approvals in this tenant.`
21501
+ });
21502
+ } catch (err) {
21503
+ emitAuthzError(err, json);
21504
+ }
21505
+ });
21506
+ cmd.command("remove <group>").description("Remove a group's tenant approver binding").option("--tenant <tenant>", "Target tenant (super-admin only)").action(async (group, opts) => {
21507
+ const ctx = getCtx();
21508
+ const json = isJson();
21509
+ try {
21510
+ await revoke(ctx, {
21511
+ granteeType: "group",
21512
+ granteeId: group,
21513
+ entityType: APPROVAL_ENTITY,
21514
+ action: RESOLVE_ACTION,
21515
+ objectId: null,
21516
+ tenant: opts.tenant
21517
+ });
21518
+ emitOk(json, {
21519
+ status: "approver_removed",
21520
+ grantee: `group:${group}`,
21521
+ text: `Group ${group} can no longer resolve approvals in this tenant.`
21522
+ });
21523
+ } catch (err) {
21524
+ emitAuthzError(err, json);
21525
+ }
21526
+ });
21527
+ cmd.command("list").description("Show which groups may resolve approvals in the tenant").option("--tenant <tenant>", "Target tenant (super-admin only)").action(async (opts) => {
21528
+ const ctx = getCtx();
21529
+ const json = isJson();
21530
+ try {
21531
+ const resp = await listGrants(ctx, {
21532
+ entityType: APPROVAL_ENTITY,
21533
+ action: RESOLVE_ACTION,
21534
+ tenant: opts.tenant
21535
+ });
21536
+ if (json) {
21537
+ console.log(JSON.stringify(resp, null, 2));
21538
+ } else {
21539
+ console.log(renderGrantsTable(resp));
21540
+ }
21541
+ } catch (err) {
21542
+ emitAuthzError(err, json);
21543
+ }
21544
+ });
21545
+ }
21482
21546
  function emitOk(json, payload) {
21483
21547
  if (json) {
21484
21548
  const rest = { ...payload };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiaiai-pt/martha-cli",
3
- "version": "0.48.0",
3
+ "version": "0.50.0",
4
4
  "description": "Terminal-first client for the Martha AI platform",
5
5
  "homepage": "https://docs.martha.nomadriver.co",
6
6
  "repository": {