@vike-io/cli 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/LICENSE +21 -0
  3. package/README.md +98 -0
  4. package/package.json +73 -0
  5. package/scripts/postinstall.js +20 -0
  6. package/skills/vike-alerts-setup/SKILL.md +75 -0
  7. package/skills/vike-alerts-webhook/SKILL.md +84 -0
  8. package/skills/vike-core/SKILL.md +67 -0
  9. package/skills/vike-cross-venue-perps/SKILL.md +52 -0
  10. package/skills/vike-defi-positions/SKILL.md +59 -0
  11. package/skills/vike-fund-holdings/SKILL.md +53 -0
  12. package/skills/vike-hl-top-traders/SKILL.md +52 -0
  13. package/skills/vike-hl-trader-profile/SKILL.md +65 -0
  14. package/skills/vike-options-flow/SKILL.md +49 -0
  15. package/skills/vike-perp-funding-arb/SKILL.md +53 -0
  16. package/skills/vike-perp-screener/SKILL.md +49 -0
  17. package/skills/vike-perp-spread-arb/SKILL.md +38 -0
  18. package/skills/vike-polymarket-market-detail/SKILL.md +42 -0
  19. package/skills/vike-polymarket-markets/SKILL.md +44 -0
  20. package/skills/vike-polymarket-screener/SKILL.md +59 -0
  21. package/skills/vike-polymarket-smart-money/SKILL.md +58 -0
  22. package/skills/vike-polymarket-trader/SKILL.md +55 -0
  23. package/skills/vike-router/SKILL.md +53 -0
  24. package/skills/vike-smart-money-discovery/SKILL.md +74 -0
  25. package/skills/vike-token-holders/SKILL.md +45 -0
  26. package/skills/vike-token-research/SKILL.md +55 -0
  27. package/skills/vike-token-search/SKILL.md +40 -0
  28. package/skills/vike-token-transfers/SKILL.md +43 -0
  29. package/skills/vike-wallet-balances/SKILL.md +60 -0
  30. package/skills/vike-wallet-counterparties/SKILL.md +48 -0
  31. package/skills/vike-wallet-discover/SKILL.md +49 -0
  32. package/skills/vike-wallet-ens/SKILL.md +41 -0
  33. package/skills/vike-wallet-label-provenance/SKILL.md +65 -0
  34. package/skills/vike-wallet-pnl-history/SKILL.md +58 -0
  35. package/skills/vike-wallet-portfolio/SKILL.md +61 -0
  36. package/skills/vike-wallet-summary/SKILL.md +35 -0
  37. package/skills/vike-web-fetch/SKILL.md +55 -0
  38. package/skills/vike-web-research/SKILL.md +58 -0
  39. package/skills/vike-web-search/SKILL.md +60 -0
  40. package/src/auth.js +55 -0
  41. package/src/commands/alerts.js +118 -0
  42. package/src/commands/auth.js +43 -0
  43. package/src/commands/doctor.js +87 -0
  44. package/src/commands/init.js +50 -0
  45. package/src/commands/labels.js +48 -0
  46. package/src/commands/options.js +24 -0
  47. package/src/commands/perp.js +59 -0
  48. package/src/commands/polymarket.js +74 -0
  49. package/src/commands/schema.js +31 -0
  50. package/src/commands/token.js +77 -0
  51. package/src/commands/wallet.js +106 -0
  52. package/src/commands/web.js +41 -0
  53. package/src/format.js +83 -0
  54. package/src/index.js +44 -0
  55. package/src/mcp-client.js +94 -0
  56. package/src/util.js +25 -0
