@vike-io/cli 0.6.0 → 0.7.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  All notable changes are documented here. Entries follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
4
4
 
5
+ ## 0.7.1 — eval harness v2 + help tweaks + SQL fix
6
+
7
+ - **Eval schema upgraded** (`evals/questions.yaml`): multi-command list, per-skill tag, multi-step flag, word-boundary forbidden matching. Per-skill scoring breakdown + single-vs-multi-step split in the runner output.
8
+ - **10 new multi-step questions** exercising composite playbook skills (smart-money-discovery, wallet-portfolio, polymarket-screener, perp-screener, hl-trader-profile, alerts-setup, etc.) — 32 questions total.
9
+ - **Help discoverability tweaks**: `wallet counterparties --limit` and `wallet balances --min-usd` descriptions improved (eval surfaced both as commonly-missed flags).
10
+ - **Backend bug fix shipped (server-side)**: `wallet_transactions` returned 0 rows due to ClickHouse SELECT-alias shadowing — fixed in monorepo, deployed to prod.
11
+
12
+ ## 0.7.0 — 5 new commands (transactions, compare, trace, batch, screener)
13
+
14
+ - **`vike wallet transactions <address>`** (alias `txs`) — raw per-wallet transfer list with `--direction in|out|all`, `--days`, `--min-usd`, `--token` filters.
15
+ - **`vike wallet compare <a> <b>`** — diff two wallets (shared counterparties + shared tokens within a window).
16
+ - **`vike wallet trace <address>`** — counterparty graph traversal, depth 1-5, width 1-10, with min-USD threshold.
17
+ - **`vike wallet batch <addr1> <addr2> ...`** — bulk label + 30d summary lookup for up to 100 addresses, preserves input order.
18
+ - **`vike token screener`** — token discovery filter ranked by volume / net inflow / holders / smart-money inflow.
19
+ - 5 new SKILL.md playbooks: `vike-wallet-transactions`, `vike-wallet-compare`, `vike-wallet-trace`, `vike-wallet-batch`, `vike-token-screener`.
20
+
21
+ Total: 38 skills (was 33), 34 MCP tools (was 29).
22
+
5
23
  ## 0.6.0 — infra hardening + observability + skill eval harness
6
24
 
7
25
  Mostly internal-quality improvements; no new commands. Backbone for everything that follows.
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.6.0",
6
+ "version": "0.7.1",
7
7
  "description": "AI-agent CLI for vike.io on-chain analytics, perps, options, and prediction markets across 11 chains",
8
8
  "type": "module",
9
9
  "main": "src/index.js",
