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