@@ -0,0 +1,59 @@
1
+ import { callTool } from '../mcp-client.js';
2
+ import { emit, emitError } from '../format.js';
3
+ import { parseInt10 } from '../util.js';
4
+
5
+ export function registerPerp(program) {
6
+ const cmd = program
7
+ .command('perp')
8
+ .description('Perpetual-futures funding, spreads, and Hyperliquid trader leaderboard');
9
+
10
+ cmd
11
+ .command('funding')
12
+ .description('Funding rates per venue, or cross-venue funding-arb opportunities')
13
+ .option('--symbol <s>', 'Specific symbol (e.g. BTC). Omit for top arb opportunities.')
14
+ .option('--json', 'Emit JSON')
15
+ .action(async (opts) => {
16
+ try {
17
+ const r = await callTool('perp_funding', { symbol: opts.symbol });
18
+ emit(r, opts);
19
+ } catch (err) { emitError(err, opts); }
20
+ });
21
+
22
+ cmd
23
+ .command('spreads')
24
+ .description('Cross-venue spot-perp spread arbitrage opportunities')
25
+ .option('--symbol <s>', 'Specific symbol. Omit for full matrix.')
26
+ .option('--json', 'Emit JSON')
27
+ .action(async (opts) => {
28
+ try {
29
+ const r = await callTool('perp_spreads', { symbol: opts.symbol });
30
+ emit(r, opts);
31
+ } catch (err) { emitError(err, opts); }
32
+ });
33
+
34
+ cmd
35
+ .command('top-traders')
36
+ .description('Top Hyperliquid perp wallets by PnL / ROI / win rate / volume')
37
+ .option('--window <w>', '1d | 7d | 30d | all', '30d')
38
+ .option('--sort <s>', 'pnl | roi | win_rate | volume | trade_count | drawdown', 'pnl')
39
+ .option('--order <o>', 'asc | desc', 'desc')
40
+ .option('--min-trades <n>', 'Minimum trade count', '3')
41
+ .option('--min-win-rate <p>', 'Minimum win rate percent (0-100)', '0')
42
+ .option('--min-volume <usd>', 'Minimum volume USD', '0')
43
+ .option('--size <n>', 'Page size (max 20)', '10')
44
+ .option('--json', 'Emit JSON')
45
+ .action(async (opts) => {
46
+ try {
47
+ const r = await callTool('hl_perp_top_traders', {
48
+ window: opts.window,
49
+ sort: opts.sort,
50
+ order: opts.order,
51
+ min_trades: parseInt10(opts.minTrades, 3),
52
+ min_win_rate: opts.minWinRate,
53
+ min_volume: opts.minVolume,
54
+ size: parseInt10(opts.size, 10),
55
+ });
56
+ emit(r, opts);
57
+ } catch (err) { emitError(err, opts); }
58
+ });
59
+ }
@@ -0,0 +1,74 @@
1
+ import { callTool } from '../mcp-client.js';
2
+ import { emit, emitError } from '../format.js';
3
+ import { parseInt10 } from '../util.js';
4
+
5
+ export function registerPolymarket(program) {
6
+ const cmd = program
7
+ .command('polymarket')
8
+ .alias('pm')
9
+ .description('Polymarket prediction-market analytics (markets, traders, smart money)');
10
+
11
+ cmd
12
+ .command('markets')
13
+ .description('Trending Polymarket markets ranked by 24h volume')
14
+ .option('--category <c>', 'Crypto | Sports | Politics | Pop-Culture | Tech | all', 'all')
15
+ .option('--limit <n>', 'Max markets (max 30)', '10')
16
+ .option('--json', 'Emit JSON')
17
+ .action(async (opts) => {
18
+ try {
19
+ const r = await callTool('polymarket_markets', {
20
+ category: opts.category,
21
+ limit: parseInt10(opts.limit, 10),
22
+ });
23
+ emit(r, opts);
24
+ } catch (err) { emitError(err, opts); }
25
+ });
26
+
27
+ cmd
28
+ .command('market <condition_id>')
29
+ .description('Deep-dive on one Polymarket market by condition_id')
30
+ .option('--json', 'Emit JSON')
31
+ .action(async (conditionId, opts) => {
32
+ try {
33
+ const r = await callTool('polymarket_market_detail', {
34
+ condition_id: conditionId,
35
+ });
36
+ emit(r, opts);
37
+ } catch (err) { emitError(err, opts); }
38
+ });
39
+
40
+ cmd
41
+ .command('wallet <address>')
42
+ .description('Profile a Polymarket trader (PnL / hit-rate / categories)')
43
+ .option('--window <w>', '24h | 7d | 30d | all', 'all')
44
+ .option('--json', 'Emit JSON')
45
+ .action(async (address, opts) => {
46
+ try {
47
+ const r = await callTool('polymarket_wallet', {
48
+ address,
49
+ window: opts.window,
50
+ });
51
+ emit(r, opts);
52
+ } catch (err) { emitError(err, opts); }
53
+ });
54
+
55
+ cmd
56
+ .command('smart-money')
57
+ .description('Smart-money flows or mispricings on Polymarket')
58
+ .option('--mode <m>', 'flows | mispricings', 'flows')
59
+ .option('--hours <n>', 'Lookback hours', '24')
60
+ .option('--category <c>', 'Crypto | Sports | Politics | Pop-Culture | Tech | all', 'all')
61
+ .option('--limit <n>', 'Max rows (max 20)', '10')
62
+ .option('--json', 'Emit JSON')
63
+ .action(async (opts) => {
64
+ try {
65
+ const r = await callTool('polymarket_smart_money', {
66
+ mode: opts.mode,
67
+ hours: parseInt10(opts.hours, 24),
68
+ category: opts.category,
69
+ limit: parseInt10(opts.limit, 10),
70
+ });
71
+ emit(r, opts);
72
+ } catch (err) { emitError(err, opts); }
73
+ });
74
+ }
@@ -0,0 +1,31 @@
1
+ import { listTools } from '../mcp-client.js';
2
+ import { emit, emitError } from '../format.js';
3
+
4
+ export function registerSchema(program) {
5
+ program
6
+ .command('schema')
7
+ .description('Print the full MCP tool schema (names, descriptions, input schemas)')
8
+ .option('--pretty', 'Human-friendly summary instead of raw JSON')
9
+ .option('--json', 'Emit JSON (default)')
10
+ .action(async (opts) => {
11
+ try {
12
+ const tools = await listTools();
13
+ if (opts.pretty) {
14
+ for (const t of tools) {
15
+ console.log(`\n ${t.name}`);
16
+ console.log(` ${(t.description || '').split('\n')[0]}`);
17
+ const props = t.inputSchema?.properties ?? {};
18
+ const required = new Set(t.inputSchema?.required ?? []);
19
+ for (const [k, v] of Object.entries(props)) {
20
+ const tag = required.has(k) ? '(required)' : '';
21
+ const enumStr = Array.isArray(v.enum) ? ` [${v.enum.join('|')}]` : '';
22
+ console.log(` --${k}${enumStr} ${tag}`);
23
+ }
24
+ }
25
+ console.log(`\n${tools.length} tools.`);
26
+ } else {
27
+ emit({ tools }, { json: true });
28
+ }
29
+ } catch (err) { emitError(err, opts); }
30
+ });
31
+ }
@@ -0,0 +1,77 @@
1
+ import { callTool } from '../mcp-client.js';
2
+ import { emit, emitError } from '../format.js';
3
+ import { parseInt10 } from '../util.js';
4
+
5
+ export function registerToken(program) {
6
+ const cmd = program
7
+ .command('token')
8
+ .description('Token search, transfers, and price charts');
9
+
10
+ cmd
11
+ .command('search <query>')
12
+ .description('Search tokens by symbol or name')
13
+ .option('--chain <chain>', 'ethereum | bsc | base', 'ethereum')
14
+ .option('--limit <n>', 'Max results', '10')
15
+ .option('--json', 'Emit JSON')
16
+ .action(async (query, opts) => {
17
+ try {
18
+ const r = await callTool('token_search', {
19
+ query,
20
+ chain: opts.chain,
21
+ limit: parseInt10(opts.limit, 10),
22
+ });
23
+ emit(r, opts);
24
+ } catch (err) { emitError(err, opts); }
25
+ });
26
+
27
+ cmd
28
+ .command('transfers <token_address>')
29
+ .description('Top buyers/sellers for a token in a window')
30
+ .option('--period <p>', '1h | 24h | 7d | 30d', '24h')
31
+ .option('--tab <t>', 'bought | sold', 'sold')
32
+ .option('--chain <chain>', 'ethereum | bsc | base | all', 'ethereum')
33
+ .option('--json', 'Emit JSON')
34
+ .action(async (tokenAddress, opts) => {
35
+ try {
36
+ const r = await callTool('token_transfers', {
37
+ token_address: tokenAddress,
38
+ period: opts.period,
39
+ tab: opts.tab,
40
+ chain: opts.chain,
41
+ });
42
+ emit(r, opts);
43
+ } catch (err) { emitError(err, opts); }
44
+ });
45
+
46
+ cmd
47
+ .command('chart <token_address>')
48
+ .description('OHLCV candle data for a token')
49
+ .option('--interval <m>', '5 | 30 | 120 minutes', '30')
50
+ .option('--json', 'Emit JSON')
51
+ .action(async (tokenAddress, opts) => {
52
+ try {
53
+ const r = await callTool('token_chart', {
54
+ token_address: tokenAddress,
55
+ interval: opts.interval,
56
+ });
57
+ emit(r, opts);
58
+ } catch (err) { emitError(err, opts); }
59
+ });
60
+
61
+ cmd
62
+ .command('holders <token_address>')
63
+ .description('Top holders of a token by cumulative net inflow USD')
64
+ .option('--chain <chain>', 'ethereum | bsc | base', 'ethereum')
65
+ .option('--limit <n>', 'Max holders (max 50)', '10')
66
+ .option('--json', 'Emit JSON')
67
+ .action(async (tokenAddress, opts) => {
68
+ try {
69
+ const r = await callTool('token_holders', {
70
+ token_address: tokenAddress,
71
+ chain: opts.chain,
72
+ limit: parseInt10(opts.limit, 10),
73
+ });
74
+ emit(r, opts);
75
+ } catch (err) { emitError(err, opts); }
76
+ });
77
+ }
@@ -0,0 +1,106 @@
1
+ import { callTool } from '../mcp-client.js';
2
+ import { emit, emitError } from '../format.js';
3
+ import { parseInt10 } from '../util.js';
4
+
5
+ export function registerWallet(program) {
6
+ const cmd = program
7
+ .command('wallet')
8
+ .description('Wallet metrics, discovery, and ranking');
9
+
10
+ cmd
11
+ .command('summary <address>')
12
+ .description('Aggregate metrics: volume / inflow / outflow / pnl across windows')
13
+ .option('--json', 'Emit JSON')
14
+ .action(async (address, opts) => {
15
+ try {
16
+ const r = await callTool('wallet_summary', { address });
17
+ emit(r, opts);
18
+ } catch (err) { emitError(err, opts); }
19
+ });
20
+
21
+ cmd
22
+ .command('counterparties <address>')
23
+ .description('Top trading partners of a wallet by combined transfer volume')
24
+ .option('--chain <c>', 'ethereum | bsc | base', 'ethereum')
25
+ .option('--window <w>', '24h | 7d | 30d | 90d | 180d | all', '30d')
26
+ .option('--limit <n>', 'Max counterparties (max 50)', '10')
27
+ .option('--json', 'Emit JSON')
28
+ .action(async (address, opts) => {
29
+ try {
30
+ const r = await callTool('wallet_counterparties', {
31
+ address,
32
+ chain: opts.chain,
33
+ window: opts.window,
34
+ limit: parseInt10(opts.limit, 10),
35
+ });
36
+ emit(r, opts);
37
+ } catch (err) { emitError(err, opts); }
38
+ });
39
+
40
+ cmd
41
+ .command('pnl-history <address>')
42
+ .description('Daily net-flow series (proxy for daily PnL)')
43
+ .option('--chain <c>', 'ethereum | bsc | base', 'ethereum')
44
+ .option('--days <n>', 'Days back (max 365)', '30')
45
+ .option('--json', 'Emit JSON')
46
+ .action(async (address, opts) => {
47
+ try {
48
+ const r = await callTool('wallet_pnl_history', {
49
+ address,
50
+ chain: opts.chain,
51
+ days: parseInt10(opts.days, 30),
52
+ });
53
+ emit(r, opts);
54
+ } catch (err) { emitError(err, opts); }
55
+ });
56
+
57
+ cmd
58
+ .command('balances <address>')
59
+ .description('Current ERC-20 holdings across major EVM chains')
60
+ .option('--chains <list>', 'Comma-separated chains (eth,bsc,base,arbitrum,polygon,optimism)')
61
+ .option('--min-usd <n>', 'Filter dust below this USD value', '1')
62
+ .option('--json', 'Emit JSON')
63
+ .action(async (address, opts) => {
64
+ try {
65
+ const payload = { address, min_usd: opts.minUsd };
66
+ if (opts.chains) {
67
+ payload.chains = opts.chains.split(',').map((c) => c.trim()).filter(Boolean);
68
+ }
69
+ const r = await callTool('wallet_token_balances', payload);
70
+ emit(r, opts);
71
+ } catch (err) { emitError(err, opts); }
72
+ });
73
+
74
+ cmd
75
+ .command('ens <address>')
76
+ .description('Reverse ENS lookup: address → vitalik.eth style name')
77
+ .option('--json', 'Emit JSON')
78
+ .action(async (address, opts) => {
79
+ try {
80
+ const r = await callTool('wallet_ens', { address });
81
+ emit(r, opts);
82
+ } catch (err) { emitError(err, opts); }
83
+ });
84
+
85
+ cmd
86
+ .command('discover')
87
+ .description('Top wallets ranked by volume / inflow / outflow / pnl / net_flow / tx_count')
88
+ .option('--window <w>', '24h | 7d | 30d | 90d | all', '30d')
89
+ .option('--sort <s>', 'volume | inflow | outflow | net_flow | tx_count | pnl', 'volume')
90
+ .option('--order <o>', 'asc | desc', 'desc')
91
+ .option('--chain <c>', 'ethereum | bsc', 'ethereum')
92
+ .option('--size <n>', 'Page size (max 20)', '10')
93
+ .option('--json', 'Emit JSON')
94
+ .action(async (opts) => {
95
+ try {
96
+ const r = await callTool('wallet_discover', {
97
+ window: opts.window,
98
+ sort: opts.sort,
99
+ order: opts.order,
100
+ chain: opts.chain,
101
+ size: parseInt10(opts.size, 10),
102
+ });
103
+ emit(r, opts);
104
+ } catch (err) { emitError(err, opts); }
105
+ });
106
+ }
@@ -0,0 +1,41 @@
1
+ import { callTool } from '../mcp-client.js';
2
+ import { emit, emitError } from '../format.js';
3
+ import { parseInt10 } from '../util.js';
4
+
5
+ export function registerWeb(program) {
6
+ const cmd = program
7
+ .command('web')
8
+ .description('Web search + fetch (Tavily / Serper / Cerebras)');
9
+
10
+ cmd
11
+ .command('search <query...>')
12
+ .description('Web search (Tavily primary, Serper Google fallback)')
13
+ .option('--max <n>', 'Max results (default 5, max 10)', '5')
14
+ .option('--depth <d>', 'Tavily depth: basic | advanced', 'basic')
15
+ .option('--json', 'Emit JSON')
16
+ .action(async (queryParts, opts) => {
17
+ try {
18
+ const r = await callTool('web_search', {
19
+ query: queryParts.join(' '),
20
+ max_results: parseInt10(opts.max, 5),
21
+ search_depth: opts.depth,
22
+ });
23
+ emit(r, opts);
24
+ } catch (err) { emitError(err, opts); }
25
+ });
26
+
27
+ cmd
28
+ .command('fetch <url>')
29
+ .description('Fetch URL and optionally answer a question about it')
30
+ .option('--ask <question>', 'Question to answer from the content (uses Cerebras)')
31
+ .option('--json', 'Emit JSON')
32
+ .action(async (url, opts) => {
33
+ try {
34
+ const r = await callTool('web_fetch', {
35
+ url,
36
+ question: opts.ask,
37
+ });
38
+ emit(r, opts);
39
+ } catch (err) { emitError(err, opts); }
40
+ });
41
+ }
package/src/format.js ADDED
@@ -0,0 +1,83 @@
1
+ // Output formatting — pretty-print for humans, JSON for pipes.
2
+
3
+ export function isJsonMode(opts) {
4
+ return Boolean(opts?.json) || !process.stdout.isTTY;
5
+ }
6
+
7
+ export function emit(data, opts = {}) {
8
+ if (isJsonMode(opts)) {
9
+ process.stdout.write(JSON.stringify(data, null, 2) + '\n');
10
+ return;
11
+ }
12
+ // Human mode: light formatting for arrays of objects (most MCP responses).
13
+ if (Array.isArray(data)) {
14
+ if (data.length === 0) {
15
+ console.log('(no results)');
16
+ return;
17
+ }
18
+ printTable(data);
19
+ return;
20
+ }
21
+ if (data && typeof data === 'object') {
22
+ if (data.error) {
23
+ console.error(`error: ${data.error}`);
24
+ process.exitCode = 1;
25
+ return;
26
+ }
27
+ // If it has a single array prop, print that as table.
28
+ const arrayKey = Object.keys(data).find((k) => Array.isArray(data[k]));
29
+ if (arrayKey && Object.keys(data).length <= 3) {
30
+ printTable(data[arrayKey]);
31
+ return;
32
+ }
33
+ console.log(JSON.stringify(data, null, 2));
34
+ return;
35
+ }
36
+ console.log(String(data));
37
+ }
38
+
39
+ function printTable(rows) {
40
+ if (!rows.length) {
41
+ console.log('(empty)');
42
+ return;
43
+ }
44
+ // Collect a stable column order from the first row, then keep any
45
+ // new keys at the end. Truncate values >80 chars.
46
+ const cols = [];
47
+ const seen = new Set();
48
+ for (const row of rows) {
49
+ for (const k of Object.keys(row || {})) {
50
+ if (!seen.has(k)) { seen.add(k); cols.push(k); }
51
+ }
52
+ }
53
+ const widths = cols.map((c) => Math.min(40, Math.max(c.length, ...rows.map((r) => fmt(r?.[c]).length))));
54
+ const sep = ' ';
55
+ console.log(cols.map((c, i) => c.padEnd(widths[i])).join(sep));
56
+ console.log(widths.map((w) => '-'.repeat(w)).join(sep));
57
+ for (const row of rows) {
58
+ console.log(cols.map((c, i) => fmt(row?.[c]).padEnd(widths[i])).join(sep));
59
+ }
60
+ }
61
+
62
+ function fmt(v) {
63
+ if (v === null || v === undefined) return '';
64
+ if (typeof v === 'number') {
65
+ if (Math.abs(v) >= 1e9) return (v / 1e9).toFixed(2) + 'B';
66
+ if (Math.abs(v) >= 1e6) return (v / 1e6).toFixed(2) + 'M';
67
+ if (Math.abs(v) >= 1e3) return (v / 1e3).toFixed(2) + 'K';
68
+ return String(v);
69
+ }
70
+ if (typeof v === 'object') return JSON.stringify(v);
71
+ const s = String(v);
72
+ return s.length > 80 ? s.slice(0, 77) + '...' : s;
73
+ }
74
+
75
+ export function emitError(err, opts = {}) {
76
+ const msg = err?.message ?? String(err);
77
+ if (isJsonMode(opts)) {
78
+ process.stdout.write(JSON.stringify({ error: msg }) + '\n');
79
+ } else {
80
+ console.error(`vike: ${msg}`);
81
+ }
82
+ process.exitCode = 1;
83
+ }
package/src/index.js ADDED
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import { registerToken } from './commands/token.js';
4
+ import { registerWallet } from './commands/wallet.js';
5
+ import { registerPerp } from './commands/perp.js';
6
+ import { registerOptions } from './commands/options.js';
7
+ import { registerAlerts } from './commands/alerts.js';
8
+ import { registerPolymarket } from './commands/polymarket.js';
9
+ import { registerLabels } from './commands/labels.js';
10
+ import { registerWeb } from './commands/web.js';
11
+ // Note: registerLabels also registers `vike funds` and `vike defi` top-level
12
+ // commands. New wallet subcommands (counterparties, pnl-history, balances,
13
+ // ens) are added under registerWallet.
14
+ import { registerInit } from './commands/init.js';
15
+ import { registerDoctor } from './commands/doctor.js';
16
+ import { registerSchema } from './commands/schema.js';
17
+ import { registerLogin, registerLogout } from './commands/auth.js';
18
+ import { readPackageVersion } from './util.js';
19
+
20
+ const program = new Command();
21
+
22
+ program
23
+ .name('vike')
24
+ .description('AI-agent CLI for vike.io on-chain analytics')
25
+ .version(readPackageVersion(), '-v, --version', 'Show CLI version');
26
+
27
+ registerLogin(program);
28
+ registerLogout(program);
29
+ registerInit(program);
30
+ registerDoctor(program);
31
+ registerSchema(program);
32
+ registerToken(program);
33
+ registerWallet(program);
34
+ registerPerp(program);
35
+ registerOptions(program);
36
+ registerAlerts(program);
37
+ registerPolymarket(program);
38
+ registerLabels(program);
39
+ registerWeb(program);
40
+
41
+ program.parseAsync(process.argv).catch((err) => {
42
+ console.error(`vike: ${err.message ?? err}`);
43
+ process.exitCode = 1;
44
+ });
@@ -0,0 +1,94 @@
1
+ import { requireApiKey, getEndpoint, getApiKey } from './auth.js';
2
+
3
+ let _id = 0;
4
+ function nextId() { return ++_id; }
5
+
6
+ export async function callTool(toolName, args = {}, opts = {}) {
7
+ const apiKey = opts.apiKey ?? requireApiKey();
8
+ const endpoint = opts.endpoint ?? getEndpoint();
9
+ const timeoutMs = opts.timeoutMs ?? 60_000;
10
+
11
+ const body = {
12
+ jsonrpc: '2.0',
13
+ id: nextId(),
14
+ method: 'tools/call',
15
+ params: { name: toolName, arguments: args },
16
+ };
17
+
18
+ const ctrl = new AbortController();
19
+ const t = setTimeout(() => ctrl.abort(), timeoutMs);
20
+
21
+ let resp;
22
+ try {
23
+ resp = await fetch(endpoint, {
24
+ method: 'POST',
25
+ headers: {
26
+ 'Content-Type': 'application/json',
27
+ 'X-API-KEY': apiKey,
28
+ 'User-Agent': `vike-cli/${process.env.npm_package_version ?? 'dev'}`,
29
+ },
30
+ body: JSON.stringify(body),
31
+ signal: ctrl.signal,
32
+ });
33
+ } catch (err) {
34
+ if (err.name === 'AbortError') {
35
+ throw new Error(`Request timed out after ${timeoutMs}ms`);
36
+ }
37
+ throw new Error(`Network error: ${err.message}`);
38
+ } finally {
39
+ clearTimeout(t);
40
+ }
41
+
42
+ const text = await resp.text();
43
+ let json;
44
+ try { json = JSON.parse(text); } catch {
45
+ throw new Error(`Bad response (HTTP ${resp.status}): ${text.slice(0, 200)}`);
46
+ }
47
+
48
+ if (json.error) {
49
+ const msg = json.error.message ?? 'Unknown MCP error';
50
+ throw new Error(`MCP error ${json.error.code}: ${msg}`);
51
+ }
52
+
53
+ // tools/call returns { content: [{type:'text', text: JSON}], isError }
54
+ const content = json.result?.content?.[0]?.text;
55
+ if (!content) return json.result;
56
+ try { return JSON.parse(content); } catch {
57
+ return content;
58
+ }
59
+ }
60
+
61
+ export async function listTools(opts = {}) {
62
+ const apiKey = opts.apiKey ?? requireApiKey();
63
+ const endpoint = opts.endpoint ?? getEndpoint();
64
+ const body = {
65
+ jsonrpc: '2.0',
66
+ id: nextId(),
67
+ method: 'tools/list',
68
+ params: {},
69
+ };
70
+ const resp = await fetch(endpoint, {
71
+ method: 'POST',
72
+ headers: { 'Content-Type': 'application/json', 'X-API-KEY': apiKey },
73
+ body: JSON.stringify(body),
74
+ });
75
+ const json = await resp.json();
76
+ if (json.error) throw new Error(json.error.message);
77
+ return json.result?.tools ?? [];
78
+ }
79
+
80
+ export async function ping(opts = {}) {
81
+ // initialize doesn't require auth — useful for `vike doctor`
82
+ const endpoint = opts.endpoint ?? getEndpoint();
83
+ const apiKey = opts.apiKey ?? getApiKey();
84
+ const headers = { 'Content-Type': 'application/json' };
85
+ if (apiKey) headers['X-API-KEY'] = apiKey;
86
+ const resp = await fetch(endpoint, {
87
+ method: 'POST',
88
+ headers,
89
+ body: JSON.stringify({
90
+ jsonrpc: '2.0', id: nextId(), method: 'initialize', params: {},
91
+ }),
92
+ });
93
+ return { status: resp.status, body: await resp.json() };
94
+ }
package/src/util.js ADDED
@@ -0,0 +1,25 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, join } from 'node:path';
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+
8
+ export function readPackageVersion() {
9
+ const pkgPath = join(__dirname, '..', 'package.json');
10
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
11
+ return pkg.version;
12
+ }
13
+
14
+ export function parseBool(v, fallback = false) {
15
+ if (v === undefined || v === null || v === '') return fallback;
16
+ if (typeof v === 'boolean') return v;
17
+ const s = String(v).toLowerCase();
18
+ return s === 'true' || s === '1' || s === 'yes' || s === 'y';
19
+ }
20
+
21
+ export function parseInt10(v, fallback) {
22
+ if (v === undefined || v === null || v === '') return fallback;
23
+ const n = parseInt(v, 10);
24
+ return Number.isFinite(n) ? n : fallback;
25
+ }