@sherwoodagent/cli 0.42.0 → 0.47.1

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 (68) hide show
  1. package/dist/{addresses-DCQMJJFI.js → addresses-DOWLGXGE.js} +4 -4
  2. package/dist/{agent-5YEJ6W6W.js → agent-4HKHLQEJ.js} +3035 -2029
  3. package/dist/agent-4HKHLQEJ.js.map +1 -0
  4. package/dist/autoresearch-IA7HGSNW.js +267 -0
  5. package/dist/autoresearch-IA7HGSNW.js.map +1 -0
  6. package/dist/{chat-UWJ6JBFE.js → chat-MRTPUZ3X.js} +8 -8
  7. package/dist/{chunk-FOOZC4AM.js → chunk-2LRC7I33.js} +2 -2
  8. package/dist/{chunk-4EHI4SKM.js → chunk-2W4KGGPU.js} +11 -1
  9. package/dist/chunk-2W4KGGPU.js.map +1 -0
  10. package/dist/chunk-7HJXZ4NM.js +189 -0
  11. package/dist/chunk-7HJXZ4NM.js.map +1 -0
  12. package/dist/{chunk-JNDEZFXW.js → chunk-E6LH2FJ6.js} +4 -4
  13. package/dist/{chunk-XAUMJZU2.js → chunk-FWC57PT7.js} +2 -2
  14. package/dist/{chunk-4OAZ7TP5.js → chunk-IS2CLLUT.js} +4 -4
  15. package/dist/{chunk-T2IA6CCW.js → chunk-KJ35EF7N.js} +4 -4
  16. package/dist/{chunk-GMVDHSCF.js → chunk-OHQOTSFG.js} +39 -3
  17. package/dist/chunk-OHQOTSFG.js.map +1 -0
  18. package/dist/chunk-R2P4C2I7.js +560 -0
  19. package/dist/chunk-R2P4C2I7.js.map +1 -0
  20. package/dist/{chunk-5Q3VT6NQ.js → chunk-R7X33D2S.js} +5 -5
  21. package/dist/{chunk-6U3A6ZJ2.js → chunk-WMZEOR5W.js} +6 -127
  22. package/dist/chunk-WMZEOR5W.js.map +1 -0
  23. package/dist/{chunk-SWKHSKDH.js → chunk-XDBRKW7I.js} +3 -3
  24. package/dist/chunk-YTYXBX7B.js +495 -0
  25. package/dist/chunk-YTYXBX7B.js.map +1 -0
  26. package/dist/{client-DRVUILER.js → client-UHHCB6EZ.js} +4 -4
  27. package/dist/{config-YRERDZSL.js → config-REASKDIK.js} +6 -2
  28. package/dist/{eas-KBU2BAOD.js → eas-PEEWGSAO.js} +6 -6
  29. package/dist/{governor-KH7RNH2E.js → governor-MG5VVSU4.js} +6 -6
  30. package/dist/index.js +1012 -265
  31. package/dist/index.js.map +1 -1
  32. package/dist/{network-3HB46JMQ.js → network-3ZU7UBDU.js} +3 -3
  33. package/dist/{price-TTQWI672.js → price-WCCXWPDM.js} +5 -5
  34. package/dist/{research-J3HYU3N6.js → research-QBKISW2M.js} +9 -9
  35. package/dist/research-YJWSQS2A.js +14 -0
  36. package/dist/serve-6MYBOAX6.js +222 -0
  37. package/dist/serve-6MYBOAX6.js.map +1 -0
  38. package/dist/{session-NUPHC6ZN.js → session-FPCPCVQX.js} +10 -10
  39. package/dist/summary-formatter-JIGWN4QS.js +180 -0
  40. package/dist/summary-formatter-JIGWN4QS.js.map +1 -0
  41. package/dist/{trade-VGECC4QZ.js → trade-NO6CNWCA.js} +19 -17
  42. package/dist/{trade-VGECC4QZ.js.map → trade-NO6CNWCA.js.map} +1 -1
  43. package/dist/{xmtp-JO7W6RFK.js → xmtp-ACB2W573.js} +6 -6
  44. package/package.json +5 -2
  45. package/dist/agent-5YEJ6W6W.js.map +0 -1
  46. package/dist/chunk-4EHI4SKM.js.map +0 -1
  47. package/dist/chunk-6U3A6ZJ2.js.map +0 -1
  48. package/dist/chunk-GMVDHSCF.js.map +0 -1
  49. package/dist/research-NR4VC5LN.js +0 -14
  50. /package/dist/{addresses-DCQMJJFI.js.map → addresses-DOWLGXGE.js.map} +0 -0
  51. /package/dist/{chat-UWJ6JBFE.js.map → chat-MRTPUZ3X.js.map} +0 -0
  52. /package/dist/{chunk-FOOZC4AM.js.map → chunk-2LRC7I33.js.map} +0 -0
  53. /package/dist/{chunk-JNDEZFXW.js.map → chunk-E6LH2FJ6.js.map} +0 -0
  54. /package/dist/{chunk-XAUMJZU2.js.map → chunk-FWC57PT7.js.map} +0 -0
  55. /package/dist/{chunk-4OAZ7TP5.js.map → chunk-IS2CLLUT.js.map} +0 -0
  56. /package/dist/{chunk-T2IA6CCW.js.map → chunk-KJ35EF7N.js.map} +0 -0
  57. /package/dist/{chunk-5Q3VT6NQ.js.map → chunk-R7X33D2S.js.map} +0 -0
  58. /package/dist/{chunk-SWKHSKDH.js.map → chunk-XDBRKW7I.js.map} +0 -0
  59. /package/dist/{client-DRVUILER.js.map → client-UHHCB6EZ.js.map} +0 -0
  60. /package/dist/{config-YRERDZSL.js.map → config-REASKDIK.js.map} +0 -0
  61. /package/dist/{eas-KBU2BAOD.js.map → eas-PEEWGSAO.js.map} +0 -0
  62. /package/dist/{governor-KH7RNH2E.js.map → governor-MG5VVSU4.js.map} +0 -0
  63. /package/dist/{network-3HB46JMQ.js.map → network-3ZU7UBDU.js.map} +0 -0
  64. /package/dist/{price-TTQWI672.js.map → price-WCCXWPDM.js.map} +0 -0
  65. /package/dist/{research-J3HYU3N6.js.map → research-QBKISW2M.js.map} +0 -0
  66. /package/dist/{research-NR4VC5LN.js.map → research-YJWSQS2A.js.map} +0 -0
  67. /package/dist/{session-NUPHC6ZN.js.map → session-FPCPCVQX.js.map} +0 -0
  68. /package/dist/{xmtp-JO7W6RFK.js.map → xmtp-ACB2W573.js.map} +0 -0
