@sherwoodagent/cli 0.75.0 → 0.77.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/index.js CHANGED
@@ -3888,7 +3888,24 @@ async function verifyBinding(params) {
3888
3888
  return false;
3889
3889
  }
3890
3890
  }
3891
+ var robinhoodChain = {
3892
+ id: 4663,
3893
+ name: "Robinhood Chain",
3894
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
3895
+ rpcUrls: { default: { http: ["https://rpc.mainnet.chain.robinhood.com"] } },
3896
+ blockExplorers: {
3897
+ default: {
3898
+ name: "Robinhood Chain Explorer",
3899
+ url: "https://explorer.mainnet.chain.robinhood.com"
3900
+ }
3901
+ }
3902
+ };
3903
+ var DEFAULT_ISSUING_CHAIN_ID = robinhoodChain.id;
3891
3904
  var ISSUING_CHAINS = {
3905
+ [robinhoodChain.id]: {
3906
+ chain: robinhoodChain,
3907
+ identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
3908
+ },
3892
3909
  [base.id]: {
3893
3910
  chain: base,
3894
3911
  identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
@@ -3908,6 +3925,7 @@ var OWNER_OF_ABI = [
3908
3925
  }
3909
3926
  ];
3910
3927
  var ISSUING_RPC_ENV = {
3928
+ [robinhoodChain.id]: "ROBINHOOD_RPC_URL",
3911
3929
  [base.id]: "BASE_RPC_URL",
3912
3930
  [baseSepolia.id]: "BASE_SEPOLIA_RPC_URL"
3913
3931
  };
@@ -3927,6 +3945,7 @@ async function ownerOfOnIssuingChain(issuingChainId, tokenId) {
3927
3945
  args: [tokenId]
3928
3946
  });
3929
3947
  }
3948
+ var WALLET_ONLY_CHAIN_ID = 0;
3930
3949
  var VID_TAG_RE = /\s*\[vid:(v\d+):(\d+):(\d+):(0x[0-9a-fA-F]{40}):(self|0x[0-9a-fA-F]{130})\]\s*$/;