@@ -0,0 +1,82 @@
1
+ ---
2
+ name: vike-token-screener
3
+ description: Token discovery filter — rank tokens by volume / net inflow / holder count / smart-money inflow within a window, with min-volume and min-holder filters. Use when the user asks "what tokens are trending today" / "find tokens with smart money accumulating" / "rising tokens this week" / token discovery from scratch.
4
+ allowed-tools: Bash(vike:*)
5
+ ---
6
+
7
+ # vike-token-screener
8
+
9
+ ## Command
10
+
11
+ ```bash
12
+ vike token screener
13
+ [--chain ethereum|bsc|base]
14
+ [--window 24h|7d|30d|90d]
15
+ [--sort volume|net_inflow|holders|smart_inflow]
16
+ [--limit N] (max 100)
17
+ [--min-volume USD] (filter dust)
18
+ [--min-holders N] (require N+ unique holders)
19
+ [--smart-money-only] (restrict to smart-money cohort flows)
20
+ [--json]
21
+ ```
22
+
23
+ ## Examples
24
+
25
+ ```bash
26
+ # Trending today by volume
27
+ vike token screener --window 24h --sort volume --limit 20
28
+
29
+ # Find tokens smart money is accumulating
30
+ vike token screener --window 7d --sort smart_inflow --smart-money-only
31
+
32
+ # Rising holders count (organic growth signal)
33
+ vike token screener --window 30d --sort holders --min-volume 100000
34
+
35
+ # Mid-cap tokens with real activity
36
+ vike token screener --min-volume 1000000 --min-holders 100 --sort net_inflow
37
+ ```
38
+
39
+ ## Output columns
40
+
41
+ `token_address`, `symbol` (when known), `name`, `volume_usd`, `net_flow_usd`, `in_usd`, `out_usd`, `unique_holders`, `tx_count`.
42
+
43
+ ## Sort modes
44
+
45
+ | Sort | What it surfaces |
46
+ |---|---|
47
+ | `volume` | Most-traded tokens (default) — captures attention-driven action |
48
+ | `net_inflow` | Tokens with biggest accumulation (in > out) — "what's being bought" |
49
+ | `holders` | Tokens gaining unique addresses — organic growth signal |
50
+ | `smart_inflow` | Tokens our smart-money cohort is buying — alpha signal |
51
+
52
+ ## Reading
53
+
54
+ - **High volume + balanced in/out** = churn (DEX MM, arb bots). Low signal.
55
+ - **High volume + strong net_inflow** = real demand. Worth investigating.
56
+ - **Strong holder growth + flat volume** = small buys, distribution widening. Often early signal.
57
+ - **`smart_inflow` mode** + high values + low overall volume = cohort is positioned BEFORE retail. Highest-conviction signal in the tool.
58
+
59
+ ## Filter tips
60
+
61
+ | Goal | Filters |
62
+ |---|---|
63
+ | "Rising memecoins" | `--window 24h --sort holders --min-holders 50 --min-volume 50000` |
64
+ | "Mid-cap alpha" | `--sort smart_inflow --min-volume 500000 --smart-money-only` |
65
+ | "What's getting dumped" | `--sort net_inflow` then reverse — bottom rows have biggest outflows |
66
+
67
+ ## Anti-patterns
68
+
69
+ - Don't quote the symbol as authoritative if `symbol` is null/blank — token hasn't been mapped, identify by address instead
70
+ - Don't use `--window 24h --sort smart_inflow` for hot-new-token discovery — smart money usually positions BEFORE the 24h window; try `--window 7d` for that mode
71
+ - Don't omit `--min-holders` when sorting by holders — junk airdrops with 50,000 1-tx addresses dominate the top otherwise
72
+ - Don't omit `--min-volume` when sorting by net_inflow — tiny tokens with $100 net flow can rank high in % terms
73
+
74
+ ## Cost note
75
+
76
+ 3 credits per call. Cheaper than `wallet trace` (which is 4) but heavier than per-tool lookups. Use deliberately for discovery, not as a default.
77
+
78
+ ## Pairs well with
79
+
80
+ - `vike token holders <addr>` — drill into the top holders of any flagged token
81
+ - `vike token transfers <addr>` — see WHO is buying/selling once a token is interesting
82
+ - `vike-smart-money-discovery` — composite playbook starting from this screen
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: vike-wallet-batch
3
+ description: Bulk label + 30d summary lookup for up to 100 addresses in one call. Use when the user pastes a CSV of addresses, asks "enrich this list with labels", or wants to quickly screen many wallets for entity / risk / activity.
4
+ allowed-tools: Bash(vike:*)
5
+ ---
6
+
7
+ # vike-wallet-batch
8
+
9
+ ## Command
10
+
11
+ ```bash
12
+ vike wallet batch <addr1> <addr2> <addr3> ...
13
+ [--chain ethereum|bsc|base]
14
+ [--json]
15
+ ```
16
+
17
+ Caps at 100 addresses per call. For larger lists, split into chunks.
18
+
19
+ ## Example
20
+
21
+ ```bash
22
+ vike wallet batch 0xd8da... 0xabc... 0xdef... --json
23
+ ```
24
+
25
+ ## Output
26
+
27
+ One row per INPUT address (preserves input order — useful when joining back to a source CSV):
28
+
29
+ ```json
30
+ [
31
+ { "wallet": "0xd8da...", "entity": null, "wallet_type": "user", "confidence": "Medium", "risk_flag": null, "net_30d_usd": 12000, "volume_30d_usd": 50000, "tx_30d": 42, "tokens_30d_count": 8, "found": true },
32
+ { "wallet": "0xabc...", "entity": "Binance", "wallet_type": "cex", "confidence": "High", "risk_flag": null, "net_30d_usd": -5e9, "volume_30d_usd": 9e9, "tx_30d": 2000, "tokens_30d_count": 80, "found": true },
33
+ { "wallet": "0xdef...", "entity": null, "wallet_type": null, "confidence": null, "risk_flag": null, "net_30d_usd": 0, "volume_30d_usd": 0, "tx_30d": 0, "tokens_30d_count": 0, "found": false }
34
+ ]
35
+ ```
36
+
37
+ `found: false` = address has no labels AND no 30d activity in our DB (might be brand-new wallet or one we haven't indexed).
38
+
39
+ ## Reading
40
+
41
+ - Filter to `wallet_type = "user"` to find real-people addresses worth investigating further
42
+ - Any `risk_flag != null` → flag prominently in any user-facing report
43
+ - High `volume_30d_usd` but `tx_30d = 0` shouldn't happen — if it does, indicates stale aggregate; recompute
44
+ - `entity = "Binance"` + `wallet_type = "cex"` rows in a "smart money" list = false positives (CEX deposits aren't traders)
45
+
46
+ ## Anti-patterns
47
+
48
+ - Don't run individual `vike wallet summary` in a loop for >5 addresses — this batch is ~20× faster
49
+ - Don't pass mixed-case addresses inconsistently — they're normalised but cleaner CSVs help readers
50
+ - Don't expect lifetime data — this is 30d window. For lifetime use the individual `wallet summary`
51
+
52
+ ## Pairs well with
53
+
54
+ - `vike labels <addr>` — drill into any address showing high-confidence labels
55
+ - `vike wallet compare <a> <b>` — pick two interesting batch results and diff them
56
+ - `vike funds` — when batch reveals fund/MM/treasury wallets, get their flows
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: vike-wallet-compare
3
+ description: Diff two wallets — find their shared counterparties (both transacted with these addresses) and shared tokens (both touched these tokens) within a window. Use when the user asks "are these two wallets related" / "what do X and Y have in common" / "find connections between wallet A and B".
4
+ allowed-tools: Bash(vike:*)
5
+ ---
6
+
7
+ # vike-wallet-compare
8
+
9
+ ## Command
10
+
11
+ ```bash
12
+ vike wallet compare <address_a> <address_b>
13
+ [--chain ethereum|bsc|base]
14
+ [--window 24h|7d|30d|90d|180d|all]
15
+ [--limit N] (max 50)
16
+ [--json]
17
+ ```
18
+
19
+ ## Output
20
+
21
+ ```json
22
+ {
23
+ "address_a": "0x...",
24
+ "address_b": "0x...",
25
+ "window": "30d",
26
+ "shared_counterparties": [
27
+ { "wallet": "0x...", "a_volume_usd": 50000, "b_volume_usd": 75000, "a_tx_count": 3, "b_tx_count": 5, "entity": "Binance", "wallet_type": "cex" },
28
+ ...
29
+ ],
30
+ "shared_tokens": [
31
+ { "token_address": "0x...", "a_volume_usd": 12000, "b_volume_usd": 8000, "a_tx_count": 2, "b_tx_count": 4 },
32
+ ...
33
+ ],
34
+ "summary": { "shared_counterparty_count": 7, "shared_token_count": 12 }
35
+ }
36
+ ```
37
+
38
+ ## Reading
39
+
40
+ - Many shared counterparties + same entity types = likely operated by same person/group
41
+ - Same exchange (Binance hot wallet) as counterparty for both = trivial overlap, both users of that CEX
42
+ - Shared NICHE tokens (long-tail memes, low-vol) with similar tx counts = strong signal of coordination
43
+ - Shared infra contracts (Uniswap, 1inch) = trivial overlap, ignore
44
+ - Zero shared = wallets genuinely independent
45
+
46
+ ## Anti-patterns
47
+
48
+ - **Don't infer common ownership from CEX overlap.** Millions of users deposit to the same Binance hot wallets. Shared CEX counterparty = nothing.
49
+ - **Don't claim coordination from common DEX router overlap** (Uniswap, 1inch routers). Almost every DEX user shares those.
50
+ - Filter mentally for `wallet_type IN ('user', 'unknown')` overlap if you want a meaningful relatedness signal.
51
+
52
+ ## Pairs well with
53
+
54
+ - `vike labels <addr>` — drill into any interesting shared counterparty
55
+ - `vike wallet trace <addr>` — follow money outward from either wallet
56
+ - `vike wallet counterparties <addr>` — top partners per wallet individually
@@ -0,0 +1,75 @@
1
+ ---
2
+ name: vike-wallet-trace
3
+ description: Counterparty graph traversal from a root wallet outward. At each hop, expand to the top N counterparties by USD volume. Use when the user asks "where did funds from X go" / "follow the money 3 hops out" / "trace the network around this wallet" / wallet investigation.
4
+ allowed-tools: Bash(vike:*)
5
+ ---
6
+
7
+ # vike-wallet-trace
8
+
9
+ ## Command
10
+
11
+ ```bash
12
+ vike wallet trace <address>
13
+ [--chain ethereum|bsc|base]
14
+ [--depth N] (1-5, default 2)
15
+ [--width N] (1-10, default 5)
16
+ [--window 24h|7d|30d|90d|all]
17
+ [--min-usd N] (default 10000 — prunes noise)
18
+ [--json]
19
+ ```
20
+
21
+ ## Output
22
+
23
+ ```json
24
+ {
25
+ "root": "0xabc...",
26
+ "depth": 2, "width": 5, "window": "30d", "min_usd": 10000,
27
+ "nodes": [
28
+ { "address": "0xabc...", "depth": 0, "total_volume_usd": 0.0 },
29
+ { "address": "0xdef...", "depth": 1, "total_volume_usd": 250000, "label": "Binance", "wallet_type": "cex" },
30
+ { "address": "0x123...", "depth": 2, "total_volume_usd": 45000, "label": null, "wallet_type": null },
31
+ ...
32
+ ],
33
+ "edges": [
34
+ { "from": "0xabc...", "to": "0xdef...", "volume_usd": 200000, "tx_count": 4 },
35
+ ...
36
+ ],
37
+ "stats": { "node_count": 23, "edge_count": 31, "max_depth_reached": 2 }
38
+ }
39
+ ```
40
+
41
+ ## Reading the graph
42
+
43
+ - **Root (depth 0)** = the wallet you traced from. `total_volume_usd` = 0 because it's where edges originate.
44
+ - **Depth 1** = direct counterparties. Most useful layer.
45
+ - **Depth 2-3** = "friend-of-friend" — useful for finding where funds end up.
46
+ - **Edge volume_usd** = the volume between those two specific addresses, NOT cumulative.
47
+ - **`wallet_type = "cex"`** at depth 1 = funds went to / came from an exchange. Often the END of the trail (anonymous from there).
48
+ - **Unlabeled wallet with high volume at depth 1-2** = potentially related wallet, investigate with `vike labels`.
49
+
50
+ ## Parameter tuning
51
+
52
+ | Parameter | Effect | Use when |
53
+ |---|---|---|
54
+ | `--depth 1` | Direct counterparties only | "Who does X trade with" — same as `wallet counterparties` |
55
+ | `--depth 2` | One degree of separation | Default. Reveals immediate networks. |
56
+ | `--depth 3+` | Wider net | Investigation / OSINT. Returns much more data; graph gets noisy. |
57
+ | `--width 3` | Top 3 per hop | Cleaner, focused on biggest flows |
58
+ | `--width 10` | Top 10 per hop | Wider scan, more noise |
59
+ | `--min-usd 50000` | High-value flows only | Strip out dust/airdrops |
60
+
61
+ ## Cost note
62
+
63
+ Tool credits = 4 per call (heavier than other graph-less tools). Graph explodes exponentially with depth — depth 3 + width 10 = up to 1000 nodes per scan. Use `--depth 2 --width 5` as default.
64
+
65
+ ## Anti-patterns
66
+
67
+ - Don't trace through CEX deposits. Once funds enter Binance/Coinbase, the trail goes opaque (CEX internal accounting, not on-chain). Note CEX nodes and stop following.
68
+ - Don't depth-5 by default. Graph blows up; results become noise.
69
+ - Don't ignore `min_usd` — without it, dust transfers create false-positive edges.
70
+
71
+ ## Pairs well with
72
+
73
+ - `vike labels <addr>` — identify any interesting node
74
+ - `vike wallet compare <addr_a> <addr_b>` — confirm relatedness once trace surfaces candidates
75
+ - `vike wallet transactions <addr>` — drill into specific transfers between two nodes
@@ -0,0 +1,59 @@
1
+ ---
2
+ name: vike-wallet-transactions
3
+ description: Raw per-wallet transfer list (individual transactions, not aggregates) with direction, day, USD, and token filters. Use when the user asks "show me recent transfers for X" / "last 100 transactions of Y" / "all USDC moves from this wallet" / any forensic audit query.
4
+ allowed-tools: Bash(vike:*)
5
+ ---
6
+
7
+ # vike-wallet-transactions
8
+
9
+ ## Command
10
+
11
+ ```bash
12
+ vike wallet transactions <address> # alias: vike wallet txs
13
+ [--chain ethereum|bsc|base]
14
+ [--direction in|out|all]
15
+ [--days N] (max 365)
16
+ [--limit N] (max 500)
17
+ [--min-usd N]
18
+ [--token <addr>]
19
+ [--json]
20
+ ```
21
+
22
+ ## Examples
23
+
24
+ ```bash
25
+ # Recent in+out transfers, last 7 days
26
+ vike wallet txs 0xd8da6bf26964af9d7eed9e03e53415d37aa96045 --days 7 --limit 20
27
+
28
+ # Only outgoing > $10k in last 30d
29
+ vike wallet txs 0xabc... --direction out --min-usd 10000
30
+
31
+ # Only USDC transfers
32
+ vike wallet txs 0xabc... --token 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
33
+ ```
34
+
35
+ ## Output columns
36
+
37
+ `time`, `tx_hash`, `from_address`, `to_address`, `token_address`, `value_usd`, `direction` (in/out), `block`.
38
+
39
+ Sorted descending by time (most recent first).
40
+
41
+ ## Reading
42
+
43
+ - High `tx_count` over short window + low `value_usd` per tx = bot / MM / contract
44
+ - Mixed in/out with similar volumes = active trader
45
+ - Many `out` to one address = sweep / deposit pattern
46
+ - One huge `in` then nothing = airdrop receiver / one-time deposit
47
+
48
+ ## Anti-patterns
49
+
50
+ - Don't use this for aggregated metrics (volume, PnL) — use `wallet summary` instead, it's faster
51
+ - Don't paginate by re-running with smaller windows — limit max 500, just bump `--limit`
52
+ - Don't use `--token` on every query if you want full activity; the filter restricts to one token
53
+
54
+ ## Pairs well with
55
+
56
+ - `vike wallet summary <addr>` — aggregate metrics over same window
57
+ - `vike wallet counterparties <addr>` — who they trade with most
58
+ - `vike wallet trace <addr>` — graph-traverse outward from this wallet
59
+ - `vike labels <addr>` — identify the wallet itself
@@ -58,6 +58,32 @@ export function registerToken(program) {
58
58
  } catch (err) { emitError(err, opts); }
59
59
  });
