@haven_ai/cli 0.2.0-alpha.0 → 0.3.0-alpha.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/dist/cli.js CHANGED
@@ -602,9 +602,9 @@ async function runConnector(connectorCommand, spawner, onStderr) {
602
602
 
603
603
  // src/commands.ts
604
604
  var DEFAULT_API = "https://havenbackend-production-8a00.up.railway.app";
605
- var CLI_VERSION = "0.2.0-alpha.0";
605
+ var CLI_VERSION = "0.3.0-alpha.0";
606
606
  function accountAddressOf(s) {
607
- return s.account_address ?? s.safe_address ?? "";
607
+ return s.account_address ?? "";
608
608
  }
609
609
  async function run(argv, deps = {}) {
610
610
  const out = deps.out ?? ((l) => process.stdout.write(`${l}
@@ -874,24 +874,32 @@ async function cmdWhoami(args, d) {
874
874
  );
875
875
  return EXIT.ok;
876
876
  }
877
+ function accountsEnvelope(body) {
878
+ if (!Array.isArray(body.accounts)) {
879
+ throw new Error(
880
+ "GET /user/accounts did not return an `accounts` array. This CLI needs a Haven backend from the release that carries #2914 or later; an older server returns the retired `safes` envelope. Upgrade the backend, or pin an older @haven_ai/cli."
881
+ );
882
+ }
883
+ return body.accounts;
884
+ }
877
885
  async function cmdWalletsList(args, d) {
878
886
  const { api } = await authed(args, d);
879
- const { safes } = await api.get("/user/accounts");
887
+ const accounts = accountsEnvelope(await api.get("/user/accounts"));
880
888
  emit(
881
889
  d,
882
890
  args.flags.json,
883
- safes,
884
- () => safes.length === 0 ? "No Haven wallets yet." : table(
891
+ accounts,
892
+ () => accounts.length === 0 ? "No Haven wallets yet." : table(
885
893
  ["NAME", "NETWORK", "ADDRESS", "DEFAULT"],
886
- safes.map((s) => [s.name, chainName(s.chain_id), truncateAddress(accountAddressOf(s)), s.is_default ? "\u2713" : ""])
894
+ accounts.map((s) => [s.name, chainName(s.chain_id), truncateAddress(accountAddressOf(s)), s.is_default ? "\u2713" : ""])
887
895
  )
888
896
  );
889
897
  return EXIT.ok;
890
898
  }
891
899
  async function cmdWalletsBalances(args, d) {
892
900
  const { api } = await authed(args, d);
893
- const { safes } = await api.get("/user/accounts");
894
- const safe = pickSafe(safes, args.flags.safe);
901
+ const accounts = accountsEnvelope(await api.get("/user/accounts"));
902
+ const safe = pickSafe(accounts, args.flags.safe);
895
903
  if (!safe) {
896
904
  if (args.flags.safe) throw new UsageError(`No wallet matches "${args.flags.safe}".`);
897
905
  throw new CliApiError("No Haven wallet found.", 404);
@@ -902,7 +910,7 @@ async function cmdWalletsBalances(args, d) {
902
910
  emit(
903
911
  d,
904
912
  args.flags.json,
905
- { account: safe.name, safe: safe.name, chainId: safe.chain_id, balances },
913
+ { account: safe.name, chainId: safe.chain_id, balances },
906
914
  () => [
907
915
  `${safe.name} \xB7 ${chainName(safe.chain_id)} \xB7 ${truncateAddress(accountAddressOf(safe))}`,
908
916
  balances.length === 0 ? " (no balances)" : table(["TOKEN", "BALANCE"], balances.map((b) => [b.symbol, b.formatted]))
@@ -910,15 +918,15 @@ async function cmdWalletsBalances(args, d) {
910
918
  );
911
919
  return EXIT.ok;
912
920
  }
913
- function pickSafe(safes, ref) {
914
- if (!ref) return safes.find((s) => s.is_default) ?? safes[0];
921
+ function pickSafe(accounts, ref) {
922
+ if (!ref) return accounts.find((s) => s.is_default) ?? accounts[0];
915
923
  const lower = ref.toLowerCase();
916
- return safes.find((s) => s.id === ref || accountAddressOf(s).toLowerCase() === lower);
924
+ return accounts.find((s) => s.id === ref || accountAddressOf(s).toLowerCase() === lower);
917
925
  }
918
926
  async function cmdWalletsFunding(args, d) {
919
927
  const { api } = await authed(args, d);
920
- const { safes } = await api.get("/user/accounts");
921
- const safe = pickSafe(safes, args.flags.safe);
928
+ const accounts = accountsEnvelope(await api.get("/user/accounts"));
929
+ const safe = pickSafe(accounts, args.flags.safe);
922
930
  if (!safe) {
923
931
  if (args.flags.safe) throw new UsageError(`No wallet matches "${args.flags.safe}".`);
924
932
  throw new CliApiError("No Haven wallet found.", 404);
@@ -1061,8 +1069,8 @@ async function cmdBudgetGrant(args, d) {
1061
1069
  EXIT.refused
1062
1070
  );
1063
1071
  }
1064
- const accountAddress = agent.account_address ?? agent.safe_address;
1065
- const accountChainId = agent.account_chain_id ?? agent.safe_chain_id;
1072
+ const accountAddress = agent.account_address;
1073
+ const accountChainId = agent.account_chain_id;
1066
1074
  if (!accountAddress || !accountChainId) {
1067
1075
  throw new HavenCliError(`Agent ${id} has no wallet assigned yet \u2014 connect it first.`, EXIT.refused);
1068
1076
  }
@@ -1237,27 +1245,24 @@ async function cmdWalletRename(args, d) {
1237
1245
  if (!id || !name) throw new UsageError("Usage: haven wallets rename <id> <name>");
1238
1246
  const { api } = await authed(args, d);
1239
1247
  await api.put(`/user/accounts/${id}`, { name });
1240
- emit(d, args.flags.json, { ok: true, account_id: id, safe_id: id, name }, () => `Wallet ${id} renamed to "${name}".`);
1248
+ emit(d, args.flags.json, { ok: true, account_id: id, name }, () => `Wallet ${id} renamed to "${name}".`);
1241
1249
  return EXIT.ok;
1242
1250
  }
1243
- async function resolveSafeId(args, api) {
1251
+ async function resolveAccountId(args, api) {
1244
1252
  if (!args.flags.safe) return void 0;
1245
- const { safes } = await api.get("/user/accounts");
1246
- const safe = pickSafe(safes, args.flags.safe);
1253
+ const accounts = accountsEnvelope(await api.get("/user/accounts"));
1254
+ const safe = pickSafe(accounts, args.flags.safe);
1247
1255
  if (!safe) throw new UsageError(`No wallet matches "${args.flags.safe}".`);
1248
1256
  return safe.id;
1249
1257
  }
1250
1258
  async function cmdActivityList(args, d) {
1251
1259
  const { api } = await authed(args, d);
1252
- const safeId = await resolveSafeId(args, api);
1260
+ const accountId = await resolveAccountId(args, api);
1253
1261
  const params = new URLSearchParams({
1254
1262
  offset: String(args.flags.offset ?? 0),
1255
1263
  limit: String(args.flags.limit ?? 25)
1256
1264
  });
1257
- if (safeId) {
1258
- params.set("accountId", safeId);
1259
- params.set("safeId", safeId);
1260
- }
1265
+ if (accountId) params.set("accountId", accountId);
1261
1266
  if (args.flags.agent) params.set("agentId", args.flags.agent);
1262
1267
  const { transactions } = await api.get(`/transactions?${params.toString()}`);
1263
1268
  const visible = args.flags.direction ? transactions.filter((t) => t.direction === args.flags.direction) : transactions;
@@ -1272,7 +1277,7 @@ async function cmdActivityList(args, d) {
1272
1277
  t.direction === "in" ? "in" : "out",
1273
1278
  `${t.direction === "in" ? "+" : "-"}${t.valueFormatted} ${t.asset}`,
1274
1279
  t.source ?? "transfer",
1275
- t.safeName ?? ""
1280
+ t.accountName ?? ""
1276
1281
  ])
1277
1282
  )
1278
1283
  );
@@ -1281,15 +1286,12 @@ async function cmdActivityList(args, d) {
1281
1286
  async function cmdActivityExport(args, d) {
1282
1287
  if (args.flags.format === "sie") return exportSie(args, d);
1283
1288
  const { api } = await authed(args, d);
1284
- const safeId = await resolveSafeId(args, api);
1289
+ const accountId = await resolveAccountId(args, api);
1285
1290
  const params = new URLSearchParams({
1286
1291
  offset: String(args.flags.offset ?? 0),
1287
1292
  limit: String(args.flags.limit ?? 1e3)
1288
1293
  });
1289
- if (safeId) {
1290
- params.set("accountId", safeId);
1291
- params.set("safeId", safeId);
1292
- }
1294
+ if (accountId) params.set("accountId", accountId);
1293
1295
  if (args.flags.agent) params.set("agentId", args.flags.agent);
1294
1296
  const { transactions } = await api.get(`/transactions?${params.toString()}`);
1295
1297
  const visible = args.flags.direction ? transactions.filter((t) => t.direction === args.flags.direction) : transactions;
@@ -1302,7 +1304,6 @@ async function cmdActivityExport(args, d) {
1302
1304
  "token_symbol",
1303
1305
  "token_address",
1304
1306
  "counterparty_address",
1305
- "safe_address",
1306
1307
  "agent_name",
1307
1308
  "tx_hash",
1308
1309
  "chain_id",
@@ -1317,11 +1318,10 @@ async function cmdActivityExport(args, d) {
1317
1318
  t.tokenSymbol ?? t.asset ?? "",
1318
1319
  t.tokenAddress ?? "",
1319
1320
  (t.direction === "in" ? t.from : t.to) ?? "",
1320
- t.accountAddress ?? t.safeAddress ?? "",
1321
1321
  t.agentName ?? "",
1322
1322
  t.hash,
1323
1323
  t.chainId != null ? String(t.chainId) : "",
1324
- t.accountAddress ?? t.safeAddress ?? ""
1324
+ t.accountAddress ?? ""
1325
1325
  ]);
1326
1326
  d.o.text(toCsv(headers, rows), { format: "csv", rows: rows.length });
1327
1327
  return EXIT.ok;
@@ -1362,11 +1362,11 @@ async function cmdCatalogList(args, d) {
1362
1362
  return EXIT.ok;
1363
1363
  }
1364
1364
  async function resolveWalletAndToken(args, api, symbol) {
1365
- const { safes } = await api.get("/user/accounts");
1366
- if (safes.length === 0) {
1365
+ const accounts = accountsEnvelope(await api.get("/user/accounts"));
1366
+ if (accounts.length === 0) {
1367
1367
  throw new HavenCliError("No wallet on this account yet \u2014 finish onboarding first.", EXIT.refused);
1368
1368
  }
1369
- const safe = args.flags.safe ? safes.find((s) => s.id === args.flags.safe || accountAddressOf(s) === args.flags.safe) : safes.find((s) => s.is_default) ?? safes[0];
1369
+ const safe = args.flags.safe ? accounts.find((s) => s.id === args.flags.safe || accountAddressOf(s) === args.flags.safe) : accounts.find((s) => s.is_default) ?? accounts[0];
1370
1370
  if (!safe) throw new UsageError(`No wallet matches --safe ${args.flags.safe}`);
1371
1371
  const { balances } = await api.get(
1372
1372
  `/balances/${accountAddressOf(safe)}?chain_id=${safe.chain_id}`
@@ -1377,7 +1377,7 @@ async function resolveWalletAndToken(args, api, symbol) {
1377
1377
  const known = balances.map((b) => b.symbol).join(", ");
1378
1378
  throw new UsageError(`Unknown token ${symbol} on this wallet's chain. Available: ${known || "none"}`);
1379
1379
  }
1380
- return { safeId: safe.id, token };
1380
+ return { accountId: safe.id, token };
1381
1381
  }
1382
1382
  var SETTLED = /* @__PURE__ */ new Set(["active", "expired", "cancelled", "failed"]);
1383
1383
  async function pollSetup(api, setupId, d, wait) {
@@ -1411,16 +1411,12 @@ async function cmdAgentsConnect(args, d) {
1411
1411
  if (!args.flags.budget || !args.flags.token || args.flags.period === void 0) {
1412
1412
  throw new UsageError("--budget, --token and --period are required (period is whole minutes; 0 means one-time)");
1413
1413
  }
1414
- const { safeId, token } = await resolveWalletAndToken(args, api, args.flags.token);
1414
+ const { accountId, token } = await resolveWalletAndToken(args, api, args.flags.token);
1415
1415
  const amount = parseTokenAmount(args.flags.budget, token.decimals, token.symbol);
1416
1416
  if (!amount.ok) throw new UsageError(amount.message);
1417
1417
  const setup = await api.post("/agent-connection-setups", {
1418
1418
  name,
1419
- // #2908: both id keys for the window — `account_id` is the #2907 twin
1420
- // (landing in P0's second round), `safe_id` is what a server without it
1421
- // reads; the request works against either.
1422
- account_id: safeId,
1423
- safe_id: safeId,
1419
+ account_id: accountId,
1424
1420
  allowances: [
1425
1421
  {
1426
1422
  token_address: token.address ?? "0x0000000000000000000000000000000000000000",