@sherwoodagent/cli 0.74.3 → 0.76.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 (60) hide show
  1. package/dist/{addresses-OFFTM6NG.js → addresses-JJPQTF6S.js} +4 -4
  2. package/dist/{agent-B7V5L2ZL.js → agent-FYRYTKYM.js} +7 -7
  3. package/dist/{chat-CXUU4AXK.js → chat-CO244AHH.js} +8 -8
  4. package/dist/{chunk-6MV4ESXM.js → chunk-3TZIOAPH.js} +25 -1
  5. package/dist/chunk-3TZIOAPH.js.map +1 -0
  6. package/dist/{chunk-EW6FTUOL.js → chunk-EVTDWMXQ.js} +4 -4
  7. package/dist/{chunk-2OHX3O55.js → chunk-FP5DZCOM.js} +3 -3
  8. package/dist/{chunk-UINMHN6S.js → chunk-I6X6NL65.js} +2 -2
  9. package/dist/{chunk-LHVSS27T.js → chunk-LSVCF24W.js} +2 -2
  10. package/dist/{chunk-YADJ5YWY.js → chunk-M7CGUYUX.js} +6 -6
  11. package/dist/{chunk-3ZOWP3VO.js → chunk-MEMYGZWQ.js} +3 -3
  12. package/dist/{chunk-BD4ZV7FQ.js → chunk-RGFA732Z.js} +3 -3
  13. package/dist/{chunk-DGLLSZ2D.js → chunk-T2HVR3O6.js} +2 -2
  14. package/dist/{chunk-4LKU7ASB.js → chunk-TI64P5R4.js} +4 -4
  15. package/dist/{chunk-6UEQUVTQ.js → chunk-TN7J5LXW.js} +4 -4
  16. package/dist/{chunk-O65AC2YS.js → chunk-WCX7DKLQ.js} +4 -4
  17. package/dist/{chunk-K3EYEJMT.js → chunk-WGXZ623D.js} +4 -4
  18. package/dist/{client-C3C6IXAH.js → client-GRPJRISD.js} +4 -4
  19. package/dist/{config-7HU4X7EK.js → config-ZGFS4I7K.js} +12 -4
  20. package/dist/{eas-XWQYAUEM.js → eas-4RIW3IS4.js} +6 -6
  21. package/dist/{governor-NHXBIFFB.js → governor-7KETSN47.js} +6 -6
  22. package/dist/index.js +428 -61
  23. package/dist/index.js.map +1 -1
  24. package/dist/{network-WU2QC3L4.js → network-UP2X5XDW.js} +3 -3
  25. package/dist/{price-QSVIM6QY.js → price-LAQSXN7M.js} +6 -6
  26. package/dist/{providers-YOOQFBN2.js → providers-2J6LL67W.js} +5 -5
  27. package/dist/{research-NQKYGTLY.js → research-FHQCSLTZ.js} +9 -9
  28. package/dist/{session-NLI6UFKB.js → session-JQ3IF3IV.js} +11 -11
  29. package/dist/{trade-6VYB6YJZ.js → trade-5EYPZN7M.js} +17 -17
  30. package/dist/{vault-45POYGLN.js → vault-5YYTHS5W.js} +8 -8
  31. package/dist/{xmtp-KH5I6GOL.js → xmtp-OZ5PJFCT.js} +6 -6
  32. package/package.json +1 -1
  33. package/dist/chunk-6MV4ESXM.js.map +0 -1
  34. /package/dist/{addresses-OFFTM6NG.js.map → addresses-JJPQTF6S.js.map} +0 -0
  35. /package/dist/{agent-B7V5L2ZL.js.map → agent-FYRYTKYM.js.map} +0 -0
  36. /package/dist/{chat-CXUU4AXK.js.map → chat-CO244AHH.js.map} +0 -0
  37. /package/dist/{chunk-EW6FTUOL.js.map → chunk-EVTDWMXQ.js.map} +0 -0
  38. /package/dist/{chunk-2OHX3O55.js.map → chunk-FP5DZCOM.js.map} +0 -0
  39. /package/dist/{chunk-UINMHN6S.js.map → chunk-I6X6NL65.js.map} +0 -0
  40. /package/dist/{chunk-LHVSS27T.js.map → chunk-LSVCF24W.js.map} +0 -0
  41. /package/dist/{chunk-YADJ5YWY.js.map → chunk-M7CGUYUX.js.map} +0 -0
  42. /package/dist/{chunk-3ZOWP3VO.js.map → chunk-MEMYGZWQ.js.map} +0 -0
  43. /package/dist/{chunk-BD4ZV7FQ.js.map → chunk-RGFA732Z.js.map} +0 -0
  44. /package/dist/{chunk-DGLLSZ2D.js.map → chunk-T2HVR3O6.js.map} +0 -0
  45. /package/dist/{chunk-4LKU7ASB.js.map → chunk-TI64P5R4.js.map} +0 -0
  46. /package/dist/{chunk-6UEQUVTQ.js.map → chunk-TN7J5LXW.js.map} +0 -0
  47. /package/dist/{chunk-O65AC2YS.js.map → chunk-WCX7DKLQ.js.map} +0 -0
  48. /package/dist/{chunk-K3EYEJMT.js.map → chunk-WGXZ623D.js.map} +0 -0
  49. /package/dist/{client-C3C6IXAH.js.map → client-GRPJRISD.js.map} +0 -0
  50. /package/dist/{config-7HU4X7EK.js.map → config-ZGFS4I7K.js.map} +0 -0
  51. /package/dist/{eas-XWQYAUEM.js.map → eas-4RIW3IS4.js.map} +0 -0
  52. /package/dist/{governor-NHXBIFFB.js.map → governor-7KETSN47.js.map} +0 -0
  53. /package/dist/{network-WU2QC3L4.js.map → network-UP2X5XDW.js.map} +0 -0
  54. /package/dist/{price-QSVIM6QY.js.map → price-LAQSXN7M.js.map} +0 -0
  55. /package/dist/{providers-YOOQFBN2.js.map → providers-2J6LL67W.js.map} +0 -0
  56. /package/dist/{research-NQKYGTLY.js.map → research-FHQCSLTZ.js.map} +0 -0
  57. /package/dist/{session-NLI6UFKB.js.map → session-JQ3IF3IV.js.map} +0 -0
  58. /package/dist/{trade-6VYB6YJZ.js.map → trade-5EYPZN7M.js.map} +0 -0
  59. /package/dist/{vault-45POYGLN.js.map → vault-5YYTHS5W.js.map} +0 -0
  60. /package/dist/{xmtp-KH5I6GOL.js.map → xmtp-OZ5PJFCT.js.map} +0 -0
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  checkApiKeyValid,
16
16
  listModels,
17
17
  provisionApiKey