60
60
 
61
+ cmd
62
+ .command('screener')
63
+ .description('Token discovery filter — rank tokens by volume / inflow / holders / smart-money inflow')
64
+ .option('--chain <c>', 'ethereum | bsc | base', 'ethereum')
65
+ .option('--window <w>', '24h | 7d | 30d | 90d', '24h')
66
+ .option('--sort <s>', 'volume | net_inflow | holders | smart_inflow', 'volume')
67
+ .option('--limit <n>', 'Max tokens (max 100)', '20')
68
+ .option('--min-volume <usd>', 'Minimum window volume USD', '0')
69
+ .option('--min-holders <n>', 'Minimum unique holders', '0')
70
+ .option('--smart-money-only', 'Restrict flows to smart-money cohort')
71
+ .option('--json', 'Emit JSON')
72
+ .action(async (opts) => {
73
+ try {
74
+ const r = await callTool('token_screener', {
75
+ chain: opts.chain,
76
+ window: opts.window,
77
+ sort: opts.sort,
78
+ limit: parseInt10(opts.limit, 20),
79
+ min_volume_usd: parseFloat(opts.minVolume) || 0,
80
+ min_holders: parseInt10(opts.minHolders, 0),
81
+ smart_money_only: Boolean(opts.smartMoneyOnly),
82
+ });
83
+ emit(r, opts);
84
+ } catch (err) { emitError(err, opts); }
85
+ });
86
+
61
87
  cmd
