alpha-cli-toolkit 1.0.0 → 1.2.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.
- package/bin/alpha.js +66 -3
- package/package.json +1 -1
- package/utils/auth.js +2 -6
package/bin/alpha.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
require('dotenv').config();
|
|
2
3
|
const { Command } = require('commander');
|
|
3
4
|
const chalk = require('chalk');
|
|
4
5
|
const gradient = require('gradient-string');
|
|
@@ -6,7 +7,7 @@ const Table = require('cli-table3');
|
|
|
6
7
|
const { authenticateViaBrowser, getToken, clearToken } = require('../utils/auth');
|
|
7
8
|
|
|
8
9
|
const program = new Command();
|
|
9
|
-
const BACKEND_URL = process.env.ALPHA_BACKEND_URL
|
|
10
|
+
const BACKEND_URL = process.env.ALPHA_BACKEND_URL;
|
|
10
11
|
|
|
11
12
|
program
|
|
12
13
|
.name('alpha')
|
|
@@ -70,11 +71,12 @@ program
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
// Backend health
|
|
74
|
+
const healthUrl = BACKEND_URL ? `${BACKEND_URL.replace(/\/api$/, '')}/health` : 'http://localhost:4000/health';
|
|
73
75
|
try {
|
|
74
|
-
const { data } = await axios.get(
|
|
76
|
+
const { data } = await axios.get(healthUrl, { timeout: 3000 });
|
|
75
77
|
console.log(chalk.green(' ✅ Backend online') + chalk.grey(` (${data.timestamp})`));
|
|
76
78
|
} catch {
|
|
77
|
-
console.log(chalk.red(' ❌ Backend offline') + chalk.grey(
|
|
79
|
+
console.log(chalk.red(' ❌ Backend offline') + chalk.grey(` — check your BACKEND_URL or start it with \`npm run dev\` in /backend`));
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
console.log('');
|
|
@@ -107,6 +109,8 @@ program
|
|
|
107
109
|
.option('-c, --crypto', 'Trending crypto from Nansen (default)')
|
|
108
110
|
.option('-s, --sp500', 'Trending S&P 500 assets via Yahoo Finance')
|
|
109
111
|
.option('-n, --nsd', 'Trending NASDAQ assets via Yahoo Finance')
|
|
112
|
+
.option('-f, --nft', 'NFT Market Indexes (Nansen)')
|
|
113
|
+
.option('-m, --macro', 'Smart Money Holdings \u0026 Macro (Nansen)')
|
|
110
114
|
.action(async (options) => {
|
|
111
115
|
const token = checkAuth();
|
|
112
116
|
const axios = require('axios');
|
|
@@ -116,6 +120,23 @@ program
|
|
|
116
120
|
|
|
117
121
|
if (options.sp500) { url = `${BACKEND_URL}/market/tradfi/sp500`; cType = 'S&P 500'; }
|
|
118
122
|
else if (options.nsd) { url = `${BACKEND_URL}/market/tradfi/nsd`; cType = 'NASDAQ'; }
|
|
123
|
+
else if (options.nft || options.macro) {
|
|
124
|
+
console.log(chalk.cyan(`\n🔍 Fetching Nansen Market Macro Insights...`));
|
|
125
|
+
try {
|
|
126
|
+
const { data } = await axios.get(`${BACKEND_URL}/market/macro`, { headers: authHeaders(token) });
|
|
127
|
+
if (options.nft) {
|
|
128
|
+
console.log(gradient.atlas(`\n─── Nansen NFT Indexes ──────────────────────────`));
|
|
129
|
+
console.log(JSON.stringify(data.nftIndexes, null, 2));
|
|
130
|
+
} else {
|
|
131
|
+
console.log(gradient.atlas(`\n─── Smart Money Holdings ─────────────────────────`));
|
|
132
|
+
console.log(JSON.stringify(data.smartMoneyHoldings, null, 2));
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
} catch (err) {
|
|
136
|
+
console.error(chalk.red('Macro fetch failed:'), err.response?.data?.error || err.message);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
119
140
|
|
|
120
141
|
console.log(chalk.cyan(`\n🔍 Fetching ${cType} market data...`));
|
|
121
142
|
|
|
@@ -169,6 +190,48 @@ program
|
|
|
169
190
|
}
|
|
170
191
|
});
|
|
171
192
|
|
|
193
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
194
|
+
// WALLET COMMAND
|
|
195
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
196
|
+
program
|
|
197
|
+
.command('wallet <address>')
|
|
198
|
+
.description('Deep dive into a wallet using Nansen Profiler \u0026 Balances')
|
|
199
|
+
.action(async (address) => {
|
|
200
|
+
const token = checkAuth();
|
|
201
|
+
const axios = require('axios');
|
|
202
|
+
|
|
203
|
+
console.log(chalk.cyan(`\n🔍 Profiling wallet: ${chalk.bold(address)}...`));
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
const { data } = await axios.get(`${BACKEND_URL}/market/wallet/${address}`, { headers: authHeaders(token) });
|
|
207
|
+
console.log(gradient.atlas(`\n─── Nansen Wallet Insights ──────────────────────`));
|
|
208
|
+
console.log(JSON.stringify(data, null, 2));
|
|
209
|
+
} catch (err) {
|
|
210
|
+
console.error(chalk.red('Wallet profiling failed:'), err.response?.data?.error || err.message);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
215
|
+
// ENTITY COMMAND
|
|
216
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
217
|
+
program
|
|
218
|
+
.command('entity <name>')
|
|
219
|
+
.description('Track token flows for a specific entity (e.g., Binance, Alameda)')
|
|
220
|
+
.action(async (name) => {
|
|
221
|
+
const token = checkAuth();
|
|
222
|
+
const axios = require('axios');
|
|
223
|
+
|
|
224
|
+
console.log(chalk.cyan(`\n🔍 Tracking entity flows: ${chalk.bold(name)}...`));
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
const { data } = await axios.get(`${BACKEND_URL}/market/entities/${name}`, { headers: authHeaders(token) });
|
|
228
|
+
console.log(gradient.atlas(`\n─── Nansen Entity Flows: ${name.toUpperCase()} ───`));
|
|
229
|
+
console.log(JSON.stringify(data.flows, null, 2));
|
|
230
|
+
} catch (err) {
|
|
231
|
+
console.error(chalk.red('Entity tracking failed:'), err.response?.data?.error || err.message);
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
172
235
|
program
|
|
173
236
|
.command('positions')
|
|
174
237
|
.description('View your simulated portfolio and open positions')
|
package/package.json
CHANGED
package/utils/auth.js
CHANGED
|
@@ -44,10 +44,6 @@ function setToken(token) {
|
|
|
44
44
|
|
|
45
45
|
// ─── Browser-based Phantom auth flow ─────────────────────────────────────────
|
|
46
46
|
|
|
47
|
-
/**
|
|
48
|
-
* Spins up a local temporary server and opens the Next.js UI
|
|
49
|
-
* to capture the Phantom wallet authentication token.
|
|
50
|
-
*/
|
|
51
47
|
async function authenticateViaBrowser() {
|
|
52
48
|
return new Promise(async (resolve, reject) => {
|
|
53
49
|
const server = http.createServer((req, res) => {
|
|
@@ -82,9 +78,9 @@ async function authenticateViaBrowser() {
|
|
|
82
78
|
});
|
|
83
79
|
|
|
84
80
|
server.listen(0, async () => {
|
|
81
|
+
const FRONTEND_URL = process.env.FRONTEND_URL || 'https://alpha-cli-ui.vercel.app';
|
|
85
82
|
const port = server.address().port;
|
|
86
|
-
const
|
|
87
|
-
const loginUrl = `http://localhost:3000/?callback=${encodeURIComponent(callbackUrl)}`;
|
|
83
|
+
const loginUrl = `${FRONTEND_URL}/?callback=${encodeURIComponent(`http://localhost:${port}`)}`;
|
|
88
84
|
|
|
89
85
|
// Dynamic import for `open` (ESM-only since v9)
|
|
90
86
|
const open = (await import('open')).default;
|