@haven_ai/cli 0.0.0-dev.202610070606.e21c002 → 0.0.0-dev.202610071154.39eddce

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/index.cjs CHANGED
@@ -39,7 +39,8 @@ function parseArgs(argv) {
39
39
  noWait: false,
40
40
  run: false,
41
41
  wait: false,
42
- hashes: false
42
+ hashes: false,
43
+ keepBudget: false
43
44
  };
44
45
  for (let i = 0; i < argv.length; i += 1) {
45
46
  const arg = argv[i];
@@ -47,6 +48,7 @@ function parseArgs(argv) {
47
48
  else if (arg === "--help" || arg === "-h") flags.help = true;
48
49
  else if (arg === "--version" || arg === "-v") flags.version = true;
49
50
  else if (arg === "--yes" || arg === "-y") flags.yes = true;
51
+ else if (arg === "--keep-budget") flags.keepBudget = true;
50
52
  else if (arg === "--no-wait") flags.noWait = true;
51
53
  else if (arg === "--run") flags.run = true;
52
54
  else if (arg === "--wait") flags.wait = true;
@@ -157,7 +159,8 @@ function helpText() {
157
159
  "Manage (backend-only \u2014 no on-chain signing):",
158
160
  " agents pause <id> Stop the agent spending; keeps its budget",
159
161
  " agents resume <id> Let it spend again",
160
- " agents revoke <id> --yes Permanently revoke an agent",
162
+ " agents revoke <id> --yes Permanently revoke an agent. Refuses while a",
163
+ " budget is still live on-chain unless --keep-budget",
161
164
  " agents rotate-key <id> Issue a new API key (shown once)",
162
165
  " agents rename <id> <name>",
163
166
  " wallets rename <id> <name>",
@@ -3145,7 +3148,7 @@ async function checkTextForSecrets(text, deps) {
3145
3148
 
3146
3149
  // src/commands.ts
3147
3150
  var DEFAULT_API = "https://havenbackend-production-8a00.up.railway.app";
3148
- var CLI_VERSION = "0.0.0-dev.202610070606.e21c002";
3151
+ var CLI_VERSION = "0.0.0-dev.202610071154.39eddce";
3149
3152
  var CLI_CLIENT_IDENTITY = `@haven_ai/cli/${CLI_VERSION}`;
3150
3153
  function accountAddressOf(s) {
3151
3154
  return s.account_address ?? "";
@@ -3699,12 +3702,6 @@ async function cmdBudgetRevoke(args, d) {
3699
3702
  if (row.status === "revoked") {
3700
3703
  throw new HavenCliError(`Delegation ${hash} is already revoked.`, EXIT.refused);
3701
3704
  }
3702
- if (row.status === "replaced") {
3703
- throw new HavenCliError(
3704
- `Delegation ${hash} was already replaced by a newer grant \u2014 nothing to revoke.`,
3705
- EXIT.refused
3706
- );
3707
- }
3708
3705
  const prepared = await api.post(`/agents/${id}/delegations/${hash}/revoke`, {});
3709
3706
  const revokeUrl = prepared.revocation_url;
3710
3707
  if (!revokeUrl) {
@@ -3760,7 +3757,7 @@ async function cmdAgentLifecycle(args, d, action) {
3760
3757
  }
3761
3758
  async function cmdAgentRevoke(args, d) {
3762
3759
  const id = args.positionals[0];
3763
- if (!id) throw new UsageError("Usage: haven agents revoke <id> --yes");
3760
+ if (!id) throw new UsageError("Usage: haven agents revoke <id> [--keep-budget] --yes");
3764
3761
  if (!args.flags.yes) {
3765
3762
  throw new UsageError(
3766
3763
  `This permanently revokes agent ${id}.`,
@@ -3768,12 +3765,45 @@ async function cmdAgentRevoke(args, d) {
3768
3765
  );
3769
3766
  }
3770
3767
  const { api } = await authed(args, d);
3768
+ let live = [];
3769
+ try {
3770
+ const agent = await api.get(`/agents/${id}`);
3771
+ if ((agent.live_delegation_count ?? 0) > 0) {
3772
+ const { delegations } = await api.get(`/agents/${id}/delegations`);
3773
+ live = delegations.filter((r) => r.status === "pending" || r.status === "active" || r.status === "replaced");
3774
+ }
3775
+ } catch (err) {
3776
+ d.o.note(`Couldn't check budgets for agent ${id}, so the revocation was not attempted.`);
3777
+ throw err;
3778
+ }
3779
+ if (live.length > 0 && !args.flags.keepBudget) {
3780
+ throw new HavenCliError(
3781
+ `Agent ${id} still has a live on-chain budget. Revoking now would leave it redeemable by the delegate key.`,
3782
+ EXIT.refused,
3783
+ [
3784
+ ...live.map((r) => `haven budget revoke ${id} ${r.delegation_hash} # ${r.status}`),
3785
+ "Remove agent\u2026 in the dashboard ends every live budget with one signature, before revoking.",
3786
+ "To revoke the agent anyway and leave the budget live on-chain, re-run with --keep-budget."
3787
+ ].join("\n"),
3788
+ // The machine branch: a script skips the prose and reads the rows.
3789
+ { live_delegations: live.map(({ delegation_hash, status }) => ({ delegation_hash, status })) }
3790
+ );
3791
+ }
3771
3792
  await api.post(`/agents/${id}/revoke`);
3772
3793
  emit(
3773
3794
  d,
3774
3795
  args.flags.json,
3775
- { ok: true, agent_id: id, status: "revoked" },
3776
- () => `Agent ${id} revoked. To also remove its on-chain allowance, use the dashboard.`
3796
+ live.length > 0 ? {
3797
+ ok: true,
3798
+ agent_id: id,
3799
+ status: "revoked",
3800
+ live_delegations: live.map(({ delegation_hash, status }) => ({ delegation_hash, status }))
3801
+ } : { ok: true, agent_id: id, status: "revoked" },
3802
+ () => live.length > 0 ? [
3803
+ `Agent ${id} revoked.`,
3804
+ `Its budget is still live on-chain: the delegate key can keep spending until each delegation is revoked.`,
3805
+ ...live.map((r) => `haven budget revoke ${id} ${r.delegation_hash} # ${r.status}`)
3806
+ ].join("\n") : `Agent ${id} revoked. To also remove its on-chain allowance, use the dashboard.`
3777
3807
  );
3778
3808
  return EXIT.ok;
3779
3809
  }