@sherwoodagent/cli 0.7.2 → 0.8.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 (30) hide show
  1. package/dist/{chat-BSLMAYM5.js → chat-O34BTHII.js} +5 -5
  2. package/dist/{chunk-5F5LFNIC.js → chunk-4MTHXGTK.js} +20 -11
  3. package/dist/chunk-4MTHXGTK.js.map +1 -0
  4. package/dist/{chunk-QMWMT6EH.js → chunk-5ADWTXNT.js} +115 -31
  5. package/dist/chunk-5ADWTXNT.js.map +1 -0
  6. package/dist/{chunk-B7XDUFI3.js → chunk-ARZIQ7YZ.js} +3 -3
  7. package/dist/{chunk-6MEYSN2W.js → chunk-BXUNWV52.js} +480 -36
  8. package/dist/chunk-BXUNWV52.js.map +1 -0
  9. package/dist/{chunk-P3GYAMGZ.js → chunk-VQP4XR67.js} +15 -5
  10. package/dist/chunk-VQP4XR67.js.map +1 -0
  11. package/dist/{eas-TMHFTX43.js → eas-TI4XI5VU.js} +4 -4
  12. package/dist/index.js +1064 -210
  13. package/dist/index.js.map +1 -1
  14. package/dist/{research-SESA7KGU.js → research-GX32VMP7.js} +5 -5
  15. package/dist/{research-JMGCIJ4H.js → research-ZR7HXITG.js} +3 -3
  16. package/dist/{session-XUOMZWOT.js → session-QEIVURQO.js} +5 -5
  17. package/dist/{xmtp-4XTQQ7RE.js → xmtp-A6F63GZH.js} +6 -6
  18. package/dist/xmtp-A6F63GZH.js.map +1 -0
  19. package/package.json +1 -1
  20. package/dist/chunk-5F5LFNIC.js.map +0 -1
  21. package/dist/chunk-6MEYSN2W.js.map +0 -1
  22. package/dist/chunk-P3GYAMGZ.js.map +0 -1
  23. package/dist/chunk-QMWMT6EH.js.map +0 -1
  24. package/dist/xmtp-4XTQQ7RE.js.map +0 -1
  25. /package/dist/{chat-BSLMAYM5.js.map → chat-O34BTHII.js.map} +0 -0
  26. /package/dist/{chunk-B7XDUFI3.js.map → chunk-ARZIQ7YZ.js.map} +0 -0
  27. /package/dist/{eas-TMHFTX43.js.map → eas-TI4XI5VU.js.map} +0 -0
  28. /package/dist/{research-SESA7KGU.js.map → research-GX32VMP7.js.map} +0 -0
  29. /package/dist/{research-JMGCIJ4H.js.map → research-ZR7HXITG.js.map} +0 -0
  30. /package/dist/{session-XUOMZWOT.js.map → session-QEIVURQO.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ fetchMetadata,
3
4
  uploadMetadata
4
5
  } from "./chunk-DVWORPEY.js";
5
6
  import {
@@ -9,7 +10,7 @@ import {
9
10
  queryApprovals,
10
11
  queryJoinRequests,
11
12
  revokeAttestation
12
- } from "./chunk-P3GYAMGZ.js";
13
+ } from "./chunk-VQP4XR67.js";
13
14
  import {
14
15
  approveDepositor,
15
16
  deposit,
@@ -27,7 +28,7 @@ import {
27
28
  setTextRecord,
28
29
  setVaultAddress,
29
30
  simulateBatch
30
- } from "./chunk-B7XDUFI3.js";
31
+ } from "./chunk-ARZIQ7YZ.js";
31
32
  import {
32
33
  AGENT_REGISTRY,
33
34
  EAS_SCHEMAS,
@@ -36,20 +37,23 @@ import {
36
37
  SHERWOOD,
37
38
  STRATEGY_REGISTRY_ABI,
38
39
  SYNDICATE_FACTORY_ABI,
40
+ SYNDICATE_GOVERNOR_ABI,
39
41
  SYNDICATE_VAULT_ABI,
40
42
  TOKENS,
41
43
  UNISWAP,
42
44
  UNISWAP_QUOTER_V2_ABI,
43
45
  VENICE,
44
46
  VENICE_STAKING_ABI
45
- } from "./chunk-6MEYSN2W.js";
47
+ } from "./chunk-BXUNWV52.js";
46
48
  import {
49
+ VALID_NETWORKS,
47
50
  cacheGroupId,
48
51
  getAccount,
49
52
  getAgentId,
50
53
  getChain,
51
54
  getChainContracts,
52
55
  getExplorerUrl,
56
+ getNetwork,
53
57
  getPublicClient,
54
58
  getRpcUrl,
55
59
  getVeniceApiKey,
@@ -57,17 +61,18 @@ import {
57
61
  loadConfig,
58
62
  setAgentId,
59
63
  setChainContract,
64
+ setConfigRpcUrl,
60
65
  setNetwork,
61
66
  setPrivateKey,
62
67
  setVeniceApiKey
63
- } from "./chunk-QMWMT6EH.js";
68
+ } from "./chunk-5ADWTXNT.js";
64
69
 
65
70
  // src/index.ts
66
71
  import { config as loadDotenv } from "dotenv";
67
- import { Command } from "commander";
72
+ import { Command, Option } from "commander";
68
73
  import { parseUnits as parseUnits8 } from "viem";
69
- import chalk5 from "chalk";
70
- import ora5 from "ora";
74
+ import chalk7 from "chalk";
75
+ import ora7 from "ora";
71
76
  import { input, confirm, select } from "@inquirer/prompts";
72
77
 
73
78
  // src/providers/moonwell.ts
@@ -1674,60 +1679,892 @@ function registerIdentityCommands(program2) {
1674
1679
  });
1675
1680
  }
1676
1681
 