package/dist/index.js CHANGED
@@ -1,15 +1,21 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ HyperliquidProvider,
4
+ getLatestSignals
5
+ } from "./chunk-R2P4C2I7.js";
2
6
  import {
3
7
  UniswapProvider,
4
8
  applySlippage,
5
- chatCompletion,
6
- checkApiKeyValid,
7
9
  encodeSwapPath,
8
10
  getMultiHopQuote,
9
- getQuote,
11
+ getQuote
12
+ } from "./chunk-WMZEOR5W.js";
13
+ import {
14
+ chatCompletion,
15
+ checkApiKeyValid,
10
16
  listModels,
11
17
  provisionApiKey
12
- } from "./chunk-6U3A6ZJ2.js";
18
+ } from "./chunk-7HJXZ4NM.js";
13
19
  import {
14
20
  createApproval,
15
21
  createJoinRequest,
@@ -20,14 +26,14 @@ import {
20
26
  queryJoinRequests,
21
27
  revokeJoinRequest,
22
28
  stripReferrerPrefix
23
- } from "./chunk-JNDEZFXW.js";
29
+ } from "./chunk-E6LH2FJ6.js";
24
30
  import {
25
31
  createSyndicate,
26
32
  getActiveSyndicates,
27
33
  getSyndicate,
28
34
  subdomainExists,
29
35
  updateMetadata
30
- } from "./chunk-4OAZ7TP5.js";
36
+ } from "./chunk-IS2CLLUT.js";
31
37
  import {
32
38
  approveDepositor,
33
39
  deposit,
@@ -51,7 +57,7 @@ import {
51
57
  searchSyndicateAcrossChains,
52
58
  setTextRecord,
53
59
  setVaultAddress
54
- } from "./chunk-5Q3VT6NQ.js";
60
+ } from "./chunk-R7X33D2S.js";
55
61
  import {
56
62
  PROPOSAL_STATE,
57
63
  PROPOSAL_STATES,
@@ -83,7 +89,7 @@ import {
83
89
  setVotingPeriod,
84
90
  settleProposal,
85
91
  vote
86
- } from "./chunk-T2IA6CCW.js";
92
+ } from "./chunk-KJ35EF7N.js";
87
93
  import {
88
94
  AERODROME,
89
95
  AGENT_REGISTRY,
@@ -95,7 +101,7 @@ import {
95
101
  TOKENS,
96
102
  UNISWAP,
97
103
  VENICE
98
- } from "./chunk-XAUMJZU2.js";
104
+ } from "./chunk-FWC57PT7.js";
99
105
  import {
100
106
  formatContractError,
101
107
  getAccount,
@@ -104,7 +110,7 @@ import {
104
110
  sendTxWithRetry,
105
111
  waitForReceipt,
106
112
  writeContractWithRetry
107
- } from "./chunk-SWKHSKDH.js";
113
+ } from "./chunk-XDBRKW7I.js";
108
114
  import {
109
115
  CHAIN_REGISTRY,
110
116
  VALID_NETWORKS,
@@ -115,7 +121,7 @@ import {
115
121
  isTestnet,
116
122
  setNetwork,
117
123
  withNetwork
118
- } from "./chunk-FOOZC4AM.js";
124
+ } from "./chunk-2LRC7I33.js";
119
125
  import {
120
126
  addSyndicate,
121
127
  cacheGroupId,
@@ -131,6 +137,7 @@ import {
131
137
  getVeniceApiKey,
132
138
  loadConfig,
133
139
  setAgentId,
140
+ setAnthropicApiKey,
134
141
  setChainContract,
135
142
  setConfigRpcUrl,
136
143
  setNotifyTo,
@@ -138,7 +145,7 @@ import {
138
145
  setPrivateKey,
139
146
  setUniswapApiKey,
140
147
  setVeniceApiKey
141
- } from "./chunk-4EHI4SKM.js";
148
+ } from "./chunk-2W4KGGPU.js";
142
149
  import {
143
150
  BASE_STRATEGY_ABI,
144
151
  ERC20_ABI,
@@ -158,7 +165,7 @@ import { config as loadDotenv } from "dotenv";
158
165
  import { createRequire } from "module";
159
166
  import { Command, Option } from "commander";
160
167
  import { parseUnits as parseUnits6, formatUnits as formatUnits5, isAddress as isAddress6 } from "viem";
161
- import chalk9 from "chalk";
168
+ import chalk13 from "chalk";
162
169
  import ora8 from "ora";
163
170
  import { input, confirm, select } from "@inquirer/prompts";
164
171
 
@@ -1447,9 +1454,9 @@ function registerStrategyTemplateCommands(strategy2) {
1447
1454
  console.error(chalk.red("Missing --name, --performance-fee, or --duration. Use --write-calls to skip proposal submission."));
1448
1455
  process.exit(1);
1449
1456
  }
1450
- const { propose: propose2 } = await import("./governor-KH7RNH2E.js");
1457
+ const { propose: propose2 } = await import("./governor-MG5VVSU4.js");
1451
1458
  const { pinJSON } = await import("./ipfs-IGXLLJCF.js");
1452
- const { parseDuration: parseDuration2 } = await import("./governor-KH7RNH2E.js");
1459
+ const { parseDuration: parseDuration2 } = await import("./governor-MG5VVSU4.js");
1453
1460
  const performanceFeeBps = BigInt(opts.performanceFee);
1454
1461
  if (performanceFeeBps < 0n || performanceFeeBps > 10000n) {
1455
1462
  console.error(chalk.red("--performance-fee must be 0-10000 (basis points)"));
@@ -1556,7 +1563,7 @@ function registerStrategyTemplateCommands(strategy2) {
1556
1563
  let prices = [];
1557
1564
  let priceSource = null;
1558
1565
  try {
1559
- const { getTokenPricesInAsset } = await import("./price-TTQWI672.js");
1566
+ const { getTokenPricesInAsset } = await import("./price-WCCXWPDM.js");
1560
1567
  prices = await getTokenPricesInAsset({
1561
1568
  tokens: allocations.map((a, i) => ({
1562
1569
  token: a.token,
@@ -1986,7 +1993,7 @@ function registerVeniceCommands(program2) {
1986
1993
  console.log(chalk2.dim(` Key: ${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`));
1987
1994
  console.log(chalk2.dim(" Saved to ~/.sherwood/config.json"));
1988
1995
  try {
1989
- const { createVeniceProvisionAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-KBU2BAOD.js");
1996
+ const { createVeniceProvisionAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-PEEWGSAO.js");
1990
1997
  const { uid } = await createVeniceProvisionAttestation(account.address);
1991
1998
  if (uid !== "0x0000000000000000000000000000000000000000000000000000000000000000") {
1992
1999
  console.log(chalk2.dim(` Attested: ${getEasScanUrl2(uid)}`));
@@ -2342,10 +2349,10 @@ ${opts.prompt}`;
2342
2349
  console.log(chalk2.dim(`Model: ${result.model} | Tokens: ${result.usage.promptTokens} in, ${result.usage.completionTokens} out, ${result.usage.totalTokens} total`));
2343
2350
  }
2344
2351
  try {
2345
- const { createVeniceInferenceAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-KBU2BAOD.js");
2352
+ const { createVeniceInferenceAttestation, getEasScanUrl: getEasScanUrl2 } = await import("./eas-PEEWGSAO.js");
2346
2353
  const { keccak256, toHex, isAddress: isAddr } = await import("viem");
2347
- const { getChainContracts: getChainContracts2 } = await import("./config-YRERDZSL.js");
2348
- const { getChain: getActiveChain } = await import("./network-3HB46JMQ.js");
2354
+ const { getChainContracts: getChainContracts2 } = await import("./config-REASKDIK.js");
2355
+ const { getChain: getActiveChain } = await import("./network-3ZU7UBDU.js");
2349
2356
  const vaultRecipient = opts.vault && isAddr(opts.vault) ? opts.vault : getChainContracts2(getActiveChain().id).vault;
2350
2357
  const promptHash = keccak256(toHex(userContent)).slice(0, 18);
2351
2358
  const { uid } = await createVeniceInferenceAttestation(
@@ -3518,8 +3525,8 @@ function printSimulationResult(result, callType) {
3518
3525
  }
3519
3526
  async function sendSimulationAlert(subdomain, proposalId, vault, execResult, settleResult) {
3520
3527
  try {
3521
- const xmtp = await import("./xmtp-JO7W6RFK.js");
3522
- const { getAccount: getAccount2 } = await import("./client-DRVUILER.js");
3528
+ const xmtp = await import("./xmtp-ACB2W573.js");
3529
+ const { getAccount: getAccount2 } = await import("./client-UHHCB6EZ.js");
3523
3530
  const group = await xmtp.getGroup("", subdomain);
3524
3531
  const allRisks = [...execResult.risks, ...settleResult?.risks ?? []];
3525
3532
  const criticals = allRisks.filter((r) => r.level === "critical");
@@ -4610,6 +4617,740 @@ function registerGuardianCommands(program2) {
4610
4617
  });
4611
4618
  }
4612
4619
 
4620
+ // src/commands/grid.ts
4621
+ import chalk12 from "chalk";
4622
+
4623
+ // src/grid/loop.ts
4624
+ import chalk11 from "chalk";
4625
+ import { appendFile, mkdir as mkdir3 } from "fs/promises";
4626
+ import { join as join3 } from "path";
4627
+ import { homedir as homedir3 } from "os";
4628
+
4629
+ // src/grid/manager.ts
4630
+ import chalk9 from "chalk";
4631
+
4632
+ // src/grid/portfolio.ts
4633
+ import { readFile, writeFile, rename, mkdir } from "fs/promises";
4634
+ import { join, dirname } from "path";
4635
+ import { homedir } from "os";
4636
+ var GRID_STATE_PATH = join(homedir(), ".sherwood", "grid", "portfolio.json");
4637
+ function emptyStats() {
4638
+ return {
4639
+ totalRoundTrips: 0,
4640
+ totalPnlUsd: 0,
4641
+ todayPnlUsd: 0,
4642
+ totalFills: 0,
4643
+ todayFills: 0,
4644
+ lastDailyReset: 0,
4645
+ lastRebalanceAt: 0
4646
+ };
4647
+ }
4648
+ var GridPortfolio = class {
4649
+ state = null;
4650
+ /** Load grid state from disk. Returns null if no grid initialized yet. */
4651
+ async load() {
4652
+ try {
4653
+ const raw = await readFile(GRID_STATE_PATH, "utf-8");
4654
+ this.state = JSON.parse(raw);
4655
+ return this.state;
4656
+ } catch {
4657
+ return null;
4658
+ }
4659
+ }
4660
+ /** Save grid state to disk (atomic write). */
4661
+ async save(state) {
4662
+ this.state = state;
4663
+ await mkdir(dirname(GRID_STATE_PATH), { recursive: true });
4664
+ const tmp = `${GRID_STATE_PATH}.tmp.${process.pid}`;
4665
+ await writeFile(tmp, JSON.stringify(state, null, 2), "utf-8");
4666
+ await rename(tmp, GRID_STATE_PATH);
4667
+ }
4668
+ /**
4669
+ * Initialize the grid by carving capital from the directional portfolio.
4670
+ * Called once on first startup when grid-portfolio.json doesn't exist.
4671
+ *
4672
+ * Returns the USD amount carved out (caller must deduct from directional portfolio).
4673
+ */
4674
+ async initialize(capital, config) {
4675
+ const allocation = capital;
4676
+ const grids = config.tokens.map((token) => ({
4677
+ token,
4678
+ levels: [],
4679
+ openFills: [],
4680
+ allocation: allocation * (config.tokenSplit[token] ?? 1 / config.tokens.length),
4681
+ stats: emptyStats(),
4682
+ centerPrice: 0,
4683
+ atr: 0
4684
+ }));
4685
+ const state = {
4686
+ totalAllocation: allocation,
4687
+ grids,
4688
+ paused: false,
4689
+ pauseReason: "",
4690
+ initializedAt: Date.now()
4691
+ };
4692
+ await this.save(state);
4693
+ this.state = state;
4694
+ }
4695
+ /** Get current state (must load() first). */
4696
+ getState() {
4697
+ return this.state;
4698
+ }
4699
+ /** Reset daily counters if UTC day boundary crossed. */
4700
+ resetDailyStats(state) {
4701
+ const now = Date.now();
4702
+ const todayMidnight = /* @__PURE__ */ new Date();
4703
+ todayMidnight.setUTCHours(0, 0, 0, 0);
4704
+ const todayMs = todayMidnight.getTime();
4705
+ let changed = false;
4706
+ for (const grid of state.grids) {
4707
+ if (!grid.stats.lastDailyReset || grid.stats.lastDailyReset < todayMs) {
4708
+ grid.stats.todayPnlUsd = 0;
4709
+ grid.stats.todayFills = 0;
4710
+ grid.stats.lastDailyReset = now;
4711
+ changed = true;
4712
+ }
4713
+ }
4714
+ return changed;
4715
+ }
4716
+ /** Check if grid should be paused (pool dropped below threshold). */
4717
+ checkPauseThreshold(state, config) {
4718
+ const currentValue = state.grids.reduce((sum, g) => {
4719
+ const openFillValue = g.openFills.filter((f) => !f.closed).reduce((s, f) => s + f.quantity * f.buyPrice, 0);
4720
+ return sum + g.allocation + openFillValue;
4721
+ }, 0);
4722
+ const dropPct = 1 - currentValue / state.totalAllocation;
4723
+ if (dropPct >= config.pauseThresholdPct) {
4724
+ state.paused = true;
4725
+ state.pauseReason = `Grid pool dropped ${(dropPct * 100).toFixed(1)}% (threshold: ${(config.pauseThresholdPct * 100).toFixed(0)}%)`;
4726
+ return true;
4727
+ }
4728
+ return false;
4729
+ }
4730
+ /** Aggregate stats across all token grids. */
4731
+ aggregateStats(state) {
4732
+ return {
4733
+ totalPnlUsd: state.grids.reduce((s, g) => s + g.stats.totalPnlUsd, 0),
4734
+ todayPnlUsd: state.grids.reduce((s, g) => s + g.stats.todayPnlUsd, 0),
4735
+ todayFills: state.grids.reduce((s, g) => s + g.stats.todayFills, 0),
4736
+ totalRoundTrips: state.grids.reduce((s, g) => s + g.stats.totalRoundTrips, 0)
4737
+ };
4738
+ }
4739
+ };
4740
+
4741
+ // src/grid/manager.ts
4742
+ var GridManager = class {
4743
+ config;
4744
+ portfolio;
4745
+ hl;
4746
+ constructor(config) {
4747
+ this.config = config;
4748
+ this.portfolio = new GridPortfolio();
4749
+ this.hl = new HyperliquidProvider();
4750
+ }
4751
+ /** Load or initialize grid state.
4752
+ * Also syncs new tokens added to config after initial grid setup. */
4753
+ async init(totalPortfolioValue) {
4754
+ const existing = await this.portfolio.load();
4755
+ if (!existing) {
4756
+ await this.portfolio.initialize(totalPortfolioValue, this.config);
4757
+ return;
4758
+ }
4759
+ let addedAllocation = 0;
4760
+ for (const token of this.config.tokens) {
4761
+ if (!existing.grids.find((g) => g.token === token)) {
4762
+ const split = this.config.tokenSplit[token] ?? 1 / this.config.tokens.length;
4763
+ const alloc = existing.totalAllocation * split;
4764
+ existing.grids.push({
4765
+ token,
4766
+ levels: [],
4767
+ openFills: [],
4768
+ allocation: alloc,
4769
+ stats: { totalRoundTrips: 0, totalPnlUsd: 0, todayPnlUsd: 0, totalFills: 0, todayFills: 0, lastDailyReset: 0, lastRebalanceAt: 0 },
4770
+ centerPrice: 0,
4771
+ atr: 0
4772
+ });
4773
+ addedAllocation += alloc;
4774
+ console.error(` [grid] Added new token grid: ${token} ($${alloc.toFixed(0)} allocation)`);
4775
+ }
4776
+ }
4777
+ if (addedAllocation > 0) {
4778
+ await this.portfolio.save(existing);
4779
+ }
4780
+ }
4781
+ /**
4782
+ * Run one grid tick — called every cycle from the agent loop.
4783
+ *
4784
+ * 1. Load state + reset daily counters
4785
+ * 2. For each token grid: fetch price, simulate fills, check rebalance
4786
+ * 3. Persist state
4787
+ *
4788
+ * Returns a summary for the cycle log.
4789
+ */
4790
+ async tick(prices, regime) {
4791
+ const state = await this.portfolio.load();
4792
+ if (!state || state.paused || !this.config.enabled) {
4793
+ return { fills: 0, roundTrips: 0, pnlUsd: 0, paused: state?.paused ?? false };
4794
+ }
4795
+ if (regime === "high-volatility") {
4796
+ console.error(chalk9.dim(` [grid] Paused: high-volatility regime \u2014 too risky for grid`));
4797
+ return { fills: 0, roundTrips: 0, pnlUsd: 0, paused: false };
4798
+ }
4799
+ this.portfolio.resetDailyStats(state);
4800
+ let totalFills = 0;
4801
+ let totalRoundTrips = 0;
4802
+ let totalPnl = 0;
4803
+ for (const grid of state.grids) {
4804
+ const price = prices[grid.token];
4805
+ if (!price || price <= 0) continue;
4806
+ if (grid.levels.length === 0 || this.needsFullRebuild(grid)) {
4807
+ await this.buildGrid(grid, price);
4808
+ }
4809
+ const { fills, roundTrips, pnlUsd } = this.simulateFills(grid, price);
4810
+ totalFills += fills;
4811
+ totalRoundTrips += roundTrips;
4812
+ totalPnl += pnlUsd;
4813
+ if (this.needsShift(grid, price)) {
4814
+ await this.shiftGrid(grid, price);
4815
+ }
4816
+ }
4817
+ this.portfolio.checkPauseThreshold(state, this.config);
4818
+ await this.portfolio.save(state);
4819
+ return { fills: totalFills, roundTrips: totalRoundTrips, pnlUsd: totalPnl, paused: false };
4820
+ }
4821
+ /** Build a fresh grid centered on the current price using ATR. */
4822
+ async buildGrid(grid, currentPrice) {
4823
+ const candles = await this.hl.getCandles(grid.token, "4h", 14 * 24 * 60 * 60 * 1e3);
4824
+ if (!candles || candles.length < this.config.atrPeriod) {
4825
+ console.error(chalk9.dim(` [grid] Cannot build grid for ${grid.token}: insufficient candle data`));
4826
+ return;
4827
+ }
4828
+ const signals = getLatestSignals(candles);
4829
+ const atr = signals.atr;
4830
+ if (!Number.isFinite(atr) || atr <= 0) {
4831
+ console.error(chalk9.dim(` [grid] Cannot build grid for ${grid.token}: invalid ATR (${atr})`));
4832
+ return;
4833
+ }
4834
+ const range = atr * this.config.atrMultiplier;
4835
+ const spacing = range / this.config.levelsPerSide;
4836
+ const effectiveCapital = grid.allocation * this.config.leverage;
4837
+ const quantity = effectiveCapital / (this.config.levelsPerSide * currentPrice);
4838
+ const levels = [];
4839
+ for (let i = 1; i <= this.config.levelsPerSide; i++) {
4840
+ levels.push({
4841
+ price: currentPrice - spacing * i,
4842
+ side: "buy",
4843
+ quantity,
4844
+ filled: false,
4845
+ filledAt: 0
4846
+ });
4847
+ }
4848
+ for (let i = 1; i <= this.config.levelsPerSide; i++) {
4849
+ levels.push({
4850
+ price: currentPrice + spacing * i,
4851
+ side: "sell",
4852
+ quantity,
4853
+ filled: false,
4854
+ filledAt: 0
4855
+ });
4856
+ }
4857
+ grid.levels = levels;
4858
+ grid.centerPrice = currentPrice;
4859
+ grid.atr = atr;
4860
+ grid.stats.lastRebalanceAt = Date.now();
4861
+ console.error(chalk9.dim(
4862
+ ` [grid] Built ${grid.token} grid: center=$${currentPrice.toFixed(2)} ATR=$${atr.toFixed(2)} range=$${(currentPrice - range).toFixed(2)}-$${(currentPrice + range).toFixed(2)} spacing=$${spacing.toFixed(2)} qty=${quantity.toFixed(6)}`
4863
+ ));
4864
+ }
4865
+ /** Simulate order fills against the current price. */
4866
+ simulateFills(grid, currentPrice) {
4867
+ let fills = 0;
4868
+ let roundTrips = 0;
4869
+ let pnlUsd = 0;
4870
+ const now = Date.now();
4871
+ const spacing = grid.atr > 0 ? grid.atr * this.config.atrMultiplier / this.config.levelsPerSide : 0;
4872
+ if (spacing <= 0) return { fills: 0, roundTrips: 0, pnlUsd: 0 };
4873
+ for (const level of grid.levels) {
4874
+ if (level.filled) continue;
4875
+ if (level.side === "buy" && currentPrice <= level.price) {
4876
+ level.filled = true;
4877
+ level.filledAt = now;
4878
+ fills++;
4879
+ grid.stats.totalFills++;
4880
+ grid.stats.todayFills++;
4881
+ grid.openFills.push({
4882
+ token: grid.token,
4883
+ buyPrice: level.price,
4884
+ targetSellPrice: level.price + spacing,
4885
+ quantity: level.quantity,
4886
+ filledAt: now,
4887
+ closed: false,
4888
+ pnlUsd: 0,
4889
+ closedAt: 0
4890
+ });
4891
+ console.error(chalk9.dim(
4892
+ ` [grid] BUY fill ${grid.token} @ $${level.price.toFixed(2)} qty=${level.quantity.toFixed(6)}`
4893
+ ));
4894
+ }
4895
+ if (level.side === "sell" && currentPrice >= level.price) {
4896
+ level.filled = true;
4897
+ level.filledAt = now;
4898
+ fills++;
4899
+ grid.stats.totalFills++;
4900
+ grid.stats.todayFills++;
4901
+ console.error(chalk9.dim(
4902
+ ` [grid] SELL level ${grid.token} @ $${level.price.toFixed(2)} qty=${level.quantity.toFixed(6)}`
4903
+ ));
4904
+ }
4905
+ }
4906
+ for (const openFill of grid.openFills) {
4907
+ if (openFill.closed) continue;
4908
+ if (currentPrice >= openFill.targetSellPrice) {
4909
+ const profit = (currentPrice - openFill.buyPrice) * openFill.quantity * this.config.leverage;
4910
+ if (profit >= this.config.minProfitPerFillUsd) {
4911
+ openFill.closed = true;
4912
+ openFill.pnlUsd = profit;
4913
+ openFill.closedAt = now;
4914
+ pnlUsd += profit;
4915
+ roundTrips++;
4916
+ grid.stats.totalRoundTrips++;
4917
+ grid.stats.totalPnlUsd += profit;
4918
+ grid.stats.todayPnlUsd += profit;
4919
+ grid.allocation += profit;
4920
+ console.error(chalk9.green(
4921
+ ` [grid] ROUND-TRIP ${grid.token}: buy $${openFill.buyPrice.toFixed(2)} \u2192 sell $${currentPrice.toFixed(2)} = +$${profit.toFixed(2)}`
4922
+ ));
4923
+ }
4924
+ }
4925
+ }
4926
+ const pruneThreshold = now - 24 * 60 * 60 * 1e3;
4927
+ grid.openFills = grid.openFills.filter((f) => !f.closed || f.closedAt > pruneThreshold);
4928
+ return { fills, roundTrips, pnlUsd };
4929
+ }
4930
+ /** Check if the grid needs a full rebuild. */
4931
+ needsFullRebuild(grid) {
4932
+ if (grid.levels.length === 0) return true;
4933
+ const elapsed = Date.now() - grid.stats.lastRebalanceAt;
4934
+ return elapsed >= this.config.fullRebuildIntervalMs;
4935
+ }
4936
+ /** Check if price has drifted enough to warrant shifting the grid. */
4937
+ needsShift(grid, currentPrice) {
4938
+ if (grid.centerPrice <= 0 || grid.atr <= 0) return false;
4939
+ const range = grid.atr * this.config.atrMultiplier;
4940
+ const distFromCenter = Math.abs(currentPrice - grid.centerPrice);
4941
+ return distFromCenter / range >= this.config.rebalanceDriftPct;
4942
+ }
4943
+ /** Shift the grid to re-center on the current price. */
4944
+ async shiftGrid(grid, currentPrice) {
4945
+ console.error(chalk9.dim(
4946
+ ` [grid] Shifting ${grid.token} grid: center $${grid.centerPrice.toFixed(2)} \u2192 $${currentPrice.toFixed(2)}`
4947
+ ));
4948
+ await this.buildGrid(grid, currentPrice);
4949
+ }
4950
+ /** Get open fill exposure per token — used by the hedge manager. */
4951
+ getOpenFillExposure() {
4952
+ const state = this.portfolio.getState();
4953
+ if (!state) return [];
4954
+ return state.grids.map((g) => {
4955
+ const opens = g.openFills.filter((f) => !f.closed);
4956
+ const totalQty = opens.reduce((s, f) => s + f.quantity, 0);
4957
+ const totalNotional = opens.reduce((s, f) => s + f.quantity * f.buyPrice, 0);
4958
+ return {
4959
+ token: g.token,
4960
+ totalQuantity: totalQty,
4961
+ totalNotional,
4962
+ avgEntryPrice: totalQty > 0 ? totalNotional / totalQty : 0,
4963
+ fillCount: opens.length
4964
+ };
4965
+ }).filter((e) => e.fillCount > 0);
4966
+ }
4967
+ /** Get aggregate stats for display. */
4968
+ getStats() {
4969
+ const state = this.portfolio.getState();
4970
+ if (!state) return null;
4971
+ const agg = this.portfolio.aggregateStats(state);
4972
+ return {
4973
+ ...agg,
4974
+ allocation: state.totalAllocation,
4975
+ paused: state.paused
4976
+ };
4977
+ }
4978
+ };
4979
+
4980
+ // src/grid/config.ts
4981
+ var DEFAULT_GRID_CONFIG = {
4982
+ enabled: true,
4983
+ tokens: ["bitcoin", "ethereum", "solana"],
4984
+ allocationPct: 0.5,
4985
+ leverage: 5,
4986
+ // was 4 — +25% profit per RT
4987
+ levelsPerSide: 15,
4988
+ atrMultiplier: 2,
4989
+ atrPeriod: 14,
4990
+ rebalanceDriftPct: 0.4,
4991
+ // was 0.55 — rebalance faster, keep levels near price
4992
+ fullRebuildIntervalMs: 12 * 60 * 60 * 1e3,
4993
+ // 12h
4994
+ tokenSplit: { bitcoin: 0.45, ethereum: 0.3, solana: 0.25 },
4995
+ minProfitPerFillUsd: 0.5,
4996
+ pauseThresholdPct: 0.2
4997
+ };
4998
+
4999
+ // src/grid/hedge.ts
5000
+ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
5001
+ import { join as join2, dirname as dirname2 } from "path";
5002
+ import { homedir as homedir2 } from "os";
5003
+ import chalk10 from "chalk";
5004
+ var HEDGE_RATIO = 0.3;
5005
+ var MIN_FILLS_TO_HEDGE = 3;
5006
+ var ADJUSTMENT_THRESHOLD = 0.1;
5007
+ var HEDGE_STATE_PATH = join2(homedir2(), ".sherwood", "grid", "hedge.json");
5008
+ var GridHedgeManager = class {
5009
+ state = null;
5010
+ async load() {
5011
+ if (this.state) return this.state;
5012
+ try {
5013
+ const raw = await readFile2(HEDGE_STATE_PATH, "utf-8");
5014
+ this.state = JSON.parse(raw);
5015
+ } catch {
5016
+ this.state = {
5017
+ positions: [],
5018
+ totalRealizedPnl: 0,
5019
+ todayRealizedPnl: 0,
5020
+ lastDailyReset: Date.now()
5021
+ };
5022
+ }
5023
+ const todayMidnight = /* @__PURE__ */ new Date();
5024
+ todayMidnight.setUTCHours(0, 0, 0, 0);
5025
+ if (this.state.lastDailyReset < todayMidnight.getTime()) {
5026
+ this.state.todayRealizedPnl = 0;
5027
+ this.state.lastDailyReset = Date.now();
5028
+ }
5029
+ return this.state;
5030
+ }
5031
+ async save() {
5032
+ if (!this.state) return;
5033
+ await mkdir2(dirname2(HEDGE_STATE_PATH), { recursive: true });
5034
+ const tmp = `${HEDGE_STATE_PATH}.tmp.${process.pid}`;
5035
+ await writeFile2(tmp, JSON.stringify(this.state, null, 2), "utf-8");
5036
+ const { rename: rename2 } = await import("fs/promises");
5037
+ await rename2(tmp, HEDGE_STATE_PATH);
5038
+ }
5039
+ /**
5040
+ * Run one hedge tick. Call after grid tick with current prices and open fill data.
5041
+ *
5042
+ * @param openFills - Per-token open fill exposure from the grid portfolio
5043
+ * @param prices - Current mark prices per token
5044
+ */
5045
+ async tick(openFills, prices) {
5046
+ const state = await this.load();
5047
+ let adjustments = 0;
5048
+ let unrealizedPnl = 0;
5049
+ for (const fill of openFills) {
5050
+ const price = prices[fill.token];
5051
+ if (!price || price <= 0) continue;
5052
+ const desiredShortQty = fill.fillCount >= MIN_FILLS_TO_HEDGE ? fill.totalQuantity * HEDGE_RATIO : 0;
5053
+ const existing = state.positions.find((p) => p.token === fill.token);
5054
+ if (desiredShortQty <= 0) {
5055
+ if (existing && existing.quantity > 0) {
5056
+ const closePnl = (existing.entryPrice - price) * existing.quantity;
5057
+ state.totalRealizedPnl += closePnl;
5058
+ state.todayRealizedPnl += closePnl;
5059
+ existing.realizedPnl += closePnl;
5060
+ console.error(chalk10.yellow(
5061
+ ` [hedge] CLOSE ${fill.token} short ${existing.quantity.toFixed(6)} @ $${price.toFixed(2)} PnL: $${closePnl.toFixed(2)}`
5062
+ ));
5063
+ existing.quantity = 0;
5064
+ existing.entryPrice = 0;
5065
+ adjustments++;
5066
+ }
5067
+ continue;
5068
+ }
5069
+ if (!existing) {
5070
+ state.positions.push({
5071
+ token: fill.token,
5072
+ entryPrice: price,
5073
+ quantity: desiredShortQty,
5074
+ lastAdjustedAt: Date.now(),
5075
+ realizedPnl: 0
5076
+ });
5077
+ console.error(chalk10.magenta(
5078
+ ` [hedge] OPEN ${fill.token} short ${desiredShortQty.toFixed(6)} @ $${price.toFixed(2)} (${(HEDGE_RATIO * 100).toFixed(0)}% of ${fill.fillCount} open fills)`
5079
+ ));
5080
+ adjustments++;
5081
+ } else if (existing.quantity > 0) {
5082
+ const diff = Math.abs(desiredShortQty - existing.quantity) / existing.quantity;
5083
+ if (diff > ADJUSTMENT_THRESHOLD) {
5084
+ if (desiredShortQty > existing.quantity) {
5085
+ const addQty = desiredShortQty - existing.quantity;
5086
+ const newAvgEntry = (existing.entryPrice * existing.quantity + price * addQty) / desiredShortQty;
5087
+ existing.entryPrice = newAvgEntry;
5088
+ existing.quantity = desiredShortQty;
5089
+ existing.lastAdjustedAt = Date.now();
5090
+ console.error(chalk10.magenta(
5091
+ ` [hedge] INCREASE ${fill.token} short to ${desiredShortQty.toFixed(6)} @ avg $${newAvgEntry.toFixed(2)}`
5092
+ ));
5093
+ adjustments++;
5094
+ } else {
5095
+ const closeQty = existing.quantity - desiredShortQty;
5096
+ const closePnl = (existing.entryPrice - price) * closeQty;
5097
+ state.totalRealizedPnl += closePnl;
5098
+ state.todayRealizedPnl += closePnl;
5099
+ existing.realizedPnl += closePnl;
5100
+ existing.quantity = desiredShortQty;
5101
+ existing.lastAdjustedAt = Date.now();
5102
+ console.error(chalk10.magenta(
5103
+ ` [hedge] DECREASE ${fill.token} short to ${desiredShortQty.toFixed(6)}, closed ${closeQty.toFixed(6)} PnL: $${closePnl.toFixed(2)}`
5104
+ ));
5105
+ adjustments++;
5106
+ }
5107
+ }
5108
+ const uPnl = (existing.entryPrice - price) * existing.quantity;
5109
+ unrealizedPnl += uPnl;
5110
+ } else {
5111
+ existing.entryPrice = price;
5112
+ existing.quantity = desiredShortQty;
5113
+ existing.lastAdjustedAt = Date.now();
5114
+ console.error(chalk10.magenta(
5115
+ ` [hedge] REOPEN ${fill.token} short ${desiredShortQty.toFixed(6)} @ $${price.toFixed(2)}`
5116
+ ));
5117
+ adjustments++;
5118
+ }
5119
+ }
5120
+ for (const pos of state.positions) {
5121
+ if (pos.quantity <= 0) continue;
5122
+ if (!openFills.find((f) => f.token === pos.token)) {
5123
+ const price = prices[pos.token];
5124
+ if (price) {
5125
+ const closePnl = (pos.entryPrice - price) * pos.quantity;
5126
+ state.totalRealizedPnl += closePnl;
5127
+ state.todayRealizedPnl += closePnl;
5128
+ pos.realizedPnl += closePnl;
5129
+ console.error(chalk10.yellow(
5130
+ ` [hedge] CLOSE orphaned ${pos.token} short, PnL: $${closePnl.toFixed(2)}`
5131
+ ));
5132
+ pos.quantity = 0;
5133
+ adjustments++;
5134
+ }
5135
+ }
5136
+ }
5137
+ await this.save();
5138
+ return {
5139
+ adjustments,
5140
+ unrealizedPnl,
5141
+ totalRealizedPnl: state.totalRealizedPnl
5142
+ };
5143
+ }
5144
+ /** Get current hedge status for display. */
5145
+ getStatus() {
5146
+ if (!this.state) return null;
5147
+ return {
5148
+ positions: this.state.positions.filter((p) => p.quantity > 0),
5149
+ totalRealizedPnl: this.state.totalRealizedPnl,
5150
+ todayRealizedPnl: this.state.todayRealizedPnl
5151
+ };
5152
+ }
5153
+ };
5154
+
5155
+ // src/grid/loop.ts
5156
+ var GRID_CYCLES_PATH = join3(homedir3(), ".sherwood", "grid", "cycles.jsonl");
5157
+ var GridLoop = class {
5158
+ cfg;
5159
+ gridConfig;
5160
+ manager;
5161
+ hedge;
5162
+ hl;
5163
+ running = false;
5164
+ cycleCount = 0;
5165
+ timer = null;
5166
+ constructor(cfg) {
5167
+ this.cfg = cfg;
5168
+ this.gridConfig = { ...DEFAULT_GRID_CONFIG, ...cfg.config };
5169
+ this.manager = new GridManager(this.gridConfig);
5170
+ this.hedge = new GridHedgeManager();
5171
+ this.hl = new HyperliquidProvider();
5172
+ }
5173
+ /** Start the grid loop. Resolves when shut down via SIGINT/SIGTERM. */
5174
+ async start() {
5175
+ this.running = true;
5176
+ const shutdown = () => {
5177
+ console.error(chalk11.yellow("\n [grid-loop] Shutting down\u2026"));
5178
+ this.running = false;
5179
+ if (this.timer) {
5180
+ clearTimeout(this.timer);
5181
+ this.timer = null;
5182
+ }
5183
+ };
5184
+ process.on("SIGINT", shutdown);
5185
+ process.on("SIGTERM", shutdown);
5186
+ await this.manager.init(this.cfg.capital);
5187
+ console.error(chalk11.cyan(
5188
+ `
5189
+ [grid-loop] Started \u2014 capital=$${this.cfg.capital.toFixed(0)} cycle=${(this.cfg.cycle / 1e3).toFixed(0)}s tokens=[${this.gridConfig.tokens.join(", ")}] leverage=${this.gridConfig.leverage}x levels=${this.gridConfig.levelsPerSide}/side
5190
+ `
5191
+ ));
5192
+ while (this.running) {
5193
+ try {
5194
+ await this.tick();
5195
+ } catch (err) {
5196
+ console.error(chalk11.red(` [grid-loop] Tick error: ${err.message}`));
5197
+ }
5198
+ if (this.running) {
5199
+ await new Promise((resolve2) => {
5200
+ this.timer = setTimeout(resolve2, this.cfg.cycle);
5201
+ });
5202
+ }
5203
+ }
5204
+ process.off("SIGINT", shutdown);
5205
+ process.off("SIGTERM", shutdown);
5206
+ console.error(chalk11.yellow(" [grid-loop] Stopped."));
5207
+ }
5208
+ /** Execute one grid cycle. */
5209
+ async tick() {
5210
+ this.cycleCount++;
5211
+ const start = Date.now();
5212
+ const prices = {};
5213
+ for (const token of this.gridConfig.tokens) {
5214
+ const data = await this.hl.getHyperliquidData(token);
5215
+ if (data?.markPrice && data.markPrice > 0) {
5216
+ prices[token] = data.markPrice;
5217
+ }
5218
+ }
5219
+ if (Object.keys(prices).length === 0) {
5220
+ console.error(chalk11.dim(` [grid-loop] #${this.cycleCount} \u2014 no prices, skipping`));
5221
+ return;
5222
+ }
5223
+ const result = await this.manager.tick(prices);
5224
+ const elapsed = Date.now() - start;
5225
+ if (result.roundTrips > 0) {
5226
+ console.error(chalk11.green(
5227
+ ` [grid-loop] #${this.cycleCount} \u2014 ${result.roundTrips} RT(s), +$${result.pnlUsd.toFixed(2)} PnL, ${result.fills} fill(s) [${elapsed}ms]`
5228
+ ));
5229
+ }
5230
+ if (result.fills > 0 && result.roundTrips === 0) {
5231
+ console.error(chalk11.dim(
5232
+ ` [grid-loop] #${this.cycleCount} \u2014 ${result.fills} fill(s), 0 RTs [${elapsed}ms]`
5233
+ ));
5234
+ }
5235
+ const openExposure = this.manager.getOpenFillExposure();
5236
+ const hedgeResult = await this.hedge.tick(openExposure, prices);
5237
+ if (hedgeResult.adjustments > 0) {
5238
+ console.error(chalk11.magenta(
5239
+ ` [hedge] ${hedgeResult.adjustments} adjustment(s), unrealized: $${hedgeResult.unrealizedPnl.toFixed(2)}, total realized: $${hedgeResult.totalRealizedPnl.toFixed(2)}`
5240
+ ));
5241
+ }
5242
+ const stats = this.manager.getStats();
5243
+ const cycleEntry = {
5244
+ cycleNumber: this.cycleCount,
5245
+ timestamp: Date.now(),
5246
+ gridFills: result.fills,
5247
+ gridRoundTrips: result.roundTrips,
5248
+ gridPnlUsd: result.pnlUsd,
5249
+ totalPnlUsd: stats?.totalPnlUsd ?? 0,
5250
+ todayPnlUsd: stats?.todayPnlUsd ?? 0,
5251
+ totalRoundTrips: stats?.totalRoundTrips ?? 0,
5252
+ allocation: stats?.allocation ?? 0,
5253
+ paused: stats?.paused ?? false,
5254
+ hedgeUnrealizedPnl: hedgeResult.unrealizedPnl,
5255
+ hedgeTotalRealizedPnl: hedgeResult.totalRealizedPnl
5256
+ };
5257
+ try {
5258
+ await mkdir3(join3(homedir3(), ".sherwood", "grid"), { recursive: true });
5259
+ await appendFile(GRID_CYCLES_PATH, JSON.stringify(cycleEntry) + "\n");
5260
+ } catch {
5261
+ }
5262
+ if (this.cycleCount % 60 === 0) {
5263
+ const stats2 = this.manager.getStats();
5264
+ if (stats2) {
5265
+ const hedgeStatus = this.hedge.getStatus();
5266
+ const hedgeInfo = hedgeStatus && hedgeStatus.positions.length > 0 ? ` hedge=$${hedgeResult.unrealizedPnl.toFixed(2)}unr/$${hedgeStatus.totalRealizedPnl.toFixed(2)}real` : "";
5267
+ console.error(chalk11.cyan(
5268
+ ` [grid-loop] Status #${this.cycleCount} \u2014 totalPnL=$${stats2.totalPnlUsd.toFixed(2)} todayPnL=$${stats2.todayPnlUsd.toFixed(2)} RTs=${stats2.totalRoundTrips} alloc=$${stats2.allocation.toFixed(0)}${hedgeInfo}${stats2.paused ? " (PAUSED)" : ""}`
5269
+ ));
5270
+ }
5271
+ }
5272
+ }
5273
+ };
5274
+
5275
+ // src/commands/grid.ts
5276
+ var DIM5 = chalk12.gray;
5277
+ var G5 = chalk12.green;
5278
+ var BOLD5 = chalk12.white.bold;
5279
+ var W5 = chalk12.white;
5280
+ var SEP5 = () => console.log(DIM5("\u2500".repeat(60)));
5281
+ function registerGridCommand(program2) {
5282
+ const grid = program2.command("grid").description("Grid trading strategy \u2014 ATR-based grid on BTC/ETH/SOL");
5283
+ grid.command("start").description("Start the grid trading loop").option("--capital <usd>", "Starting capital in USD", "5000").option("--cycle <seconds>", "Cycle interval in seconds", "60").option("--tokens <list>", "Comma-separated token list", "bitcoin,ethereum,solana").option("--leverage <n>", "Leverage multiplier", "5").option("--levels <n>", "Grid levels per side", "15").action(async (opts) => {
5284
+ const capital = parseFloat(opts.capital);
5285
+ const cycleMs = parseInt(opts.cycle, 10) * 1e3;
5286
+ const tokens = opts.tokens.split(",").map((t) => t.trim());
5287
+ const leverage = parseFloat(opts.leverage);
5288
+ const levels = parseInt(opts.levels, 10);
5289
+ const weight = 1 / tokens.length;
5290
+ const tokenSplit = {};
5291
+ for (const t of tokens) {
5292
+ tokenSplit[t] = weight;
5293
+ }
5294
+ console.log();
5295
+ console.log(G5.bold(" Grid Strategy"));
5296
+ SEP5();
5297
+ console.log(W5(` Capital: $${capital.toLocaleString()}`));
5298
+ console.log(W5(` Cycle: ${opts.cycle}s`));
5299
+ console.log(W5(` Tokens: ${tokens.join(", ")}`));
5300
+ console.log(W5(` Leverage: ${leverage}x`));
5301
+ console.log(W5(` Levels: ${levels}/side`));
5302
+ SEP5();
5303
+ const loop = new GridLoop({
5304
+ capital,
5305
+ cycle: cycleMs,
5306
+ config: {
5307
+ ...DEFAULT_GRID_CONFIG,
5308
+ tokens,
5309
+ leverage,
5310
+ levelsPerSide: levels,
5311
+ tokenSplit
5312
+ }
5313
+ });
5314
+ await loop.start();
5315
+ });
5316
+ grid.command("status").description("Show current grid portfolio status").action(async () => {
5317
+ const portfolio = new GridPortfolio();
5318
+ const state = await portfolio.load();
5319
+ if (!state) {
5320
+ console.log(DIM5("\n No grid portfolio found. Run `sherwood grid start` first.\n"));
5321
+ return;
5322
+ }
5323
+ portfolio.resetDailyStats(state);
5324
+ const agg = portfolio.aggregateStats(state);
5325
+ console.log();
5326
+ console.log(G5.bold(" Grid Portfolio"));
5327
+ SEP5();
5328
+ console.log(W5(` Allocation: $${state.totalAllocation.toLocaleString()}`));
5329
+ console.log(W5(` Status: ${state.paused ? chalk12.red("PAUSED \u2014 " + state.pauseReason) : G5("Active")}`));
5330
+ console.log(W5(` Initialized: ${new Date(state.initializedAt).toLocaleString()}`));
5331
+ SEP5();
5332
+ console.log();
5333
+ console.log(BOLD5(" Token Alloc RTs PnL Today PnL Fills"));
5334
+ console.log(DIM5(" " + "\u2500".repeat(72)));
5335
+ for (const g of state.grids) {
5336
+ const name = g.token.padEnd(13);
5337
+ const alloc = `$${g.allocation.toFixed(0)}`.padStart(8);
5338
+ const rts = String(g.stats.totalRoundTrips).padStart(6);
5339
+ const pnl = `$${g.stats.totalPnlUsd.toFixed(2)}`.padStart(10);
5340
+ const todayPnl = `$${g.stats.todayPnlUsd.toFixed(2)}`.padStart(10);
5341
+ const fills = String(g.stats.totalFills).padStart(6);
5342
+ const pnlColor = g.stats.totalPnlUsd >= 0 ? G5 : chalk12.red;
5343
+ const todayColor = g.stats.todayPnlUsd >= 0 ? G5 : chalk12.red;
5344
+ console.log(` ${W5(name)} ${alloc} ${rts} ${pnlColor(pnl)} ${todayColor(todayPnl)} ${fills}`);
5345
+ }
5346
+ console.log(DIM5(" " + "\u2500".repeat(72)));
5347
+ const totalPnlColor = agg.totalPnlUsd >= 0 ? G5 : chalk12.red;
5348
+ const todayTotalColor = agg.todayPnlUsd >= 0 ? G5 : chalk12.red;
5349
+ console.log(` ${BOLD5("TOTAL".padEnd(13))} ${`$${state.totalAllocation.toFixed(0)}`.padStart(8)} ${String(agg.totalRoundTrips).padStart(6)} ${totalPnlColor(`$${agg.totalPnlUsd.toFixed(2)}`.padStart(10))} ${todayTotalColor(`$${agg.todayPnlUsd.toFixed(2)}`.padStart(10))} ${String(agg.todayFills).padStart(6)}`);
5350
+ console.log();
5351
+ });
5352
+ }
5353
+
4613
5354
  // src/index.ts
4614
5355
  try {
4615
5356
  loadDotenv();
@@ -4618,20 +5359,20 @@ try {
4618
5359
  var require2 = createRequire(import.meta.url);
4619
5360
  var { version: CLI_VERSION } = require2("../package.json");
4620
5361
  async function loadXmtp() {
4621
- return import("./xmtp-JO7W6RFK.js");
5362
+ return import("./xmtp-ACB2W573.js");
4622
5363
  }
4623
5364
  async function loadCron() {
4624
5365
  return import("./cron-EOULYO3R.js");
4625
5366
  }
4626
- var G5 = chalk9.green;
4627
- var W5 = chalk9.white;
4628
- var DIM5 = chalk9.gray;
4629
- var BOLD5 = chalk9.white.bold;
4630
- var LABEL5 = chalk9.green.bold;
4631
- var SEP5 = () => console.log(DIM5("\u2500".repeat(60)));
5367
+ var G6 = chalk13.green;
5368
+ var W6 = chalk13.white;
5369
+ var DIM6 = chalk13.gray;
5370
+ var BOLD6 = chalk13.white.bold;
5371
+ var LABEL5 = chalk13.green.bold;
5372
+ var SEP6 = () => console.log(DIM6("\u2500".repeat(60)));
4632
5373
  function validateAddress(value, name) {
4633
5374
  if (!isAddress6(value)) {
4634
- console.error(chalk9.red(`Invalid ${name} address: ${value}`));
5375
+ console.error(chalk13.red(`Invalid ${name} address: ${value}`));
4635
5376
  process.exit(1);
4636
5377
  }
4637
5378
  return value;
@@ -4651,7 +5392,7 @@ program.name("sherwood").description("CLI for agent-managed investment syndicate
4651
5392
  process.env.ENABLE_TESTNET = "true";
4652
5393
  if (network !== "base") {
4653
5394
  console.warn(
4654
- chalk9.yellow("[warn] --testnet ignored, --chain takes precedence")
5395
+ chalk13.yellow("[warn] --testnet ignored, --chain takes precedence")
4655
5396
  );
4656
5397
  } else {
4657
5398
  network = "base-sepolia";
@@ -4659,7 +5400,7 @@ program.name("sherwood").description("CLI for agent-managed investment syndicate
4659
5400
  }
4660
5401
  setNetwork(network);
4661
5402
  if (getNetwork() !== "base") {
4662
- console.log(chalk9.yellow(`[${getNetwork()}]`));
5403
+ console.log(chalk13.yellow(`[${getNetwork()}]`));
4663
5404
  }
4664
5405
  });
4665
5406
  var syndicate = program.command("syndicate");
@@ -4667,31 +5408,31 @@ syndicate.command("create").description("Create a new syndicate via the factory
4667
5408
  try {
4668
5409
  console.log();
4669
5410
  console.log(LABEL5(" \u25C6 Create Syndicate"));
4670
- SEP5();
5411
+ SEP6();
4671
5412
  const wallet = getAccount();
4672
- console.log(DIM5(` Wallet: ${wallet.address}`));
4673
- console.log(DIM5(` Network: ${getChain().name}`));
4674
- SEP5();
5413
+ console.log(DIM6(` Wallet: ${wallet.address}`));
5414
+ console.log(DIM6(` Network: ${getChain().name}`));
5415
+ SEP6();
4675
5416
  const savedAgentId = getAgentId();
4676
5417
  const nonInteractive = opts.yes;
4677
5418
  const name = opts.name || (nonInteractive ? (() => {
4678
5419
  throw new Error("--name is required in non-interactive mode (-y)");
4679
5420
  })() : await input({
4680
- message: G5("Syndicate name"),
5421
+ message: G6("Syndicate name"),
4681
5422
  validate: (v) => v.length > 0 || "Name is required"
4682
5423
  }));
4683
5424
  const subdomain = opts.subdomain || (nonInteractive ? name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "") : await input({
4684
- message: G5("ENS subdomain"),
5425
+ message: G6("ENS subdomain"),
4685
5426
  default: name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, ""),
4686
5427
  validate: (v) => v.length >= 3 || "Must be at least 3 characters"
4687
5428
  }));
4688
5429
  const description = opts.description || (nonInteractive ? `${name} \u2014 a Sherwood syndicate` : await input({
4689
- message: G5("Description"),
5430
+ message: G6("Description"),
4690
5431
  default: `${name} \u2014 a Sherwood syndicate`
4691
5432
  }));
4692
- const agentIdStr = opts.agentId || (savedAgentId ? nonInteractive ? String(savedAgentId) : await input({ message: G5("Agent ID (ERC-8004)"), default: String(savedAgentId) }) : nonInteractive ? "0" : await input({ message: G5("Agent ID (ERC-8004)"), validate: (v) => /^\d+$/.test(v) || "Must be a number" }));
5433
+ const agentIdStr = opts.agentId || (savedAgentId ? nonInteractive ? String(savedAgentId) : await input({ message: G6("Agent ID (ERC-8004)"), default: String(savedAgentId) }) : nonInteractive ? "0" : await input({ message: G6("Agent ID (ERC-8004)"), validate: (v) => /^\d+$/.test(v) || "Must be a number" }));
4693
5434
  const openDeposits = opts.openDeposits !== void 0 ? opts.openDeposits : nonInteractive ? true : await confirm({
4694
- message: G5("Open deposits? (anyone can deposit)"),
5435
+ message: G6("Open deposits? (anyone can deposit)"),
4695
5436
  default: true
4696
5437
  });
4697
5438
  const ASSET_SYMBOLS = {
@@ -4707,14 +5448,14 @@ syndicate.command("create").description("Create a new syndicate via the factory
4707
5448
  asset = opts.asset;
4708
5449
  } else {
4709
5450
  const supported = Object.keys(ASSET_SYMBOLS).join(", ");
4710
- console.error(chalk9.red(` Unknown asset "${opts.asset}". Use a symbol (${supported}) or a 0x address.`));
5451
+ console.error(chalk13.red(` Unknown asset "${opts.asset}". Use a symbol (${supported}) or a 0x address.`));
4711
5452
  process.exit(1);
4712
5453
  }
4713
5454
  } else if (nonInteractive) {
4714
5455
  asset = TOKENS().USDC !== "0x0000000000000000000000000000000000000000" ? ASSET_SYMBOLS.USDC : ASSET_SYMBOLS.WETH;
4715
5456
  } else {
4716
5457
  const assetChoice = await select({
4717
- message: G5("Vault asset (what token do depositors provide?)"),
5458
+ message: G6("Vault asset (what token do depositors provide?)"),
4718
5459
  choices: [
4719
5460
  { name: "USDC", value: "USDC", description: "USD Coin (6 decimals)" },
4720
5461
  { name: "WETH", value: "WETH", description: "Wrapped Ether (18 decimals)" }
@@ -4730,25 +5471,25 @@ syndicate.command("create").description("Create a new syndicate via the factory
4730
5471
  const symbol = `sw${assetSymbol}`;
4731
5472
  console.log();
4732
5473
  console.log(LABEL5(" \u25C6 Review"));
4733
- SEP5();
4734
- console.log(W5(` Name: ${BOLD5(name)}`));
4735
- console.log(W5(` ENS: ${G5(`${subdomain}.sherwoodagent.eth`)}`));
4736
- console.log(W5(` Description: ${DIM5(description)}`));
4737
- console.log(W5(` Agent ID: #${agentIdStr}`));
4738
- console.log(W5(` Asset: ${assetSymbol} (${asset.slice(0, 10)}...)`));
4739
- console.log(W5(` Share token: ${symbol}`));
4740
- console.log(W5(` Open deposits: ${openDeposits ? G5("yes") : chalk9.red("no (whitelist)")}`));
4741
- SEP5();
5474
+ SEP6();
5475
+ console.log(W6(` Name: ${BOLD6(name)}`));
5476
+ console.log(W6(` ENS: ${G6(`${subdomain}.sherwoodagent.eth`)}`));
5477
+ console.log(W6(` Description: ${DIM6(description)}`));
5478
+ console.log(W6(` Agent ID: #${agentIdStr}`));
5479
+ console.log(W6(` Asset: ${assetSymbol} (${asset.slice(0, 10)}...)`));
5480
+ console.log(W6(` Share token: ${symbol}`));
5481
+ console.log(W6(` Open deposits: ${openDeposits ? G6("yes") : chalk13.red("no (whitelist)")}`));
5482
+ SEP6();
4742
5483
  if (!nonInteractive) {
4743
- const go = await confirm({ message: G5("Deploy syndicate?"), default: true });
5484
+ const go = await confirm({ message: G6("Deploy syndicate?"), default: true });
4744
5485
  if (!go) {
4745
- console.log(DIM5(" Cancelled."));
5486
+ console.log(DIM6(" Cancelled."));
4746
5487
  return;
4747
5488
  }
4748
5489
  }
4749
5490
  let metadataURI = opts.metadataUri || "";
4750
5491
  if (!metadataURI) {
4751
- const spinner2 = ora8({ text: W5("Uploading metadata to IPFS..."), color: "green" }).start();
5492
+ const spinner2 = ora8({ text: W6("Uploading metadata to IPFS..."), color: "green" }).start();
4752
5493
  try {
4753
5494
  const metadata = {
4754
5495
  schema: "sherwood/syndicate/v1",
@@ -4762,9 +5503,9 @@ syndicate.command("create").description("Create a new syndicate via the factory
4762
5503
  links: {}
4763
5504
  };
4764
5505
  metadataURI = await uploadMetadata(metadata);
4765
- spinner2.succeed(G5(`Metadata pinned: ${DIM5(metadataURI)}`));
5506
+ spinner2.succeed(G6(`Metadata pinned: ${DIM6(metadataURI)}`));
4766
5507
  } catch (err) {
4767
- spinner2.warn(chalk9.yellow(`IPFS upload failed \u2014 using inline metadata`));
5508
+ spinner2.warn(chalk13.yellow(`IPFS upload failed \u2014 using inline metadata`));
4768
5509
  const json = JSON.stringify({ name, description, subdomain, asset: assetSymbol, openDeposits, createdBy: "@sherwoodagent/cli" });
4769
5510
  metadataURI = `data:application/json;base64,${Buffer.from(json).toString("base64")}`;
4770
5511
  }
@@ -4774,43 +5515,43 @@ syndicate.command("create").description("Create a new syndicate via the factory
4774
5515
  const existingInfo = await getSyndicate(existingId);
4775
5516
  const callerAddress = getAccount().address.toLowerCase();
4776
5517
  if (existingInfo.creator.toLowerCase() !== callerAddress) {
4777
- console.error(chalk9.red(`
5518
+ console.error(chalk13.red(`
4778
5519
  \u2716 Subdomain '${subdomain}' is already taken by another syndicate.
4779
5520
  `));
4780
5521
  process.exit(1);
4781
5522
  }
4782
- console.log(chalk9.yellow(`
5523
+ console.log(chalk13.yellow(`
4783
5524
  \u26A0 Syndicate '${subdomain}' already exists \u2014 resuming setup...
4784
5525
  `));
4785
- const spinner2 = ora8({ text: W5("Resuming setup..."), color: "green" }).start();
5526
+ const spinner2 = ora8({ text: W6("Resuming setup..."), color: "green" }).start();
4786
5527
  const chainId2 = getChain().id;
4787
5528
  setChainContract(chainId2, "vault", existingInfo.vault);
4788
5529
  addSyndicate(chainId2, { subdomain, vault: existingInfo.vault, role: "creator" });
4789
5530
  setPrimarySyndicate(chainId2, subdomain);
4790
- spinner2.text = W5("Checking agent registration...");
5531
+ spinner2.text = W6("Checking agent registration...");
4791
5532
  try {
4792
5533
  setVaultAddress(existingInfo.vault);
4793
5534
  const isAlreadyAgent = await isAgent(getAccount().address);
4794
5535
  if (!isAlreadyAgent) {
4795
- spinner2.text = W5("Registering creator as agent...");
5536
+ spinner2.text = W6("Registering creator as agent...");
4796
5537
  await registerAgent(BigInt(agentIdStr), getAccount().address);
4797
5538
  }
4798
5539
  } catch {
4799
5540
  }
4800
- spinner2.text = W5("Checking chat group...");
5541
+ spinner2.text = W6("Checking chat group...");
4801
5542
  try {
4802
5543
  const xmtp = await loadXmtp();
4803
5544
  const xmtpClient = await xmtp.getXmtpClient();
4804
5545
  try {
4805
5546
  await xmtp.getGroup(xmtpClient, subdomain);
4806
5547
  } catch {
4807
- spinner2.text = W5("Creating chat group...");
5548
+ spinner2.text = W6("Creating chat group...");
4808
5549
  const groupId = await xmtp.createSyndicateGroup(xmtpClient, subdomain, opts.publicChat);
4809
5550
  await setTextRecord(subdomain, "xmtpGroupId", groupId, existingInfo.vault);
4810
5551
  cacheGroupId(subdomain, groupId);
4811
5552
  }
4812
5553
  } catch {
4813
- console.warn(chalk9.yellow("\n \u26A0 Could not set up XMTP chat group"));
5554
+ console.warn(chalk13.yellow("\n \u26A0 Could not set up XMTP chat group"));
4814
5555
  }
4815
5556
  try {
4816
5557
  const cron = await loadCron();
@@ -4820,19 +5561,19 @@ syndicate.command("create").description("Create a new syndicate via the factory
4820
5561
  spinner2.stop();
4821
5562
  console.log();
4822
5563
  console.log(LABEL5(" \u25C6 Syndicate Setup Resumed"));
4823
- SEP5();
4824
- console.log(W5(` ID: ${G5(`#${existingId}`)}`));
4825
- console.log(W5(` Vault: ${G5(existingInfo.vault)}`));
4826
- console.log(W5(` ENS: ${G5(`${subdomain}.sherwoodagent.eth`)}`));
4827
- console.log(W5(` Chat: ${DIM5(`sherwood chat ${subdomain}`)}`));
5564
+ SEP6();
5565
+ console.log(W6(` ID: ${G6(`#${existingId}`)}`));
5566
+ console.log(W6(` Vault: ${G6(existingInfo.vault)}`));
5567
+ console.log(W6(` ENS: ${G6(`${subdomain}.sherwoodagent.eth`)}`));
5568
+ console.log(W6(` Chat: ${DIM6(`sherwood chat ${subdomain}`)}`));
4828
5569
  const refParam2 = getAgentId() ? `?ref=${getAgentId()}` : "";
4829
- console.log(W5(` Share: ${G5(`https://sherwood.sh/syndicate/${subdomain}${refParam2}`)}`));
4830
- SEP5();
4831
- console.log(G5(" \u2713 Syndicate saved to ~/.sherwood/config.json (set as primary)"));
5570
+ console.log(W6(` Share: ${G6(`https://sherwood.sh/syndicate/${subdomain}${refParam2}`)}`));
5571
+ SEP6();
5572
+ console.log(G6(" \u2713 Syndicate saved to ~/.sherwood/config.json (set as primary)"));
4832
5573
  console.log();
4833
5574
  return;
4834
5575
  }
4835
- const spinner = ora8({ text: W5("Deploying vault via factory..."), color: "green" }).start();
5576
+ const spinner = ora8({ text: W6("Deploying vault via factory..."), color: "green" }).start();
4836
5577
  const result = await createSyndicate({
4837
5578
  creatorAgentId: BigInt(agentIdStr),
4838
5579
  metadataURI,
@@ -4847,7 +5588,7 @@ syndicate.command("create").description("Create a new syndicate via the factory
4847
5588
  addSyndicate(chainId, { subdomain, vault: result.vault, role: "creator" });
4848
5589
  setPrimarySyndicate(chainId, subdomain);
4849
5590
  await new Promise((r) => setTimeout(r, 2e3));
4850
- spinner.text = W5("Registering creator as agent...");
5591
+ spinner.text = W6("Registering creator as agent...");
4851
5592
  try {
4852
5593
  setVaultAddress(result.vault);
4853
5594
  const creatorAddress = getAccount().address;
@@ -4857,9 +5598,9 @@ syndicate.command("create").description("Create a new syndicate via the factory
4857
5598
  // agentAddress = creator EOA (direct execution)
4858
5599
  );
4859
5600
  } catch (regErr) {
4860
- console.warn(chalk9.yellow("\n \u26A0 Could not auto-register creator as agent \u2014 register manually with `syndicate add`"));
5601
+ console.warn(chalk13.yellow("\n \u26A0 Could not auto-register creator as agent \u2014 register manually with `syndicate add`"));
4861
5602
  }
4862
- spinner.text = W5("Setting up chat...");
5603
+ spinner.text = W6("Setting up chat...");
4863
5604
  try {
4864
5605
  const xmtp = await loadXmtp();
4865
5606
  const xmtpClient = await xmtp.getXmtpClient();
@@ -4870,36 +5611,36 @@ syndicate.command("create").description("Create a new syndicate via the factory
4870
5611
  } catch {
4871
5612
  }
4872
5613
  } catch {
4873
- console.warn(chalk9.yellow("\n \u26A0 Could not create XMTP chat group"));
4874
- console.warn(chalk9.dim(` Recover later with: sherwood chat ${subdomain} init`));
5614
+ console.warn(chalk13.yellow("\n \u26A0 Could not create XMTP chat group"));
5615
+ console.warn(chalk13.dim(` Recover later with: sherwood chat ${subdomain} init`));
4875
5616
  }
4876
5617
  try {
4877
5618
  const cron = await loadCron();
4878
5619
  const cronResult = cron.registerSyndicateCrons(subdomain, isTestnet(), getNotifyTo());
4879
5620
  if (cronResult.isOpenClaw && cronResult.registered) {
4880
- console.log(G5(" \u2713 Participation crons registered (15m check + hourly summary)"));
5621
+ console.log(G6(" \u2713 Participation crons registered (15m check + hourly summary)"));
4881
5622
  } else if (!cronResult.isOpenClaw) {
4882
- console.log(DIM5(" Tip: Set up a scheduled process to run `sherwood session check " + subdomain + "` periodically"));
5623
+ console.log(DIM6(" Tip: Set up a scheduled process to run `sherwood session check " + subdomain + "` periodically"));
4883
5624
  }
4884
5625
  } catch {
4885
5626
  }
4886
5627
  spinner.stop();
4887
5628
  console.log();
4888
5629
  console.log(LABEL5(" \u25C6 Syndicate Created"));
4889
- SEP5();
4890
- console.log(W5(` ID: ${G5(`#${result.syndicateId}`)}`));
4891
- console.log(W5(` Vault: ${G5(result.vault)}`));
4892
- console.log(W5(` ENS: ${G5(`${subdomain}.sherwoodagent.eth`)}`));
4893
- console.log(W5(` Metadata: ${DIM5(metadataURI.length > 50 ? metadataURI.slice(0, 50) + "..." : metadataURI)}`));
4894
- console.log(W5(` Explorer: ${DIM5(getExplorerUrl(result.hash))}`));
4895
- console.log(W5(` Chat: ${DIM5(`sherwood chat ${subdomain}`)}`));
5630
+ SEP6();
5631
+ console.log(W6(` ID: ${G6(`#${result.syndicateId}`)}`));
5632
+ console.log(W6(` Vault: ${G6(result.vault)}`));
5633
+ console.log(W6(` ENS: ${G6(`${subdomain}.sherwoodagent.eth`)}`));
5634
+ console.log(W6(` Metadata: ${DIM6(metadataURI.length > 50 ? metadataURI.slice(0, 50) + "..." : metadataURI)}`));
5635
+ console.log(W6(` Explorer: ${DIM6(getExplorerUrl(result.hash))}`));
5636
+ console.log(W6(` Chat: ${DIM6(`sherwood chat ${subdomain}`)}`));
4896
5637
  const refParam = getAgentId() ? `?ref=${getAgentId()}` : "";
4897
- console.log(W5(` Share: ${G5(`https://sherwood.sh/syndicate/${subdomain}${refParam}`)}`));
4898
- SEP5();
4899
- console.log(G5(" \u2713 Syndicate saved to ~/.sherwood/config.json (set as primary)"));
5638
+ console.log(W6(` Share: ${G6(`https://sherwood.sh/syndicate/${subdomain}${refParam}`)}`));
5639
+ SEP6();
5640
+ console.log(G6(" \u2713 Syndicate saved to ~/.sherwood/config.json (set as primary)"));
4900
5641
  console.log();
4901
5642
  } catch (err) {
4902
- console.error(chalk9.red(`
5643
+ console.error(chalk13.red(`
4903
5644
  \u2716 ${formatContractError(err)}`));
4904
5645
  process.exit(1);
4905
5646
  }
@@ -4949,38 +5690,38 @@ syndicate.command("list").description("List active syndicates (queries subgraph,
4949
5690
  }
4950
5691
  spinner.stop();
4951
5692
  if (syndicates.length === 0) {
4952
- console.log(chalk9.dim("No active syndicates found."));
5693
+ console.log(chalk13.dim("No active syndicates found."));
4953
5694
  return;
4954
5695
  }
4955
5696
  console.log();
4956
- console.log(chalk9.bold(`Active Syndicates (${syndicates.length})`));
5697
+ console.log(chalk13.bold(`Active Syndicates (${syndicates.length})`));
4957
5698
  if (!process.env.SUBGRAPH_URL && !opts.allChains) {
4958
- console.log(chalk9.dim(" (Set SUBGRAPH_URL for faster indexed queries)"));
5699
+ console.log(chalk13.dim(" (Set SUBGRAPH_URL for faster indexed queries)"));
4959
5700
  }
4960
5701
  if (opts.allChains) {
4961
- console.log(chalk9.dim(" (Aggregated across chains via on-chain factory calls; SUBGRAPH_URL is single-chain only)"));
5702
+ console.log(chalk13.dim(" (Aggregated across chains via on-chain factory calls; SUBGRAPH_URL is single-chain only)"));
4962
5703
  }
4963
- console.log(chalk9.dim("\u2500".repeat(70)));
5704
+ console.log(chalk13.dim("\u2500".repeat(70)));
4964
5705
  for (const s of syndicates) {
4965
5706
  const ts = typeof s.createdAt === "string" ? Number(s.createdAt) : Number(s.createdAt);
4966
5707
  const date = new Date(ts * 1e3).toLocaleDateString();
4967
5708
  const ensName = s.subdomain ? `${s.subdomain}.sherwoodagent.eth` : "";
4968
- const chainTag = s.chain ? chalk9.dim(`[${s.chain}] `) : "";
4969
- console.log(` ${chainTag}#${s.id} ${chalk9.bold(ensName || String(s.vault))}`);
4970
- if (ensName) console.log(` Vault: ${chalk9.cyan(String(s.vault))}`);
5709
+ const chainTag = s.chain ? chalk13.dim(`[${s.chain}] `) : "";
5710
+ console.log(` ${chainTag}#${s.id} ${chalk13.bold(ensName || String(s.vault))}`);
5711
+ if (ensName) console.log(` Vault: ${chalk13.cyan(String(s.vault))}`);
4971
5712
  console.log(` Creator: ${s.creator}`);
4972
5713
  console.log(` Created: ${date}`);
4973
5714
  if (s.totalDeposits) {
4974
5715
  console.log(` Deposits: ${s.totalDeposits} USDC`);
4975
5716
  }
4976
5717
  if (s.metadataURI) {
4977
- console.log(` Metadata: ${chalk9.dim(s.metadataURI)}`);
5718
+ console.log(` Metadata: ${chalk13.dim(s.metadataURI)}`);
4978
5719
  }
4979
5720
  console.log();
4980
5721
  }
4981
5722
  } catch (err) {
4982
5723
  spinner.fail("Failed to load syndicates");
4983
- console.error(chalk9.red(formatContractError(err)));
5724
+ console.error(chalk13.red(formatContractError(err)));
4984
5725
  process.exit(1);
4985
5726
  }
4986
5727
  });
@@ -5020,38 +5761,38 @@ syndicate.command("info").description("Display syndicate details by ID or subdom
5020
5761
  spinner.stop();
5021
5762
  if (crossChainHint) {
5022
5763
  const others = crossChainHint.others.length > 0 ? ` (also on: ${crossChainHint.others.join(", ")})` : "";
5023
- console.log(chalk9.yellow(` Found on chain: ${chalk9.bold(crossChainHint.network)}${others}`));
5024
- console.log(chalk9.dim(` Re-run with --chain ${crossChainHint.network} to interact with this syndicate.`));
5764
+ console.log(chalk13.yellow(` Found on chain: ${chalk13.bold(crossChainHint.network)}${others}`));
5765
+ console.log(chalk13.dim(` Re-run with --chain ${crossChainHint.network} to interact with this syndicate.`));
5025
5766
  console.log();
5026
5767
  }
5027
5768
  if (!info.vault || info.vault === "0x0000000000000000000000000000000000000000") {
5028
- console.log(chalk9.red(`Syndicate #${id} not found.`));
5769
+ console.log(chalk13.red(`Syndicate #${id} not found.`));
5029
5770
  process.exit(1);
5030
5771
  }
5031
5772
  const date = new Date(Number(info.createdAt) * 1e3).toLocaleDateString();
5032
5773
  console.log();
5033
- console.log(chalk9.bold(`Syndicate #${info.id}`));
5034
- console.log(chalk9.dim("\u2500".repeat(40)));
5774
+ console.log(chalk13.bold(`Syndicate #${info.id}`));
5775
+ console.log(chalk13.dim("\u2500".repeat(40)));
5035
5776
  if (info.subdomain) {
5036
- console.log(` ENS: ${chalk9.bold(`${info.subdomain}.sherwoodagent.eth`)}`);
5777
+ console.log(` ENS: ${chalk13.bold(`${info.subdomain}.sherwoodagent.eth`)}`);
5037
5778
  }
5038
- console.log(` Vault: ${chalk9.cyan(info.vault)}`);
5779
+ console.log(` Vault: ${chalk13.cyan(info.vault)}`);
5039
5780
  console.log(` Creator: ${info.creator}`);
5040
5781
  console.log(` Created: ${date}`);
5041
- console.log(` Active: ${info.active ? chalk9.green("yes") : chalk9.red("no")}`);
5782
+ console.log(` Active: ${info.active ? chalk13.green("yes") : chalk13.red("no")}`);
5042
5783
  if (info.metadataURI) {
5043
- console.log(` Metadata: ${chalk9.dim(info.metadataURI)}`);
5784
+ console.log(` Metadata: ${chalk13.dim(info.metadataURI)}`);
5044
5785
  }
5045
5786
  if (info.subdomain) {
5046
5787
  const xmtpGroupId = getCachedGroupId(info.subdomain);
5047
5788
  if (xmtpGroupId) {
5048
- console.log(` XMTP Group: ${chalk9.cyan(xmtpGroupId)}`);
5789
+ console.log(` XMTP Group: ${chalk13.cyan(xmtpGroupId)}`);
5049
5790
  }
5050
5791
  }
5051
5792
  setVaultAddress(info.vault);
5052
5793
  const vaultInfo = crossChainHint ? await withNetwork(crossChainHint.network, () => getVaultInfo()) : await getVaultInfo();
5053
5794
  console.log();
5054
- console.log(chalk9.bold(" Vault Stats"));
5795
+ console.log(chalk13.bold(" Vault Stats"));
5055
5796
  console.log(` Total Assets: ${vaultInfo.totalAssets}`);
5056
5797
  console.log(` Agent Count: ${vaultInfo.agentCount}`);
5057
5798
  console.log(` Redemptions Locked: ${vaultInfo.redemptionsLocked}`);
@@ -5059,12 +5800,12 @@ syndicate.command("info").description("Display syndicate details by ID or subdom
5059
5800
  console.log();
5060
5801
  } catch (err) {
5061
5802
  spinner.fail("Failed to load syndicate info");
5062
- console.error(chalk9.red(formatContractError(err)));
5803
+ console.error(chalk13.red(formatContractError(err)));
5063
5804
  process.exit(1);
5064
5805
  }
5065
5806
  });
5066
5807
  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) => {
5067
- const spinner = ora8({ text: W5("Loading syndicate..."), color: "green" }).start();
5808
+ const spinner = ora8({ text: W6("Loading syndicate..."), color: "green" }).start();
5068
5809
  try {
5069
5810
  const syndicateId = BigInt(opts.id);
5070
5811
  let metadataURI = opts.uri;
@@ -5076,7 +5817,7 @@ syndicate.command("update-metadata").description("Update syndicate metadata (cre
5076
5817
  }
5077
5818
  const name = opts.name || info.subdomain;
5078
5819
  const description = opts.description || `${name} \u2014 a Sherwood syndicate on ${info.subdomain}.sherwoodagent.eth`;
5079
- spinner.text = W5("Uploading metadata to IPFS...");
5820
+ spinner.text = W6("Uploading metadata to IPFS...");
5080
5821
  const metadata = {
5081
5822
  schema: "sherwood/syndicate/v1",
5082
5823
  name,
@@ -5087,15 +5828,15 @@ syndicate.command("update-metadata").description("Update syndicate metadata (cre
5087
5828
  links: {}
5088
5829
  };
5089
5830
  metadataURI = await uploadMetadata(metadata);
5090
- spinner.text = W5("Updating on-chain metadata...");
5831
+ spinner.text = W6("Updating on-chain metadata...");
5091
5832
  }
5092
5833
  const hash = await updateMetadata(syndicateId, metadataURI);
5093
- spinner.succeed(G5(`Metadata updated`));
5094
- console.log(DIM5(` IPFS: ${metadataURI}`));
5095
- console.log(DIM5(` ${getExplorerUrl(hash)}`));
5834
+ spinner.succeed(G6(`Metadata updated`));
5835
+ console.log(DIM6(` IPFS: ${metadataURI}`));
5836
+ console.log(DIM6(` ${getExplorerUrl(hash)}`));
5096
5837
  } catch (err) {
5097
5838
  spinner.fail("Metadata update failed");
5098
- console.error(chalk9.red(formatContractError(err)));
5839
+ console.error(chalk13.red(formatContractError(err)));
5099
5840
  process.exit(1);
5100
5841
  }
5101
5842
  });
@@ -5106,10 +5847,10 @@ syndicate.command("approve-depositor").description("Approve an address to deposi
5106
5847
  const depositor = validateAddress(opts.depositor, "depositor");
5107
5848
  const hash = await approveDepositor(depositor);
5108
5849
  spinner.succeed(`Depositor approved: ${hash}`);
5109
- console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
5850
+ console.log(chalk13.dim(` ${getExplorerUrl(hash)}`));
5110
5851
  } catch (err) {
5111
5852
  spinner.fail("Approval failed");
5112
- console.error(chalk9.red(formatContractError(err)));
5853
+ console.error(chalk13.red(formatContractError(err)));
5113
5854
  process.exit(1);
5114
5855
  }
5115
5856
  });
@@ -5120,10 +5861,10 @@ syndicate.command("remove-depositor").description("Remove an address from the de
5120
5861
  const depositor = validateAddress(opts.depositor, "depositor");
5121
5862
  const hash = await removeDepositor(depositor);
5122
5863
  spinner.succeed(`Depositor removed: ${hash}`);
5123
- console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
5864
+ console.log(chalk13.dim(` ${getExplorerUrl(hash)}`));
5124
5865
  } catch (err) {
5125
5866
  spinner.fail("Removal failed");
5126
- console.error(chalk9.red(formatContractError(err)));
5867
+ console.error(chalk13.red(formatContractError(err)));
5127
5868
  process.exit(1);
5128
5869
  }
5129
5870
  });
@@ -5143,7 +5884,7 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
5143
5884
  if (opts.agentId) {
5144
5885
  agentId = BigInt(opts.agentId);
5145
5886
  } else {
5146
- const { AGENT_REGISTRY: AGENT_REGISTRY2 } = await import("./addresses-DCQMJJFI.js");
5887
+ const { AGENT_REGISTRY: AGENT_REGISTRY2 } = await import("./addresses-DOWLGXGE.js");
5147
5888
  const registry2 = AGENT_REGISTRY2().IDENTITY_REGISTRY;
5148
5889
  if (registry2 === "0x0000000000000000000000000000000000000000") {
5149
5890
  agentId = 0n;
@@ -5164,7 +5905,7 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
5164
5905
  });
5165
5906
  if (balance === 0n) {
5166
5907
  spinner.fail("Agent wallet does not own an ERC-8004 identity NFT");
5167
- console.error(chalk9.dim(" Mint one first: sherwood identity mint --name <name>"));
5908
+ console.error(chalk13.dim(" Mint one first: sherwood identity mint --name <name>"));
5168
5909
  process.exit(1);
5169
5910
  }
5170
5911
  const tokenId = await client.readContract({
@@ -5180,13 +5921,13 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
5180
5921
  args: [agentWallet, 0n]
5181
5922
  });
5182
5923
  agentId = tokenId;
5183
- console.log(chalk9.dim(` Resolved agent ID: #${agentId}`));
5924
+ console.log(chalk13.dim(` Resolved agent ID: #${agentId}`));
5184
5925
  }
5185
5926
  }
5186
5927
  spinner.text = "Registering agent...";
5187
5928
  const hash = await registerAgent(agentId, agentWallet);
5188
5929
  spinner.succeed(`Agent registered: ${hash}`);
5189
- console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
5930
+ console.log(chalk13.dim(` ${getExplorerUrl(hash)}`));
5190
5931
  try {
5191
5932
  const xmtp = await loadXmtp();
5192
5933
  const xmtpClient = await xmtp.getXmtpClient();
@@ -5198,14 +5939,14 @@ syndicate.command("add").description("Register an agent on a syndicate vault (cr
5198
5939
  syndicate: subdomain,
5199
5940
  timestamp: Math.floor(Date.now() / 1e3)
5200
5941
  });
5201
- console.log(chalk9.dim(` Added to chat: ${subdomain}`));
5942
+ console.log(chalk13.dim(` Added to chat: ${subdomain}`));
5202
5943
  } catch {
5203
- console.warn(chalk9.yellow(" \u26A0 Could not add agent to chat group"));
5204
- console.warn(chalk9.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
5944
+ console.warn(chalk13.yellow(" \u26A0 Could not add agent to chat group"));
5945
+ console.warn(chalk13.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
5205
5946
  }
5206
5947
  } catch (err) {
5207
5948
  spinner.fail("Registration failed");
5208
- console.error(chalk9.red(formatContractError(err)));
5949
+ console.error(chalk13.red(formatContractError(err)));
5209
5950
  process.exit(1);
5210
5951
  }
5211
5952
  });
@@ -5213,7 +5954,7 @@ syndicate.command("share").description("Print the shareable dashboard URL for yo
5213
5954
  try {
5214
5955
  const subdomain = opts.subdomain || getPrimarySyndicate(getChain().id)?.subdomain;
5215
5956
  if (!subdomain) {
5216
- console.error(chalk9.red(" No syndicate configured. Pass --subdomain <name> or run 'syndicate create/join' first."));
5957
+ console.error(chalk13.red(" No syndicate configured. Pass --subdomain <name> or run 'syndicate create/join' first."));
5217
5958
  process.exit(1);
5218
5959
  }
5219
5960
  const syndicateInfo = await resolveSyndicate(subdomain);
@@ -5222,12 +5963,12 @@ syndicate.command("share").description("Print the shareable dashboard URL for yo
5222
5963
  const dashboardUrl = `https://sherwood.sh/syndicate/${subdomain}${refParam}`;
5223
5964
  console.log();
5224
5965
  console.log(LABEL5(" \u25C6 Share Your Syndicate"));
5225
- SEP5();
5226
- console.log(W5(` Dashboard: ${G5(dashboardUrl)}`));
5227
- console.log(W5(` ENS: ${DIM5(`${subdomain}.sherwoodagent.eth`)}`));
5228
- console.log(W5(` Vault: ${DIM5(syndicateInfo.vault)}`));
5229
- console.log(W5(` Join CLI: ${DIM5(`sherwood syndicate join --subdomain ${subdomain}`)}`));
5230
- SEP5();
5966
+ SEP6();
5967
+ console.log(W6(` Dashboard: ${G6(dashboardUrl)}`));
5968
+ console.log(W6(` ENS: ${DIM6(`${subdomain}.sherwoodagent.eth`)}`));
5969
+ console.log(W6(` Vault: ${DIM6(syndicateInfo.vault)}`));
5970
+ console.log(W6(` Join CLI: ${DIM6(`sherwood syndicate join --subdomain ${subdomain}`)}`));
5971
+ SEP6();
5231
5972
  try {
5232
5973
  const { exec } = await import("child_process");
5233
5974
  const platform = (await import("os")).platform();
@@ -5235,12 +5976,12 @@ syndicate.command("share").description("Print the shareable dashboard URL for yo
5235
5976
  const proc = exec(cmd);
5236
5977
  proc.stdin?.write(dashboardUrl);
5237
5978
  proc.stdin?.end();
5238
- console.log(G5(" \u2713 Dashboard URL copied to clipboard"));
5979
+ console.log(G6(" \u2713 Dashboard URL copied to clipboard"));
5239
5980
  } catch {
5240
5981
  }
5241
5982
  console.log();
5242
5983
  } catch (err) {
5243
- console.error(chalk9.red(` \u2716 ${formatContractError(err)}`));
5984
+ console.error(chalk13.red(` \u2716 ${formatContractError(err)}`));
5244
5985
  process.exit(1);
5245
5986
  }
5246
5987
  });
@@ -5265,14 +6006,14 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
5265
6006
  const hits = await searchSyndicateAcrossChains(subdomain);
5266
6007
  spinner.fail(`Syndicate "${subdomain}" not found on ${getNetwork()}`);
5267
6008
  if (hits.length === 0) {
5268
- console.error(chalk9.red(` Not found on any supported chain.`));
6009
+ console.error(chalk13.red(` Not found on any supported chain.`));
5269
6010
  } else if (hits.length === 1) {
5270
- console.error(chalk9.yellow(` Found on chain: ${chalk9.bold(hits[0].network)}`));
5271
- console.error(chalk9.dim(` Re-run: sherwood --chain ${hits[0].network} syndicate join --subdomain ${subdomain}`));
6011
+ console.error(chalk13.yellow(` Found on chain: ${chalk13.bold(hits[0].network)}`));
6012
+ console.error(chalk13.dim(` Re-run: sherwood --chain ${hits[0].network} syndicate join --subdomain ${subdomain}`));
5272
6013
  } else {
5273
6014
  const chains = hits.map((h) => h.network).join(", ");
5274
- console.error(chalk9.yellow(` Found on chains: ${chalk9.bold(chains)}`));
5275
- console.error(chalk9.dim(` Specify which chain to join with --chain <network>.`));
6015
+ console.error(chalk13.yellow(` Found on chains: ${chalk13.bold(chains)}`));
6016
+ console.error(chalk13.dim(` Specify which chain to join with --chain <network>.`));
5276
6017
  }
5277
6018
  process.exit(1);
5278
6019
  }
@@ -5285,17 +6026,17 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
5285
6026
  try {
5286
6027
  const xmtp = await loadXmtp();
5287
6028
  await xmtp.getXmtpClient();
5288
- console.log(chalk9.dim(" XMTP identity ready"));
6029
+ console.log(chalk13.dim(" XMTP identity ready"));
5289
6030
  } catch {
5290
- console.warn(chalk9.yellow(" \u26A0 Could not initialize XMTP identity"));
6031
+ console.warn(chalk13.yellow(" \u26A0 Could not initialize XMTP identity"));
5291
6032
  }
5292
6033
  try {
5293
6034
  const cron = await loadCron();
5294
6035
  const cronResult = cron.registerSyndicateCrons(subdomain, isTestnet(), getNotifyTo());
5295
6036
  if (cronResult.isOpenClaw && cronResult.registered) {
5296
- console.log(chalk9.green(" \u2713 Participation crons registered"));
6037
+ console.log(chalk13.green(" \u2713 Participation crons registered"));
5297
6038
  } else if (!cronResult.isOpenClaw) {
5298
- console.log(chalk9.dim(" Tip: Set up a scheduled process to run `sherwood session check " + subdomain + "` periodically"));
6039
+ console.log(chalk13.dim(" Tip: Set up a scheduled process to run `sherwood session check " + subdomain + "` periodically"));
5299
6040
  }
5300
6041
  } catch {
5301
6042
  }
@@ -5308,14 +6049,14 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
5308
6049
  );
5309
6050
  if (existingRequest) {
5310
6051
  spinner.succeed("You already have a pending join request for this syndicate");
5311
- console.log(chalk9.dim(` Attestation: ${existingRequest.uid}`));
5312
- console.log(chalk9.dim(` Submitted: ${new Date(existingRequest.time * 1e3).toLocaleString()}`));
6052
+ console.log(chalk13.dim(` Attestation: ${existingRequest.uid}`));
6053
+ console.log(chalk13.dim(` Submitted: ${new Date(existingRequest.time * 1e3).toLocaleString()}`));
5313
6054
  try {
5314
6055
  const xmtp = await loadXmtp();
5315
6056
  await xmtp.getXmtpClient();
5316
- console.log(chalk9.dim(" XMTP identity ready"));
6057
+ console.log(chalk13.dim(" XMTP identity ready"));
5317
6058
  } catch {
5318
- console.warn(chalk9.yellow(" \u26A0 Could not initialize XMTP identity"));
6059
+ console.warn(chalk13.yellow(" \u26A0 Could not initialize XMTP identity"));
5319
6060
  }
5320
6061
  return;
5321
6062
  }
@@ -5336,7 +6077,7 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
5336
6077
  spinner.succeed("Join request created (XMTP identity ready)");
5337
6078
  } catch {
5338
6079
  spinner.succeed("Join request created");
5339
- console.warn(chalk9.yellow(" \u26A0 Could not initialize XMTP identity \u2014 creator may not be able to auto-add you to chat"));
6080
+ console.warn(chalk13.yellow(" \u26A0 Could not initialize XMTP identity \u2014 creator may not be able to auto-add you to chat"));
5340
6081
  }
5341
6082
  addSyndicate(getChain().id, { subdomain, vault: syndicate2.vault, role: "agent" });
5342
6083
  setPrimarySyndicate(getChain().id, subdomain);
@@ -5344,29 +6085,29 @@ syndicate.command("join").description("Request to join a syndicate (creates an E
5344
6085
  const cron = await loadCron();
5345
6086
  const cronResult = cron.registerSyndicateCrons(subdomain, isTestnet(), getNotifyTo());
5346
6087
  if (cronResult.isOpenClaw && cronResult.registered) {
5347
- console.log(G5(" \u2713 Participation crons registered (will activate after approval)"));
6088
+ console.log(G6(" \u2713 Participation crons registered (will activate after approval)"));
5348
6089
  } else if (!cronResult.isOpenClaw) {
5349
- console.log(DIM5(" Tip: Set up a scheduled process to run `sherwood session check " + subdomain + "` periodically"));
6090
+ console.log(DIM6(" Tip: Set up a scheduled process to run `sherwood session check " + subdomain + "` periodically"));
5350
6091
  }
5351
6092
  } catch {
5352
6093
  }
5353
6094
  console.log();
5354
6095
  console.log(LABEL5(" \u25C6 Join Request Submitted"));
5355
- SEP5();
5356
- console.log(W5(` Syndicate: ${G5(`${subdomain}.sherwoodagent.eth`)}`));
5357
- console.log(W5(` Agent ID: #${agentId}`));
5358
- console.log(W5(` Creator: ${DIM5(syndicate2.creator)}`));
5359
- console.log(W5(` Attestation: ${DIM5(uid)}`));
5360
- console.log(W5(` EAS Scan: ${DIM5(getEasScanUrl(uid))}`));
5361
- console.log(W5(` Explorer: ${DIM5(getEasExplorerUrl(hash))}`));
5362
- SEP5();
5363
- console.log(G5(" \u2713 Syndicate saved to ~/.sherwood/config.json (set as primary)"));
5364
- console.log(G5(" \u2713 The creator can review with:"));
5365
- console.log(DIM5(` sherwood syndicate requests --subdomain ${subdomain}`));
6096
+ SEP6();
6097
+ console.log(W6(` Syndicate: ${G6(`${subdomain}.sherwoodagent.eth`)}`));
6098
+ console.log(W6(` Agent ID: #${agentId}`));
6099
+ console.log(W6(` Creator: ${DIM6(syndicate2.creator)}`));
6100
+ console.log(W6(` Attestation: ${DIM6(uid)}`));
6101
+ console.log(W6(` EAS Scan: ${DIM6(getEasScanUrl(uid))}`));
6102
+ console.log(W6(` Explorer: ${DIM6(getEasExplorerUrl(hash))}`));
6103
+ SEP6();
6104
+ console.log(G6(" \u2713 Syndicate saved to ~/.sherwood/config.json (set as primary)"));
6105
+ console.log(G6(" \u2713 The creator can review with:"));
6106
+ console.log(DIM6(` sherwood syndicate requests --subdomain ${subdomain}`));
5366
6107
  console.log();
5367
6108
  } catch (err) {
5368
6109
  spinner.fail("Join request failed");
5369
- console.error(chalk9.red(formatContractError(err)));
6110
+ console.error(chalk13.red(formatContractError(err)));
5370
6111
  process.exit(1);
5371
6112
  }
5372
6113
  });
@@ -5407,34 +6148,34 @@ syndicate.command("requests").description("View pending join requests for a synd
5407
6148
  );
5408
6149
  spinner.stop();
5409
6150
  if (requests.length === 0) {
5410
- console.log(DIM5("\n No pending join requests.\n"));
6151
+ console.log(DIM6("\n No pending join requests.\n"));
5411
6152
  return;
5412
6153
  }
5413
6154
  console.log();
5414
6155
  console.log(LABEL5(` \u25C6 Pending Join Requests (${requests.length})`));
5415
- SEP5();
6156
+ SEP6();
5416
6157
  for (let i = 0; i < requests.length; i++) {
5417
6158
  const req = requests[i];
5418
6159
  const date = new Date(req.time * 1e3).toLocaleString();
5419
6160
  const referrer = parseReferrer(req.decoded.message);
5420
6161
  const cleanMessage = stripReferrerPrefix(req.decoded.message);
5421
- console.log(W5(` ${i + 1}. Agent #${req.decoded.agentId} ${DIM5(`(${req.attester})`)}`));
5422
- console.log(DIM5(` Message: "${cleanMessage}"`));
6162
+ console.log(W6(` ${i + 1}. Agent #${req.decoded.agentId} ${DIM6(`(${req.attester})`)}`));
6163
+ console.log(DIM6(` Message: "${cleanMessage}"`));
5423
6164
  if (referrer !== null) {
5424
- console.log(G5(` Referred by: Agent #${referrer}`));
6165
+ console.log(G6(` Referred by: Agent #${referrer}`));
5425
6166
  }
5426
- console.log(DIM5(` Requested: ${date}`));
5427
- console.log(DIM5(` Attestation: ${req.uid}`));
6167
+ console.log(DIM6(` Requested: ${date}`));
6168
+ console.log(DIM6(` Attestation: ${req.uid}`));
5428
6169
  console.log();
5429
6170
  }
5430
- console.log(G5(" To approve:"));
5431
- console.log(DIM5(` sherwood syndicate approve --agent-id <id> --wallet <addr>`));
5432
- console.log(G5(" To reject:"));
5433
- console.log(DIM5(` sherwood syndicate reject --attestation <uid>`));
6171
+ console.log(G6(" To approve:"));
6172
+ console.log(DIM6(` sherwood syndicate approve --agent-id <id> --wallet <addr>`));
6173
+ console.log(G6(" To reject:"));
6174
+ console.log(DIM6(` sherwood syndicate reject --attestation <uid>`));
5434
6175
  console.log();
5435
6176
  } catch (err) {
5436
6177
  spinner.fail("Failed to load requests");
5437
- console.error(chalk9.red(formatContractError(err)));
6178
+ console.error(chalk13.red(formatContractError(err)));
5438
6179
  process.exit(1);
5439
6180
  }
5440
6181
  });
@@ -5464,11 +6205,11 @@ syndicate.command("approve").description("Approve an agent join request (registe
5464
6205
  agentWallet
5465
6206
  );
5466
6207
  agentWasRegistered = true;
5467
- console.log(DIM5(` Agent registered: ${getExplorerUrl(regHash)}`));
6208
+ console.log(DIM6(` Agent registered: ${getExplorerUrl(regHash)}`));
5468
6209
  } catch (regErr) {
5469
6210
  const msg = regErr instanceof Error ? regErr.message : String(regErr);
5470
6211
  if (msg.includes("0xe098d3ee") || msg.includes("AgentAlreadyRegistered")) {
5471
- console.log(DIM5(" Agent already registered on vault \u2014 skipping"));
6212
+ console.log(DIM6(" Agent already registered on vault \u2014 skipping"));
5472
6213
  } else {
5473
6214
  throw regErr;
5474
6215
  }
@@ -5484,7 +6225,7 @@ syndicate.command("approve").description("Approve an agent join request (registe
5484
6225
  let approvalUid;
5485
6226
  if (alreadyApproved) {
5486
6227
  approvalUid = alreadyApproved.uid;
5487
- console.log(DIM5(` Approval attestation already exists \u2014 skipping`));
6228
+ console.log(DIM6(` Approval attestation already exists \u2014 skipping`));
5488
6229
  } else {
5489
6230
  spinner.text = "Creating approval attestation...";
5490
6231
  const result = await createApproval(
@@ -5507,23 +6248,23 @@ syndicate.command("approve").description("Approve an agent join request (registe
5507
6248
  syndicate: subdomain,
5508
6249
  timestamp: Math.floor(Date.now() / 1e3)
5509
6250
  });
5510
- console.log(DIM5(` Added to chat: ${subdomain}`));
6251
+ console.log(DIM6(` Added to chat: ${subdomain}`));
5511
6252
  } catch {
5512
- console.warn(chalk9.yellow(" \u26A0 Could not add agent to chat group"));
5513
- console.warn(chalk9.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
6253
+ console.warn(chalk13.yellow(" \u26A0 Could not add agent to chat group"));
6254
+ console.warn(chalk13.dim(` If no group exists, run: sherwood chat ${subdomain} init`));
5514
6255
  }
5515
6256
  spinner.succeed("Agent approved and registered");
5516
6257
  console.log();
5517
6258
  console.log(LABEL5(" \u25C6 Agent Approved"));
5518
- SEP5();
5519
- console.log(W5(` Agent ID: #${opts.agentId}`));
5520
- console.log(W5(` Wallet: ${G5(opts.wallet)}`));
5521
- console.log(W5(` Approval: ${DIM5(approvalUid)}`));
5522
- console.log(W5(` EAS Scan: ${DIM5(getEasScanUrl(approvalUid))}`));
5523
- SEP5();
6259
+ SEP6();
6260
+ console.log(W6(` Agent ID: #${opts.agentId}`));
6261
+ console.log(W6(` Wallet: ${G6(opts.wallet)}`));
6262
+ console.log(W6(` Approval: ${DIM6(approvalUid)}`));
6263
+ console.log(W6(` EAS Scan: ${DIM6(getEasScanUrl(approvalUid))}`));
6264
+ SEP6();
5524
6265
  } catch (err) {
5525
6266
  spinner.fail("Approval failed");
5526
- console.error(chalk9.red(formatContractError(err)));
6267
+ console.error(chalk13.red(formatContractError(err)));
5527
6268
  process.exit(1);
5528
6269
  }
5529
6270
  });
@@ -5532,17 +6273,17 @@ syndicate.command("reject").description("Reject a join request by revoking its a
5532
6273
  try {
5533
6274
  const hash = await revokeJoinRequest(opts.attestation);
5534
6275
  spinner.succeed("Join request rejected");
5535
- console.log(DIM5(` ${getEasExplorerUrl(hash)}`));
6276
+ console.log(DIM6(` ${getEasExplorerUrl(hash)}`));
5536
6277
  } catch (err) {
5537
6278
  spinner.fail("Rejection failed");
5538
- console.error(chalk9.red(formatContractError(err)));
6279
+ console.error(chalk13.red(formatContractError(err)));
5539
6280
  process.exit(1);
5540
6281
  }
5541
6282
  });
5542
6283
  syndicate.command("leave").description("Leave a syndicate \u2014 removes participation crons and session state").option("--subdomain <name>", "Syndicate subdomain to leave").action(async (opts) => {
5543
6284
  const subdomain = opts.subdomain || getPrimarySyndicate(getChain().id)?.subdomain;
5544
6285
  if (!subdomain) {
5545
- console.error(chalk9.red(" No syndicate configured. Pass --subdomain <name>."));
6286
+ console.error(chalk13.red(" No syndicate configured. Pass --subdomain <name>."));
5546
6287
  process.exit(1);
5547
6288
  }
5548
6289
  const spinner = ora8("Cleaning up...").start();
@@ -5558,17 +6299,17 @@ syndicate.command("leave").description("Leave a syndicate \u2014 removes partici
5558
6299
  resetSession(subdomain);
5559
6300
  spinner.succeed("Left syndicate");
5560
6301
  if (cronsRemoved) {
5561
- console.log(G5(" \u2713 Participation crons removed"));
6302
+ console.log(G6(" \u2713 Participation crons removed"));
5562
6303
  }
5563
- console.log(G5(" \u2713 Session state cleared"));
6304
+ console.log(G6(" \u2713 Session state cleared"));
5564
6305
  console.log();
5565
- console.log(chalk9.dim(" Note: This does not remove you on-chain. To exit your position:"));
5566
- console.log(chalk9.dim(" sherwood vault balance \u2014 check your LP share balance"));
5567
- console.log(chalk9.dim(" Redeem shares via the vault contract or dashboard"));
6306
+ console.log(chalk13.dim(" Note: This does not remove you on-chain. To exit your position:"));
6307
+ console.log(chalk13.dim(" sherwood vault balance \u2014 check your LP share balance"));
6308
+ console.log(chalk13.dim(" Redeem shares via the vault contract or dashboard"));
5568
6309
  console.log();
5569
6310
  } catch (err) {
5570
6311
  spinner.fail("Leave failed");
5571
- console.error(chalk9.red(err instanceof Error ? err.message : String(err)));
6312
+ console.error(chalk13.red(err instanceof Error ? err.message : String(err)));
5572
6313
  process.exit(1);
5573
6314
  }
5574
6315
  });
@@ -5579,21 +6320,21 @@ syndicate.command("set-primary").description("Set the active syndicate for CLI c
5579
6320
  if (!opts.subdomain && !opts.vault) {
5580
6321
  const primary = getPrimarySyndicate(chainId);
5581
6322
  if (memberships.length === 0) {
5582
- console.log(DIM5("\n No syndicates saved. Create or join one first.\n"));
6323
+ console.log(DIM6("\n No syndicates saved. Create or join one first.\n"));
5583
6324
  return;
5584
6325
  }
5585
6326
  console.log();
5586
6327
  console.log(LABEL5(" \u25C6 Your Syndicates"));
5587
- SEP5();
6328
+ SEP6();
5588
6329
  for (const m of memberships) {
5589
6330
  const isPrimary = primary?.subdomain === m.subdomain;
5590
- const marker = isPrimary ? G5(" \u2605") : "";
5591
- console.log(W5(` ${m.subdomain}.sherwoodagent.eth${marker} ${DIM5(`(${m.role})`)}`));
5592
- console.log(DIM5(` vault: ${m.vault}`));
6331
+ const marker = isPrimary ? G6(" \u2605") : "";
6332
+ console.log(W6(` ${m.subdomain}.sherwoodagent.eth${marker} ${DIM6(`(${m.role})`)}`));
6333
+ console.log(DIM6(` vault: ${m.vault}`));
5593
6334
  }
5594
- SEP5();
6335
+ SEP6();
5595
6336
  if (memberships.length > 1) {
5596
- console.log(DIM5(" Switch with: sherwood syndicate set-primary --subdomain <name>"));
6337
+ console.log(DIM6(" Switch with: sherwood syndicate set-primary --subdomain <name>"));
5597
6338
  }
5598
6339
  console.log();
5599
6340
  return;
@@ -5619,15 +6360,15 @@ syndicate.command("set-primary").description("Set the active syndicate for CLI c
5619
6360
  }
5620
6361
  }
5621
6362
  if (!target) {
5622
- console.error(chalk9.red(" Could not resolve syndicate. Pass --subdomain or --vault."));
6363
+ console.error(chalk13.red(" Could not resolve syndicate. Pass --subdomain or --vault."));
5623
6364
  process.exit(1);
5624
6365
  }
5625
6366
  setPrimarySyndicate(chainId, target);
5626
- console.log(G5(`
6367
+ console.log(G6(`
5627
6368
  \u2713 Primary syndicate set to ${target}.sherwoodagent.eth
5628
6369
  `));
5629
6370
  } catch (err) {
5630
- console.error(chalk9.red(formatContractError(err)));
6371
+ console.error(chalk13.red(formatContractError(err)));
5631
6372
  process.exit(1);
5632
6373
  }
5633
6374
  });
@@ -5641,7 +6382,7 @@ vaultCmd.command("deposit").description("Deposit into a vault").option("--vault
5641
6382
  await preflightDeposit(amount);
5642
6383
  }
5643
6384
  } catch (err) {
5644
- console.error(chalk9.red(`
6385
+ console.error(chalk13.red(`
5645
6386
  \u2716 ${err instanceof Error ? err.message : String(err)}
5646
6387
  `));
5647
6388
  process.exit(1);
@@ -5656,10 +6397,10 @@ vaultCmd.command("deposit").description("Deposit into a vault").option("--vault
5656
6397
  hash = await deposit(amount);
5657
6398
  }
5658
6399
  spinner.succeed(`Deposited: ${hash}`);
5659
- console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
6400
+ console.log(chalk13.dim(` ${getExplorerUrl(hash)}`));
5660
6401
  } catch (err) {
5661
6402
  spinner.fail("Deposit failed");
5662
- console.error(chalk9.red(formatContractError(err)));
6403
+ console.error(chalk13.red(formatContractError(err)));
5663
6404
  process.exit(1);
5664
6405
  }
5665
6406
  });
@@ -5670,8 +6411,8 @@ vaultCmd.command("info").description("Display vault state").option("--vault <add
5670
6411
  const info = await getVaultInfo();
5671
6412
  spinner.stop();
5672
6413
  console.log();
5673
- console.log(chalk9.bold("Vault Info"));
5674
- console.log(chalk9.dim("\u2500".repeat(40)));
6414
+ console.log(chalk13.bold("Vault Info"));
6415
+ console.log(chalk13.dim("\u2500".repeat(40)));
5675
6416
  console.log(` Address: ${info.address}`);
5676
6417
  console.log(` Total Assets: ${info.totalAssets}`);
5677
6418
  console.log(` Agent Count: ${info.agentCount}`);
@@ -5680,7 +6421,7 @@ vaultCmd.command("info").description("Display vault state").option("--vault <add
5680
6421
  console.log();
5681
6422
  } catch (err) {
5682
6423
  spinner.fail("Failed to load vault info");
5683
- console.error(chalk9.red(formatContractError(err)));
6424
+ console.error(chalk13.red(formatContractError(err)));
5684
6425
  process.exit(1);
5685
6426
  }
5686
6427
  });
@@ -5691,15 +6432,15 @@ vaultCmd.command("balance").description("Show LP share balance and asset value")
5691
6432
  const balance = await getBalance(opts.address);
5692
6433
  spinner.stop();
5693
6434
  console.log();
5694
- console.log(chalk9.bold("LP Position"));
5695
- console.log(chalk9.dim("\u2500".repeat(40)));
6435
+ console.log(chalk13.bold("LP Position"));
6436
+ console.log(chalk13.dim("\u2500".repeat(40)));
5696
6437
  console.log(` Shares: ${balance.shares.toString()}`);
5697
6438
  console.log(` Asset Value: ${balance.assetsValue}`);
5698
6439
  console.log(` % of Vault: ${balance.percentOfVault}`);
5699
6440
  console.log();
5700
6441
  } catch (err) {
5701
6442
  spinner.fail("Failed to load balance");
5702
- console.error(chalk9.red(formatContractError(err)));
6443
+ console.error(chalk13.red(formatContractError(err)));
5703
6444
  process.exit(1);
5704
6445
  }
5705
6446
  });
@@ -5714,18 +6455,18 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
5714
6455
  } else {
5715
6456
  shares = await getShareBalance();
5716
6457
  if (shares === 0n) {
5717
- console.error(chalk9.red("\n \u2716 No shares to redeem.\n"));
6458
+ console.error(chalk13.red("\n \u2716 No shares to redeem.\n"));
5718
6459
  process.exit(1);
5719
6460
  }
5720
6461
  }
5721
6462
  } catch (err) {
5722
- console.error(chalk9.red(`
6463
+ console.error(chalk13.red(`
5723
6464
  \u2716 ${err instanceof Error ? err.message : String(err)}
5724
6465
  `));
5725
6466
  process.exit(1);
5726
6467
  }
5727
6468
  if (opts.receiver && !isAddress6(opts.receiver)) {
5728
- console.error(chalk9.red(`
6469
+ console.error(chalk13.red(`
5729
6470
  \u2716 Invalid receiver address: ${opts.receiver}
5730
6471
  `));
5731
6472
  process.exit(1);
@@ -5733,7 +6474,7 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
5733
6474
  try {
5734
6475
  await preflightRedeem(shares);
5735
6476
  } catch (err) {
5736
- console.error(chalk9.red(`
6477
+ console.error(chalk13.red(`
5737
6478
  \u2716 ${err instanceof Error ? err.message : String(err)}
5738
6479
  `));
5739
6480
  process.exit(1);
@@ -5746,18 +6487,18 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
5746
6487
  opts.receiver
5747
6488
  );
5748
6489
  spinner.succeed(`Redeemed: ${hash}`);
5749
- console.log(chalk9.dim(` ${getExplorerUrl(hash)}`));
6490
+ console.log(chalk13.dim(` ${getExplorerUrl(hash)}`));
5750
6491
  console.log(` Assets received: ${formatUnits5(assetsOut, assetDecimals)}`);
5751
6492
  } catch (err) {
5752
6493
  spinner.fail("Redeem failed");
5753
- console.error(chalk9.red(formatContractError(err)));
6494
+ console.error(chalk13.red(formatContractError(err)));
5754
6495
  process.exit(1);
5755
6496
  }
5756
6497
  });
5757
6498
  var strategy = program.command("strategy").description("Strategy templates \u2014 list, clone, propose");
5758
6499
  registerStrategyTemplateCommands(strategy);
5759
6500
  program.command("providers").description("List available DeFi providers").action(async () => {
5760
- const { MessariProvider, NansenProvider } = await import("./research-NR4VC5LN.js");
6501
+ const { MessariProvider, NansenProvider } = await import("./research-YJWSQS2A.js");
5761
6502
  const providers = [new MoonwellProvider(), new UniswapProvider(), new MessariProvider(), new NansenProvider()];
5762
6503
  for (const p of providers) {
5763
6504
  const info = p.info();
@@ -5768,17 +6509,17 @@ ${info.name} (${info.type})`);
5768
6509
  }
5769
6510
  });
5770
6511
  try {
5771
- const { registerChatCommands } = await import("./chat-UWJ6JBFE.js");
6512
+ const { registerChatCommands } = await import("./chat-MRTPUZ3X.js");
5772
6513
  registerChatCommands(program);
5773
6514
  } catch {
5774
6515
  program.command("chat <name> [action] [actionArgs...]").description("Syndicate chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
5775
- console.error(chalk9.red("XMTP CLI not available."));
5776
- console.error(chalk9.dim("Install with: npm install -g @xmtp/cli"));
5777
- console.error(chalk9.dim("Or reinstall: npm i -g @sherwoodagent/cli"));
6516
+ console.error(chalk13.red("XMTP CLI not available."));
6517
+ console.error(chalk13.dim("Install with: npm install -g @xmtp/cli"));
6518
+ console.error(chalk13.dim("Or reinstall: npm i -g @sherwoodagent/cli"));
5778
6519
  process.exit(1);
5779
6520
  });
5780
6521
  }
5781
- var { registerSessionCommands } = await import("./session-NUPHC6ZN.js");
6522
+ var { registerSessionCommands } = await import("./session-FPCPCVQX.js");
5782
6523
  registerSessionCommands(program);
5783
6524
  registerVeniceCommands(program);
5784
6525
  registerAllowanceCommands(program);
@@ -5786,65 +6527,71 @@ registerIdentityCommands(program);
5786
6527
  registerProposalCommands(program);
5787
6528
  registerGovernorCommands(program);
5788
6529
  registerGuardianCommands(program);
5789
- var { registerResearchCommands } = await import("./research-J3HYU3N6.js");
6530
+ var { registerResearchCommands } = await import("./research-QBKISW2M.js");
5790
6531
  registerResearchCommands(program);
5791
- var { registerAgentCommands } = await import("./agent-5YEJ6W6W.js");
6532
+ var { registerAgentCommands } = await import("./agent-4HKHLQEJ.js");
5792
6533
  registerAgentCommands(program);
5793
- var { registerTradeCommands } = await import("./trade-VGECC4QZ.js");
6534
+ var { registerTradeCommands } = await import("./trade-NO6CNWCA.js");
5794
6535
  registerTradeCommands(program);
6536
+ registerGridCommand(program);
5795
6537
  var configCmd = program.command("config");
5796
- 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").option("--notify-to <id>", "Destination for cron summaries (Telegram chat ID, phone, etc.)").option("--uniswap-api-key <key>", "Uniswap Trading API key (from developers.uniswap.org)").option("--venice-api-key <key>", "Venice AI inference API key").option("--xmtp-group <subdomain:groupId>", "Cache an XMTP group ID for a syndicate (e.g. my-fund:abc123)").action((opts) => {
6538
+ 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").option("--notify-to <id>", "Destination for cron summaries (Telegram chat ID, phone, etc.)").option("--uniswap-api-key <key>", "Uniswap Trading API key (from developers.uniswap.org)").option("--venice-api-key <key>", "Venice AI inference API key").option("--anthropic-api-key <key>", "Anthropic Claude API key (for LLM judge)").option("--xmtp-group <subdomain:groupId>", "Cache an XMTP group ID for a syndicate (e.g. my-fund:abc123)").action((opts) => {
5797
6539
  let saved = false;
5798
6540
  if (opts.privateKey) {
5799
6541
  setPrivateKey(opts.privateKey);
5800
6542
  const account = getAccount();
5801
- console.log(chalk9.green("Private key saved to ~/.sherwood/config.json"));
5802
- console.log(chalk9.dim(` Wallet: ${account.address}`));
6543
+ console.log(chalk13.green("Private key saved to ~/.sherwood/config.json"));
6544
+ console.log(chalk13.dim(` Wallet: ${account.address}`));
5803
6545
  saved = true;
5804
6546
  }
5805
6547
  if (opts.vault) {
5806
6548
  const chainId = getChain().id;
5807
6549
  setChainContract(chainId, "vault", opts.vault);
5808
- console.log(chalk9.green(`Vault saved to ~/.sherwood/config.json (chain ${chainId})`));
5809
- console.log(chalk9.dim(` Vault: ${opts.vault}`));
6550
+ console.log(chalk13.green(`Vault saved to ~/.sherwood/config.json (chain ${chainId})`));
6551
+ console.log(chalk13.dim(` Vault: ${opts.vault}`));
5810
6552
  saved = true;
5811
6553
  }
5812
6554
  if (opts.rpc) {
5813
6555
  const network = getNetwork();
5814
6556
  setConfigRpcUrl(network, opts.rpc);
5815
- console.log(chalk9.green(`RPC URL saved for ${network}`));
5816
- console.log(chalk9.dim(` RPC: ${opts.rpc}`));
6557
+ console.log(chalk13.green(`RPC URL saved for ${network}`));
6558
+ console.log(chalk13.dim(` RPC: ${opts.rpc}`));
5817
6559
  saved = true;
5818
6560
  }
5819
6561
  if (opts.notifyTo) {
5820
6562
  setNotifyTo(opts.notifyTo);
5821
- console.log(chalk9.green("Notify destination saved to ~/.sherwood/config.json"));
5822
- console.log(chalk9.dim(` Notify to: ${opts.notifyTo}`));
6563
+ console.log(chalk13.green("Notify destination saved to ~/.sherwood/config.json"));
6564
+ console.log(chalk13.dim(` Notify to: ${opts.notifyTo}`));
5823
6565
  saved = true;
5824
6566
  }
5825
6567
  if (opts.uniswapApiKey) {
5826
6568
  setUniswapApiKey(opts.uniswapApiKey);
5827
- console.log(chalk9.green("Uniswap API key saved to ~/.sherwood/config.json"));
6569
+ console.log(chalk13.green("Uniswap API key saved to ~/.sherwood/config.json"));
5828
6570
  saved = true;
5829
6571
  }
5830
6572
  if (opts.veniceApiKey) {
5831
6573
  setVeniceApiKey(opts.veniceApiKey);
5832
- console.log(chalk9.green("Venice API key saved to ~/.sherwood/config.json"));
6574
+ console.log(chalk13.green("Venice API key saved to ~/.sherwood/config.json"));
6575
+ saved = true;
6576
+ }
6577
+ if (opts.anthropicApiKey) {
6578
+ setAnthropicApiKey(opts.anthropicApiKey);
6579
+ console.log(chalk13.green("Anthropic API key saved to ~/.sherwood/config.json"));
5833
6580
  saved = true;
5834
6581
  }
5835
6582
  if (opts.xmtpGroup) {
5836
6583
  const parts = opts.xmtpGroup.split(":");
5837
6584
  if (parts.length !== 2 || !parts[0] || !parts[1]) {
5838
- console.log(chalk9.red("Format: --xmtp-group <subdomain>:<groupId>"));
6585
+ console.log(chalk13.red("Format: --xmtp-group <subdomain>:<groupId>"));
5839
6586
  process.exit(1);
5840
6587
  }
5841
6588
  cacheGroupId(parts[0], parts[1]);
5842
- console.log(chalk9.green(`XMTP group ID cached for ${parts[0]}`));
5843
- console.log(chalk9.dim(` Group ID: ${parts[1]}`));
6589
+ console.log(chalk13.green(`XMTP group ID cached for ${parts[0]}`));
6590
+ console.log(chalk13.dim(` Group ID: ${parts[1]}`));
5844
6591
  saved = true;
5845
6592
  }
5846
6593
  if (!saved) {
5847
- console.log(chalk9.red("Provide at least one of: --private-key, --vault, --rpc, --notify-to, --uniswap-api-key, --venice-api-key, --xmtp-group"));
6594
+ console.log(chalk13.red("Provide at least one of: --private-key, --vault, --rpc, --notify-to, --uniswap-api-key, --venice-api-key, --anthropic-api-key, --xmtp-group"));
5848
6595
  process.exit(1);
5849
6596
  }
5850
6597
  });
@@ -5855,25 +6602,25 @@ configCmd.command("show").description("Display current config for the active net
5855
6602
  const config = loadConfig();
5856
6603
  const customRpc = config.rpc?.[network];
5857
6604
  console.log();
5858
- console.log(chalk9.bold(`Sherwood Config`));
5859
- console.log(chalk9.dim("\u2500".repeat(50)));
5860
- console.log(` Network: ${chalk9.cyan(network)} (chain ${chainId})`);
5861
- console.log(` RPC: ${customRpc ? chalk9.green(customRpc) : chalk9.dim("default")}`);
5862
- console.log(` Wallet: ${config.privateKey ? chalk9.green("configured") : chalk9.dim("not set")}`);
5863
- console.log(` Agent ID: ${config.agentId ?? chalk9.dim("not set")}`);
5864
- console.log(` Vault: ${contracts.vault ?? chalk9.dim("not set")}`);
5865
- console.log(` Uniswap: ${getUniswapApiKey() ? chalk9.green("API key configured") : chalk9.dim("not set")}`);
5866
- console.log(` Venice: ${getVeniceApiKey() ? chalk9.green("API key configured") : chalk9.dim("not set")}`);
6605
+ console.log(chalk13.bold(`Sherwood Config`));
6606
+ console.log(chalk13.dim("\u2500".repeat(50)));
6607
+ console.log(` Network: ${chalk13.cyan(network)} (chain ${chainId})`);
6608
+ console.log(` RPC: ${customRpc ? chalk13.green(customRpc) : chalk13.dim("default")}`);
6609
+ console.log(` Wallet: ${config.privateKey ? chalk13.green("configured") : chalk13.dim("not set")}`);
6610
+ console.log(` Agent ID: ${config.agentId ?? chalk13.dim("not set")}`);
6611
+ console.log(` Vault: ${contracts.vault ?? chalk13.dim("not set")}`);
6612
+ console.log(` Uniswap: ${getUniswapApiKey() ? chalk13.green("API key configured") : chalk13.dim("not set")}`);
6613
+ console.log(` Venice: ${getVeniceApiKey() ? chalk13.green("API key configured") : chalk13.dim("not set")}`);
5867
6614
  const groupEntries = Object.entries(config.groupCache || {}).filter(([, v]) => v);
5868
6615
  if (groupEntries.length > 0) {
5869
6616
  console.log();
5870
- console.log(chalk9.bold(" XMTP Groups"));
6617
+ console.log(chalk13.bold(" XMTP Groups"));
5871
6618
  for (const [sub, gid] of groupEntries) {
5872
- console.log(` ${sub}: ${chalk9.cyan(gid)}`);
6619
+ console.log(` ${sub}: ${chalk13.cyan(gid)}`);
5873
6620
  }
5874
6621
  }
5875
6622
  console.log();
5876
- console.log(chalk9.dim(" Config file: ~/.sherwood/config.json"));
6623
+ console.log(chalk13.dim(" Config file: ~/.sherwood/config.json"));
5877
6624
  console.log();
5878
6625
  });
5879
6626
  program.parse();