18
- } from "./chunk-BD4ZV7FQ.js";
18
+ } from "./chunk-RGFA732Z.js";
19
19
  import {
20
20
  approveDepositor,
21
21
  deposit,
@@ -38,8 +38,8 @@ import {
38
38
  removeDepositor,
39
39
  setAgentFeeBps,
40
40
  setVaultAddress
41
- } from "./chunk-YADJ5YWY.js";
42
- import "./chunk-3ZOWP3VO.js";
41
+ } from "./chunk-M7CGUYUX.js";
42
+ import "./chunk-MEMYGZWQ.js";
43
43
  import {
44
44
  applySlippage,
45
45
  assetDecimalsForSymbol,
@@ -50,7 +50,7 @@ import {
50
50
  getMultiHopQuote,
51
51
  getQuote,
52
52
  resolveToken
53
- } from "./chunk-4LKU7ASB.js";
53
+ } from "./chunk-TI64P5R4.js";
54
54
  import {
55
55
  createApproval,
56
56
  createJoinRequest,
@@ -61,20 +61,20 @@ import {
61
61
  queryJoinRequests,
62
62
  revokeJoinRequest,
63
63
  stripReferrerPrefix
64
- } from "./chunk-O65AC2YS.js";
64
+ } from "./chunk-WCX7DKLQ.js";
65
65
  import {
66
66
  createFund,
67
67
  getActiveFunds,
68
68
  getFund,
69
69
  subdomainExists,
70
70
  updateMetadata
71
- } from "./chunk-K3EYEJMT.js";
71
+ } from "./chunk-WGXZ623D.js";
72
72
  import {
73
73
  resolveFund,
74
74
  resolveVaultFund,
75
75
  searchFundAcrossChains,
76
76
  setTextRecord
77
- } from "./chunk-6UEQUVTQ.js";
77
+ } from "./chunk-TN7J5LXW.js";
78
78
  import {
79
79
  PROPOSAL_STATE,
80
80
  PROPOSAL_STATES,
@@ -108,7 +108,7 @@ import {
108
108
  setVotingPeriod,
109
109
  settleProposal,
110
110
  vote
111
- } from "./chunk-EW6FTUOL.js";
111
+ } from "./chunk-EVTDWMXQ.js";
112
112
  import {
113
113
  AERODROME,
114
114
  AGENT_REGISTRY,
@@ -118,7 +118,7 @@ import {
118
118
  TOKENS,
119
119
  UNISWAP,
120
120
  VENICE
121
- } from "./chunk-UINMHN6S.js";
121
+ } from "./chunk-I6X6NL65.js";
122
122
  import {
123
123
  GAS_UNITS,
124
124
  estimateGasCushion,
@@ -129,7 +129,7 @@ import {
129
129
  sendTxWithRetry,
130
130
  waitForReceipt,
131
131
  writeContractWithRetry
132
- } from "./chunk-2OHX3O55.js";
132
+ } from "./chunk-FP5DZCOM.js";
133
133
  import {
134
134
  DEFAULT_NETWORK,
135
135
  VALID_NETWORKS,
@@ -141,7 +141,7 @@ import {
141
141
  isTestnet,
142
142
  setNetwork,
143
143
  withNetwork
144
- } from "./chunk-LHVSS27T.js";
144
+ } from "./chunk-LSVCF24W.js";
145
145
  import {
146
146
  addFund,
147
147
  cacheGroupId,
@@ -149,10 +149,13 @@ import {
149
149
  getCachedGroupId,
150
150
  getChainContracts,
151
151
  getFunds,
152
+ getIdentityChainId,
153
+ getIdentityProvider,
152
154
  getNotifyTo,
153
155
  getPrimaryFund,
154
156
  getUniswapApiKey,
155
157
  getVeniceApiKey,
158
+ getVirtualsIdentity,
156
159
  loadConfig,
157
160
  requirePrivateKey,
158
161
  setAgentId,
@@ -163,8 +166,9 @@ import {
163
166
  setPrimaryFund,
164
167
  setPrivateKey,
165
168
  setUniswapApiKey,
166
- setVeniceApiKey
167
- } from "./chunk-6MV4ESXM.js";
169
+ setVeniceApiKey,
170
+ setVirtualsIdentity
171
+ } from "./chunk-3TZIOAPH.js";
168
172
  import {
169
173
  BASE_STRATEGY_ABI,
170
174
  ERC20_ABI,
@@ -185,7 +189,7 @@ import {
185
189
  import { config as loadDotenv } from "dotenv";
186
190
  import { createRequire } from "module";
187
191
  import { Command, Option } from "commander";
188
- import { parseUnits as parseUnits8, formatUnits as formatUnits7, isAddress as isAddress9 } from "viem";
192
+ import { parseUnits as parseUnits8, formatUnits as formatUnits7, isAddress as isAddress10 } from "viem";
189
193
  import chalk16 from "chalk";
190
194
  import ora9 from "ora";
191
195
  import { input, confirm, select } from "@inquirer/prompts";
@@ -2432,7 +2436,7 @@ function registerStrategyTemplateCommands(strategy2) {
2432
2436
  process.exit(1);
2433
2437
  }
2434
2438
  if (!opts.agent) opts.agent = proposer;
2435
- const { parseDuration: parseDuration3, getGovernorOf: getGovernorOf2 } = await import("./governor-NHXBIFFB.js");
2439
+ const { parseDuration: parseDuration3, getGovernorOf: getGovernorOf2 } = await import("./governor-7KETSN47.js");
2436
2440
  const strategyDuration2 = parseDuration3(opts.duration);
2437
2441
  const chainId = getChain().id;
2438
2442
  try {
@@ -2658,9 +2662,9 @@ function registerStrategyTemplateCommands(strategy2) {
2658
2662
  console.error(chalk.red("Missing --name or --duration. Use --write-calls to skip proposal submission."));
2659
2663
  process.exit(1);
2660
2664
  }
2661
- const { propose: propose2 } = await import("./governor-NHXBIFFB.js");
2665
+ const { propose: propose2 } = await import("./governor-7KETSN47.js");
2662
2666
  const { pinJSON } = await import("./ipfs-RWSTXTZM.js");
2663
- const { parseDuration: parseDuration2 } = await import("./governor-NHXBIFFB.js");
2667
+ const { parseDuration: parseDuration2 } = await import("./governor-7KETSN47.js");
2664
2668
  const strategyDuration = parseDuration2(opts.duration);
2665
2669
  const metaSpinner = ora("Pinning metadata to IPFS...").start();
2666
2670
  let metadataURI;
@@ -2683,7 +2687,7 @@ function registerStrategyTemplateCommands(strategy2) {
2683
2687
  process.exit(1);
2684
2688
  }
2685
2689
  try {
2686
- const { getAgentFeeBps: getAgentFeeBps2 } = await import("./vault-45POYGLN.js");
2690
+ const { getAgentFeeBps: getAgentFeeBps2 } = await import("./vault-5YYTHS5W.js");
2687
2691
  const feeBps = await getAgentFeeBps2(vault);
2688
2692
  console.log(
2689
2693
  chalk.yellow(
@@ -2771,7 +2775,7 @@ function registerStrategyTemplateCommands(strategy2) {
2771
2775
  let prices = [];
2772
2776
  let priceSource = null;
2773
2777
  try {
2774
- const { getTokenPricesInAsset } = await import("./price-QSVIM6QY.js");
2778
+ const { getTokenPricesInAsset } = await import("./price-LAQSXN7M.js");
2775
2779
  prices = await getTokenPricesInAsset({
2776
2780
  tokens: allocations.map((a, i) => ({
2777
2781
  token: a.token,
@@ -3201,7 +3205,7 @@ function registerVeniceCommands(program2) {
3201
3205
  console.log(chalk2.dim(` Key: ${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`));
3202
3206
  console.log(chalk2.dim(" Saved to ~/.sherwood/config.json"));
3203
3207
  try {
3204
- const { createVeniceProvisionAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-XWQYAUEM.js");
3208
+ const { createVeniceProvisionAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-4RIW3IS4.js");
3205
3209
  const { uid } = await createVeniceProvisionAttestation(account.address);
3206
3210
  if (uid !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
3207
3211
  console.log(chalk2.dim(` Attested: ${getEasScanUrl2(uid)}`));
@@ -3557,10 +3561,10 @@ ${opts.prompt}`;
3557
3561
  console.log(chalk2.dim(`Model: ${result.model} | Tokens: ${result.usage.promptTokens} in, ${result.usage.completionTokens} out, ${result.usage.totalTokens} total`));
3558
3562
  }
3559
3563
  try {
3560
- const { createVeniceInferenceAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-XWQYAUEM.js");
3564
+ const { createVeniceInferenceAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-4RIW3IS4.js");
3561
3565
  const { keccak256: keccak2563, toHex, isAddress: isAddr } = await import("viem");
3562
- const { getChainContracts: getChainContracts2 } = await import("./config-7HU4X7EK.js");
3563
- const { getChain: getActiveChain } = await import("./network-WU2QC3L4.js");
3566
+ const { getChainContracts: getChainContracts2 } = await import("./config-ZGFS4I7K.js");
3567
+ const { getChain: getActiveChain } = await import("./network-UP2X5XDW.js");
3564
3568
  const vaultRecipient = opts.vault && isAddr(opts.vault) ? opts.vault : getChainContracts2(getActiveChain().id).vault;
3565
3569
  const promptHash = keccak2563(toHex(userContent)).slice(0, 18);
3566
3570
  const { uid } = await createVeniceInferenceAttestation(
@@ -3858,9 +3862,194 @@ function registerAllowanceCommands(program2) {
3858
3862
  }
3859
3863
 
3860
3864
  // src/commands/identity.ts
3865
+ import { generatePrivateKey } from "viem/accounts";
3861
3866
  import chalk4 from "chalk";
3862
3867
  import ora4 from "ora";
3863
3868
  import { SDK } from "agent0-sdk";
3869
+
3870
+ // src/lib/virtuals.ts
3871
+ import { execFile } from "child_process";
3872
+ import { promisify } from "util";
3873
+ import { createPublicClient, http, recoverMessageAddress, isAddress as isAddress5 } from "viem";
3874
+ import { base, baseSepolia } from "viem/chains";
3875
+ var execFileAsync = promisify(execFile);
3876
+ var BINDING_VERSION = "v1";
3877
+ function buildBindingMessage(sherwoodEoa, issuingChainId, tokenId) {
3878
+ return `sherwood-identity-link:${BINDING_VERSION}:${sherwoodEoa.toLowerCase()}:${issuingChainId}:${tokenId}`;
3879
+ }
3880
+ async function verifyBinding(params) {
3881
+ try {
3882
+ const recovered = await recoverMessageAddress({
3883
+ message: buildBindingMessage(params.sherwoodEoa, params.issuingChainId, params.tokenId),
3884
+ signature: params.signature
3885
+ });
3886
+ return recovered.toLowerCase() === params.virtualsWallet.toLowerCase();
3887
+ } catch {
3888
+ return false;
3889
+ }
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;
3904
+ var ISSUING_CHAINS = {
3905
+ [robinhoodChain.id]: {
3906
+ chain: robinhoodChain,
3907
+ identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
3908
+ },
3909
+ [base.id]: {
3910
+ chain: base,
3911
+ identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
3912
+ },
3913
+ [baseSepolia.id]: {
3914
+ chain: baseSepolia,
3915
+ identityRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e"
3916
+ }
3917
+ };
3918
+ var OWNER_OF_ABI = [
3919
+ {
3920
+ name: "ownerOf",
3921
+ type: "function",
3922
+ stateMutability: "view",
3923
+ inputs: [{ name: "tokenId", type: "uint256" }],
3924
+ outputs: [{ name: "", type: "address" }]
3925
+ }
3926
+ ];
3927
+ var ISSUING_RPC_ENV = {
3928
+ [robinhoodChain.id]: "ROBINHOOD_RPC_URL",
3929
+ [base.id]: "BASE_RPC_URL",
3930
+ [baseSepolia.id]: "BASE_SEPOLIA_RPC_URL"
3931
+ };
3932
+ async function ownerOfOnIssuingChain(issuingChainId, tokenId) {
3933
+ const issuing = ISSUING_CHAINS[issuingChainId];
3934
+ if (!issuing) {
3935
+ throw new Error(
3936
+ `Unsupported issuing chain ${issuingChainId}. Supported: ${Object.keys(ISSUING_CHAINS).join(", ")}`
3937
+ );
3938
+ }
3939
+ const rpcOverride = process.env[ISSUING_RPC_ENV[issuingChainId]];
3940
+ const client = createPublicClient({ chain: issuing.chain, transport: http(rpcOverride) });
3941
+ return client.readContract({
3942
+ address: issuing.identityRegistry,
3943
+ abi: OWNER_OF_ABI,
3944
+ functionName: "ownerOf",
3945
+ args: [tokenId]
3946
+ });
3947
+ }
3948
+ var VID_TAG_RE = /\s*\[vid:(v\d+):(\d+):(\d+):(0x[0-9a-fA-F]{40}):(self|0x[0-9a-fA-F]{130})\]\s*$/;
3949
+ function formatVidTag(tag) {
3950
+ return `[vid:${BINDING_VERSION}:${tag.issuingChainId}:${tag.tokenId}:${tag.wallet.toLowerCase()}:${tag.signature}]`;
3951
+ }
3952
+ function appendVidTag(message, tag) {
3953
+ return `${message} ${formatVidTag(tag)}`;
3954
+ }
3955
+ function parseVidTag(message) {
3956
+ if (message.indexOf("[vid:") !== message.lastIndexOf("[vid:")) return null;
3957
+ const match = message.match(VID_TAG_RE);
3958
+ if (!match) return null;
3959
+ if (!isAddress5(match[4])) return null;
3960
+ return {
3961
+ version: match[1],
3962
+ issuingChainId: parseInt(match[2], 10),
3963
+ tokenId: BigInt(match[3]),
3964
+ wallet: match[4],
3965
+ signature: match[5] === "self" ? "self" : match[5]
3966
+ };
3967
+ }
3968
+ function stripVidTag(message) {
3969
+ return message.replace(VID_TAG_RE, "");
3970
+ }
3971
+ async function verifyVidTag(tag, attester, ownerOf = ownerOfOnIssuingChain) {
3972
+ let bindingOk;
3973
+ if (tag.signature === "self") {
3974
+ bindingOk = attester.toLowerCase() === tag.wallet.toLowerCase();
3975
+ } else {
3976
+ bindingOk = await verifyBinding({
3977
+ sherwoodEoa: attester,
3978
+ issuingChainId: tag.issuingChainId,
3979
+ tokenId: tag.tokenId,
3980
+ virtualsWallet: tag.wallet,
3981
+ signature: tag.signature
3982
+ });
3983
+ }
3984
+ if (!bindingOk) {
3985
+ return { bindingOk: false, ownerOk: false, error: "binding failed \u2014 ownership check skipped" };
3986
+ }
3987
+ try {
3988
+ const owner = await ownerOf(tag.issuingChainId, tag.tokenId);
3989
+ return {
3990
+ bindingOk,
3991
+ ownerOk: owner.toLowerCase() === tag.wallet.toLowerCase(),
3992
+ owner
3993
+ };
3994
+ } catch (err) {
3995
+ return { bindingOk, ownerOk: false, error: err.message };
3996
+ }
3997
+ }
3998
+ function makeOwnerOfCache() {
3999
+ const cache = /* @__PURE__ */ new Map();
4000
+ return (chainId, tokenId) => {
4001
+ const key = `${chainId}:${tokenId}`;
4002
+ let p = cache.get(key);
4003
+ if (!p) {
4004
+ p = ownerOfOnIssuingChain(chainId, tokenId);
4005
+ p.catch(() => {
4006
+ });
4007
+ cache.set(key, p);
4008
+ }
4009
+ return p;
4010
+ };
4011
+ }
4012
+ async function acpJson(args) {
4013
+ try {
4014
+ const { stdout } = await execFileAsync("acp", [...args, "--json"], {
4015
+ timeout: 15e3
4016
+ });
4017
+ const start = stdout.indexOf("{");
4018
+ if (start < 0) return null;
4019
+ return JSON.parse(stdout.slice(start));
4020
+ } catch {
4021
+ return null;
4022
+ }
4023
+ }
4024
+ async function detectAcp() {
4025
+ try {
4026
+ await execFileAsync("acp", ["--version"], { timeout: 1e4 });
4027
+ return true;
4028
+ } catch {
4029
+ return false;
4030
+ }
4031
+ }
4032
+ async function acpWhoami() {
4033
+ const json = await acpJson(["agent", "whoami"]);
4034
+ if (!json) return null;
4035
+ const agentId = json.agentId ?? json.id ?? json.agent?.id;
4036
+ const name = json.name ?? json.agent?.name;
4037
+ return {
4038
+ agentId: agentId != null ? String(agentId) : void 0,
4039
+ name: name != null ? String(name) : void 0
4040
+ };
4041
+ }
4042
+ async function acpWalletAddress() {
4043
+ const json = await acpJson(["wallet", "address"]);
4044
+ if (!json) return null;
4045
+ for (const key of ["address", "evmAddress", "evm", "wallet"]) {
4046
+ const value = json[key];
4047
+ if (typeof value === "string" && isAddress5(value)) return value;
4048
+ }
4049
+ return null;
4050
+ }
4051
+
4052
+ // src/commands/identity.ts
3864
4053
  var IDENTITY_REGISTRY_ABI2 = [
3865
4054
  {
3866
4055
  name: "balanceOf",
@@ -3976,6 +4165,123 @@ function registerIdentityCommands(program2) {
3976
4165
  process.exit(1);
3977
4166
  }
3978
4167
  });
4168
+ 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").action(async (opts) => {
4169
+ const account = getAccount();
4170
+ const issuingChainId = parseInt(opts.chainId, 10);
4171
+ if (!ISSUING_CHAINS[issuingChainId]) {
4172
+ console.error(chalk4.red(`Unsupported issuing chain ${opts.chainId}. Supported: ${Object.keys(ISSUING_CHAINS).join(", ")}`));
4173
+ process.exit(1);
4174
+ }
4175
+ const spinner = ora4("Resolving economyOS agent...").start();
4176
+ try {
4177
+ let virtualsWallet = opts.wallet;
4178
+ let virtualsAgentId;
4179
+ if (await detectAcp()) {
4180
+ const who = await acpWhoami();
4181
+ virtualsAgentId = who?.agentId;
4182
+ if (!virtualsWallet) {
4183
+ virtualsWallet = await acpWalletAddress() ?? void 0;
4184
+ }
4185
+ }
4186
+ if (!virtualsWallet) {
4187
+ spinner.fail("Could not resolve the economyOS agent wallet");
4188
+ console.error(chalk4.dim(" Install + authenticate the acp CLI (npm i -g @virtuals-protocol/acp-cli; acp configure)"));
4189
+ console.error(chalk4.dim(" or pass --wallet <address> explicitly."));
4190
+ process.exit(1);
4191
+ }
4192
+ let tokenId;
4193
+ if (opts.agentId) {
4194
+ tokenId = BigInt(opts.agentId);
4195
+ } else {
4196
+ spinner.text = `Searching ERC-8004 registry on chain ${issuingChainId} for ${virtualsWallet}...`;
4197
+ const sdk = new SDK({
4198
+ chainId: issuingChainId,
4199
+ rpcUrl: ISSUING_CHAINS[issuingChainId].chain.rpcUrls.default.http[0],
4200
+ privateKey: generatePrivateKey()
4201
+ });
4202
+ const results = await sdk.searchAgents({
4203
+ walletAddress: virtualsWallet,
4204
+ chains: [issuingChainId]
4205
+ });
4206
+ if (results.length === 0) {
4207
+ spinner.fail(`No ERC-8004 registration found for ${virtualsWallet} on chain ${issuingChainId}`);
4208
+ console.error(chalk4.dim(" Register first via the Virtuals CLI:"));
4209
+ console.error(chalk4.dim(` acp agent register-erc8004 --agent-id ${virtualsAgentId ?? "<id>"} --chain-id ${issuingChainId}`));
4210
+ console.error(chalk4.dim(" Then re-run this command (or pass --agent-id <tokenId> directly)."));
4211
+ process.exit(1);
4212
+ }
4213
+ if (results.length > 1) {
4214
+ spinner.fail(`Wallet ${virtualsWallet} has ${results.length} ERC-8004 registrations on chain ${issuingChainId} \u2014 pick one explicitly`);
4215
+ for (const a of results) {
4216
+ const idStr2 = String(a.agentId);
4217
+ const tid = idStr2.includes(":") ? idStr2.split(":")[1] : idStr2;
4218
+ console.error(chalk4.dim(` #${tid} ${a.name || "(no name)"}`));
4219
+ }
4220
+ console.error(chalk4.green(" Re-run with: sherwood identity link-virtuals --agent-id <tokenId>"));
4221
+ process.exit(1);
4222
+ }
4223
+ const idStr = String(results[0].agentId);
4224
+ tokenId = BigInt(idStr.includes(":") ? idStr.split(":")[1] : idStr);
4225
+ }
4226
+ if (tokenId > BigInt(Number.MAX_SAFE_INTEGER)) {
4227
+ spinner.fail(`Token ID ${tokenId} exceeds Number.MAX_SAFE_INTEGER \u2014 cannot be stored in config`);
4228
+ process.exit(1);
4229
+ }
4230
+ spinner.text = `Verifying ownerOf(#${tokenId}) on chain ${issuingChainId}...`;
4231
+ const owner = await ownerOfOnIssuingChain(issuingChainId, tokenId);
4232
+ if (owner.toLowerCase() !== virtualsWallet.toLowerCase()) {
4233
+ spinner.fail(`Agent #${tokenId} on chain ${issuingChainId} is owned by ${owner}, not ${virtualsWallet}`);
4234
+ process.exit(1);
4235
+ }
4236
+ const self = virtualsWallet.toLowerCase() === account.address.toLowerCase();
4237
+ const bindingMessage = buildBindingMessage(account.address, issuingChainId, tokenId);
4238
+ let binding;
4239
+ if (!self) {
4240
+ if (!opts.bindingSig) {
4241
+ spinner.fail("Binding signature required (economyOS wallet differs from your Sherwood wallet)");
4242
+ console.error();
4243
+ console.error(chalk4.bold(" Sign this exact message with the economyOS agent wallet:"));
4244
+ console.error(chalk4.green(` ${bindingMessage}`));
4245
+ console.error();
4246
+ console.error(chalk4.dim(" (e.g. via the acp CLI / app.virtuals.io wallet signing, EIP-191 personal_sign)"));
4247
+ console.error(chalk4.dim(" Then re-run with --binding-sig <signature>."));
4248
+ process.exit(1);
4249
+ }
4250
+ spinner.text = "Verifying binding signature...";
4251
+ const ok = await verifyBinding({
4252
+ sherwoodEoa: account.address,
4253
+ issuingChainId,
4254
+ tokenId,
4255
+ virtualsWallet,
4256
+ signature: opts.bindingSig
4257
+ });
4258
+ if (!ok) {
4259
+ spinner.fail("Binding signature does not recover to the economyOS wallet");
4260
+ console.error(chalk4.dim(` Expected signer: ${virtualsWallet}`));
4261
+ console.error(chalk4.dim(` Signed message must be exactly: ${bindingMessage}`));
4262
+ process.exit(1);
4263
+ }
4264
+ binding = { sig: opts.bindingSig, message: bindingMessage };
4265
+ }
4266
+ setVirtualsIdentity(Number(tokenId), issuingChainId, {
4267
+ agentId: virtualsAgentId,
4268
+ wallet: virtualsWallet,
4269
+ binding
4270
+ });
4271
+ spinner.succeed(`Virtuals identity linked: agent #${tokenId} (chain ${issuingChainId})`);
4272
+ console.log(chalk4.dim(` economyOS wallet: ${virtualsWallet}`));
4273
+ if (virtualsAgentId) console.log(chalk4.dim(` Virtuals agent: ${virtualsAgentId}`));
4274
+ console.log(chalk4.dim(` Sherwood wallet: ${account.address}${self ? " (same as economyOS wallet \u2014 no binding needed)" : " (bound via signature)"}`));
4275
+ console.log(chalk4.dim(` Saved to ~/.sherwood/config.json`));
4276
+ console.log();
4277
+ console.log(chalk4.green("You can now create or join funds with this identity:"));
4278
+ console.log(chalk4.dim(` sherwood fund create --agent-id ${tokenId} --subdomain <name> --name <name>`));
4279
+ } catch (err) {
4280
+ spinner.fail("Failed to link Virtuals identity");
4281
+ console.error(chalk4.red(formatContractError(err)));
4282
+ process.exit(1);
4283
+ }
4284
+ });
3979
4285
  identity.command("find").description("Search ERC-8004 agents by wallet address or name (recover a lost agent ID)").option("--wallet <address>", "Filter by owner / wallet address").option("--name <text>", "Filter by agent name (exact or substring match, depending on registry)").option("--all-chains", "Search across all chains, not just the active one").action(async (opts) => {
3980
4286
  if (!opts.wallet && !opts.name) {
3981
4287
  console.error(chalk4.red("Pass --wallet <address> or --name <text> (or both)."));
@@ -4022,6 +4328,47 @@ function registerIdentityCommands(program2) {
4022
4328
  });
4023
4329
  identity.command("status").description("Show your agent identity status").action(async () => {
4024
4330
  const account = getAccount();
4331
+ if (getIdentityProvider() === "virtuals") {
4332
+ const virtuals = getVirtualsIdentity();
4333
+ const savedId = getAgentId();
4334
+ const issuingChainId = getIdentityChainId();
4335
+ console.log();
4336
+ console.log(chalk4.bold("Agent Identity (ERC-8004 via Virtuals economyOS)"));
4337
+ console.log(chalk4.dim("\u2500".repeat(40)));
4338
+ console.log(` Sherwood wallet: ${account.address}`);
4339
+ console.log(` economyOS wallet: ${virtuals?.wallet ?? chalk4.red("(missing)")}`);
4340
+ if (virtuals?.agentId) console.log(` Virtuals agent: ${virtuals.agentId}`);
4341
+ console.log(` Issuing chain: ${issuingChainId ?? chalk4.red("(missing)")}`);
4342
+ console.log(` Saved ID: ${savedId != null ? `#${savedId}` : chalk4.red("(missing)")}`);
4343
+ if (virtuals?.wallet && savedId != null && issuingChainId != null) {
4344
+ const spinner2 = ora4("Re-verifying link...").start();
4345
+ try {
4346
+ const owner = await ownerOfOnIssuingChain(issuingChainId, BigInt(savedId));
4347
+ const ownerOk = owner.toLowerCase() === virtuals.wallet.toLowerCase();
4348
+ let bindingOk = virtuals.wallet.toLowerCase() === account.address.toLowerCase();
4349
+ if (!bindingOk && virtuals.binding?.sig) {
4350
+ bindingOk = await verifyBinding({
4351
+ sherwoodEoa: account.address,
4352
+ issuingChainId,
4353
+ tokenId: BigInt(savedId),
4354
+ virtualsWallet: virtuals.wallet,
4355
+ signature: virtuals.binding.sig
4356
+ });
4357
+ }
4358
+ spinner2.stop();
4359
+ console.log(` NFT ownership: ${ownerOk ? chalk4.green("verified") : chalk4.red(`FAILED (owner is ${owner})`)}`);
4360
+ console.log(` Binding: ${bindingOk ? chalk4.green("verified") : chalk4.red("FAILED")}`);
4361
+ if (!ownerOk) {
4362
+ console.log(chalk4.yellow(" The NFT moved since linking \u2014 re-run 'sherwood identity link-virtuals'."));
4363
+ }
4364
+ } catch (err) {
4365
+ spinner2.warn("Could not re-verify against the issuing chain");
4366
+ console.log(chalk4.dim(` ${err.message}`));
4367
+ }
4368
+ }
4369
+ console.log();
4370
+ return;
4371
+ }
4025
4372
  const registry = AGENT_REGISTRY().IDENTITY_REGISTRY;
4026
4373
  const client = getPublicClient();
4027
4374
  const spinner = ora4("Checking identity...").start();
@@ -4115,7 +4462,7 @@ function registerIdentityCommands(program2) {
4115
4462
  }
4116
4463
 
4117
4464
  // src/commands/proposal.ts
4118
- import { isAddress as isAddress5, encodeFunctionData as encodeFunctionData10 } from "viem";
4465
+ import { isAddress as isAddress6, encodeFunctionData as encodeFunctionData10 } from "viem";
4119
4466
  import chalk6 from "chalk";
4120
4467
  import ora5 from "ora";
4121
4468
  import { readFileSync as readFileSync2 } from "fs";
@@ -4808,8 +5155,8 @@ function printSimulationResult(result, callType) {
4808
5155
  }
4809
5156
  async function sendSimulationAlert(subdomain, proposalId, vault, execResult, settleResult) {
4810
5157
  try {
4811
- const xmtp = await import("./xmtp-KH5I6GOL.js");
4812
- const { getAccount: getAccount2 } = await import("./client-C3C6IXAH.js");
5158
+ const xmtp = await import("./xmtp-OZ5PJFCT.js");
5159
+ const { getAccount: getAccount2 } = await import("./client-GRPJRISD.js");
4813
5160
  const group = await xmtp.getGroup("", subdomain);
4814
5161
  const allRisks = [...execResult.risks, ...settleResult?.risks ?? []];
4815
5162
  const criticals = allRisks.filter((r) => r.level === "critical");
@@ -4902,7 +5249,7 @@ function formatTimestamp(ts) {
4902
5249
  }
4903
5250
  function parseVaultOption(raw, spinner) {
4904
5251
  const vault = String(raw);
4905
- if (!isAddress5(vault)) {
5252
+ if (!isAddress6(vault)) {
4906
5253
  if (spinner) spinner.fail(`Invalid vault address: ${vault}`);
4907
5254
  else console.error(chalk6.red(`Invalid vault address: ${vault}`));
4908
5255
  process.exit(1);
@@ -4956,7 +5303,7 @@ function registerProposalCommands(program2) {
4956
5303
  proposal.command("create").description("Submit a strategy proposal").requiredOption("--vault <address>", "Vault address the proposal targets").requiredOption("--name <name>", "Strategy name").requiredOption("--description <text>", "Strategy rationale and risk summary").requiredOption("--duration <duration>", "Strategy duration (e.g. 7d, 24h, 3600)").requiredOption("--execute-calls <path>", "Path to JSON file with execute Call[] array").requiredOption("--settle-calls <path>", "Path to JSON file with settlement Call[] array").option("--strategy <address>", "Live-NAV strategy clone address (default: none \u2014 queue-only)").option("--metadata-uri <uri>", "Override \u2014 skip IPFS upload and use this URI directly").option("--simulate", "Simulate calls via Tenderly before submitting").option("--force", "Submit even if simulation fails (requires --simulate)").action(async (opts) => {
4957
5304
  try {
4958
5305
  const vault = opts.vault;
4959
- if (!isAddress5(vault)) {
5306
+ if (!isAddress6(vault)) {
4960
5307
  console.error(chalk6.red(`Invalid vault address: ${opts.vault}`));
4961
5308
  process.exit(1);
4962
5309
  }
@@ -4966,7 +5313,7 @@ function registerProposalCommands(program2) {
4966
5313
  const ZERO_STRATEGY = "0x0000000000000000000000000000000000000000";
4967
5314
  let strategy2 = ZERO_STRATEGY;
4968
5315
  if (opts.strategy) {
4969
- if (!isAddress5(opts.strategy)) {
5316
+ if (!isAddress6(opts.strategy)) {
4970
5317
  console.error(chalk6.red(`Invalid strategy address: ${opts.strategy}`));
4971
5318
  process.exit(1);
4972
5319
  }
@@ -5748,7 +6095,7 @@ function registerProposalCommands(program2) {
5748
6095
  let riskContext = {};
5749
6096
  let proposalId;
5750
6097
  if (opts.id) {
5751
- if (!opts.vault || !isAddress5(opts.vault)) {
6098
+ if (!opts.vault || !isAddress6(opts.vault)) {
5752
6099
  console.error(chalk6.red("\n \u2716 --vault is required when using --id (proposal IDs are per-vault)"));
5753
6100
  process.exit(1);
5754
6101
  }
@@ -5772,7 +6119,7 @@ function registerProposalCommands(program2) {
5772
6119
  console.log(DIM2(`
5773
6120
  Simulating proposal #${proposalId} on vault ${vault.slice(0, 10)}...`));
5774
6121
  } else if (opts.executeCalls) {
5775
- if (!opts.vault || !isAddress5(opts.vault)) {
6122
+ if (!opts.vault || !isAddress6(opts.vault)) {
5776
6123
  console.error(chalk6.red("\n \u2716 --vault is required when using --execute-calls"));
5777
6124
  process.exit(1);
5778
6125
  }
@@ -5815,7 +6162,7 @@ function registerProposalCommands(program2) {
5815
6162
  }
5816
6163
 
5817
6164
  // src/commands/queue.ts
5818
- import { parseUnits as parseUnits5, formatUnits as formatUnits5, isAddress as isAddress6, parseEventLogs } from "viem";
6165
+ import { parseUnits as parseUnits5, formatUnits as formatUnits5, isAddress as isAddress7, parseEventLogs } from "viem";
5819
6166
  import chalk7 from "chalk";
5820
6167
  import ora6 from "ora";
5821
6168
  var WETH_ABI2 = [
@@ -5951,7 +6298,7 @@ var QUEUE_ABI = [
5951
6298
  ];
5952
6299
  var KIND_LABELS = ["Redeem", "Deposit"];
5953
6300
  function resolveVaultAddress(opt) {
5954
- if (!opt || !isAddress6(opt)) {
6301
+ if (!opt || !isAddress7(opt)) {
5955
6302
  console.error(chalk7.red(`Invalid or missing --vault address: ${opt ?? "(none)"}`));
5956
6303
  process.exit(1);
5957
6304
  }
@@ -6204,7 +6551,7 @@ function registerQueueCommands(program2) {
6204
6551
  // src/commands/governor.ts
6205
6552
  import chalk8 from "chalk";
6206
6553
  import ora7 from "ora";
6207
- import { isAddress as isAddress7 } from "viem";
6554
+ import { isAddress as isAddress8 } from "viem";
6208
6555
  var G3 = chalk8.green;
6209
6556
  var W3 = chalk8.white;
6210
6557
  var DIM3 = chalk8.gray;
@@ -6213,7 +6560,7 @@ var LABEL3 = chalk8.green.bold;
6213
6560
  var SEP3 = () => console.log(DIM3("\u2500".repeat(60)));
6214
6561
  function parseVaultArg(raw) {
6215
6562
  const vault = String(raw);
6216
- if (!isAddress7(vault)) {
6563
+ if (!isAddress8(vault)) {
6217
6564
  console.error(chalk8.red(`Invalid vault address: ${vault}`));
6218
6565
  process.exit(1);
6219
6566
  }
@@ -6388,7 +6735,7 @@ function registerGovernorCommands(program2) {
6388
6735
  // src/commands/guardian-delegate.ts
6389
6736
  import chalk9 from "chalk";
6390
6737
  import ora8 from "ora";
6391
- import { formatUnits as formatUnits6, isAddress as isAddress8, parseUnits as parseUnits6 } from "viem";
6738
+ import { formatUnits as formatUnits6, isAddress as isAddress9, parseUnits as parseUnits6 } from "viem";
6392
6739
  var G4 = chalk9.green;
6393
6740
  var W4 = chalk9.white;
6394
6741
  var DIM4 = chalk9.gray;
@@ -6470,7 +6817,7 @@ function registerGuardianCommands(program2) {
6470
6817
  const pc = getPublicClient();
6471
6818
  let target;
6472
6819
  if (addressArg) {
6473
- if (!isAddress8(addressArg)) {
6820
+ if (!isAddress9(addressArg)) {
6474
6821
  console.error(chalk9.red("Invalid address"));
6475
6822
  process.exit(1);
6476
6823
  }
@@ -6588,7 +6935,7 @@ function registerGuardianCommands(program2) {
6588
6935
  }
6589
6936
  });
6590
6937
  guardian.command("delegate <delegate> <amount>").description("Delegate WOOD stake to a guardian. Amount in WOOD.").action(async (delegate, amountStr) => {
6591
- if (!isAddress8(delegate)) {
6938
+ if (!isAddress9(delegate)) {
6592
6939
  console.error(chalk9.red("Invalid delegate address"));
6593
6940
  process.exit(1);
6594
6941
  }
@@ -6612,7 +6959,7 @@ function registerGuardianCommands(program2) {
6612
6959
  }
6613
6960
  });
6614
6961
  guardian.command("undelegate <delegate> <action>").description("Unstake-delegation flow: 'request' | 'cancel' | 'claim'").action(async (delegate, action) => {
6615
- if (!isAddress8(delegate)) {
6962
+ if (!isAddress9(delegate)) {
6616
6963
  console.error(chalk9.red("Invalid delegate address"));
6617
6964
  process.exit(1);
6618
6965
  }
@@ -8646,13 +8993,13 @@ import { join as join4 } from "path";
8646
8993
  import { homedir as homedir4 } from "os";
8647
8994
  import { createHash as createHash2 } from "crypto";
8648
8995
  var DEFAULT_SWEEP_DIR = join4(homedir4(), ".sherwood", "grid", "sweeps");
8649
- function expandSweep(sweep, base) {
8996
+ function expandSweep(sweep, base2) {
8650
8997
  const fields = ["leverage", "levelsPerSide", "atrMultiplier", "rebalanceDriftPct"];
8651
8998
  const valueLists = {
8652
- leverage: sweep.leverage && sweep.leverage.length > 0 ? sweep.leverage : [base.leverage],
8653
- levelsPerSide: sweep.levelsPerSide && sweep.levelsPerSide.length > 0 ? sweep.levelsPerSide : [base.levelsPerSide],
8654
- atrMultiplier: sweep.atrMultiplier && sweep.atrMultiplier.length > 0 ? sweep.atrMultiplier : [base.atrMultiplier],
8655
- rebalanceDriftPct: sweep.rebalanceDriftPct && sweep.rebalanceDriftPct.length > 0 ? sweep.rebalanceDriftPct : [base.rebalanceDriftPct]
8999
+ leverage: sweep.leverage && sweep.leverage.length > 0 ? sweep.leverage : [base2.leverage],
9000
+ levelsPerSide: sweep.levelsPerSide && sweep.levelsPerSide.length > 0 ? sweep.levelsPerSide : [base2.levelsPerSide],
9001
+ atrMultiplier: sweep.atrMultiplier && sweep.atrMultiplier.length > 0 ? sweep.atrMultiplier : [base2.atrMultiplier],
9002
+ rebalanceDriftPct: sweep.rebalanceDriftPct && sweep.rebalanceDriftPct.length > 0 ? sweep.rebalanceDriftPct : [base2.rebalanceDriftPct]
8656
9003
  };
8657
9004
  let combos = [{}];
8658
9005
  for (const field of fields) {
@@ -8691,13 +9038,13 @@ async function runSweep(opts) {
8691
9038
  tokenSplit = {};
8692
9039
  for (const t of opts.tokens) tokenSplit[t] = weight;
8693
9040
  }
8694
- const base = {
9041
+ const base2 = {
8695
9042
  ...DEFAULT_GRID_CONFIG,
8696
9043
  ...opts.baseConfig,
8697
9044
  tokens: opts.tokens,
8698
9045
  tokenSplit
8699
9046
  };
8700
- const combos = expandSweep(opts.sweep, base);
9047
+ const combos = expandSweep(opts.sweep, base2);
8701
9048
  if (combos.length === 0) throw new Error("sweep produced no combinations");
8702
9049
  const loader = new HistoricalDataLoader({ noCache: opts.noCache });
8703
9050
  if (opts.verbose !== false) {
@@ -8708,7 +9055,7 @@ async function runSweep(opts) {
8708
9055
  const runs = [];
8709
9056
  for (let i = 0; i < combos.length; i++) {
8710
9057
  const combo = combos[i];
8711
- const config = { ...base, ...combo };
9058
+ const config = { ...base2, ...combo };
8712
9059
  const runOutPath = join4(sweepDir, `run-${i.toString().padStart(3, "0")}.json`);
8713
9060
  if (opts.verbose !== false) {
8714
9061
  process.stderr.write(` [sweep] [${i + 1}/${combos.length}] ${JSON.stringify(combo)}
@@ -9246,9 +9593,9 @@ try {
9246
9593
  } catch {
9247
9594
  }
9248
9595
  var require2 = createRequire(import.meta.url);
9249
- var CLI_VERSION = "0.74.3";
9596
+ var CLI_VERSION = "0.76.0";
9250
9597
  async function loadXmtp() {
9251
- return import("./xmtp-KH5I6GOL.js");
9598
+ return import("./xmtp-OZ5PJFCT.js");
9252
9599
  }
9253
9600
  async function loadCron() {
9254
9601
  return import("./cron-QMLRWDJG.js");
@@ -9260,7 +9607,7 @@ var BOLD6 = chalk16.white.bold;
9260
9607
  var LABEL5 = chalk16.green.bold;
9261
9608
  var SEP6 = () => console.log(DIM6("\u2500".repeat(60)));
9262
9609
  function validateAddress(value, name) {
9263
- if (!isAddress9(value)) {
9610
+ if (!isAddress10(value)) {
9264
9611
  console.error(chalk16.red(`Invalid ${name} address: ${value}`));
9265
9612
  process.exit(1);
9266
9613
  }
@@ -9849,7 +10196,7 @@ fund.command("add").description("Register an agent on a fund vault (creator only
9849
10196
  if (opts.agentId) {
9850
10197
  agentId = BigInt(opts.agentId);
9851
10198
  } else {
9852
- const { AGENT_REGISTRY: AGENT_REGISTRY2 } = await import("./addresses-OFFTM6NG.js");
10199
+ const { AGENT_REGISTRY: AGENT_REGISTRY2 } = await import("./addresses-JJPQTF6S.js");
9853
10200
  const registry = AGENT_REGISTRY2().IDENTITY_REGISTRY;
9854
10201
  if (registry === "0x0000000000000000000000000000000000000000") {
9855
10202
  agentId = 0n;
@@ -9982,6 +10329,16 @@ fund.command("join").description("Request to join a fund (creates an EAS attesta
9982
10329
  }
9983
10330
  process.exit(1);
9984
10331
  }
10332
+ let joinMessage = opts.message;
10333
+ const virtualsIdentity = getVirtualsIdentity();
10334
+ if (getIdentityProvider() === "virtuals" && virtualsIdentity) {
10335
+ joinMessage = appendVidTag(joinMessage, {
10336
+ issuingChainId: getIdentityChainId() ?? DEFAULT_ISSUING_CHAIN_ID,
10337
+ tokenId: BigInt(agentId),
10338
+ wallet: virtualsIdentity.wallet,
10339
+ signature: virtualsIdentity.binding?.sig ?? "self"
10340
+ });
10341
+ }
9985
10342
  if (isCalldataOnly()) {
9986
10343
  const referrerAgentId2 = opts.ref ? parseInt(opts.ref, 10) : void 0;
9987
10344
  spinner.stop();
@@ -9992,7 +10349,7 @@ fund.command("join").description("Request to join a fund (creates an EAS attesta
9992
10349
  agentId: BigInt(agentId),
9993
10350
  vault: fund2.vault,
9994
10351
  creator: fund2.creator,
9995
- message: opts.message,
10352
+ message: joinMessage,
9996
10353
  referrerAgentId: referrerAgentId2
9997
10354
  },
9998
10355
  getChain().id
@@ -10050,7 +10407,7 @@ fund.command("join").description("Request to join a fund (creates an EAS attesta
10050
10407
  BigInt(agentId),
10051
10408
  fund2.vault,
10052
10409
  fund2.creator,
10053
- opts.message,
10410
+ joinMessage,
10054
10411
  referrerAgentId
10055
10412
  );
10056
10413
  try {
@@ -10137,16 +10494,26 @@ fund.command("requests").description("View pending join requests for a fund (cre
10137
10494
  console.log();
10138
10495
  console.log(LABEL5(` \u25C6 Pending Join Requests (${requests.length})`));
10139
10496
  SEP6();
10497
+ const ownerOfCached = makeOwnerOfCache();
10140
10498
  for (let i = 0; i < requests.length; i++) {
10141
10499
  const req = requests[i];
10142
10500
  const date = new Date(req.time * 1e3).toLocaleString();
10143
10501
  const referrer = parseReferrer(req.decoded.message);
10144
- const cleanMessage = stripReferrerPrefix(req.decoded.message);
10502
+ const vid = parseVidTag(req.decoded.message);
10503
+ const cleanMessage = stripReferrerPrefix(stripVidTag(req.decoded.message));
10145
10504
  console.log(W6(` ${i + 1}. Agent #${req.decoded.agentId} ${DIM6(`(${req.attester})`)}`));
10146
10505
  console.log(DIM6(` Message: "${cleanMessage}"`));
10147
10506
  if (referrer !== null) {
10148
10507
  console.log(G6(` Referred by: Agent #${referrer}`));
10149
10508
  }
10509
+ if (vid) {
10510
+ const v = await verifyVidTag(vid, req.attester, ownerOfCached);
10511
+ const verified = v.bindingOk && v.ownerOk;
10512
+ const badge = verified ? G6("\u2714 verified") : chalk16.red("\u2718 FAILED");
10513
+ console.log(W6(` Virtuals: ${badge} ${DIM6(`(agent #${vid.tokenId} on chain ${vid.issuingChainId}, wallet ${vid.wallet})`)}`));
10514
+ if (!v.bindingOk) console.log(chalk16.red(` binding signature invalid \u2014 do not approve based on this identity`));
10515
+ else if (!v.ownerOk) console.log(chalk16.red(` NFT ownership check failed${v.owner ? ` (owner is ${v.owner})` : v.error ? ` (${v.error})` : ""}`));
10516
+ }
10150
10517
  console.log(DIM6(` Requested: ${date}`));
10151
10518
  console.log(DIM6(` Attestation: ${req.uid}`));
10152
10519
  console.log();
@@ -10542,7 +10909,7 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
10542
10909
  `));
10543
10910
  process.exit(1);
10544
10911
  }
10545
- if (opts.receiver && !isAddress9(opts.receiver)) {
10912
+ if (opts.receiver && !isAddress10(opts.receiver)) {
10546
10913
  console.error(chalk16.red(`
10547
10914
  \u2716 Invalid receiver address: ${opts.receiver}
10548
10915
  `));
@@ -10575,7 +10942,7 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
10575
10942
  var strategy = program.command("strategy").description("Strategy templates \u2014 list, clone, propose");
10576
10943
  registerStrategyTemplateCommands(strategy);
10577
10944
  program.command("providers").description("List available providers (research + swap routing)").action(async () => {
10578
- const { listProviders } = await import("./providers-YOOQFBN2.js");
10945
+ const { listProviders } = await import("./providers-2J6LL67W.js");
10579
10946
  for (const info of listProviders()) {
10580
10947
  console.log(`
10581
10948
  ${info.name} (${info.type})`);
@@ -10585,7 +10952,7 @@ ${info.name} (${info.type})`);
10585
10952
  }
10586
10953
  });
10587
10954
  try {
10588
- const { registerChatCommands } = await import("./chat-CXUU4AXK.js");
10955
+ const { registerChatCommands } = await import("./chat-CO244AHH.js");
10589
10956
  registerChatCommands(program);
10590
10957
  } catch {
10591
10958
  program.command("chat <name> [action] [actionArgs...]").description("Fund chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
@@ -10595,7 +10962,7 @@ try {
10595
10962
  process.exit(1);
10596
10963
  });
10597
10964
  }
10598
- var { registerSessionCommands } = await import("./session-NLI6UFKB.js");
10965
+ var { registerSessionCommands } = await import("./session-JQ3IF3IV.js");
10599
10966
  registerSessionCommands(program);
10600
10967
  registerVeniceCommands(program);
10601
10968
  registerAllowanceCommands(program);
@@ -10604,11 +10971,11 @@ registerProposalCommands(program);
10604
10971
  registerQueueCommands(program);
10605
10972
  registerGovernorCommands(program);
10606
10973
  registerGuardianCommands(program);
10607
- var { registerResearchCommands } = await import("./research-NQKYGTLY.js");
10974
+ var { registerResearchCommands } = await import("./research-FHQCSLTZ.js");
10608
10975
  registerResearchCommands(program);
10609
- var { registerAgentCommands } = await import("./agent-B7V5L2ZL.js");
10976
+ var { registerAgentCommands } = await import("./agent-FYRYTKYM.js");
10610
10977
  registerAgentCommands(program);
10611
- var { registerTradeCommands } = await import("./trade-6VYB6YJZ.js");
10978
+ var { registerTradeCommands } = await import("./trade-5EYPZN7M.js");
10612
10979
  registerTradeCommands(program);
10613
10980
  registerGridCommand(program);
10614
10981
  var configCmd = program.command("config");