1677
- // src/index.ts
1678
- try {
1679
- loadDotenv();
1680
- } catch {
1682
+ // src/commands/proposal.ts
1683
+ import { isAddress as isAddress4 } from "viem";
1684
+ import chalk5 from "chalk";
1685
+ import ora5 from "ora";
1686
+ import { readFileSync } from "fs";
1687
+
1688
+ // src/lib/governor.ts
1689
+ var PROPOSAL_STATES = [
1690
+ "Pending",
1691
+ "Approved",
1692
+ "Rejected",
1693
+ "Expired",
1694
+ "Executed",
1695
+ "Settled",
1696
+ "Cancelled"
1697
+ ];
1698
+ function parseDuration(input2) {
1699
+ const match = input2.match(/^(\d+)(d|h|m|s)?$/);
1700
+ if (!match) throw new Error(`Invalid duration: ${input2}`);
1701
+ const value = BigInt(match[1]);
1702
+ switch (match[2]) {
1703
+ case "d":
1704
+ return value * 86400n;
1705
+ case "h":
1706
+ return value * 3600n;
1707
+ case "m":
1708
+ return value * 60n;
1709
+ case "s":
1710
+ case void 0:
1711
+ return value;
1712
+ default:
1713
+ throw new Error(`Unknown duration unit: ${match[2]}`);
1714
+ }
1681
1715
  }
1682
- async function loadXmtp() {
1683
- return import("./xmtp-4XTQQ7RE.js");
1716
+ function getGovernorAddress() {
1717
+ return SHERWOOD().GOVERNOR;
1718
+ }
1719
+ async function getGovernorParams() {
1720
+ const client = getPublicClient();
1721
+ const result = await client.readContract({
1722
+ address: getGovernorAddress(),
1723
+ abi: SYNDICATE_GOVERNOR_ABI,
1724
+ functionName: "getGovernorParams"
1725
+ });
1726
+ return result;
1727
+ }
1728
+ async function getProposal(id) {
1729
+ const client = getPublicClient();
1730
+ const result = await client.readContract({
1731
+ address: getGovernorAddress(),
1732
+ abi: SYNDICATE_GOVERNOR_ABI,
1733
+ functionName: "getProposal",
1734
+ args: [id]
1735
+ });
1736
+ return result;
1737
+ }
1738
+ async function getProposalState(id) {
1739
+ const client = getPublicClient();
1740
+ return client.readContract({
1741
+ address: getGovernorAddress(),
1742
+ abi: SYNDICATE_GOVERNOR_ABI,
1743
+ functionName: "getProposalState",
1744
+ args: [id]
1745
+ });
1746
+ }
1747
+ async function proposalCount() {
1748
+ const client = getPublicClient();
1749
+ return client.readContract({
1750
+ address: getGovernorAddress(),
1751
+ abi: SYNDICATE_GOVERNOR_ABI,
1752
+ functionName: "proposalCount"
1753
+ });
1754
+ }
1755
+ async function getVoteWeight(proposalId, voter) {
1756
+ const client = getPublicClient();
1757
+ return client.readContract({
1758
+ address: getGovernorAddress(),
1759
+ abi: SYNDICATE_GOVERNOR_ABI,
1760
+ functionName: "getVoteWeight",
1761
+ args: [proposalId, voter]
1762
+ });
1763
+ }
1764
+ async function hasVoted(proposalId, voter) {
1765
+ const client = getPublicClient();
1766
+ return client.readContract({
1767
+ address: getGovernorAddress(),
1768
+ abi: SYNDICATE_GOVERNOR_ABI,
1769
+ functionName: "hasVoted",
1770
+ args: [proposalId, voter]
1771
+ });
1684
1772
  }
1773
+ async function getProposalCalls(proposalId) {
1774
+ const client = getPublicClient();
1775
+ const result = await client.readContract({
1776
+ address: getGovernorAddress(),
1777
+ abi: SYNDICATE_GOVERNOR_ABI,
1778
+ functionName: "getProposalCalls",
1779
+ args: [proposalId]
1780
+ });
1781
+ return result.map((c) => ({ target: c.target, data: c.data, value: c.value }));
1782
+ }
1783
+ async function getRegisteredVaults() {
1784
+ const client = getPublicClient();
1785
+ return client.readContract({
1786
+ address: getGovernorAddress(),
1787
+ abi: SYNDICATE_GOVERNOR_ABI,
1788
+ functionName: "getRegisteredVaults"
1789
+ });
1790
+ }
1791
+ async function getCapitalSnapshot(proposalId) {
1792
+ const client = getPublicClient();
1793
+ return client.readContract({
1794
+ address: getGovernorAddress(),
1795
+ abi: SYNDICATE_GOVERNOR_ABI,
1796
+ functionName: "getCapitalSnapshot",
1797
+ args: [proposalId]
1798
+ });
1799
+ }
1800
+ async function propose(vault, metadataURI, performanceFeeBps, strategyDuration, calls, splitIndex) {
1801
+ const wallet = getWalletClient();
1802
+ const client = getPublicClient();
1803
+ const hash = await wallet.writeContract({
1804
+ account: getAccount(),
1805
+ chain: getChain(),
1806
+ address: getGovernorAddress(),
1807
+ abi: SYNDICATE_GOVERNOR_ABI,
1808
+ functionName: "propose",
1809
+ args: [vault, metadataURI, performanceFeeBps, strategyDuration, calls, splitIndex]
1810
+ });
1811
+ const receipt = await client.waitForTransactionReceipt({ hash });
1812
+ let proposalId;
1813
+ try {
1814
+ proposalId = await proposalCount();
1815
+ } catch {
1816
+ proposalId = 0n;
1817
+ }
1818
+ return { hash: receipt.transactionHash, proposalId };
1819
+ }
1820
+ async function vote(proposalId, support) {
1821
+ const wallet = getWalletClient();
1822
+ const client = getPublicClient();
1823
+ const hash = await wallet.writeContract({
1824
+ account: getAccount(),
1825
+ chain: getChain(),
1826
+ address: getGovernorAddress(),
1827
+ abi: SYNDICATE_GOVERNOR_ABI,
1828
+ functionName: "vote",
1829
+ args: [proposalId, support]
1830
+ });
1831
+ const receipt = await client.waitForTransactionReceipt({ hash });
1832
+ return receipt.transactionHash;
1833
+ }
1834
+ async function executeProposal(proposalId) {
1835
+ const wallet = getWalletClient();
1836
+ const client = getPublicClient();
1837
+ const hash = await wallet.writeContract({
1838
+ account: getAccount(),
1839
+ chain: getChain(),
1840
+ address: getGovernorAddress(),
1841
+ abi: SYNDICATE_GOVERNOR_ABI,
1842
+ functionName: "executeProposal",
1843
+ args: [proposalId]
1844
+ });
1845
+ const receipt = await client.waitForTransactionReceipt({ hash });
1846
+ return receipt.transactionHash;
1847
+ }
1848
+ async function settleProposal(proposalId) {
1849
+ const wallet = getWalletClient();
1850
+ const client = getPublicClient();
1851
+ const hash = await wallet.writeContract({
1852
+ account: getAccount(),
1853
+ chain: getChain(),
1854
+ address: getGovernorAddress(),
1855
+ abi: SYNDICATE_GOVERNOR_ABI,
1856
+ functionName: "settleProposal",
1857
+ args: [proposalId]
1858
+ });
1859
+ const receipt = await client.waitForTransactionReceipt({ hash });
1860
+ return receipt.transactionHash;
1861
+ }
1862
+ async function settleByAgent(proposalId, calls) {
1863
+ const wallet = getWalletClient();
1864
+ const client = getPublicClient();
1865
+ const hash = await wallet.writeContract({
1866
+ account: getAccount(),
1867
+ chain: getChain(),
1868
+ address: getGovernorAddress(),
1869
+ abi: SYNDICATE_GOVERNOR_ABI,
1870
+ functionName: "settleByAgent",
1871
+ args: [proposalId, calls]
1872
+ });
1873
+ const receipt = await client.waitForTransactionReceipt({ hash });
1874
+ return receipt.transactionHash;
1875
+ }
1876
+ async function emergencySettle(proposalId, calls) {
1877
+ const wallet = getWalletClient();
1878
+ const client = getPublicClient();
1879
+ const hash = await wallet.writeContract({
1880
+ account: getAccount(),
1881
+ chain: getChain(),
1882
+ address: getGovernorAddress(),
1883
+ abi: SYNDICATE_GOVERNOR_ABI,
1884
+ functionName: "emergencySettle",
1885
+ args: [proposalId, calls]
1886
+ });
1887
+ const receipt = await client.waitForTransactionReceipt({ hash });
1888
+ return receipt.transactionHash;
1889
+ }
1890
+ async function cancelProposal(proposalId) {
1891
+ const wallet = getWalletClient();
1892
+ const client = getPublicClient();
1893
+ const hash = await wallet.writeContract({
1894
+ account: getAccount(),
1895
+ chain: getChain(),
1896
+ address: getGovernorAddress(),
1897
+ abi: SYNDICATE_GOVERNOR_ABI,
1898
+ functionName: "cancelProposal",
1899
+ args: [proposalId]
1900
+ });
1901
+ const receipt = await client.waitForTransactionReceipt({ hash });
1902
+ return receipt.transactionHash;
1903
+ }
1904
+ async function emergencyCancel(proposalId) {
1905
+ const wallet = getWalletClient();
1906
+ const client = getPublicClient();
1907
+ const hash = await wallet.writeContract({
1908
+ account: getAccount(),
1909
+ chain: getChain(),
1910
+ address: getGovernorAddress(),
1911
+ abi: SYNDICATE_GOVERNOR_ABI,
1912
+ functionName: "emergencyCancel",
1913
+ args: [proposalId]
1914
+ });
1915
+ const receipt = await client.waitForTransactionReceipt({ hash });
1916
+ return receipt.transactionHash;
1917
+ }
1918
+ async function setVotingPeriod(seconds) {
1919
+ const wallet = getWalletClient();
1920
+ const client = getPublicClient();
1921
+ const hash = await wallet.writeContract({
1922
+ account: getAccount(),
1923
+ chain: getChain(),
1924
+ address: getGovernorAddress(),
1925
+ abi: SYNDICATE_GOVERNOR_ABI,
1926
+ functionName: "setVotingPeriod",
1927
+ args: [seconds]
1928
+ });
1929
+ const receipt = await client.waitForTransactionReceipt({ hash });
1930
+ return receipt.transactionHash;
1931
+ }
1932
+ async function setExecutionWindow(seconds) {
1933
+ const wallet = getWalletClient();
1934
+ const client = getPublicClient();
1935
+ const hash = await wallet.writeContract({
1936
+ account: getAccount(),
1937
+ chain: getChain(),
1938
+ address: getGovernorAddress(),
1939
+ abi: SYNDICATE_GOVERNOR_ABI,
1940
+ functionName: "setExecutionWindow",
1941
+ args: [seconds]
1942
+ });
1943
+ const receipt = await client.waitForTransactionReceipt({ hash });
1944
+ return receipt.transactionHash;
1945
+ }
1946
+ async function setQuorumBps(bps) {
1947
+ const wallet = getWalletClient();
1948
+ const client = getPublicClient();
1949
+ const hash = await wallet.writeContract({
1950
+ account: getAccount(),
1951
+ chain: getChain(),
1952
+ address: getGovernorAddress(),
1953
+ abi: SYNDICATE_GOVERNOR_ABI,
1954
+ functionName: "setQuorumBps",
1955
+ args: [bps]
1956
+ });
1957
+ const receipt = await client.waitForTransactionReceipt({ hash });
1958
+ return receipt.transactionHash;
1959
+ }
1960
+ async function setMaxPerformanceFeeBps(bps) {
1961
+ const wallet = getWalletClient();
1962
+ const client = getPublicClient();
1963
+ const hash = await wallet.writeContract({
1964
+ account: getAccount(),
1965
+ chain: getChain(),
1966
+ address: getGovernorAddress(),
1967
+ abi: SYNDICATE_GOVERNOR_ABI,
1968
+ functionName: "setMaxPerformanceFeeBps",
1969
+ args: [bps]
1970
+ });
1971
+ const receipt = await client.waitForTransactionReceipt({ hash });
1972
+ return receipt.transactionHash;
1973
+ }
1974
+ async function setMaxStrategyDuration(seconds) {
1975
+ const wallet = getWalletClient();
1976
+ const client = getPublicClient();
1977
+ const hash = await wallet.writeContract({
1978
+ account: getAccount(),
1979
+ chain: getChain(),
1980
+ address: getGovernorAddress(),
1981
+ abi: SYNDICATE_GOVERNOR_ABI,
1982
+ functionName: "setMaxStrategyDuration",
1983
+ args: [seconds]
1984
+ });
1985
+ const receipt = await client.waitForTransactionReceipt({ hash });
1986
+ return receipt.transactionHash;
1987
+ }
1988
+ async function setCooldownPeriod(seconds) {
1989
+ const wallet = getWalletClient();
1990
+ const client = getPublicClient();
1991
+ const hash = await wallet.writeContract({
1992
+ account: getAccount(),
1993
+ chain: getChain(),
1994
+ address: getGovernorAddress(),
1995
+ abi: SYNDICATE_GOVERNOR_ABI,
1996
+ functionName: "setCooldownPeriod",
1997
+ args: [seconds]
1998
+ });
1999
+ const receipt = await client.waitForTransactionReceipt({ hash });
2000
+ return receipt.transactionHash;
2001
+ }
2002
+
2003
+ // src/lib/format.ts
2004
+ function formatDurationShort(seconds) {
2005
+ const s = Number(seconds);
2006
+ if (s >= 86400) return `${(s / 86400).toFixed(s % 86400 === 0 ? 0 : 1)}d`;
2007
+ if (s >= 3600) return `${(s / 3600).toFixed(s % 3600 === 0 ? 0 : 1)}h`;
2008
+ if (s >= 60) return `${(s / 60).toFixed(0)}m`;
2009
+ return `${s}s`;
2010
+ }
2011
+ function formatDurationLong(seconds) {
2012
+ const s = Number(seconds);
2013
+ if (s >= 86400) return `${(s / 86400).toFixed(s % 86400 === 0 ? 0 : 1)} day${s >= 172800 ? "s" : ""}`;
2014
+ if (s >= 3600) return `${(s / 3600).toFixed(s % 3600 === 0 ? 0 : 1)} hour${s >= 7200 ? "s" : ""}`;
2015
+ if (s >= 60) return `${(s / 60).toFixed(0)} min`;
2016
+ return `${s}s`;
2017
+ }
2018
+ function formatShares(raw) {
2019
+ const num = Number(raw) / 1e6;
2020
+ return num.toLocaleString("en-US", { minimumFractionDigits: 0, maximumFractionDigits: 2 });
2021
+ }
2022
+ function formatUSDC(raw) {
2023
+ const num = Number(raw) / 1e6;
2024
+ return `$${num.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
2025
+ }
2026
+ function parseBigIntArg(value, name) {
2027
+ if (!/^-?\d+$/.test(value)) {
2028
+ throw new Error(`Invalid ${name}: "${value}" is not a valid integer`);
2029
+ }
2030
+ return BigInt(value);
2031
+ }
2032
+
2033
+ // src/commands/proposal.ts
1685
2034
  var G = chalk5.green;
1686
2035
  var W = chalk5.white;
1687
2036
  var DIM = chalk5.gray;
1688
2037
  var BOLD = chalk5.white.bold;
1689
2038
  var LABEL = chalk5.green.bold;
1690
2039
  var SEP = () => console.log(DIM("\u2500".repeat(60)));
2040
+ function formatTimestamp(ts) {
2041
+ if (ts === 0n) return "\u2014";
2042
+ return new Date(Number(ts) * 1e3).toLocaleString();
2043
+ }
2044
+ function parseCallsFile(path) {
2045
+ const raw = readFileSync(path, "utf-8");
2046
+ const parsed = JSON.parse(raw);
2047
+ return parsed.map((c) => ({
2048
+ target: c.target,
2049
+ data: c.data,
2050
+ value: BigInt(c.value || "0")
2051
+ }));
2052
+ }
2053
+ function registerProposalCommands(program2) {
2054
+ const proposal = program2.command("proposal").description("Governance proposals \u2014 create, vote, execute, settle");
2055
+ 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("--performance-fee <bps>", "Agent fee in bps (e.g. 1500 = 15%)").requiredOption("--duration <duration>", "Strategy duration (e.g. 7d, 24h, 3600)").requiredOption("--calls <path>", "Path to JSON file with Call[] array").requiredOption("--split-index <n>", "Index where execute calls end and settle calls begin").option("--metadata-uri <uri>", "Override \u2014 skip IPFS upload and use this URI directly").action(async (opts) => {
2056
+ try {
2057
+ const vault = opts.vault;
2058
+ if (!isAddress4(vault)) {
2059
+ console.error(chalk5.red(`Invalid vault address: ${opts.vault}`));
2060
+ process.exit(1);
2061
+ }
2062
+ const performanceFeeBps = parseBigIntArg(opts.performanceFee, "performance-fee");
2063
+ const strategyDuration = parseDuration(opts.duration);
2064
+ const splitIndex = parseBigIntArg(opts.splitIndex, "split-index");
2065
+ const calls = parseCallsFile(opts.calls);
2066
+ let metadataURI = opts.metadataUri || "";
2067
+ if (!metadataURI) {
2068
+ const spinner2 = ora5({ text: W("Uploading metadata to IPFS..."), color: "green" }).start();
2069
+ try {
2070
+ const account = getAccount();
2071
+ const metadata = {
2072
+ schema: "sherwood/proposal/v1",
2073
+ name: opts.name,
2074
+ description: opts.description,
2075
+ chain: getNetwork(),
2076
+ strategies: [],
2077
+ terms: { ragequitEnabled: true },
2078
+ links: {}
2079
+ };
2080
+ const proposalMeta = {
2081
+ ...metadata,
2082
+ proposer: account.address,
2083
+ vault,
2084
+ performanceFeeBps: Number(performanceFeeBps),
2085
+ strategyDuration: Number(strategyDuration),
2086
+ createdAt: Math.floor(Date.now() / 1e3)
2087
+ };
2088
+ metadataURI = await uploadMetadata(proposalMeta);
2089
+ spinner2.succeed(G(`Metadata pinned: ${DIM(metadataURI)}`));
2090
+ } catch (err) {
2091
+ spinner2.warn(chalk5.yellow("IPFS upload failed \u2014 using inline metadata"));
2092
+ const json = JSON.stringify({ name: opts.name, description: opts.description, vault });
2093
+ metadataURI = `data:application/json;base64,${Buffer.from(json).toString("base64")}`;
2094
+ }
2095
+ }
2096
+ console.log();
2097
+ console.log(LABEL(" \u25C6 Proposal Summary"));
2098
+ SEP();
2099
+ console.log(W(` Name: ${BOLD(opts.name)}`));
2100
+ console.log(W(` Vault: ${G(vault)}`));
2101
+ console.log(W(` Performance Fee: ${Number(performanceFeeBps) / 100}%`));
2102
+ console.log(W(` Duration: ${formatDurationShort(strategyDuration)}`));
2103
+ console.log(W(` Calls: ${calls.length} (split at ${splitIndex})`));
2104
+ console.log(W(` Metadata: ${DIM(metadataURI.length > 50 ? metadataURI.slice(0, 50) + "..." : metadataURI)}`));
2105
+ SEP();
2106
+ const spinner = ora5({ text: W("Submitting proposal..."), color: "green" }).start();
2107
+ const result = await propose(vault, metadataURI, performanceFeeBps, strategyDuration, calls, splitIndex);
2108
+ spinner.succeed(G("Proposal submitted"));
2109
+ console.log();
2110
+ console.log(LABEL(" \u25C6 Proposal Created"));
2111
+ SEP();
2112
+ console.log(W(` Proposal ID: ${G(`#${result.proposalId}`)}`));
2113
+ console.log(W(` Tx: ${DIM(getExplorerUrl(result.hash))}`));
2114
+ SEP();
2115
+ console.log();
2116
+ } catch (err) {
2117
+ console.error(chalk5.red(`
2118
+ \u2716 ${err instanceof Error ? err.message : String(err)}`));
2119
+ process.exit(1);
2120
+ }
2121
+ });
2122
+ proposal.command("list").description("List proposals").option("--vault <address>", "Filter by vault").option("--state <filter>", "Filter by state: pending, approved, executed, settled, all", "all").action(async (opts) => {
2123
+ const spinner = ora5("Loading proposals...").start();
2124
+ try {
2125
+ const count = await proposalCount();
2126
+ if (count === 0n) {
2127
+ spinner.stop();
2128
+ console.log(DIM("\n No proposals found.\n"));
2129
+ return;
2130
+ }
2131
+ const vaultFilter = opts.vault ? opts.vault.toLowerCase() : null;
2132
+ const stateFilter = opts.state.toLowerCase();
2133
+ const stateIndex = PROPOSAL_STATES.findIndex((s) => s.toLowerCase() === stateFilter);
2134
+ const ids = Array.from({ length: Number(count) }, (_, i) => BigInt(i + 1));
2135
+ const results = await Promise.all(
2136
+ ids.map(async (id) => {
2137
+ const [p, state] = await Promise.all([getProposal(id), getProposalState(id)]);
2138
+ return { ...p, computedState: state };
2139
+ })
2140
+ );
2141
+ const proposals = results.filter((p) => {
2142
+ if (vaultFilter && p.vault.toLowerCase() !== vaultFilter) return false;
2143
+ if (stateFilter !== "all" && stateIndex >= 0 && p.computedState !== stateIndex) return false;
2144
+ return true;
2145
+ });
2146
+ spinner.stop();
2147
+ if (proposals.length === 0) {
2148
+ console.log(DIM("\n No matching proposals.\n"));
2149
+ return;
2150
+ }
2151
+ console.log();
2152
+ console.log(BOLD(`Proposals (${proposals.length})`));
2153
+ console.log(DIM("\u2500".repeat(90)));
2154
+ console.log(
2155
+ DIM(" ID ") + DIM("Agent".padEnd(14)) + DIM("State".padEnd(12)) + DIM("Votes (For/Against)".padEnd(22)) + DIM("Fee".padEnd(8)) + DIM("Duration".padEnd(10)) + DIM("Created")
2156
+ );
2157
+ console.log(DIM("\u2500".repeat(90)));
2158
+ for (const p of proposals) {
2159
+ const state = PROPOSAL_STATES[p.computedState] || "Unknown";
2160
+ const created = p.snapshotTimestamp > 0n ? new Date(Number(p.snapshotTimestamp) * 1e3).toLocaleDateString() : "\u2014";
2161
+ const agent = `${p.proposer.slice(0, 6)}...${p.proposer.slice(-4)}`;
2162
+ const fee = `${Number(p.performanceFeeBps) / 100}%`;
2163
+ const dur = formatDurationShort(p.strategyDuration);
2164
+ const votes = `${formatShares(p.votesFor)}/${formatShares(p.votesAgainst)}`;
2165
+ console.log(
2166
+ ` ${String(p.id).padEnd(4)}${agent.padEnd(14)}${state.padEnd(12)}${votes.padEnd(22)}${fee.padEnd(8)}${dur.padEnd(10)}${created}`
2167
+ );
2168
+ }
2169
+ console.log();
2170
+ } catch (err) {
2171
+ spinner.fail("Failed to load proposals");
2172
+ console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
2173
+ process.exit(1);
2174
+ }
2175
+ });
2176
+ proposal.command("show").description("Show full proposal details").argument("<id>", "Proposal ID").action(async (idStr) => {
2177
+ const spinner = ora5("Loading proposal...").start();
2178
+ try {
2179
+ const id = parseBigIntArg(idStr, "proposal ID");
2180
+ const p = await getProposal(id);
2181
+ const state = await getProposalState(id);
2182
+ const calls = await getProposalCalls(id);
2183
+ const params = await getGovernorParams();
2184
+ spinner.stop();
2185
+ const stateLabel = PROPOSAL_STATES[state] || "Unknown";
2186
+ const totalVotes = p.votesFor + p.votesAgainst;
2187
+ const quorumNeeded = totalVotes > 0n ? `${Number(params.quorumBps) / 100}%` : "\u2014";
2188
+ console.log();
2189
+ console.log(LABEL(` \u25C6 Proposal #${p.id}`));
2190
+ SEP();
2191
+ if (p.metadataURI && p.metadataURI.startsWith("ipfs://")) {
2192
+ try {
2193
+ const meta = await fetchMetadata(p.metadataURI);
2194
+ console.log(W(` Name: ${BOLD(meta.name)}`));
2195
+ console.log(W(` Description: ${DIM(meta.description)}`));
2196
+ } catch {
2197
+ console.log(W(` Metadata: ${DIM(p.metadataURI)}`));
2198
+ }
2199
+ } else if (p.metadataURI) {
2200
+ console.log(W(` Metadata: ${DIM(p.metadataURI)}`));
2201
+ }
2202
+ console.log(W(` State: ${BOLD(stateLabel)}`));
2203
+ console.log(W(` Proposer: ${G(p.proposer)}`));
2204
+ console.log(W(` Vault: ${G(p.vault)}`));
2205
+ console.log(W(` Performance Fee: ${Number(p.performanceFeeBps) / 100}%`));
2206
+ console.log(W(` Duration: ${formatDurationShort(p.strategyDuration)}`));
2207
+ console.log();
2208
+ console.log(LABEL(" Timestamps"));
2209
+ console.log(W(` Snapshot: ${formatTimestamp(p.snapshotTimestamp)}`));
2210
+ console.log(W(` Vote End: ${formatTimestamp(p.voteEnd)}`));
2211
+ console.log(W(` Execute By: ${formatTimestamp(p.executeBy)}`));
2212
+ console.log(W(` Executed At: ${formatTimestamp(p.executedAt)}`));
2213
+ console.log();
2214
+ console.log(LABEL(" Votes"));
2215
+ console.log(W(` For: ${formatShares(p.votesFor)}`));
2216
+ console.log(W(` Against: ${formatShares(p.votesAgainst)}`));
2217
+ console.log(W(` Quorum: ${quorumNeeded}`));
2218
+ if (state === 4 || state === 5) {
2219
+ try {
2220
+ const cap = await getCapitalSnapshot(id);
2221
+ console.log();
2222
+ console.log(LABEL(" Capital"));
2223
+ console.log(W(` Snapshot: ${formatUSDC(cap)}`));
2224
+ } catch {
2225
+ }
2226
+ }
2227
+ console.log();
2228
+ console.log(LABEL(` Calls (${calls.length}, split at ${p.splitIndex})`));
2229
+ for (let i = 0; i < calls.length; i++) {
2230
+ const phase = BigInt(i) < p.splitIndex ? "execute" : "settle";
2231
+ console.log(DIM(` [${i}] (${phase}) target=${calls[i].target}`));
2232
+ console.log(DIM(` data=${calls[i].data.slice(0, 20)}... value=${calls[i].value}`));
2233
+ }
2234
+ SEP();
2235
+ console.log();
2236
+ } catch (err) {
2237
+ spinner.fail("Failed to load proposal");
2238
+ console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
2239
+ process.exit(1);
2240
+ }
2241
+ });
2242
+ proposal.command("vote").description("Cast a vote on a pending proposal").requiredOption("--id <proposalId>", "Proposal ID").requiredOption("--support <yes|no>", "Vote direction: yes or no").action(async (opts) => {
2243
+ try {
2244
+ const proposalId = parseBigIntArg(opts.id, "proposal ID");
2245
+ const support = opts.support.toLowerCase() === "yes";
2246
+ const account = getAccount();
2247
+ const spinner = ora5("Loading proposal...").start();
2248
+ const p = await getProposal(proposalId);
2249
+ const state = await getProposalState(proposalId);
2250
+ if (state !== 0) {
2251
+ spinner.fail(`Proposal is ${PROPOSAL_STATES[state] || "Unknown"}, not Pending`);
2252
+ process.exit(1);
2253
+ }
2254
+ const alreadyVoted = await hasVoted(proposalId, account.address);
2255
+ if (alreadyVoted) {
2256
+ spinner.fail("You have already voted on this proposal");
2257
+ process.exit(1);
2258
+ }
2259
+ const weight = await getVoteWeight(proposalId, account.address);
2260
+ spinner.stop();
2261
+ console.log();
2262
+ console.log(LABEL(" \u25C6 Cast Vote"));
2263
+ SEP();
2264
+ console.log(W(` Proposal: #${proposalId}`));
2265
+ console.log(W(` Vault: ${G(p.vault)}`));
2266
+ console.log(W(` Support: ${support ? G("YES") : chalk5.red("NO")}`));
2267
+ console.log(W(` Weight: ${formatShares(weight)} shares`));
2268
+ SEP();
2269
+ const voteSpinner = ora5({ text: W("Submitting vote..."), color: "green" }).start();
2270
+ const hash = await vote(proposalId, support);
2271
+ voteSpinner.succeed(G("Vote cast"));
2272
+ console.log(DIM(` ${getExplorerUrl(hash)}`));
2273
+ console.log();
2274
+ } catch (err) {
2275
+ console.error(chalk5.red(`
2276
+ \u2716 ${err instanceof Error ? err.message : String(err)}`));
2277
+ process.exit(1);
2278
+ }
2279
+ });
2280
+ proposal.command("execute").description("Execute an approved proposal").requiredOption("--id <proposalId>", "Proposal ID").action(async (opts) => {
2281
+ try {
2282
+ const proposalId = parseBigIntArg(opts.id, "proposal ID");
2283
+ const spinner = ora5("Loading proposal...").start();
2284
+ const state = await getProposalState(proposalId);
2285
+ if (state !== 1) {
2286
+ spinner.fail(`Proposal is ${PROPOSAL_STATES[state] || "Unknown"}, not Approved`);
2287
+ process.exit(1);
2288
+ }
2289
+ spinner.text = W("Executing proposal...");
2290
+ const hash = await executeProposal(proposalId);
2291
+ spinner.succeed(G("Proposal executed"));
2292
+ console.log(DIM(` ${getExplorerUrl(hash)}`));
2293
+ try {
2294
+ const cap = await getCapitalSnapshot(proposalId);
2295
+ console.log(DIM(` Capital snapshot: ${formatUSDC(cap)}`));
2296
+ } catch {
2297
+ }
2298
+ console.log();
2299
+ } catch (err) {
2300
+ console.error(chalk5.red(`
2301
+ \u2716 ${err instanceof Error ? err.message : String(err)}`));
2302
+ process.exit(1);
2303
+ }
2304
+ });
2305
+ proposal.command("settle").description("Settle an executed proposal (auto-routes settlement path)").requiredOption("--id <proposalId>", "Proposal ID").option("--calls <path>", "Path to JSON file with settle Call[] (for agent/emergency settle)").action(async (opts) => {
2306
+ try {
2307
+ const proposalId = parseBigIntArg(opts.id, "proposal ID");
2308
+ const account = getAccount();
2309
+ const spinner = ora5("Loading proposal...").start();
2310
+ const p = await getProposal(proposalId);
2311
+ const state = await getProposalState(proposalId);
2312
+ if (state !== 4) {
2313
+ spinner.fail(`Proposal is ${PROPOSAL_STATES[state] || "Unknown"}, not Executed`);
2314
+ process.exit(1);
2315
+ }
2316
+ const isProposer = account.address.toLowerCase() === p.proposer.toLowerCase();
2317
+ const now = BigInt(Math.floor(Date.now() / 1e3));
2318
+ const durationElapsed = p.executedAt > 0n && now >= p.executedAt + p.strategyDuration;
2319
+ let hash;
2320
+ if (isProposer && opts.calls) {
2321
+ spinner.text = W("Settling by agent...");
2322
+ const calls = parseCallsFile(opts.calls);
2323
+ hash = await settleByAgent(proposalId, calls);
2324
+ spinner.succeed(G("Settled by agent"));
2325
+ } else if (durationElapsed && !opts.calls) {
2326
+ spinner.text = W("Settling (permissionless)...");
2327
+ hash = await settleProposal(proposalId);
2328
+ spinner.succeed(G("Settled (permissionless)"));
2329
+ } else if (durationElapsed && opts.calls) {
2330
+ spinner.text = W("Emergency settling...");
2331
+ const calls = parseCallsFile(opts.calls);
2332
+ hash = await emergencySettle(proposalId, calls);
2333
+ spinner.succeed(G("Emergency settled"));
2334
+ } else {
2335
+ spinner.fail("Cannot settle: duration not elapsed. If you are the proposer, provide --calls.");
2336
+ process.exit(1);
2337
+ }
2338
+ console.log(DIM(` ${getExplorerUrl(hash)}`));
2339
+ console.log();
2340
+ } catch (err) {
2341
+ console.error(chalk5.red(`
2342
+ \u2716 ${err instanceof Error ? err.message : String(err)}`));
2343
+ process.exit(1);
2344
+ }
2345
+ });
2346
+ proposal.command("cancel").description("Cancel a proposal (proposer or vault owner)").requiredOption("--id <proposalId>", "Proposal ID").option("--emergency", "Emergency cancel (vault owner only, any non-settled state)").action(async (opts) => {
2347
+ try {
2348
+ const proposalId = parseBigIntArg(opts.id, "proposal ID");
2349
+ const spinner = ora5("Loading proposal...").start();
2350
+ const state = await getProposalState(proposalId);
2351
+ if (state === 5 || state === 6) {
2352
+ spinner.fail(`Proposal is already ${PROPOSAL_STATES[state]}`);
2353
+ process.exit(1);
2354
+ }
2355
+ let hash;
2356
+ if (opts.emergency) {
2357
+ spinner.text = W("Emergency cancelling...");
2358
+ hash = await emergencyCancel(proposalId);
2359
+ spinner.succeed(G("Emergency cancelled"));
2360
+ } else {
2361
+ if (state !== 0 && state !== 1) {
2362
+ spinner.fail(`Proposal is ${PROPOSAL_STATES[state] || "Unknown"} \u2014 use --emergency for non-pending/approved`);
2363
+ process.exit(1);
2364
+ }
2365
+ spinner.text = W("Cancelling proposal...");
2366
+ hash = await cancelProposal(proposalId);
2367
+ spinner.succeed(G("Proposal cancelled"));
2368
+ }
2369
+ console.log(DIM(` ${getExplorerUrl(hash)}`));
2370
+ console.log();
2371
+ } catch (err) {
2372
+ console.error(chalk5.red(`
2373
+ \u2716 ${err instanceof Error ? err.message : String(err)}`));
2374
+ process.exit(1);
2375
+ }
2376
+ });
2377
+ }
2378
+
2379
+ // src/commands/governor.ts
2380
+ import chalk6 from "chalk";
2381
+ import ora6 from "ora";
2382
+ var G2 = chalk6.green;
2383
+ var W2 = chalk6.white;
2384
+ var DIM2 = chalk6.gray;
2385
+ var BOLD2 = chalk6.white.bold;
2386
+ var LABEL2 = chalk6.green.bold;
2387
+ var SEP2 = () => console.log(DIM2("\u2500".repeat(60)));
2388
+ function registerGovernorCommands(program2) {
2389
+ const governor = program2.command("governor").description("Governor parameters and vault management");
2390
+ governor.command("info").description("Display current governor parameters and registered vaults").action(async () => {
2391
+ const spinner = ora6("Loading governor info...").start();
2392
+ try {
2393
+ const [params, vaults] = await Promise.all([
2394
+ getGovernorParams(),
2395
+ getRegisteredVaults()
2396
+ ]);
2397
+ spinner.stop();
2398
+ console.log();
2399
+ console.log(LABEL2(" \u25C6 Governor Parameters"));
2400
+ SEP2();
2401
+ console.log(W2(` Address: ${G2(getGovernorAddress())}`));
2402
+ console.log(W2(` Voting Period: ${BOLD2(formatDurationLong(params.votingPeriod))}`));
2403
+ console.log(W2(` Execution Window: ${BOLD2(formatDurationLong(params.executionWindow))}`));
2404
+ console.log(W2(` Quorum: ${BOLD2(`${Number(params.quorumBps) / 100}%`)}`));
2405
+ console.log(W2(` Max Performance Fee: ${BOLD2(`${Number(params.maxPerformanceFeeBps) / 100}%`)}`));
2406
+ console.log(W2(` Max Strategy Duration:${BOLD2(` ${formatDurationLong(params.maxStrategyDuration)}`)}`));
2407
+ console.log(W2(` Cooldown Period: ${BOLD2(formatDurationLong(params.cooldownPeriod))}`));
2408
+ console.log();
2409
+ console.log(LABEL2(` Registered Vaults (${vaults.length})`));
2410
+ if (vaults.length === 0) {
2411
+ console.log(DIM2(" (none)"));
2412
+ } else {
2413
+ for (const v of vaults) {
2414
+ console.log(W2(` ${G2(v)}`));
2415
+ }
2416
+ }
2417
+ SEP2();
2418
+ console.log();
2419
+ } catch (err) {
2420
+ spinner.fail("Failed to load governor info");
2421
+ console.error(chalk6.red(err instanceof Error ? err.message : String(err)));
2422
+ process.exit(1);
2423
+ }
2424
+ });
2425
+ governor.command("set-voting-period").description("Set the voting period (owner only)").requiredOption("--seconds <n>", "New voting period in seconds").action(async (opts) => {
2426
+ const spinner = ora6("Setting voting period...").start();
2427
+ try {
2428
+ const hash = await setVotingPeriod(parseBigIntArg(opts.seconds, "seconds"));
2429
+ spinner.succeed(G2(`Voting period updated to ${opts.seconds}s`));
2430
+ console.log(DIM2(` ${getExplorerUrl(hash)}`));
2431
+ } catch (err) {
2432
+ spinner.fail("Failed to set voting period");
2433
+ console.error(chalk6.red(err instanceof Error ? err.message : String(err)));
2434
+ process.exit(1);
2435
+ }
2436
+ });
2437
+ governor.command("set-execution-window").description("Set the execution window (owner only)").requiredOption("--seconds <n>", "New execution window in seconds").action(async (opts) => {
2438
+ const spinner = ora6("Setting execution window...").start();
2439
+ try {
2440
+ const hash = await setExecutionWindow(parseBigIntArg(opts.seconds, "seconds"));
2441
+ spinner.succeed(G2(`Execution window updated to ${opts.seconds}s`));
2442
+ console.log(DIM2(` ${getExplorerUrl(hash)}`));
2443
+ } catch (err) {
2444
+ spinner.fail("Failed to set execution window");
2445
+ console.error(chalk6.red(err instanceof Error ? err.message : String(err)));
2446
+ process.exit(1);
2447
+ }
2448
+ });
2449
+ governor.command("set-quorum").description("Set the quorum threshold in bps (owner only)").requiredOption("--bps <n>", "New quorum in bps (e.g. 4000 = 40%)").action(async (opts) => {
2450
+ const spinner = ora6("Setting quorum...").start();
2451
+ try {
2452
+ const hash = await setQuorumBps(parseBigIntArg(opts.bps, "bps"));
2453
+ spinner.succeed(G2(`Quorum updated to ${Number(opts.bps) / 100}%`));
2454
+ console.log(DIM2(` ${getExplorerUrl(hash)}`));
2455
+ } catch (err) {
2456
+ spinner.fail("Failed to set quorum");
2457
+ console.error(chalk6.red(err instanceof Error ? err.message : String(err)));
2458
+ process.exit(1);
2459
+ }
2460
+ });
2461
+ governor.command("set-max-fee").description("Set the max performance fee in bps (owner only)").requiredOption("--bps <n>", "New max fee in bps (e.g. 3000 = 30%)").action(async (opts) => {
2462
+ const spinner = ora6("Setting max fee...").start();
2463
+ try {
2464
+ const hash = await setMaxPerformanceFeeBps(parseBigIntArg(opts.bps, "bps"));
2465
+ spinner.succeed(G2(`Max performance fee updated to ${Number(opts.bps) / 100}%`));
2466
+ console.log(DIM2(` ${getExplorerUrl(hash)}`));
2467
+ } catch (err) {
2468
+ spinner.fail("Failed to set max fee");
2469
+ console.error(chalk6.red(err instanceof Error ? err.message : String(err)));
2470
+ process.exit(1);
2471
+ }
2472
+ });
2473
+ governor.command("set-max-duration").description("Set the max strategy duration in seconds (owner only)").requiredOption("--seconds <n>", "New max duration in seconds").action(async (opts) => {
2474
+ const spinner = ora6("Setting max duration...").start();
2475
+ try {
2476
+ const hash = await setMaxStrategyDuration(parseBigIntArg(opts.seconds, "seconds"));
2477
+ spinner.succeed(G2(`Max strategy duration updated to ${opts.seconds}s`));
2478
+ console.log(DIM2(` ${getExplorerUrl(hash)}`));
2479
+ } catch (err) {
2480
+ spinner.fail("Failed to set max duration");
2481
+ console.error(chalk6.red(err instanceof Error ? err.message : String(err)));
2482
+ process.exit(1);
2483
+ }
2484
+ });
2485
+ governor.command("set-cooldown").description("Set the cooldown period in seconds (owner only)").requiredOption("--seconds <n>", "New cooldown in seconds").action(async (opts) => {
2486
+ const spinner = ora6("Setting cooldown...").start();
2487
+ try {
2488
+ const hash = await setCooldownPeriod(parseBigIntArg(opts.seconds, "seconds"));
2489
+ spinner.succeed(G2(`Cooldown period updated to ${opts.seconds}s`));
2490
+ console.log(DIM2(` ${getExplorerUrl(hash)}`));
2491
+ } catch (err) {
2492
+ spinner.fail("Failed to set cooldown");
2493
+ console.error(chalk6.red(err instanceof Error ? err.message : String(err)));
2494
+ process.exit(1);
2495
+ }
2496
+ });
2497
+ }
2498
+
2499
+ // src/index.ts
2500
+ try {
2501
+ loadDotenv();
2502
+ } catch {
2503
+ }
2504
+ async function loadXmtp() {
2505
+ return import("./xmtp-A6F63GZH.js");
2506
+ }
2507
+ var G3 = chalk7.green;
2508
+ var W3 = chalk7.white;
2509
+ var DIM3 = chalk7.gray;
2510
+ var BOLD3 = chalk7.white.bold;
2511
+ var LABEL3 = chalk7.green.bold;
2512
+ var SEP3 = () => console.log(DIM3("\u2500".repeat(60)));
1691
2513
  function resolveVault(opts) {
1692
2514
  if (opts.vault) {
1693
2515
  setVaultAddress(opts.vault);
1694
2516
  }
1695
2517
  }
