solana-tui-explorer 1.0.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/st.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('../index.js');
package/config.js ADDED
@@ -0,0 +1,87 @@
1
+ // =============================================
2
+ // SOLANA TUI EXPLORER CLI — Config
3
+ // =============================================
4
+
5
+ module.exports = {
6
+ // Solana Public RPC — override via SOLANA_RPC in .env for better reliability
7
+ SOLANA_RPC: process.env.SOLANA_RPC || 'https://api.mainnet-beta.solana.com',
8
+
9
+ // High-capacity public node for heavy Explorer queries
10
+ EXPLORER_RPC: 'https://solana-rpc.publicnode.com',
11
+
12
+ // DexScreener (Solana token prices — free, no key)
13
+ DEXSCREENER_BASE: 'https://api.dexscreener.com',
14
+
15
+ // CoinDesk Data API (major crypto prices — free tier works without key)
16
+ // Set COINDESK_API_KEY env var when you have one for higher rate limits.
17
+ COINDESK_BASE: 'https://data-api.coindesk.com',
18
+ COINDESK_MARKET: process.env.COINDESK_MARKET || 'coinbase',
19
+ COINDESK_API_KEY: process.env.COINDESK_API_KEY || '',
20
+ BIRDEYE_API_KEY: process.env.BIRDEYE_API_KEY || '',
21
+ RUGCHECK_API_KEY: process.env.RUGCHECK_API_KEY || '',
22
+ WHALE_ALERT_API_KEY: process.env.WHALE_ALERT_API_KEY || '',
23
+ BITQUERY_API_KEY: process.env.BITQUERY_API_KEY || '',
24
+ CRYPTOPANIC_API_KEY: process.env.CRYPTOPANIC_API_KEY || '',
25
+ COINMARKETCAP_API_KEY: process.env.COINMARKETCAP_API_KEY || '',
26
+
27
+ // SECURE BACKEND PROXY
28
+ // Routes traffic through our AWS EC2 instance instead of exposing keys to clients
29
+ PROXY_URL: process.env.PROXY_URL || 'http://100.26.192.172:3000',
30
+
31
+ AI_MODEL: 'llama-3.3-70b-versatile',
32
+ AI_SYSTEM_PROMPT: 'You are the Antigravity Solana Developer TUI AI. You act as an expert Solana systems developer, smart contract compiler, and transaction debugger. Help developers diagnose RPC simulation failures, decode hexadecimal transaction instruction error codes, explain Anchor constraints, and optimize compute units. Your responses must be concise, technical, and formatted for a terminal (no markdown headers, use plain text with accents).',
33
+ FAIRSCALE_API_KEY: process.env.FAIRSCALE_API_KEY || '',
34
+
35
+ // Major cryptos — fetched from CoinDesk (accurate spot prices in USD)
36
+ COINDESK_SYMBOLS: ['BTC', 'ETH', 'SOL'],
37
+
38
+ // Solana-native tokens — fetched from DexScreener
39
+ DEX_SYMBOLS: ['BONK','WIF','JUP','PYTH','RAY','ORCA','DRIFT','RENDER','POPCAT','FARTCOIN','TRUMP'],
40
+
41
+ // Combined display order (CoinDesk first, then DEX tokens)
42
+ MARKET_SYMBOLS: ['SOL','BTC','ETH','BONK','WIF','JUP','PYTH','RAY','ORCA','DRIFT','RENDER','POPCAT','FARTCOIN','TRUMP'],
43
+
44
+ // ── Token mint addresses on Solana (for DexScreener) ───────────
45
+ TOKEN_MINTS: {
46
+ SOL: 'So11111111111111111111111111111111111111112',
47
+ BTC: '9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E', // Portal wBTC
48
+ ETH: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs', // Portal wETH
49
+ BONK: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',
50
+ WIF: 'EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm',
51
+ JUP: 'JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN',
52
+ PYTH: 'HZ1JovNiVvGrGNiiYvEozEVgZ58xaU3RKwX8eACQBCt3',
53
+ RAY: '4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R',
54
+ ORCA: 'orcaEKTdK7LKz57vaAYr9QeNsVEPfiu6QeMU1kektZE',
55
+ DRIFT: 'DriFtupJYLTosbwoN8koMbEYSx54aFAVLddWsbksjwg7',
56
+ RENDER: 'rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof',
57
+ POPCAT: '7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr',
58
+ FARTCOIN: '9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump',
59
+ TRUMP: '6p6xgHyF7AeE6TZkSmFsko444wqoP15icUSqi2jfGiPN',
60
+ },
61
+
62
+ TOKEN_NAMES: {
63
+ SOL: 'Solana',
64
+ BTC: 'Bitcoin',
65
+ ETH: 'Ethereum',
66
+ BONK: 'Bonk',
67
+ WIF: 'dogwifhat',
68
+ JUP: 'Jupiter',
69
+ PYTH: 'Pyth Network',
70
+ RAY: 'Raydium',
71
+ ORCA: 'Orca',
72
+ DRIFT: 'Drift Protocol',
73
+ RENDER: 'Render',
74
+ POPCAT: 'Popcat',
75
+ FARTCOIN: 'Fartcoin',
76
+ TRUMP: 'Official Trump',
77
+ },
78
+
79
+ // Refresh intervals (ms)
80
+ MARKET_REFRESH_MS: 30000,
81
+ NETWORK_REFRESH_MS: 30000,
82
+ TOKEN_REFRESH_MS: 30000,
83
+ WALLET_REFRESH_MS: 60000,
84
+
85
+ // Local testing session path
86
+ LITESVM_SESSION_PATH: process.env.LITESVM_SESSION_PATH || 'litesvm-session.json',
87
+ };
package/data.js ADDED
@@ -0,0 +1,197 @@
1
+ // =============================================
2
+ // SOLANA TUI EXPLORER CLI — Live Data Store
3
+ // This module holds the current live state.
4
+ // dashboard.js calls loadMarketData(), loadNetworkData(), etc.
5
+ // Each returns the updated store or throws on failure.
6
+ // =============================================
7
+
8
+ const API = require('./api');
9
+ const CFG = require('./config');
10
+ const { fetchNewsAggregated } = API;
11
+
12
+ // ── Live data store ────────────────────────────────────
13
+ const DATA = {
14
+ // Populated by loadMarketData()
15
+ market: [],
16
+ topGainers: [],
17
+ topLosers: [],
18
+ sparklines: {},
19
+ chartData: { x: [], y: [] },
20
+ priceExchanges: [], // not available from DexScreener — show empty
21
+
22
+ // Populated by loadNetworkData()
23
+ networkStats: null,
24
+
25
+ // Populated on demand by loadWalletData(address)
26
+ wallet: null,
27
+
28
+ // Populated on demand by loadTokenData(mintOrSymbol)
29
+ token: null,
30
+
31
+ // Static/dummy — live feed is simulated from on-chain data
32
+ liveFeed: [
33
+ { type: 'SWAP', text: 'SWAP 10,420,000 BONK → 243.8 SOL via Jupiter [4kXm...9nQr]' },
34
+ { type: 'BUY', text: 'BUY 2,400 WIF ($6,888) on Raydium [7pLn...2wKs]' },
35
+ { type: 'WHALE', text: 'WHALE 50,000 SOL moved from Binance [2rMk...8vPt]' },
36
+ { type: 'SWAP', text: 'SWAP 84,200 USDC → 590 SOL via Orca [9sNp...5hJu]' },
37
+ { type: 'ALERT', text: 'VOL SPIKE BONK +5% in 45min — unusual activity' },
38
+ { type: 'BUY', text: 'BUY 120,000,000 BONK ($2,809) large wallet [6tQr...1dCv]' },
39
+ { type: 'SWAP', text: 'SWAP 500 JUP → 402 USDC via Jupiter [3mNk...7rQs]' },
40
+ { type: 'WHALE', text: 'WHALE 15,000 SOL staked new validator [8vLq...1uRp]' },
41
+ ],
42
+
43
+ // Explorer Tab state
44
+ explorer: {
45
+ list: [],
46
+ details: null,
47
+ loading: false,
48
+ error: null
49
+ },
50
+
51
+ // Alerts are static (no free alert API available)
52
+ alerts: [
53
+ { id: 'ALT001', token: 'SOL', condition: 'PRICE > $150', status: 'ACTIVE', triggered: false, created: '04-14 09:00', triggeredAt: null },
54
+ { id: 'ALT002', token: 'BONK', condition: 'VOL SPIKE > 50%/1h', status: 'TRIGGERED', triggered: true, created: '04-14 10:30', triggeredAt: '22:18:03' },
55
+ { id: 'ALT003', token: 'WIF', condition: 'PRICE > $3.00', status: 'ACTIVE', triggered: false, created: '04-14 11:15', triggeredAt: null },
56
+ { id: 'ALT004', token: 'ANY', condition: 'WHALE > $500K move', status: 'TRIGGERED', triggered: true, created: '04-14 08:00', triggeredAt: '21:47:22' },
57
+ { id: 'ALT005', token: 'JUP', condition: 'PRICE < $1.00', status: 'ACTIVE', triggered: false, created: '04-13 18:00', triggeredAt: null },
58
+ ],
59
+
60
+ // Populated by loadNewsData() — live aggregated news
61
+ news: [],
62
+ newsLastUpdated: null,
63
+ newsLoading: false,
64
+ };
65
+
66
+ // ═════════════════════════════════════════════════════════
67
+ // LOAD FUNCTIONS — called by dashboard.js
68
+ // ═════════════════════════════════════════════════════════
69
+
70
+ async function loadMarketData() {
71
+ const [result, macro] = await Promise.all([
72
+ API.fetchMarketData(),
73
+ API.fetchCMCMacroData()
74
+ ]);
75
+ DATA.market = result.market;
76
+ DATA.topGainers = result.topGainers;
77
+ DATA.topLosers = result.topLosers;
78
+ DATA.sparklines = result.sparklines;
79
+ DATA.chartData = result.chartData;
80
+ DATA.macro = macro || {
81
+ marketCap: 0, marketCapChange: 0, globalVolume: 0, globalVolumeChange: 0,
82
+ fearGreedValue: 50, fearGreedClass: 'Neutral', altcoinIndex: 35
83
+ };
84
+ return DATA;
85
+ }
86
+
87
+ async function loadNetworkData() {
88
+ const [epoch, tpsData, blocktimeData, validators, supply] = await Promise.all([
89
+ API.fetchEpochInfo(),
90
+ API.fetchTPS(),
91
+ API.fetchBlocktime(),
92
+ API.fetchValidators(),
93
+ API.fetchSupply(),
94
+ ]);
95
+
96
+ supply.epoch = epoch.current;
97
+
98
+ // Try to find SOL price from DexScreener if available to calculate totalStakedUsd
99
+ let solPrice = 145.0; // fallback default
100
+ try {
101
+ const solData = await API.fetchTokenData('So11111111111111111111111111111111111111112');
102
+ if (solData && solData.price) solPrice = solData.price;
103
+ } catch (e) {
104
+ // ignore
105
+ }
106
+
107
+ // Build networkStats in the shape dashboard.js expects
108
+ DATA.networkStats = {
109
+ epoch,
110
+ tps: tpsData,
111
+ blocktime: blocktimeData,
112
+ validators,
113
+ supply,
114
+ stakeData: {
115
+ totalStaked: supply.staked.toFixed(1) + 'M SOL',
116
+ totalStakedUsd: '$' + (supply.staked * solPrice / 1e3).toFixed(1) + 'B',
117
+ activeStakers: '—',
118
+ uniqueWallets: '—',
119
+ biggestStake: '—',
120
+ medianStake: '—',
121
+ meanStake: '—',
122
+ filterApy: supply.stakingApy + '%',
123
+ updated: 'just now',
124
+ },
125
+ // Stake graph — approximate from epoch data
126
+ stakeGraph: Array.from({ length: 8 }, (_, i) => ({
127
+ epoch: epoch.current - (7 - i) * 50,
128
+ sol: parseFloat((supply.staked * (0.95 + Math.random() * 0.1)).toFixed(2)),
129
+ })).concat([{ epoch: epoch.current, sol: supply.staked }]),
130
+ stakeDistribution: [], // Would need a staking indexer
131
+ };
132
+ return DATA;
133
+ }
134
+
135
+ async function loadWalletData(address) {
136
+ const [result, score] = await Promise.all([
137
+ API.fetchWalletData(address),
138
+ API.fetchFairScaleScore(address)
139
+ ]);
140
+ result.fairScale = score;
141
+ DATA.wallet = result;
142
+ return DATA;
143
+ }
144
+
145
+ async function loadTokenData(mintOrSymbol, timeframe) {
146
+ const [result, socials] = await Promise.all([
147
+ API.fetchTokenData(mintOrSymbol, timeframe),
148
+ API.fetchTwitterRSS(mintOrSymbol)
149
+ ]);
150
+ DATA.token = result;
151
+ DATA.tokenSocials = socials;
152
+ return DATA;
153
+ }
154
+
155
+ async function loadNewsData() {
156
+ DATA.newsLoading = true;
157
+ const [items, defaultSocials] = await Promise.all([
158
+ API.fetchNewsAggregated(),
159
+ API.fetchTwitterRSS('solana')
160
+ ]);
161
+ DATA.news = items;
162
+ if (defaultSocials) DATA.tokenSocials = defaultSocials;
163
+ DATA.newsLastUpdated = new Date();
164
+ DATA.newsLoading = false;
165
+ return DATA;
166
+ }
167
+
168
+ // ── Explorer Data Loaders ─────────────────────────────────
169
+ async function loadExplorerList() {
170
+ DATA.explorer.loading = true;
171
+ try {
172
+ const list = await API.fetchLatestTransactions();
173
+ DATA.explorer.list = list;
174
+ DATA.explorer.error = null;
175
+ } catch (e) {
176
+ DATA.explorer.error = e.message;
177
+ }
178
+ DATA.explorer.loading = false;
179
+ return DATA;
180
+ }
181
+
182
+ async function loadExplorerDetails(signature) {
183
+ DATA.explorer.loading = true;
184
+ DATA.explorer.details = null;
185
+ try {
186
+ const details = await API.fetchTransactionDetails(signature);
187
+ if (details.error) throw new Error(details.error);
188
+ DATA.explorer.details = details;
189
+ DATA.explorer.error = null;
190
+ } catch (e) {
191
+ DATA.explorer.error = e.message;
192
+ }
193
+ DATA.explorer.loading = false;
194
+ return DATA;
195
+ }
196
+
197
+ module.exports = { DATA, loadMarketData, loadNetworkData, loadWalletData, loadTokenData, loadNewsData, loadExplorerList, loadExplorerDetails };
package/index.js ADDED
@@ -0,0 +1,61 @@
1
+ // Force truecolor for Blessed layout engine on Windows
2
+ process.env.COLORTERM = 'truecolor';
3
+
4
+ // Load .env FIRST — before any other require() reads process.env
5
+ require('dotenv').config({ path: require('path').resolve(__dirname, '.env') });
6
+
7
+ const { program } = require('commander');
8
+ const chalk = require('chalk');
9
+ const clear = require('clear');
10
+ const { renderWallet } = require('./panels/wallet');
11
+ const { renderToken } = require('./panels/token');
12
+
13
+ const { startDashboard } = require('./panels/dashboard');
14
+
15
+ program
16
+ .name('st')
17
+ .description(chalk.hex('#00FF88').bold('Solana TUI Explorer (ST) — On-Chain Developer TUI for Solana'))
18
+ .version('1.0.0');
19
+
20
+ // Dashboard command (Full layout)
21
+ program
22
+ .command('dashboard')
23
+ .alias('d')
24
+ .description('Launch the full-screen developer TUI explorer')
25
+ .action(() => {
26
+ startDashboard();
27
+ });
28
+
29
+ // Header formatting hook (Only run if not dashboard to avoid clearing screen unexpectedly)
30
+ program.hook('preAction', (thisCommand, actionCommand) => {
31
+ if (actionCommand.name() === 'dashboard') return;
32
+ clear();
33
+ console.log(chalk.hex('#00FF88')('==========================================================='));
34
+ console.log(chalk.white.bold(' SOLANA DEV EXPLORER') + chalk.gray(' — On-Chain Inspection TUI'));
35
+ console.log(chalk.hex('#00FF88')('==========================================================='));
36
+ });
37
+
38
+ // st wallet <ADDRESS>
39
+ program
40
+ .command('wallet [address]')
41
+ .alias('w')
42
+ .description('Inspect any account or wallet balance and details')
43
+ .action((address) => {
44
+ renderWallet(address);
45
+ });
46
+
47
+ // st token <SYMBOL>
48
+ program
49
+ .command('token [symbol]')
50
+ .alias('t')
51
+ .description('Inspect SPL token parameters and metadata')
52
+ .action((symbol) => {
53
+ renderToken(symbol);
54
+ });
55
+
56
+ // Fallback to dashboard view if no args provided
57
+ if (process.argv.length === 2) {
58
+ process.argv.push('dashboard');
59
+ }
60
+
61
+ program.parse(process.argv);
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "solana-tui-explorer",
3
+ "version": "1.0.0",
4
+ "main": "index.js",
5
+ "bin": {
6
+ "solana-tui-explorer": "bin/st.js",
7
+ "st": "bin/st.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "panels",
12
+ "api.js",
13
+ "config.js",
14
+ "data.js",
15
+ "index.js"
16
+ ],
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/starkdevx/Solana-TUI-Explorer.git"
20
+ },
21
+ "homepage": "https://github.com/starkdevx/Solana-TUI-Explorer#readme",
22
+ "bugs": {
23
+ "url": "https://github.com/starkdevx/Solana-TUI-Explorer/issues"
24
+ },
25
+ "scripts": {
26
+ "start": "node ./bin/st.js",
27
+ "test": "echo \"Error: no test specified\" && exit 1"
28
+ },
29
+ "keywords": [
30
+ "solana",
31
+ "tui",
32
+ "explorer",
33
+ "crypto",
34
+ "cli"
35
+ ],
36
+ "author": "Superteam Builder",
37
+ "license": "ISC",
38
+ "description": "The ultimate Information Layer for the Solana ecosystem in a beautifully designed terminal.",
39
+ "dependencies": {
40
+ "bless": "^4.0.4",
41
+ "blessed": "^0.1.81",
42
+ "blessed-contrib": "^4.11.0",
43
+ "chalk": "^4.1.2",
44
+ "clear": "^0.1.0",
45
+ "cli-table3": "^0.6.5",
46
+ "commander": "^14.0.3",
47
+ "dotenv": "^17.4.2",
48
+ "inquirer": "^8.2.7",
49
+ "ora": "^5.4.1"
50
+ }
51
+ }