62
88
  .command('holders <token_address>')
63
89
  .description('Top holders of a token by cumulative net inflow USD')
@@ -18,12 +18,93 @@ export function registerWallet(program) {
18
18
  } catch (err) { emitError(err, opts); }
19
19
  });
20
20
 
21
+ cmd
22
+ .command('transactions <address>')
23
+ .alias('txs')
24
+ .description('Raw per-wallet transfer list with filters')
25
+ .option('--chain <c>', 'ethereum | bsc | base', 'ethereum')
26
+ .option('--direction <d>', 'in | out | all', 'all')
27
+ .option('--days <n>', 'Days back (max 365)', '30')
28
+ .option('--limit <n>', 'Max txs (max 500)', '50')
29
+ .option('--min-usd <n>', 'Filter dust below this USD value', '0')
30
+ .option('--token <addr>', 'Optional: restrict to one token address')
31
+ .option('--json', 'Emit JSON')
32
+ .action(async (address, opts) => {
33
+ try {
34
+ const r = await callTool('wallet_transactions', {
35
+ address,
36
+ chain: opts.chain,
37
+ direction: opts.direction,
38
+ days: parseInt10(opts.days, 30),
39
+ limit: parseInt10(opts.limit, 50),
40
+ min_usd: parseFloat(opts.minUsd) || 0,
41
+ token_address: opts.token,
42
+ });
43
+ emit(r, opts);
44
+ } catch (err) { emitError(err, opts); }
45
+ });
46
+
47
+ cmd
48
+ .command('compare <address_a> <address_b>')
49
+ .description('Diff two wallets — shared counterparties + shared tokens')
50
+ .option('--chain <c>', 'ethereum | bsc | base', 'ethereum')
51
+ .option('--window <w>', '24h | 7d | 30d | 90d | 180d | all', '30d')
52
+ .option('--limit <n>', 'Max shared items per category (max 50)', '10')
53
+ .option('--json', 'Emit JSON')
54
+ .action(async (a, b, opts) => {
55
+ try {
56
+ const r = await callTool('wallet_compare', {
57
+ address_a: a, address_b: b,
58
+ chain: opts.chain, window: opts.window,
59
+ limit: parseInt10(opts.limit, 10),
60
+ });
61
+ emit(r, opts);
62
+ } catch (err) { emitError(err, opts); }
63
+ });
64
+
65
+ cmd
66
+ .command('trace <address>')
67
+ .description('Counterparty graph traversal from a root wallet')
68
+ .option('--chain <c>', 'ethereum | bsc | base', 'ethereum')
69
+ .option('--depth <n>', 'Hops to follow (1-5)', '2')
70
+ .option('--width <n>', 'Top counterparties per hop (1-10)', '5')
71
+ .option('--window <w>', '24h | 7d | 30d | 90d | all', '30d')
72
+ .option('--min-usd <n>', 'Minimum USD per transfer to follow', '10000')
73
+ .option('--json', 'Emit JSON')
74
+ .action(async (address, opts) => {
75
+ try {
76
+ const r = await callTool('wallet_trace', {
77
+ address,
78
+ chain: opts.chain,
79
+ depth: parseInt10(opts.depth, 2),
80
+ width: parseInt10(opts.width, 5),
81
+ window: opts.window,
82
+ min_usd: parseFloat(opts.minUsd) || 10000,
83
+ });
84
+ emit(r, opts);
85
+ } catch (err) { emitError(err, opts); }
86
+ });
87
+
88
+ cmd
89
+ .command('batch <addresses...>')
90
+ .description('Bulk label + 30d summary lookup for many addresses (max 100)')
91
+ .option('--chain <c>', 'ethereum | bsc | base', 'ethereum')
92
+ .option('--json', 'Emit JSON')
93
+ .action(async (addresses, opts) => {
94
+ try {
95
+ const r = await callTool('wallet_batch_labels', {
96
+ addresses, chain: opts.chain,
97
+ });
98
+ emit(r, opts);
99
+ } catch (err) { emitError(err, opts); }
100
+ });
101
+
21
102
  cmd
22
103
  .command('counterparties <address>')
23
104
  .description('Top trading partners of a wallet by combined transfer volume')
24
105
  .option('--chain <c>', 'ethereum | bsc | base', 'ethereum')
25
106
  .option('--window <w>', '24h | 7d | 30d | 90d | 180d | all', '30d')
26
- .option('--limit <n>', 'Max counterparties (max 50)', '10')
107
+ .option('--limit <n>', 'Max counterparties returned (default 10, max 50)', '10')
27
108
  .option('--json', 'Emit JSON')
28
109
  .action(async (address, opts) => {
29
110
  try {
@@ -58,7 +139,7 @@ export function registerWallet(program) {
58
139
  .command('balances <address>')
59
140
  .description('Current ERC-20 holdings across major EVM chains')
60
141
  .option('--chains <list>', 'Comma-separated chains (eth,bsc,base,arbitrum,polygon,optimism)')
61
- .option('--min-usd <n>', 'Filter dust below this USD value', '1')
142
+ .option('--min-usd <n>', 'Filter dust below this USD value (default $1; recommend $100+ for noisy wallets)', '1')
62
143
  .option('--json', 'Emit JSON')
63
144
  .action(async (address, opts) => {
64
145
  try {