1696
2518
  var program = new Command();
1697
- program.name("sherwood").description("CLI for agent-managed investment syndicates").version("0.1.0").option("--testnet", "Use Base Sepolia testnet instead of Base mainnet", false).hook("preAction", (thisCommand) => {
2519
+ program.name("sherwood").description("CLI for agent-managed investment syndicates").version("0.1.0").addOption(
2520
+ new Option("--chain <network>", "Target network").choices(VALID_NETWORKS).default("base")
2521
+ ).option("--testnet", "Alias for --chain base-sepolia (deprecated)", false).hook("preAction", (thisCommand) => {
1698
2522
  const opts = thisCommand.optsWithGlobals();
1699
- setNetwork(opts.testnet ? "base-sepolia" : "base");
2523
+ let network = opts.chain;
1700
2524
  if (opts.testnet) {
1701
- console.log(chalk5.yellow("[testnet] Base Sepolia"));
2525
+ if (network !== "base") {
2526
+ console.warn(
2527
+ chalk7.yellow("[warn] --testnet ignored, --chain takes precedence")
2528
+ );
2529
+ } else {
2530
+ network = "base-sepolia";
2531
+ }
2532
+ }
2533
+ setNetwork(network);
2534
+ if (getNetwork() !== "base") {
2535
+ console.log(chalk7.yellow(`[${getNetwork()}]`));
1702
2536
  }
1703
2537
  });
1704
2538
  var syndicate = program.command("syndicate");
1705
- syndicate.command("create").description("Create a new syndicate via the factory (interactive)").option("--subdomain <name>", "ENS subdomain (skip prompt)").option("--name <name>", "Syndicate name (skip prompt)").option("--agent-id <id>", "ERC-8004 agent identity token ID (skip prompt)").option("--asset <symbol-or-address>", "Vault asset: USDC, WETH, or a token address").option("--description <text>", "Short description").option("--metadata-uri <uri>", "Override metadata URI (skip IPFS upload)").option("--open-deposits", "Allow anyone to deposit (no whitelist)").option("--public-chat", "Enable dashboard spectator mode", false).action(async (opts) => {
2539
+ syndicate.command("create").description("Create a new syndicate via the factory (interactive)").option("--subdomain <name>", "ENS subdomain (skip prompt)").option("--name <name>", "Syndicate name (skip prompt)").option("--agent-id <id>", "ERC-8004 agent identity token ID (skip prompt)").option("--asset <symbol-or-address>", "Vault asset: USDC, WETH, or a token address").option("--description <text>", "Short description").option("--metadata-uri <uri>", "Override metadata URI (skip IPFS upload)").option("--open-deposits", "Allow anyone to deposit (no whitelist)").option("--public-chat", "Enable dashboard spectator mode", false).option("-y, --yes", "Skip confirmation prompt (non-interactive mode)", false).action(async (opts) => {
1706
2540
  try {
1707
2541
  console.log();
1708
- console.log(LABEL(" \u25C6 Create Syndicate"));
1709
- SEP();
2542
+ console.log(LABEL3(" \u25C6 Create Syndicate"));
2543
+ SEP3();
1710
2544
  const wallet = getAccount();
1711
- console.log(DIM(` Wallet: ${wallet.address}`));
1712
- console.log(DIM(` Network: ${getChain().name}`));
1713
- SEP();
2545
+ console.log(DIM3(` Wallet: ${wallet.address}`));
2546
+ console.log(DIM3(` Network: ${getChain().name}`));
2547
+ SEP3();
1714
2548
  const savedAgentId = getAgentId();
1715
- const name = opts.name || await input({
1716
- message: G("Syndicate name"),
2549
+ const nonInteractive = opts.yes;
2550
+ const name = opts.name || (nonInteractive ? (() => {
2551
+ throw new Error("--name is required in non-interactive mode (-y)");
2552
+ })() : await input({
2553
+ message: G3("Syndicate name"),
1717
2554
  validate: (v) => v.length > 0 || "Name is required"
1718
- });
1719
- const subdomain = opts.subdomain || await input({
1720
- message: G("ENS subdomain"),
2555
+ }));
2556
+ const subdomain = opts.subdomain || (nonInteractive ? name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "") : await input({
2557
+ message: G3("ENS subdomain"),
1721
2558
  default: name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, ""),
1722
2559
  validate: (v) => v.length >= 3 || "Must be at least 3 characters"
1723
- });
1724
- const description = opts.description || await input({
1725
- message: G("Description"),
2560
+ }));
2561
+ const description = opts.description || (nonInteractive ? `${name} \u2014 a Sherwood syndicate` : await input({
2562
+ message: G3("Description"),
1726
2563
  default: `${name} \u2014 a Sherwood syndicate`
1727
- });
1728
- const agentIdStr = opts.agentId || (savedAgentId ? await input({ message: G("Agent ID (ERC-8004)"), default: String(savedAgentId) }) : await input({ message: G("Agent ID (ERC-8004)"), validate: (v) => /^\d+$/.test(v) || "Must be a number" }));
1729
- const openDeposits = opts.openDeposits !== void 0 ? opts.openDeposits : await confirm({
1730
- message: G("Open deposits? (anyone can deposit)"),
2564
+ }));
2565
+ const agentIdStr = opts.agentId || (savedAgentId ? nonInteractive ? String(savedAgentId) : await input({ message: G3("Agent ID (ERC-8004)"), default: String(savedAgentId) }) : nonInteractive ? "0" : await input({ message: G3("Agent ID (ERC-8004)"), validate: (v) => /^\d+$/.test(v) || "Must be a number" }));
2566
+ const openDeposits = opts.openDeposits !== void 0 ? opts.openDeposits : nonInteractive ? true : await confirm({
2567
+ message: G3("Open deposits? (anyone can deposit)"),
1731
2568
  default: true
1732
2569
  });
1733
2570
  const ASSET_SYMBOLS = {
@@ -1743,12 +2580,14 @@ syndicate.command("create").description("Create a new syndicate via the factory
1743
2580
  asset = opts.asset;
1744
2581
  } else {
1745
2582
  const supported = Object.keys(ASSET_SYMBOLS).join(", ");
1746
- console.error(chalk5.red(` Unknown asset "${opts.asset}". Use a symbol (${supported}) or a 0x address.`));
2583
+ console.error(chalk7.red(` Unknown asset "${opts.asset}". Use a symbol (${supported}) or a 0x address.`));
1747
2584
  process.exit(1);
1748
2585
  }
2586
+ } else if (nonInteractive) {
2587
+ asset = TOKENS().USDC !== "0x0000000000000000000000000000000000000000" ? ASSET_SYMBOLS.USDC : ASSET_SYMBOLS.WETH;
1749
2588
  } else {
1750
2589
  const assetChoice = await select({
1751
- message: G("Vault asset (what token do depositors provide?)"),
2590
+ message: G3("Vault asset (what token do depositors provide?)"),
1752
2591
  choices: [
1753
2592
  { name: "USDC", value: "USDC", description: "USD Coin (6 decimals)" },
1754
2593
  { name: "WETH", value: "WETH", description: "Wrapped Ether (18 decimals)" }
@@ -1763,24 +2602,26 @@ syndicate.command("create").description("Create a new syndicate via the factory
1763
2602
  ]);
1764
2603
  const symbol = `sw${assetSymbol}`;
1765
2604
  console.log();
1766
- console.log(LABEL(" \u25C6 Review"));
1767
- SEP();
1768
- console.log(W(` Name: ${BOLD(name)}`));
1769
- console.log(W(` ENS: ${G(`${subdomain}.sherwoodagent.eth`)}`));
1770
- console.log(W(` Description: ${DIM(description)}`));
1771
- console.log(W(` Agent ID: #${agentIdStr}`));
1772
- console.log(W(` Asset: ${assetSymbol} (${asset.slice(0, 10)}...)`));
1773
- console.log(W(` Share token: ${symbol}`));
1774
- console.log(W(` Open deposits: ${openDeposits ? G("yes") : chalk5.red("no (whitelist)")}`));
1775
- SEP();
1776
- const go = await confirm({ message: G("Deploy syndicate?"), default: true });
1777
- if (!go) {
1778
- console.log(DIM(" Cancelled."));
1779
- return;
2605
+ console.log(LABEL3(" \u25C6 Review"));
2606
+ SEP3();
2607
+ console.log(W3(` Name: ${BOLD3(name)}`));
2608
+ console.log(W3(` ENS: ${G3(`${subdomain}.sherwoodagent.eth`)}`));
2609
+ console.log(W3(` Description: ${DIM3(description)}`));
2610
+ console.log(W3(` Agent ID: #${agentIdStr}`));
2611
+ console.log(W3(` Asset: ${assetSymbol} (${asset.slice(0, 10)}...)`));
2612
+ console.log(W3(` Share token: ${symbol}`));
2613
+ console.log(W3(` Open deposits: ${openDeposits ? G3("yes") : chalk7.red("no (whitelist)")}`));
2614
+ SEP3();
2615
+ if (!nonInteractive) {
2616
+ const go = await confirm({ message: G3("Deploy syndicate?"), default: true });
2617
+ if (!go) {
2618
+ console.log(DIM3(" Cancelled."));
2619
+ return;
2620
+ }
1780
2621
  }
1781
2622
  let metadataURI = opts.metadataUri || "";
1782
2623
  if (!metadataURI) {
1783
- const spinner2 = ora5({ text: W("Uploading metadata to IPFS..."), color: "green" }).start();
2624
+ const spinner2 = ora7({ text: W3("Uploading metadata to IPFS..."), color: "green" }).start();
1784
2625
  try {
1785
2626
  const metadata = {
1786
2627
  schema: "sherwood/syndicate/v1",
@@ -1795,14 +2636,14 @@ syndicate.command("create").description("Create a new syndicate via the factory
1795
2636
  links: {}
1796
2637
  };
1797
2638
  metadataURI = await uploadMetadata(metadata);
1798
- spinner2.succeed(G(`Metadata pinned: ${DIM(metadataURI)}`));
2639
+ spinner2.succeed(G3(`Metadata pinned: ${DIM3(metadataURI)}`));
1799
2640
  } catch (err) {
1800
- spinner2.warn(chalk5.yellow(`IPFS upload failed \u2014 using inline metadata`));
2641
+ spinner2.warn(chalk7.yellow(`IPFS upload failed \u2014 using inline metadata`));
1801
2642
  const json = JSON.stringify({ name, description, subdomain, asset: assetSymbol, openDeposits, createdBy: "@sherwoodagent/cli" });
1802
2643
  metadataURI = `data:application/json;base64,${Buffer.from(json).toString("base64")}`;
1803
2644
  }
1804
2645
  }
1805
- const spinner = ora5({ text: W("Deploying vault via factory..."), color: "green" }).start();
2646
+ const spinner = ora7({ text: W3("Deploying vault via factory..."), color: "green" }).start();
1806
2647
  const result = await createSyndicate({
1807
2648
  creatorAgentId: BigInt(agentIdStr),
1808
2649
  metadataURI,
@@ -1813,7 +2654,7 @@ syndicate.command("create").description("Create a new syndicate via the factory
1813
2654
  subdomain
1814
2655
  });
1815
2656
  setChainContract(getChain().id, "vault", result.vault);
1816
- spinner.text = W("Registering creator as agent...");
2657
+ spinner.text = W3("Registering creator as agent...");
1817
2658
  try {
1818
2659
  setVaultAddress(result.vault);
1819
2660
  const creatorAddress = getAccount().address;
@@ -1825,9 +2666,9 @@ syndicate.command("create").description("Create a new syndicate via the factory
1825
2666
  // operator = creator EOA
1826
2667
  );
1827
2668
  } catch (regErr) {
1828
- console.warn(chalk5.yellow("\n \u26A0 Could not auto-register creator as agent \u2014 register manually with `syndicate add`"));
2669
+ console.warn(chalk7.yellow("\n \u26A0 Could not auto-register creator as agent \u2014 register manually with `syndicate add`"));
1829
2670
  }
1830
- spinner.text = W("Setting up chat...");
2671
+ spinner.text = W3("Setting up chat...");
1831
2672
  try {
1832
2673
  const xmtp = await loadXmtp();
1833
2674
  const xmtpClient = await xmtp.getXmtpClient();
@@ -1835,30 +2676,30 @@ syndicate.command("create").description("Create a new syndicate via the factory
1835
2676
  await setTextRecord(subdomain, "xmtpGroupId", groupId, result.vault);
1836
2677
  cacheGroupId(subdomain, groupId);
1837
2678
  } catch {
1838
- console.warn(chalk5.yellow("\n \u26A0 Could not create XMTP chat group"));
1839
- console.warn(chalk5.dim(` Recover later with: sherwood chat ${subdomain} init`));
2679
+ console.warn(chalk7.yellow("\n \u26A0 Could not create XMTP chat group"));
2680
+ console.warn(chalk7.dim(` Recover later with: sherwood chat ${subdomain} init`));
1840
2681
  }
1841
2682
  spinner.stop();
1842
2683
  console.log();
1843
- console.log(LABEL(" \u25C6 Syndicate Created"));
1844
- SEP();
1845
- console.log(W(` ID: ${G(`#${result.syndicateId}`)}`));
1846
- console.log(W(` Vault: ${G(result.vault)}`));
1847
- console.log(W(` ENS: ${G(`${subdomain}.sherwoodagent.eth`)}`));
1848
- console.log(W(` Metadata: ${DIM(metadataURI.length > 50 ? metadataURI.slice(0, 50) + "..." : metadataURI)}`));
1849
- console.log(W(` Explorer: ${DIM(getExplorerUrl(result.hash))}`));
1850
- console.log(W(` Chat: ${DIM(`sherwood chat ${subdomain}`)}`));
1851
- SEP();
1852
- console.log(G(" \u2713 Vault saved to ~/.sherwood/config.json"));
2684
+ console.log(LABEL3(" \u25C6 Syndicate Created"));
2685
+ SEP3();
2686
+ console.log(W3(` ID: ${G3(`#${result.syndicateId}`)}`));
2687
+ console.log(W3(` Vault: ${G3(result.vault)}`));
2688
+ console.log(W3(` ENS: ${G3(`${subdomain}.sherwoodagent.eth`)}`));
2689
+ console.log(W3(` Metadata: ${DIM3(metadataURI.length > 50 ? metadataURI.slice(0, 50) + "..." : metadataURI)}`));
2690
+ console.log(W3(` Explorer: ${DIM3(getExplorerUrl(result.hash))}`));
2691
+ console.log(W3(` Chat: ${DIM3(`sherwood chat ${subdomain}`)}`));
2692
+ SEP3();
2693
+ console.log(G3(" \u2713 Vault saved to ~/.sherwood/config.json"));
1853
2694
  console.log();
1854
2695
  } catch (err) {
1855
- console.error(chalk5.red(`
2696
+ console.error(chalk7.red(`
1856
2697
  \u2716 ${err instanceof Error ? err.message : String(err)}`));
1857
2698
  process.exit(1);
1858
2699
  }
1859
2700
  });
1860
2701
  syndicate.command("list").description("List active syndicates (queries subgraph, falls back to on-chain)").option("--creator <address>", "Filter by creator address").action(async (opts) => {
1861
- const spinner = ora5("Loading syndicates...").start();
2702
+ const spinner = ora7("Loading syndicates...").start();
1862
2703
  try {
1863
2704
  let syndicates;
1864
2705
  if (process.env.SUBGRAPH_URL) {
@@ -1877,65 +2718,65 @@ syndicate.command("list").description("List active syndicates (queries subgraph,
1877
2718
  }
1878
2719
  spinner.stop();
1879
2720
  if (syndicates.length === 0) {
1880
- console.log(chalk5.dim("No active syndicates found."));
2721
+ console.log(chalk7.dim("No active syndicates found."));
1881
2722
  return;
1882
2723
  }
1883
2724
  console.log();
1884
- console.log(chalk5.bold(`Active Syndicates (${syndicates.length})`));
2725
+ console.log(chalk7.bold(`Active Syndicates (${syndicates.length})`));
1885
2726
  if (!process.env.SUBGRAPH_URL) {
1886
- console.log(chalk5.dim(" (Set SUBGRAPH_URL for faster indexed queries)"));
2727
+ console.log(chalk7.dim(" (Set SUBGRAPH_URL for faster indexed queries)"));
1887
2728
  }
1888
- console.log(chalk5.dim("\u2500".repeat(70)));
2729
+ console.log(chalk7.dim("\u2500".repeat(70)));
1889
2730
  for (const s of syndicates) {
1890
2731
  const ts = typeof s.createdAt === "string" ? Number(s.createdAt) : Number(s.createdAt);
1891
2732
  const date = new Date(ts * 1e3).toLocaleDateString();
1892
2733
  const ensName = s.subdomain ? `${s.subdomain}.sherwoodagent.eth` : "";
1893
- console.log(` #${s.id} ${chalk5.bold(ensName || String(s.vault))}`);
1894
- if (ensName) console.log(` Vault: ${chalk5.cyan(String(s.vault))}`);
2734
+ console.log(` #${s.id} ${chalk7.bold(ensName || String(s.vault))}`);
2735
+ if (ensName) console.log(` Vault: ${chalk7.cyan(String(s.vault))}`);
1895
2736
  console.log(` Creator: ${s.creator}`);
1896
2737
  console.log(` Created: ${date}`);
1897
2738
  if (s.totalDeposits) {
1898
2739
  console.log(` Deposits: ${s.totalDeposits} USDC`);
1899
2740
  }
1900
2741
  if (s.metadataURI) {
1901
- console.log(` Metadata: ${chalk5.dim(s.metadataURI)}`);
2742
+ console.log(` Metadata: ${chalk7.dim(s.metadataURI)}`);
1902
2743
  }
1903
2744
  console.log();
1904
2745
  }
1905
2746
  } catch (err) {
1906
2747
  spinner.fail("Failed to load syndicates");
1907
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
2748
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
1908
2749
  process.exit(1);
1909
2750
  }
1910
2751
  });
1911
2752
  syndicate.command("info").description("Display syndicate details by ID").argument("<id>", "Syndicate ID").action(async (idStr) => {
1912
- const spinner = ora5("Loading syndicate info...").start();
2753
+ const spinner = ora7("Loading syndicate info...").start();
1913
2754
  try {
1914
2755
  const id = BigInt(idStr);
1915
2756
  const info = await getSyndicate(id);
1916
2757
  spinner.stop();
1917
2758
  if (!info.vault || info.vault === "0x0000000000000000000000000000000000000000") {
1918
- console.log(chalk5.red(`Syndicate #${id} not found.`));
2759
+ console.log(chalk7.red(`Syndicate #${id} not found.`));
1919
2760
  process.exit(1);
1920
2761
  }
1921
2762
  const date = new Date(Number(info.createdAt) * 1e3).toLocaleDateString();
1922
2763
  console.log();
1923
- console.log(chalk5.bold(`Syndicate #${info.id}`));
1924
- console.log(chalk5.dim("\u2500".repeat(40)));
2764
+ console.log(chalk7.bold(`Syndicate #${info.id}`));
2765
+ console.log(chalk7.dim("\u2500".repeat(40)));
1925
2766
  if (info.subdomain) {
1926
- console.log(` ENS: ${chalk5.bold(`${info.subdomain}.sherwoodagent.eth`)}`);
2767
+ console.log(` ENS: ${chalk7.bold(`${info.subdomain}.sherwoodagent.eth`)}`);
1927
2768
  }
1928
- console.log(` Vault: ${chalk5.cyan(info.vault)}`);
2769
+ console.log(` Vault: ${chalk7.cyan(info.vault)}`);
1929
2770
  console.log(` Creator: ${info.creator}`);
1930
2771
  console.log(` Created: ${date}`);
1931
- console.log(` Active: ${info.active ? chalk5.green("yes") : chalk5.red("no")}`);
2772
+ console.log(` Active: ${info.active ? chalk7.green("yes") : chalk7.red("no")}`);
1932
2773
  if (info.metadataURI) {
1933
- console.log(` Metadata: ${chalk5.dim(info.metadataURI)}`);
2774
+ console.log(` Metadata: ${chalk7.dim(info.metadataURI)}`);
1934
2775
  }
1935
2776
  setVaultAddress(info.vault);
1936
2777
  const vaultInfo = await getVaultInfo();
1937
2778
  console.log();
1938
- console.log(chalk5.bold(" Vault Stats"));
2779
+ console.log(chalk7.bold(" Vault Stats"));
1939
2780
  console.log(` Total Assets: ${vaultInfo.totalAssets}`);
1940
2781
  console.log(` Agent Count: ${vaultInfo.agentCount}`);
1941
2782
  console.log(` Redemptions Locked: ${vaultInfo.redemptionsLocked}`);
@@ -1943,12 +2784,12 @@ syndicate.command("info").description("Display syndicate details by ID").argumen
1943
2784
  console.log();
1944
2785
  } catch (err) {
1945
2786
  spinner.fail("Failed to load syndicate info");
1946
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
2787
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
1947
2788
  process.exit(1);
1948
2789
  }
1949
2790
  });
1950
2791
  syndicate.command("update-metadata").description("Update syndicate metadata (creator only)").requiredOption("--id <id>", "Syndicate ID").option("--name <name>", "Syndicate name").option("--description <text>", "Short description").option("--uri <uri>", "Direct metadata URI (skips IPFS upload)").action(async (opts) => {
1951
- const spinner = ora5({ text: W("Loading syndicate..."), color: "green" }).start();
2792
+ const spinner = ora7({ text: W3("Loading syndicate..."), color: "green" }).start();
1952
2793
  try {
1953
2794
  const syndicateId = BigInt(opts.id);
1954
2795
  let metadataURI = opts.uri;
@@ -1960,7 +2801,7 @@ syndicate.command("update-metadata").description("Update syndicate metadata (cre
1960
2801
  }
1961
2802
  const name = opts.name || info.subdomain;
1962
2803
  const description = opts.description || `${name} \u2014 a Sherwood syndicate on ${info.subdomain}.sherwoodagent.eth`;
1963
- spinner.text = W("Uploading metadata to IPFS...");
2804
+ spinner.text = W3("Uploading metadata to IPFS...");
1964
2805
  const metadata = {
1965
2806
  schema: "sherwood/syndicate/v1",
1966
2807
  name,
@@ -1971,46 +2812,46 @@ syndicate.command("update-metadata").description("Update syndicate metadata (cre
1971
2812
  links: {}
1972
2813
  };
1973
2814
  metadataURI = await uploadMetadata(metadata);
1974
- spinner.text = W("Updating on-chain metadata...");
2815
+ spinner.text = W3("Updating on-chain metadata...");
1975
2816
  }
1976
2817
  const hash = await updateMetadata(syndicateId, metadataURI);
1977
- spinner.succeed(G(`Metadata updated`));
1978
- console.log(DIM(` IPFS: ${metadataURI}`));
1979
- console.log(DIM(` ${getExplorerUrl(hash)}`));
2818
+ spinner.succeed(G3(`Metadata updated`));
2819
+ console.log(DIM3(` IPFS: ${metadataURI}`));
2820
+ console.log(DIM3(` ${getExplorerUrl(hash)}`));
1980
2821
  } catch (err) {
1981
2822
  spinner.fail("Metadata update failed");
1982
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
2823
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
1983
2824
  process.exit(1);
1984
2825
  }
1985
2826
  });
1986
2827
  syndicate.command("approve-depositor").description("Approve an address to deposit (owner only)").option("--vault <address>", "Vault address (default: from config)").requiredOption("--depositor <address>", "Address to approve").action(async (opts) => {
1987
2828
  resolveVault(opts);
1988
- const spinner = ora5("Approving depositor...").start();
2829
+ const spinner = ora7("Approving depositor...").start();
1989
2830
  try {
1990
2831
  const hash = await approveDepositor(opts.depositor);
1991
2832
  spinner.succeed(`Depositor approved: ${hash}`);
1992
- console.log(chalk5.dim(` ${getExplorerUrl(hash)}`));
2833
+ console.log(chalk7.dim(` ${getExplorerUrl(hash)}`));
1993
2834
  } catch (err) {
1994
2835
  spinner.fail("Approval failed");
1995
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
2836
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
1996
2837
  process.exit(1);
1997
2838
  }
1998
2839
  });
1999
2840
  syndicate.command("remove-depositor").description("Remove an address from the depositor whitelist (owner only)").option("--vault <address>", "Vault address (default: from config)").requiredOption("--depositor <address>", "Address to remove").action(async (opts) => {
2000
2841
  resolveVault(opts);
2001
- const spinner = ora5("Removing depositor...").start();
2842
+ const spinner = ora7("Removing depositor...").start();
2002
2843
  try {
2003
2844
  const hash = await removeDepositor(opts.depositor);
2004
2845
  spinner.succeed(`Depositor removed: ${hash}`);
2005
- console.log(chalk5.dim(` ${getExplorerUrl(hash)}`));
2846
+ console.log(chalk7.dim(` ${getExplorerUrl(hash)}`));
2006
2847
  } catch (err) {
2007
2848
  spinner.fail("Removal failed");
2008
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
2849
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2009
2850
  process.exit(1);
2010
2851
  }
2011
2852
  });
2012
2853
  syndicate.command("add").description("Register an agent on a syndicate vault (creator only)").option("--vault <address>", "Vault address (default: from config)").requiredOption("--agent-id <id>", "Agent's ERC-8004 identity token ID").requiredOption("--pkp <address>", "Agent PKP address").requiredOption("--eoa <address>", "Operator EOA address").action(async (opts) => {
2013
- const spinner = ora5("Verifying creator...").start();
2854
+ const spinner = ora7("Verifying creator...").start();
2014
2855
  try {
2015
2856
  resolveVault(opts);
2016
2857
  const vaultAddress = getVaultAddress();
@@ -2027,7 +2868,7 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
2027
2868
  opts.eoa
2028
2869
  );
2029
2870
  spinner.succeed(`Agent registered: ${hash}`);
2030
- console.log(chalk5.dim(` ${getExplorerUrl(hash)}`));
2871
+ console.log(chalk7.dim(` ${getExplorerUrl(hash)}`));
2031
2872
  try {
2032
2873
  const xmtp = await loadXmtp();
2033
2874
  const xmtpClient = await xmtp.getXmtpClient();
@@ -2039,19 +2880,19 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
2039
2880
  syndicate: subdomain,
2040
2881
  timestamp: Math.floor(Date.now() / 1e3)
2041
2882
  });
2042
- console.log(chalk5.dim(` Added to chat: ${subdomain}`));
2883
+ console.log(chalk7.dim(` Added to chat: ${subdomain}`));
2043
2884
  } catch {
2044
- console.warn(chalk5.yellow(" \u26A0 Could not add agent to chat group"));
2045
- console.warn(chalk5.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
2885
+ console.warn(chalk7.yellow(" \u26A0 Could not add agent to chat group"));
2886
+ console.warn(chalk7.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
2046
2887
  }
2047
2888
  } catch (err) {
2048
2889
  spinner.fail("Registration failed");
2049
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
2890
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2050
2891
  process.exit(1);
2051
2892
  }
2052
2893
  });
2053
2894
  syndicate.command("join").description("Request to join a syndicate (creates an EAS attestation)").requiredOption("--subdomain <name>", "Syndicate subdomain to join").option("--message <text>", "Message to the creator", "Requesting to join your syndicate").action(async (opts) => {
2054
- const spinner = ora5("Resolving syndicate...").start();
2895
+ const spinner = ora7("Resolving syndicate...").start();
2055
2896
  try {
2056
2897
  const agentId = getAgentId();
2057
2898
  if (!agentId) {
@@ -2068,9 +2909,9 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
2068
2909
  try {
2069
2910
  const xmtp = await loadXmtp();
2070
2911
  await xmtp.getXmtpClient();
2071
- console.log(chalk5.dim(" XMTP identity ready"));
2912
+ console.log(chalk7.dim(" XMTP identity ready"));
2072
2913
  } catch {
2073
- console.warn(chalk5.yellow(" \u26A0 Could not initialize XMTP identity"));
2914
+ console.warn(chalk7.yellow(" \u26A0 Could not initialize XMTP identity"));
2074
2915
  }
2075
2916
  return;
2076
2917
  }
@@ -2081,14 +2922,14 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
2081
2922
  );
2082
2923
  if (existingRequest) {
2083
2924
  spinner.succeed("You already have a pending join request for this syndicate");
2084
- console.log(chalk5.dim(` Attestation: ${existingRequest.uid}`));
2085
- console.log(chalk5.dim(` Submitted: ${new Date(existingRequest.time * 1e3).toLocaleString()}`));
2925
+ console.log(chalk7.dim(` Attestation: ${existingRequest.uid}`));
2926
+ console.log(chalk7.dim(` Submitted: ${new Date(existingRequest.time * 1e3).toLocaleString()}`));
2086
2927
  try {
2087
2928
  const xmtp = await loadXmtp();
2088
2929
  await xmtp.getXmtpClient();
2089
- console.log(chalk5.dim(" XMTP identity ready"));
2930
+ console.log(chalk7.dim(" XMTP identity ready"));
2090
2931
  } catch {
2091
- console.warn(chalk5.yellow(" \u26A0 Could not initialize XMTP identity"));
2932
+ console.warn(chalk7.yellow(" \u26A0 Could not initialize XMTP identity"));
2092
2933
  }
2093
2934
  return;
2094
2935
  }
@@ -2107,29 +2948,29 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
2107
2948
  spinner.succeed("Join request created (XMTP identity ready)");
2108
2949
  } catch {
2109
2950
  spinner.succeed("Join request created");
2110
- console.warn(chalk5.yellow(" \u26A0 Could not initialize XMTP identity \u2014 creator may not be able to auto-add you to chat"));
2951
+ console.warn(chalk7.yellow(" \u26A0 Could not initialize XMTP identity \u2014 creator may not be able to auto-add you to chat"));
2111
2952
  }
2112
2953
  console.log();
2113
- console.log(LABEL(" \u25C6 Join Request Submitted"));
2114
- SEP();
2115
- console.log(W(` Syndicate: ${G(`${opts.subdomain}.sherwoodagent.eth`)}`));
2116
- console.log(W(` Agent ID: #${agentId}`));
2117
- console.log(W(` Creator: ${DIM(syndicate2.creator)}`));
2118
- console.log(W(` Attestation: ${DIM(uid)}`));
2119
- console.log(W(` EAS Scan: ${DIM(getEasScanUrl(uid))}`));
2120
- console.log(W(` Explorer: ${DIM(getExplorerUrl(hash))}`));
2121
- SEP();
2122
- console.log(G(" \u2713 The creator can review with:"));
2123
- console.log(DIM(` sherwood syndicate requests --subdomain ${opts.subdomain}`));
2954
+ console.log(LABEL3(" \u25C6 Join Request Submitted"));
2955
+ SEP3();
2956
+ console.log(W3(` Syndicate: ${G3(`${opts.subdomain}.sherwoodagent.eth`)}`));
2957
+ console.log(W3(` Agent ID: #${agentId}`));
2958
+ console.log(W3(` Creator: ${DIM3(syndicate2.creator)}`));
2959
+ console.log(W3(` Attestation: ${DIM3(uid)}`));
2960
+ console.log(W3(` EAS Scan: ${DIM3(getEasScanUrl(uid))}`));
2961
+ console.log(W3(` Explorer: ${DIM3(getExplorerUrl(hash))}`));
2962
+ SEP3();
2963
+ console.log(G3(" \u2713 The creator can review with:"));
2964
+ console.log(DIM3(` sherwood syndicate requests --subdomain ${opts.subdomain}`));
2124
2965
  console.log();
2125
2966
  } catch (err) {
2126
2967
  spinner.fail("Join request failed");
2127
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
2968
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2128
2969
  process.exit(1);
2129
2970
  }
2130
2971
  });
2131
2972
  syndicate.command("requests").description("View pending join requests for a syndicate (creator only)").option("--subdomain <name>", "Syndicate subdomain").option("--vault <address>", "Vault address (default: from config)").action(async (opts) => {
2132
- const spinner = ora5("Loading join requests...").start();
2973
+ const spinner = ora7("Loading join requests...").start();
2133
2974
  try {
2134
2975
  let creatorAddress;
2135
2976
  let subdomain;
@@ -2160,34 +3001,34 @@ syndicate.command("requests").description("View pending join requests for a synd
2160
3001
  );
2161
3002
  spinner.stop();
2162
3003
  if (requests.length === 0) {
2163
- console.log(DIM("\n No pending join requests.\n"));
3004
+ console.log(DIM3("\n No pending join requests.\n"));
2164
3005
  return;
2165
3006
  }
2166
3007
  console.log();
2167
- console.log(LABEL(` \u25C6 Pending Join Requests (${requests.length})`));
2168
- SEP();
3008
+ console.log(LABEL3(` \u25C6 Pending Join Requests (${requests.length})`));
3009
+ SEP3();
2169
3010
  for (let i = 0; i < requests.length; i++) {
2170
3011
  const req = requests[i];
2171
3012
  const date = new Date(req.time * 1e3).toLocaleString();
2172
- console.log(W(` ${i + 1}. Agent #${req.decoded.agentId} ${DIM(`(${req.attester})`)}`));
2173
- console.log(DIM(` Message: "${req.decoded.message}"`));
2174
- console.log(DIM(` Requested: ${date}`));
2175
- console.log(DIM(` Attestation: ${req.uid}`));
3013
+ console.log(W3(` ${i + 1}. Agent #${req.decoded.agentId} ${DIM3(`(${req.attester})`)}`));
3014
+ console.log(DIM3(` Message: "${req.decoded.message}"`));
3015
+ console.log(DIM3(` Requested: ${date}`));
3016
+ console.log(DIM3(` Attestation: ${req.uid}`));
2176
3017
  console.log();
2177
3018
  }
2178
- console.log(G(" To approve:"));
2179
- console.log(DIM(` sherwood syndicate approve --agent-id <id> --pkp <addr> --eoa <addr>`));
2180
- console.log(G(" To reject:"));
2181
- console.log(DIM(` sherwood syndicate reject --attestation <uid>`));
3019
+ console.log(G3(" To approve:"));
3020
+ console.log(DIM3(` sherwood syndicate approve --agent-id <id> --pkp <addr> --eoa <addr>`));
3021
+ console.log(G3(" To reject:"));
3022
+ console.log(DIM3(` sherwood syndicate reject --attestation <uid>`));
2182
3023
  console.log();
2183
3024
  } catch (err) {
2184
3025
  spinner.fail("Failed to load requests");
2185
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3026
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2186
3027
  process.exit(1);
2187
3028
  }
2188
3029
  });
2189
3030
  syndicate.command("approve").description("Approve an agent join request (registers agent + creates EAS approval)").option("--vault <address>", "Vault address (default: from config)").option("--subdomain <name>", "Syndicate subdomain (alternative to --vault)").requiredOption("--agent-id <id>", "Agent's ERC-8004 identity token ID").requiredOption("--pkp <address>", "Agent PKP address").requiredOption("--eoa <address>", "Operator EOA address").action(async (opts) => {
2190
- const spinner = ora5("Verifying creator...").start();
3031
+ const spinner = ora7("Verifying creator...").start();
2191
3032
  try {
2192
3033
  if (opts.subdomain && !opts.vault) {
2193
3034
  const syndicateInfo = await resolveSyndicate(opts.subdomain);
@@ -2209,11 +3050,11 @@ syndicate.command("approve").description("Approve an agent join request (registe
2209
3050
  opts.pkp,
2210
3051
  opts.eoa
2211
3052
  );
2212
- console.log(DIM(` Agent registered: ${getExplorerUrl(regHash)}`));
3053
+ console.log(DIM3(` Agent registered: ${getExplorerUrl(regHash)}`));
2213
3054
  } catch (regErr) {
2214
3055
  const msg = regErr instanceof Error ? regErr.message : String(regErr);
2215
3056
  if (msg.includes("0xe098d3ee") || msg.includes("AgentAlreadyRegistered")) {
2216
- console.log(DIM(" Agent already registered on vault \u2014 skipping"));
3057
+ console.log(DIM3(" Agent already registered on vault \u2014 skipping"));
2217
3058
  } else {
2218
3059
  throw regErr;
2219
3060
  }
@@ -2226,7 +3067,7 @@ syndicate.command("approve").description("Approve an agent join request (registe
2226
3067
  let approvalUid;
2227
3068
  if (alreadyApproved) {
2228
3069
  approvalUid = alreadyApproved.uid;
2229
- console.log(DIM(` Approval attestation already exists \u2014 skipping`));
3070
+ console.log(DIM3(` Approval attestation already exists \u2014 skipping`));
2230
3071
  } else {
2231
3072
  spinner.text = "Creating approval attestation...";
2232
3073
  const result = await createApproval(
@@ -2249,39 +3090,39 @@ syndicate.command("approve").description("Approve an agent join request (registe
2249
3090
  syndicate: subdomain,
2250
3091
  timestamp: Math.floor(Date.now() / 1e3)
2251
3092
  });
2252
- console.log(DIM(` Added to chat: ${subdomain}`));
3093
+ console.log(DIM3(` Added to chat: ${subdomain}`));
2253
3094
  } catch {
2254
- console.warn(chalk5.yellow(" \u26A0 Could not add agent to chat group"));
2255
- console.warn(chalk5.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
3095
+ console.warn(chalk7.yellow(" \u26A0 Could not add agent to chat group"));
3096
+ console.warn(chalk7.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
2256
3097
  }
2257
3098
  spinner.succeed("Agent approved and registered");
2258
3099
  console.log();
2259
- console.log(LABEL(" \u25C6 Agent Approved"));
2260
- SEP();
2261
- console.log(W(` Agent ID: #${opts.agentId}`));
2262
- console.log(W(` PKP: ${G(opts.pkp)}`));
2263
- console.log(W(` EOA: ${G(opts.eoa)}`));
2264
- console.log(W(` Approval: ${DIM(approvalUid)}`));
2265
- console.log(W(` EAS Scan: ${DIM(getEasScanUrl(approvalUid))}`));
2266
- SEP();
3100
+ console.log(LABEL3(" \u25C6 Agent Approved"));
3101
+ SEP3();
3102
+ console.log(W3(` Agent ID: #${opts.agentId}`));
3103
+ console.log(W3(` PKP: ${G3(opts.pkp)}`));
3104
+ console.log(W3(` EOA: ${G3(opts.eoa)}`));
3105
+ console.log(W3(` Approval: ${DIM3(approvalUid)}`));
3106
+ console.log(W3(` EAS Scan: ${DIM3(getEasScanUrl(approvalUid))}`));
3107
+ SEP3();
2267
3108
  } catch (err) {
2268
3109
  spinner.fail("Approval failed");
2269
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3110
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2270
3111
  process.exit(1);
2271
3112
  }
2272
3113
  });
2273
3114
  syndicate.command("reject").description("Reject a join request by revoking its attestation").requiredOption("--attestation <uid>", "Join request attestation UID to revoke").action(async (opts) => {
2274
- const spinner = ora5("Revoking attestation...").start();
3115
+ const spinner = ora7("Revoking attestation...").start();
2275
3116
  try {
2276
3117
  const hash = await revokeAttestation(
2277
3118
  EAS_SCHEMAS().SYNDICATE_JOIN_REQUEST,
2278
3119
  opts.attestation
2279
3120
  );
2280
3121
  spinner.succeed("Join request rejected");
2281
- console.log(DIM(` ${getExplorerUrl(hash)}`));
3122
+ console.log(DIM3(` ${getExplorerUrl(hash)}`));
2282
3123
  } catch (err) {
2283
3124
  spinner.fail("Rejection failed");
2284
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3125
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2285
3126
  process.exit(1);
2286
3127
  }
2287
3128
  });
@@ -2290,39 +3131,39 @@ vaultCmd.command("deposit").description("Deposit into a vault").option("--vault
2290
3131
  resolveVault(opts);
2291
3132
  const decimals = await getAssetDecimals();
2292
3133
  const amount = parseUnits8(opts.amount, decimals);
2293
- const spinner = ora5(`Depositing ${opts.amount}...`).start();
3134
+ const spinner = ora7(`Depositing ${opts.amount}...`).start();
2294
3135
  try {
2295
3136
  const hash = await deposit(amount);
2296
3137
  spinner.succeed(`Deposited: ${hash}`);
2297
- console.log(chalk5.dim(` ${getExplorerUrl(hash)}`));
3138
+ console.log(chalk7.dim(` ${getExplorerUrl(hash)}`));
2298
3139
  } catch (err) {
2299
3140
  spinner.fail("Deposit failed");
2300
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3141
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2301
3142
  process.exit(1);
2302
3143
  }
2303
3144
  });
2304
3145
  vaultCmd.command("ragequit").description("Withdraw all shares from a vault").option("--vault <address>", "Vault address (default: from config)").action(async (opts) => {
2305
3146
  resolveVault(opts);
2306
- const spinner = ora5("Ragequitting...").start();
3147
+ const spinner = ora7("Ragequitting...").start();
2307
3148
  try {
2308
3149
  const hash = await ragequit();
2309
3150
  spinner.succeed(`Ragequit: ${hash}`);
2310
- console.log(chalk5.dim(` ${getExplorerUrl(hash)}`));
3151
+ console.log(chalk7.dim(` ${getExplorerUrl(hash)}`));
2311
3152
  } catch (err) {
2312
3153
  spinner.fail("Ragequit failed");
2313
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3154
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2314
3155
  process.exit(1);
2315
3156
  }
2316
3157
  });
2317
3158
  vaultCmd.command("info").description("Display vault state").option("--vault <address>", "Vault address (default: from config)").action(async (opts) => {
2318
3159
  resolveVault(opts);
2319
- const spinner = ora5("Loading vault info...").start();
3160
+ const spinner = ora7("Loading vault info...").start();
2320
3161
  try {
2321
3162
  const info = await getVaultInfo();
2322
3163
  spinner.stop();
2323
3164
  console.log();
2324
- console.log(chalk5.bold("Vault Info"));
2325
- console.log(chalk5.dim("\u2500".repeat(40)));
3165
+ console.log(chalk7.bold("Vault Info"));
3166
+ console.log(chalk7.dim("\u2500".repeat(40)));
2326
3167
  console.log(` Address: ${info.address}`);
2327
3168
  console.log(` Total Assets: ${info.totalAssets}`);
2328
3169
  console.log(` Agent Count: ${info.agentCount}`);
@@ -2331,85 +3172,85 @@ vaultCmd.command("info").description("Display vault state").option("--vault <add
2331
3172
  console.log();
2332
3173
  } catch (err) {
2333
3174
  spinner.fail("Failed to load vault info");
2334
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3175
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2335
3176
  process.exit(1);
2336
3177
  }
2337
3178
  });
2338
3179
  vaultCmd.command("balance").description("Show LP share balance and asset value").option("--vault <address>", "Vault address (default: from config)").option("--address <address>", "Address to check (default: your wallet)").action(async (opts) => {
2339
3180
  resolveVault(opts);
2340
- const spinner = ora5("Loading balance...").start();
3181
+ const spinner = ora7("Loading balance...").start();
2341
3182
  try {
2342
3183
  const balance = await getBalance(opts.address);
2343
3184
  spinner.stop();
2344
3185
  console.log();
2345
- console.log(chalk5.bold("LP Position"));
2346
- console.log(chalk5.dim("\u2500".repeat(40)));
3186
+ console.log(chalk7.bold("LP Position"));
3187
+ console.log(chalk7.dim("\u2500".repeat(40)));
2347
3188
  console.log(` Shares: ${balance.shares.toString()}`);
2348
3189
  console.log(` Asset Value: ${balance.assetsValue}`);
2349
3190
  console.log(` % of Vault: ${balance.percentOfVault}`);
2350
3191
  console.log();
2351
3192
  } catch (err) {
2352
3193
  spinner.fail("Failed to load balance");
2353
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3194
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2354
3195
  process.exit(1);
2355
3196
  }
2356
3197
  });
2357
3198
  var strategy = program.command("strategy");
2358
3199
  strategy.command("list").description("List registered strategies").option("--type <id>", "Filter by strategy type").action(async (opts) => {
2359
- const spinner = ora5("Loading strategies...").start();
3200
+ const spinner = ora7("Loading strategies...").start();
2360
3201
  try {
2361
3202
  const strategies = await listStrategies(
2362
3203
  opts.type ? BigInt(opts.type) : void 0
2363
3204
  );
2364
3205
  spinner.stop();
2365
3206
  if (strategies.length === 0) {
2366
- console.log(chalk5.dim("No strategies registered."));
3207
+ console.log(chalk7.dim("No strategies registered."));
2367
3208
  return;
2368
3209
  }
2369
3210
  console.log();
2370
- console.log(chalk5.bold(`Strategies (${strategies.length})`));
2371
- console.log(chalk5.dim("\u2500".repeat(70)));
3211
+ console.log(chalk7.bold(`Strategies (${strategies.length})`));
3212
+ console.log(chalk7.dim("\u2500".repeat(70)));
2372
3213
  for (const s of strategies) {
2373
- const status = s.active ? chalk5.green("active") : chalk5.red("inactive");
2374
- console.log(` #${s.id} ${chalk5.bold(s.name)} [type: ${s.strategyTypeId}] ${status}`);
3214
+ const status = s.active ? chalk7.green("active") : chalk7.red("inactive");
3215
+ console.log(` #${s.id} ${chalk7.bold(s.name)} [type: ${s.strategyTypeId}] ${status}`);
2375
3216
  console.log(` Creator: ${s.creator}`);
2376
3217
  console.log(` Implementation: ${s.implementation}`);
2377
3218
  if (s.metadataURI) {
2378
- console.log(` Metadata: ${chalk5.dim(s.metadataURI)}`);
3219
+ console.log(` Metadata: ${chalk7.dim(s.metadataURI)}`);
2379
3220
  }
2380
3221
  console.log();
2381
3222
  }
2382
3223
  } catch (err) {
2383
3224
  spinner.fail("Failed to load strategies");
2384
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3225
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2385
3226
  process.exit(1);
2386
3227
  }
2387
3228
  });
2388
3229
  strategy.command("info").description("Show strategy details").argument("<id>", "Strategy ID").action(async (idStr) => {
2389
- const spinner = ora5("Loading strategy...").start();
3230
+ const spinner = ora7("Loading strategy...").start();
2390
3231
  try {
2391
3232
  const s = await getStrategy(BigInt(idStr));
2392
3233
  spinner.stop();
2393
3234
  console.log();
2394
- console.log(chalk5.bold(`Strategy #${s.id}`));
2395
- console.log(chalk5.dim("\u2500".repeat(40)));
3235
+ console.log(chalk7.bold(`Strategy #${s.id}`));
3236
+ console.log(chalk7.dim("\u2500".repeat(40)));
2396
3237
  console.log(` Name: ${s.name}`);
2397
3238
  console.log(` Type: ${s.strategyTypeId}`);
2398
- console.log(` Active: ${s.active ? chalk5.green("yes") : chalk5.red("no")}`);
3239
+ console.log(` Active: ${s.active ? chalk7.green("yes") : chalk7.red("no")}`);
2399
3240
  console.log(` Creator: ${s.creator}`);
2400
3241
  console.log(` Implementation: ${s.implementation}`);
2401
3242
  if (s.metadataURI) {
2402
- console.log(` Metadata: ${chalk5.dim(s.metadataURI)}`);
3243
+ console.log(` Metadata: ${chalk7.dim(s.metadataURI)}`);
2403
3244
  }
2404
3245
  console.log();
2405
3246
  } catch (err) {
2406
3247
  spinner.fail("Failed to load strategy");
2407
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3248
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2408
3249
  process.exit(1);
2409
3250
  }
2410
3251
  });
2411
3252
  strategy.command("register").description("Register a new strategy on-chain").requiredOption("--implementation <address>", "Strategy contract address").requiredOption("--type <id>", "Strategy type ID").requiredOption("--name <name>", "Strategy name").option("--metadata <uri>", "Metadata URI (IPFS/Arweave)", "").action(async (opts) => {
2412
- const spinner = ora5("Registering strategy...").start();
3253
+ const spinner = ora7("Registering strategy...").start();
2413
3254
  try {
2414
3255
  const hash = await registerStrategy(
2415
3256
  opts.implementation,
@@ -2418,10 +3259,10 @@ strategy.command("register").description("Register a new strategy on-chain").req
2418
3259
  opts.metadata
2419
3260
  );
2420
3261
  spinner.succeed(`Strategy registered: ${hash}`);
2421
- console.log(chalk5.dim(` ${getExplorerUrl(hash)}`));
3262
+ console.log(chalk7.dim(` ${getExplorerUrl(hash)}`));
2422
3263
  } catch (err) {
2423
3264
  spinner.fail("Registration failed");
2424
- console.error(chalk5.red(err instanceof Error ? err.message : String(err)));
3265
+ console.error(chalk7.red(err instanceof Error ? err.message : String(err)));
2425
3266
  process.exit(1);
2426
3267
  }
2427
3268
  });
@@ -2430,7 +3271,7 @@ strategy.command("run").description("Execute the levered swap strategy").option(
2430
3271
  await runLeveredSwap(opts);
2431
3272
  });
2432
3273
  program.command("providers").description("List available DeFi providers").action(async () => {
2433
- const { MessariProvider, NansenProvider } = await import("./research-JMGCIJ4H.js");
3274
+ const { MessariProvider, NansenProvider } = await import("./research-ZR7HXITG.js");
2434
3275
  const providers = [new MoonwellProvider(), new UniswapProvider(), new MessariProvider(), new NansenProvider()];
2435
3276
  for (const p of providers) {
2436
3277
  const info = p.info();
@@ -2441,57 +3282,70 @@ ${info.name} (${info.type})`);
2441
3282
  }
2442
3283
  });
2443
3284
  try {
2444
- const { registerChatCommands } = await import("./chat-BSLMAYM5.js");
3285
+ const { registerChatCommands } = await import("./chat-O34BTHII.js");
2445
3286
  registerChatCommands(program);
2446
3287
  } catch {
2447
3288
  program.command("chat <name> [action] [actionArgs...]").description("Syndicate chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
2448
- console.error(chalk5.red("XMTP CLI not available."));
2449
- console.error(chalk5.dim("Install with: npm install -g @xmtp/cli"));
2450
- console.error(chalk5.dim("Or reinstall: npm i -g @sherwoodagent/cli"));
3289
+ console.error(chalk7.red("XMTP CLI not available."));
3290
+ console.error(chalk7.dim("Install with: npm install -g @xmtp/cli"));
3291
+ console.error(chalk7.dim("Or reinstall: npm i -g @sherwoodagent/cli"));
2451
3292
  process.exit(1);
2452
3293
  });
2453
3294
  }
2454
- var { registerSessionCommands } = await import("./session-XUOMZWOT.js");
3295
+ var { registerSessionCommands } = await import("./session-QEIVURQO.js");
2455
3296
  registerSessionCommands(program);
2456
3297
  registerVeniceCommands(program);
2457
3298
  registerAllowanceCommands(program);
2458
3299
  registerIdentityCommands(program);
2459
- var { registerResearchCommands } = await import("./research-SESA7KGU.js");
3300
+ registerProposalCommands(program);
3301
+ registerGovernorCommands(program);
3302
+ var { registerResearchCommands } = await import("./research-GX32VMP7.js");
2460
3303
  registerResearchCommands(program);
2461
3304
  var configCmd = program.command("config");
2462
- configCmd.command("set").description("Save settings to ~/.sherwood/config.json (persists across sessions)").option("--private-key <key>", "Wallet private key (0x-prefixed)").option("--vault <address>", "Default SyndicateVault address").action((opts) => {
3305
+ configCmd.command("set").description("Save settings to ~/.sherwood/config.json (persists across sessions)").option("--private-key <key>", "Wallet private key (0x-prefixed)").option("--vault <address>", "Default SyndicateVault address").option("--rpc <url>", "Custom RPC URL for the active --chain network").action((opts) => {
2463
3306
  let saved = false;
2464
3307
  if (opts.privateKey) {
2465
3308
  setPrivateKey(opts.privateKey);
2466
3309
  const account = getAccount();
2467
- console.log(chalk5.green("Private key saved to ~/.sherwood/config.json"));
2468
- console.log(chalk5.dim(` Wallet: ${account.address}`));
3310
+ console.log(chalk7.green("Private key saved to ~/.sherwood/config.json"));
3311
+ console.log(chalk7.dim(` Wallet: ${account.address}`));
2469
3312
  saved = true;
2470
3313
  }
2471
3314
  if (opts.vault) {
2472
3315
  const chainId = getChain().id;
2473
3316
  setChainContract(chainId, "vault", opts.vault);
2474
- console.log(chalk5.green(`Vault saved to ~/.sherwood/config.json (chain ${chainId})`));
2475
- console.log(chalk5.dim(` Vault: ${opts.vault}`));
3317
+ console.log(chalk7.green(`Vault saved to ~/.sherwood/config.json (chain ${chainId})`));
3318
+ console.log(chalk7.dim(` Vault: ${opts.vault}`));
3319
+ saved = true;
3320
+ }
3321
+ if (opts.rpc) {
3322
+ const network = getNetwork();
3323
+ setConfigRpcUrl(network, opts.rpc);
3324
+ console.log(chalk7.green(`RPC URL saved for ${network}`));
3325
+ console.log(chalk7.dim(` RPC: ${opts.rpc}`));
2476
3326
  saved = true;
2477
3327
  }
2478
3328
  if (!saved) {
2479
- console.log(chalk5.red("Provide at least one of: --private-key, --vault"));
3329
+ console.log(chalk7.red("Provide at least one of: --private-key, --vault, --rpc"));
2480
3330
  process.exit(1);
2481
3331
  }
2482
3332
  });
2483
3333
  configCmd.command("show").description("Display current config for the active network").action(() => {
3334
+ const network = getNetwork();
2484
3335
  const chainId = getChain().id;
2485
3336
  const contracts = getChainContracts(chainId);
2486
3337
  const config = loadConfig();
3338
+ const customRpc = config.rpc?.[network];
2487
3339
  console.log();
2488
- console.log(chalk5.bold(`Sherwood Config (chain ${chainId})`));
2489
- console.log(chalk5.dim("\u2500".repeat(50)));
2490
- console.log(` Wallet: ${config.privateKey ? chalk5.green("configured") : chalk5.dim("not set")}`);
2491
- console.log(` Agent ID: ${config.agentId ?? chalk5.dim("not set")}`);
2492
- console.log(` Vault: ${contracts.vault ?? chalk5.dim("not set")}`);
3340
+ console.log(chalk7.bold(`Sherwood Config`));
3341
+ console.log(chalk7.dim("\u2500".repeat(50)));
3342
+ console.log(` Network: ${chalk7.cyan(network)} (chain ${chainId})`);
3343
+ console.log(` RPC: ${customRpc ? chalk7.green(customRpc) : chalk7.dim("default")}`);
3344
+ console.log(` Wallet: ${config.privateKey ? chalk7.green("configured") : chalk7.dim("not set")}`);
3345
+ console.log(` Agent ID: ${config.agentId ?? chalk7.dim("not set")}`);
3346
+ console.log(` Vault: ${contracts.vault ?? chalk7.dim("not set")}`);
2493
3347
  console.log();
2494
- console.log(chalk5.dim(" Config file: ~/.sherwood/config.json"));
3348
+ console.log(chalk7.dim(" Config file: ~/.sherwood/config.json"));
2495
3349
  console.log();
2496
3350
  });
2497
3351
  program.parse();