3931
3950
  function formatVidTag(tag) {
3932
3951
  return `[vid:${BINDING_VERSION}:${tag.issuingChainId}:${tag.tokenId}:${tag.wallet.toLowerCase()}:${tag.signature}]`;
@@ -3966,6 +3985,9 @@ async function verifyVidTag(tag, attester, ownerOf = ownerOfOnIssuingChain) {
3966
3985
  if (!bindingOk) {
3967
3986
  return { bindingOk: false, ownerOk: false, error: "binding failed \u2014 ownership check skipped" };
3968
3987
  }
3988
+ if (tag.issuingChainId === WALLET_ONLY_CHAIN_ID) {
3989
+ return { bindingOk, ownerOk: true, walletOnly: true };
3990
+ }
3969
3991
  try {
3970
3992
  const owner = await ownerOf(tag.issuingChainId, tag.tokenId);
3971
3993
  return {
@@ -4147,10 +4169,10 @@ function registerIdentityCommands(program2) {
4147
4169
  process.exit(1);
4148
4170
  }
4149
4171
  });
4150
- identity.command("link-virtuals").description("Link a Virtuals economyOS agent identity (ERC-8004 on Base) to this Sherwood install").option("--wallet <address>", "economyOS agent wallet (default: auto-detect via `acp wallet address`)").option("--agent-id <tokenId>", "ERC-8004 token ID on the issuing chain (default: resolve via Agent0 SDK)").option("--chain-id <id>", "Issuing chain ID (8453 = Base, 84532 = Base Sepolia)", "8453").option("--binding-sig <hex>", "EIP-191 signature of the binding message by the economyOS wallet").action(async (opts) => {
4172
+ identity.command("link-virtuals").description("Link a Virtuals economyOS agent identity (ERC-8004 on Base) to this Sherwood install").option("--wallet <address>", "economyOS agent wallet (default: auto-detect via `acp wallet address`)").option("--agent-id <tokenId>", "ERC-8004 token ID on the issuing chain (default: resolve via Agent0 SDK)").option("--chain-id <id>", "Issuing chain ID (4663 = Robinhood Chain, 8453 = Base, 84532 = Base Sepolia)", String(DEFAULT_ISSUING_CHAIN_ID)).option("--binding-sig <hex>", "EIP-191 signature of the binding message by the economyOS wallet").option("--wallet-only", "Link without an ERC-8004 registration \u2014 the economyOS wallet + binding signature are the identity (agentId 0)").action(async (opts) => {
4151
4173
  const account = getAccount();
4152
- const issuingChainId = parseInt(opts.chainId, 10);
4153
- if (!ISSUING_CHAINS[issuingChainId]) {
4174
+ const issuingChainId = opts.walletOnly ? WALLET_ONLY_CHAIN_ID : parseInt(opts.chainId, 10);
4175
+ if (!opts.walletOnly && !ISSUING_CHAINS[issuingChainId]) {
4154
4176
  console.error(chalk4.red(`Unsupported issuing chain ${opts.chainId}. Supported: ${Object.keys(ISSUING_CHAINS).join(", ")}`));
4155
4177
  process.exit(1);
4156
4178
  }
@@ -4172,7 +4194,9 @@ function registerIdentityCommands(program2) {
4172
4194
  process.exit(1);
4173
4195
  }
4174
4196
  let tokenId;
4175
- if (opts.agentId) {
4197
+ if (opts.walletOnly) {
4198
+ tokenId = 0n;
4199
+ } else if (opts.agentId) {
4176
4200
  tokenId = BigInt(opts.agentId);
4177
4201
  } else {
4178
4202
  spinner.text = `Searching ERC-8004 registry on chain ${issuingChainId} for ${virtualsWallet}...`;
@@ -4190,6 +4214,7 @@ function registerIdentityCommands(program2) {
4190
4214
  console.error(chalk4.dim(" Register first via the Virtuals CLI:"));
4191
4215
  console.error(chalk4.dim(` acp agent register-erc8004 --agent-id ${virtualsAgentId ?? "<id>"} --chain-id ${issuingChainId}`));
4192
4216
  console.error(chalk4.dim(" Then re-run this command (or pass --agent-id <tokenId> directly)."));
4217
+ console.error(chalk4.dim(" No registration possible yet? Link without one: --wallet-only"));
4193
4218
  process.exit(1);
4194
4219
  }
4195
4220
  if (results.length > 1) {
@@ -4209,11 +4234,13 @@ function registerIdentityCommands(program2) {
4209
4234
  spinner.fail(`Token ID ${tokenId} exceeds Number.MAX_SAFE_INTEGER \u2014 cannot be stored in config`);
4210
4235
  process.exit(1);
4211
4236
  }
4212
- spinner.text = `Verifying ownerOf(#${tokenId}) on chain ${issuingChainId}...`;
4213
- const owner = await ownerOfOnIssuingChain(issuingChainId, tokenId);
4214
- if (owner.toLowerCase() !== virtualsWallet.toLowerCase()) {
4215
- spinner.fail(`Agent #${tokenId} on chain ${issuingChainId} is owned by ${owner}, not ${virtualsWallet}`);
4216
- process.exit(1);
4237
+ if (!opts.walletOnly) {
4238
+ spinner.text = `Verifying ownerOf(#${tokenId}) on chain ${issuingChainId}...`;
4239
+ const owner = await ownerOfOnIssuingChain(issuingChainId, tokenId);
4240
+ if (owner.toLowerCase() !== virtualsWallet.toLowerCase()) {
4241
+ spinner.fail(`Agent #${tokenId} on chain ${issuingChainId} is owned by ${owner}, not ${virtualsWallet}`);
4242
+ process.exit(1);
4243
+ }
4217
4244
  }
4218
4245
  const self = virtualsWallet.toLowerCase() === account.address.toLowerCase();
4219
4246
  const bindingMessage = buildBindingMessage(account.address, issuingChainId, tokenId);
@@ -4250,7 +4277,9 @@ function registerIdentityCommands(program2) {
4250
4277
  wallet: virtualsWallet,
4251
4278
  binding
4252
4279
  });
4253
- spinner.succeed(`Virtuals identity linked: agent #${tokenId} (chain ${issuingChainId})`);
4280
+ spinner.succeed(
4281
+ opts.walletOnly ? "Virtuals identity linked: wallet-only (no ERC-8004 \u2014 upgrade later by re-linking after registration)" : `Virtuals identity linked: agent #${tokenId} (chain ${issuingChainId})`
4282
+ );
4254
4283
  console.log(chalk4.dim(` economyOS wallet: ${virtualsWallet}`));
4255
4284
  if (virtualsAgentId) console.log(chalk4.dim(` Virtuals agent: ${virtualsAgentId}`));
4256
4285
  console.log(chalk4.dim(` Sherwood wallet: ${account.address}${self ? " (same as economyOS wallet \u2014 no binding needed)" : " (bound via signature)"}`));
@@ -4320,13 +4349,18 @@ function registerIdentityCommands(program2) {
4320
4349
  console.log(` Sherwood wallet: ${account.address}`);
4321
4350
  console.log(` economyOS wallet: ${virtuals?.wallet ?? chalk4.red("(missing)")}`);
4322
4351
  if (virtuals?.agentId) console.log(` Virtuals agent: ${virtuals.agentId}`);
4323
- console.log(` Issuing chain: ${issuingChainId ?? chalk4.red("(missing)")}`);
4324
- console.log(` Saved ID: ${savedId != null ? `#${savedId}` : chalk4.red("(missing)")}`);
4352
+ const walletOnly = issuingChainId === WALLET_ONLY_CHAIN_ID;
4353
+ console.log(` Issuing chain: ${walletOnly ? chalk4.yellow("wallet-only (no ERC-8004)") : issuingChainId ?? chalk4.red("(missing)")}`);
4354
+ console.log(` Saved ID: ${savedId != null ? walletOnly ? chalk4.dim("0 (wallet-only)") : `#${savedId}` : chalk4.red("(missing)")}`);
4325
4355
  if (virtuals?.wallet && savedId != null && issuingChainId != null) {
4326
4356
  const spinner2 = ora4("Re-verifying link...").start();
4327
4357
  try {
4328
- const owner = await ownerOfOnIssuingChain(issuingChainId, BigInt(savedId));
4329
- const ownerOk = owner.toLowerCase() === virtuals.wallet.toLowerCase();
4358
+ let ownerOk = true;
4359
+ let owner;
4360
+ if (!walletOnly) {
4361
+ owner = await ownerOfOnIssuingChain(issuingChainId, BigInt(savedId));
4362
+ ownerOk = owner.toLowerCase() === virtuals.wallet.toLowerCase();
4363
+ }
4330
4364
  let bindingOk = virtuals.wallet.toLowerCase() === account.address.toLowerCase();
4331
4365
  if (!bindingOk && virtuals.binding?.sig) {
4332
4366
  bindingOk = await verifyBinding({
@@ -4338,11 +4372,19 @@ function registerIdentityCommands(program2) {
4338
4372
  });
4339
4373
  }
4340
4374
  spinner2.stop();
4341
- console.log(` NFT ownership: ${ownerOk ? chalk4.green("verified") : chalk4.red(`FAILED (owner is ${owner})`)}`);
4375
+ if (walletOnly) {
4376
+ console.log(` NFT ownership: ${chalk4.dim("n/a (wallet-only link)")}`);
4377
+ } else {
4378
+ console.log(` NFT ownership: ${ownerOk ? chalk4.green("verified") : chalk4.red(`FAILED (owner is ${owner})`)}`);
4379
+ }
4342
4380
  console.log(` Binding: ${bindingOk ? chalk4.green("verified") : chalk4.red("FAILED")}`);
4343
4381
  if (!ownerOk) {
4344
4382
  console.log(chalk4.yellow(" The NFT moved since linking \u2014 re-run 'sherwood identity link-virtuals'."));
4345
4383
  }
4384
+ if (walletOnly) {
4385
+ console.log(chalk4.dim(" Upgrade to a registered link once ERC-8004 registration is available:"));
4386
+ console.log(chalk4.dim(" acp agent register-erc8004 ... && sherwood identity link-virtuals"));
4387
+ }
4346
4388
  } catch (err) {
4347
4389
  spinner2.warn("Could not re-verify against the issuing chain");
4348
4390
  console.log(chalk4.dim(` ${err.message}`));
@@ -9575,7 +9617,7 @@ try {
9575
9617
  } catch {
9576
9618
  }
9577
9619
  var require2 = createRequire(import.meta.url);
9578
- var CLI_VERSION = "0.75.0";
9620
+ var CLI_VERSION = "0.77.0";
9579
9621
  async function loadXmtp() {
9580
9622
  return import("./xmtp-OZ5PJFCT.js");
9581
9623
  }
@@ -10315,7 +10357,7 @@ fund.command("join").description("Request to join a fund (creates an EAS attesta
10315
10357
  const virtualsIdentity = getVirtualsIdentity();
10316
10358
  if (getIdentityProvider() === "virtuals" && virtualsIdentity) {
10317
10359
  joinMessage = appendVidTag(joinMessage, {
10318
- issuingChainId: getIdentityChainId() ?? 8453,
10360
+ issuingChainId: getIdentityChainId() ?? DEFAULT_ISSUING_CHAIN_ID,
10319
10361
  tokenId: BigInt(agentId),
10320
10362
  wallet: virtualsIdentity.wallet,
10321
10363
  signature: virtualsIdentity.binding?.sig ?? "self"
@@ -10492,7 +10534,8 @@ fund.command("requests").description("View pending join requests for a fund (cre
10492
10534
  const v = await verifyVidTag(vid, req.attester, ownerOfCached);
10493
10535
  const verified = v.bindingOk && v.ownerOk;
10494
10536
  const badge = verified ? G6("\u2714 verified") : chalk16.red("\u2718 FAILED");
10495
- console.log(W6(` Virtuals: ${badge} ${DIM6(`(agent #${vid.tokenId} on chain ${vid.issuingChainId}, wallet ${vid.wallet})`)}`));
10537
+ const detail = v.walletOnly ? `(wallet-only \u2014 no ERC-8004, wallet ${vid.wallet})` : `(agent #${vid.tokenId} on chain ${vid.issuingChainId}, wallet ${vid.wallet})`;
10538
+ console.log(W6(` Virtuals: ${badge} ${DIM6(detail)}`));
10496
10539
  if (!v.bindingOk) console.log(chalk16.red(` binding signature invalid \u2014 do not approve based on this identity`));
10497
10540
  else if (!v.ownerOk) console.log(chalk16.red(` NFT ownership check failed${v.owner ? ` (owner is ${v.owner})` : v.error ? ` (${v.error})` : ""}`));
10498
10541
  }