aether-hub 1.1.0 → 1.1.2

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/index.js CHANGED
@@ -1,341 +1,389 @@
1
- #!/usr/bin/env node
2
- /**
3
- * aether-cli - AeTHer Validator Command Line Interface
4
- *
5
- * Main entry point for the validator CLI tool.
6
- * Provides onboarding, system checks, validator management, and KYC integration.
7
- */
8
-
9
- const { doctorCommand } = require('./commands/doctor');
10
- const { validatorStart } = require('./commands/validator-start');
11
- const { validatorStatus } = require('./commands/validator-status');
12
- const { init } = require('./commands/init');
13
- const { monitorLoop } = require('./commands/monitor');
14
- const { logsCommand } = require('./commands/logs');
15
- const { sdkCommand } = require('./commands/sdk');
16
- const { walletCommand } = require('./commands/wallet');
17
- const { networkCommand } = require('./commands/network');
18
- const readline = require('readline');
19
-
20
- // CLI version
21
- const VERSION = '1.0.4';
22
-
23
- // Parse args early to support flags on commands
24
- function getCommandArgs() {
25
- return process.argv.slice(2);
26
- }
27
-
28
- // Tier colours
29
- const TIER_COLORS = {
30
- FULL: '\x1b[36m', // cyan
31
- LITE: '\x1b[33m', // yellow
32
- OBSERVER: '\x1b[32m', // green
33
- reset: '\x1b[0m',
34
- };
35
-
36
- /**
37
- * Display the interactive main menu
38
- */
39
- async function showMenu() {
40
- const rl = readline.createInterface({
41
- input: process.stdin,
42
- output: process.stdout,
43
- });
44
-
45
- const prompt = (q) => new Promise((res) => rl.question(q, res));
46
-
47
- console.log(
48
- TIER_COLORS.FULL + '\n ╔═══════════════════════════════════════════════╗\n' +
49
- ' ║ AETHER CHAIN — Validator Setup Wizard ║\n' +
50
- ' ╚═══════════════════════════════════════════════╝' + TIER_COLORS.reset + '\n'
51
- );
52
-
53
- console.log(' Welcome to AeTHer Chain. What would you like to do?\n');
54
- console.log(' ' + TIER_COLORS.FULL + '1)' + TIER_COLORS.reset + ' 🩺 Doctor — Check if your system meets requirements');
55
- console.log(' ' + TIER_COLORS.FULL + '2)' + TIER_COLORS.reset + ' 🚀 Start — Begin validator onboarding (recommended)');
56
- console.log(' ' + TIER_COLORS.FULL + '3)' + TIER_COLORS.reset + ' 📊 Monitor — Watch live validator stats');
57
- console.log(' ' + TIER_COLORS.FULL + '4)' + TIER_COLORS.reset + ' 📋 Logs — Tail and colourise validator logs');
58
- console.log(' ' + TIER_COLORS.FULL + '5)' + TIER_COLORS.reset + ' 📦 SDK — Get SDK links and install tools');
59
- console.log(' ' + TIER_COLORS.FULL + '6)' + TIER_COLORS.reset + ' 🌐 Network Aether network status (slot, peers, TPS)');
60
- console.log(' ' + TIER_COLORS.FULL + '7)' + TIER_COLORS.reset + ' Help Show all commands\n');
61
- console.log(' ' + TIER_COLORS.reset + ' Type a number or command name. Press Ctrl+C to exit.\n');
62
-
63
- const VALID_CHOICES = ['1', '2', '3', '4', '5', '6', '7', 'doctor', 'init', 'monitor', 'logs', 'sdk', 'network', 'help'];
64
-
65
- while (true) {
66
- const answer = (await prompt(` > `)).trim().toLowerCase();
67
-
68
- if (answer === '' || answer === '1' || answer === 'doctor') {
69
- rl.close();
70
- const { doctorCommand } = require('./commands/doctor');
71
- doctorCommand({ autoFix: false, tier: 'full' });
72
- return;
73
- }
74
-
75
- if (answer === '2' || answer === 'init' || answer === 'start') {
76
- rl.close();
77
- const { init } = require('./commands/init');
78
- init();
79
- return;
80
- }
81
-
82
- if (answer === '3' || answer === 'monitor') {
83
- rl.close();
84
- const { main } = require('./commands/monitor');
85
- main();
86
- return;
87
- }
88
-
89
- if (answer === '4' || answer === 'logs') {
90
- rl.close();
91
- const { logsCommand } = require('./commands/logs');
92
- logsCommand();
93
- return;
94
- }
95
-
96
- if (answer === '5' || answer === 'sdk') {
97
- rl.close();
98
- const { sdkCommand } = require('./commands/sdk');
99
- sdkCommand();
100
- return;
101
- }
102
-
103
- if (answer === '6' || answer === 'network') {
104
- rl.close();
105
- const { networkCommand } = require('./commands/network');
106
- networkCommand();
107
- return;
108
- }
109
-
110
- if (answer === '7' || answer === 'help') {
111
- showHelp();
112
- console.log(" Press Ctrl+C to exit or select an option above.\n");
113
- continue;
114
- }
115
-
116
- console.log(`\n ⚠️ Unknown option: "${answer}". Type 1-6 or a command name.\n`);
117
- }
118
- }
119
-
120
- // Available commands
121
- const COMMANDS = {
122
- start: {
123
- description: 'Launch interactive menu (default if no args) — same as running aether-cli with no arguments',
124
- handler: () => showMenu(),
125
- },
126
- doctor: {
127
- description: 'Run system requirements checks (CPU/RAM/Disk/Network/Firewall)',
128
- handler: () => {
129
- const args = getCommandArgs();
130
- const autoFix = args.includes('--fix') || args.includes('-f');
131
-
132
- // Parse --tier flag
133
- let tier = 'full';
134
- const tierIndex = args.findIndex(arg => arg === '--tier');
135
- if (tierIndex !== -1 && args[tierIndex + 1]) {
136
- tier = args[tierIndex + 1].toLowerCase();
137
- }
138
-
139
- doctorCommand({ autoFix, tier });
140
- },
141
- },
142
- init: {
143
- description: 'Start onboarding wizard (generate identity, create stake account, connect to testnet)',
144
- handler: init,
145
- },
146
- 'kyc generate': {
147
- description: 'Generate pre-filled KYC link with pubkey, node ID, signature',
148
- handler: () => console.log('🚧 kyc generate command under development'),
149
- },
150
- monitor: {
151
- description: 'Real-time validator dashboard (slot, block height, peers, TPS)',
152
- handler: () => {
153
- // monitor command runs its own loop
154
- const { main } = require('./commands/monitor');
155
- main();
156
- },
157
- },
158
- logs: {
159
- description: 'Tail validator logs with colour-coded output (ERROR=red, WARN=yellow, INFO=green)',
160
- handler: logsCommand,
161
- },
162
- sdk: {
163
- description: 'Aether SDK download links and install instructions (JS, Rust, FLUX/ATH tokens)',
164
- handler: sdkCommand,
165
- },
166
- wallet: {
167
- description: 'Wallet management — create, import, list, default, connect, balance, stake, transfer',
168
- handler: () => {
169
- const { walletCommand } = require('./commands/wallet');
170
- walletCommand();
171
- },
172
- },
173
- stake: {
174
- description: 'Stake AETH to a validator — aether stake --validator <addr> --amount <aeth>',
175
- handler: () => {
176
- const { walletCommand } = require('./commands/wallet');
177
- // Intercept argv so walletCommand receives 'stake' as the subcmd
178
- const originalArgv = process.argv;
179
- process.argv = [...originalArgv.slice(0, 2), 'wallet', 'stake', ...originalArgv.slice(3)];
180
- walletCommand();
181
- process.argv = originalArgv;
182
- },
183
- },
184
- transfer: {
185
- description: 'Transfer AETH to another address — aether transfer --to <addr> --amount <aeth>',
186
- handler: () => {
187
- const { walletCommand } = require('./commands/wallet');
188
- const originalArgv = process.argv;
189
- process.argv = [...originalArgv.slice(0, 2), 'wallet', 'transfer', ...originalArgv.slice(3)];
190
- walletCommand();
191
- process.argv = originalArgv;
192
- },
193
- },
194
- tx: {
195
- description: 'Transaction history aether tx history --address <addr> [--limit 20] [--json]',
196
- handler: () => {
197
- const { walletCommand } = require('./commands/wallet');
198
- const originalArgv = process.argv;
199
- process.argv = [...originalArgv.slice(0, 2), 'wallet', 'history', ...originalArgv.slice(3)];
200
- walletCommand();
201
- process.argv = originalArgv;
202
- },
203
- },
204
- network: {
205
- description: 'Aether network status — slot, block height, peers, TPS, epoch info',
206
- handler: () => {
207
- const { networkCommand } = require('./commands/network');
208
- networkCommand();
209
- },
210
- },
211
- history: {
212
- description: 'Transaction history for an address — alias for tx history',
213
- handler: () => {
214
- const { walletCommand } = require('./commands/wallet');
215
- const originalArgv = process.argv;
216
- process.argv = [...originalArgv.slice(0, 2), 'wallet', 'history', ...originalArgv.slice(3)];
217
- walletCommand();
218
- process.argv = originalArgv;
219
- },
220
- },
221
- validator: {
222
- description: 'Validator node management',
223
- handler: () => {
224
- // Handle validator subcommands
225
- const subcmd = process.argv[3];
226
-
227
- if (!subcmd) {
228
- console.log('Usage: aether-cli validator <command>');
229
- console.log('');
230
- console.log('Commands:');
231
- console.log(' start Start the validator node');
232
- console.log(' status Check validator status');
233
- console.log('');
234
- return;
235
- }
236
-
237
- switch (subcmd) {
238
- case 'start':
239
- validatorStart();
240
- break;
241
- case 'status':
242
- validatorStatus();
243
- break;
244
- default:
245
- console.error(`Unknown validator command: ${subcmd}`);
246
- console.error('Valid commands: start, status');
247
- process.exit(1);
248
- }
249
- },
250
- },
251
- help: {
252
- description: 'Show this help message',
253
- handler: showHelp,
254
- },
255
- version: {
256
- description: 'Show version number',
257
- handler: () => console.log(`aether-cli v${VERSION}`),
258
- },
259
- };
260
-
261
- /**
262
- * Display help message with ASCII art
263
- */
264
- function showHelp() {
265
- const header = `
266
- ███╗ ███╗██╗███████╗███████╗██╗ ██████╗ ███╗ ██╗
267
- ████╗ ████║██║██╔════╝██╔════╝██║██╔═══██╗████╗ ██║
268
- ██╔████╔██║██║███████╗███████╗██║██║ ██║██╔██╗ ██║
269
- ██║╚██╔╝██║██║╚════██║╚════██║██║██║ ██║██║╚██╗██║
270
- ██║ ╚═╝ ██║██║███████║███████║██║╚██████╔╝██║ ╚████║
271
- ╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝
272
-
273
- Validator CLI v${VERSION}
274
- `.trim();
275
-
276
- console.log(header);
277
- console.log('\nUsage: aether-cli <command> [options]\n');
278
- console.log('Commands:');
279
- Object.entries(COMMANDS).forEach(([cmd, info]) => {
280
- console.log(` ${cmd.padEnd(18)} ${info.description}`);
281
- });
282
- console.log('\nExamples:');
283
- console.log(' aether-cli doctor # Check system requirements');
284
- console.log(' aether-cli init # Start onboarding wizard');
285
- console.log(' aether-cli monitor # Real-time validator dashboard');
286
- console.log(' aether-cli validator start # Start validator node');
287
- console.log(' aether-cli validator status # Check validator status');
288
- console.log(' aether-cli wallet balance # Query AETH balance');
289
- console.log(' aether-cli network # Network status, peers, slot info');
290
- console.log(' aether-cli network --peers # Detailed peer list');
291
- console.log(' aether-cli tx history # Show transaction history');
292
- console.log(' aether-cli --version # Show version');
293
- console.log('\nDocumentation: https://github.com/jelly-legs-ai/Jelly-legs-unsteady-workshop');
294
- console.log('Spec: docs/MINING_VALIDATOR_TOOLS.md\n');
295
- }
296
-
297
- /**
298
- * Parse command line arguments
299
- */
300
- function parseArgs() {
301
- const args = process.argv.slice(2);
302
-
303
- // Handle version flag
304
- if (args.includes('--version') || args.includes('-v')) {
305
- return 'version';
306
- }
307
-
308
- // No args → interactive menu
309
- if (args.length === 0) {
310
- return 'start';
311
- }
312
-
313
- // Handle multi-word commands (e.g., "validator start", "kyc generate")
314
- if (args.length >= 2) {
315
- const multiCmd = `${args[0]} ${args[1]}`;
316
- if (COMMANDS[multiCmd]) {
317
- return multiCmd;
318
- }
319
- }
320
-
321
- // Single word command
322
- return args[0] || 'help';
323
- }
324
-
325
- /**
326
- * Main CLI entry point
327
- */
328
- function main() {
329
- const command = parseArgs();
330
-
331
- if (COMMANDS[command]) {
332
- COMMANDS[command].handler();
333
- } else {
334
- console.error(`❌ Unknown command: ${command}`);
335
- console.error('Run "aether-cli help" for usage.\n');
336
- process.exit(1);
337
- }
338
- }
339
-
340
- // Run CLI
341
- main();
1
+ #!/usr/bin/env node
2
+ /**
3
+ * aether-cli - AeTHer Validator Command Line Interface
4
+ *
5
+ * Main entry point for the validator CLI tool.
6
+ * Provides onboarding, system checks, validator management, and KYC integration.
7
+ */
8
+
9
+ const { doctorCommand } = require('./commands/doctor');
10
+ const { validatorStart } = require('./commands/validator-start');
11
+ const { validatorStatus } = require('./commands/validator-status');
12
+ const { init } = require('./commands/init');
13
+ const { monitorLoop } = require('./commands/monitor');
14
+ const { logsCommand } = require('./commands/logs');
15
+ const { sdkCommand } = require('./commands/sdk');
16
+ const { snapshotCommand } = require('./commands/snapshot');
17
+ const { walletCommand } = require('./commands/wallet');
18
+ const { networkCommand } = require('./commands/network');
19
+ const { validatorsListCommand } = require('./commands/validators');
20
+ const { delegationsCommand } = require('./commands/delegations');
21
+ const { rewardsCommand } = require('./commands/rewards');
22
+ const { emergencyCommand } = require('./commands/emergency');
23
+ const readline = require('readline');
24
+
25
+ // CLI version
26
+ const VERSION = '1.0.5';
27
+
28
+ // Parse args early to support flags on commands
29
+ function getCommandArgs() {
30
+ return process.argv.slice(2);
31
+ }
32
+
33
+ // Tier colours
34
+ const TIER_COLORS = {
35
+ FULL: '\x1b[36m', // cyan
36
+ LITE: '\x1b[33m', // yellow
37
+ OBSERVER: '\x1b[32m', // green
38
+ reset: '\x1b[0m',
39
+ };
40
+
41
+ /**
42
+ * Display the interactive main menu
43
+ */
44
+ async function showMenu() {
45
+ const rl = readline.createInterface({
46
+ input: process.stdin,
47
+ output: process.stdout,
48
+ });
49
+
50
+ const prompt = (q) => new Promise((res) => rl.question(q, res));
51
+
52
+ console.log(
53
+ TIER_COLORS.FULL + '\n ╔═══════════════════════════════════════════════╗\n' +
54
+ ' ║ AETHER CHAIN Validator Setup Wizard ║\n' +
55
+ ' ╚═══════════════════════════════════════════════╝' + TIER_COLORS.reset + '\n'
56
+ );
57
+
58
+ console.log(' Welcome to AeTHer Chain. What would you like to do?\n');
59
+ console.log(' ' + TIER_COLORS.FULL + '1)' + TIER_COLORS.reset + ' 🩺 Doctor Check if your system meets requirements');
60
+ console.log(' ' + TIER_COLORS.FULL + '2)' + TIER_COLORS.reset + ' 🚀 Start Begin validator onboarding (recommended)');
61
+ console.log(' ' + TIER_COLORS.FULL + '3)' + TIER_COLORS.reset + ' 📊 Monitor Watch live validator stats');
62
+ console.log(' ' + TIER_COLORS.FULL + '4)' + TIER_COLORS.reset + ' 📋 Logs — Tail and colourise validator logs');
63
+ console.log(' ' + TIER_COLORS.FULL + '5)' + TIER_COLORS.reset + ' 📦 SDK — Get SDK links and install tools');
64
+ console.log(' ' + TIER_COLORS.FULL + '6)' + TIER_COLORS.reset + ' 🌐 Network — Aether network status (slot, peers, TPS)');
65
+ console.log(' ' + TIER_COLORS.FULL + '7)' + TIER_COLORS.reset + ' ❓ Help — Show all commands\n');
66
+ console.log(' ' + TIER_COLORS.reset + ' Type a number or command name. Press Ctrl+C to exit.\n');
67
+
68
+ const VALID_CHOICES = ['1', '2', '3', '4', '5', '6', '7', 'doctor', 'init', 'monitor', 'logs', 'sdk', 'network', 'help'];
69
+
70
+ while (true) {
71
+ const answer = (await prompt(` > `)).trim().toLowerCase();
72
+
73
+ if (answer === '' || answer === '1' || answer === 'doctor') {
74
+ rl.close();
75
+ const { doctorCommand } = require('./commands/doctor');
76
+ doctorCommand({ autoFix: false, tier: 'full' });
77
+ return;
78
+ }
79
+
80
+ if (answer === '2' || answer === 'init' || answer === 'start') {
81
+ rl.close();
82
+ const { init } = require('./commands/init');
83
+ init();
84
+ return;
85
+ }
86
+
87
+ if (answer === '3' || answer === 'monitor') {
88
+ rl.close();
89
+ const { main } = require('./commands/monitor');
90
+ main();
91
+ return;
92
+ }
93
+
94
+ if (answer === '4' || answer === 'logs') {
95
+ rl.close();
96
+ const { logsCommand } = require('./commands/logs');
97
+ logsCommand();
98
+ return;
99
+ }
100
+
101
+ if (answer === '5' || answer === 'sdk') {
102
+ rl.close();
103
+ const { sdkCommand } = require('./commands/sdk');
104
+ const { snapshotCommand } = require('./commands/snapshot');
105
+ sdkCommand();
106
+ return;
107
+ }
108
+
109
+ if (answer === '6' || answer === 'network') {
110
+ rl.close();
111
+ const { networkCommand } = require('./commands/network');
112
+ networkCommand();
113
+ return;
114
+ }
115
+
116
+ if (answer === '7' || answer === 'help') {
117
+ showHelp();
118
+ console.log(" Press Ctrl+C to exit or select an option above.\n");
119
+ continue;
120
+ }
121
+
122
+ console.log(`\n ⚠️ Unknown option: "${answer}". Type 1-6 or a command name.\n`);
123
+ }
124
+ }
125
+
126
+ // Available commands
127
+ const COMMANDS = {
128
+ start: {
129
+ description: 'Launch interactive menu (default if no args) — same as running aether-cli with no arguments',
130
+ handler: () => showMenu(),
131
+ },
132
+ doctor: {
133
+ description: 'Run system requirements checks (CPU/RAM/Disk/Network/Firewall)',
134
+ handler: () => {
135
+ const args = getCommandArgs();
136
+ const autoFix = args.includes('--fix') || args.includes('-f');
137
+
138
+ // Parse --tier flag
139
+ let tier = 'full';
140
+ const tierIndex = args.findIndex(arg => arg === '--tier');
141
+ if (tierIndex !== -1 && args[tierIndex + 1]) {
142
+ tier = args[tierIndex + 1].toLowerCase();
143
+ }
144
+
145
+ doctorCommand({ autoFix, tier });
146
+ },
147
+ },
148
+ init: {
149
+ description: 'Start onboarding wizard (generate identity, create stake account, connect to testnet)',
150
+ handler: init,
151
+ },
152
+ 'kyc generate': {
153
+ description: 'Generate pre-filled KYC link with pubkey, node ID, signature',
154
+ handler: () => console.log('🚧 kyc generate command under development'),
155
+ },
156
+ monitor: {
157
+ description: 'Real-time validator dashboard (slot, block height, peers, TPS)',
158
+ handler: () => {
159
+ // monitor command runs its own loop
160
+ const { main } = require('./commands/monitor');
161
+ main();
162
+ },
163
+ },
164
+ logs: {
165
+ description: 'Tail validator logs with colour-coded output (ERROR=red, WARN=yellow, INFO=green)',
166
+ handler: logsCommand,
167
+ },
168
+ sdk: {
169
+ description: 'Aether SDK download links and install instructions (JS, Rust, FLUX/ATH tokens)',
170
+ handler: sdkCommand,
171
+ },
172
+ wallet: {
173
+ description: 'Wallet management — create, import, list, default, connect, balance, stake, transfer',
174
+ handler: () => {
175
+ const { walletCommand } = require('./commands/wallet');
176
+ walletCommand();
177
+ },
178
+ },
179
+ stake: {
180
+ description: 'Stake AETH to a validator — aether stake --validator <addr> --amount <aeth>',
181
+ handler: () => {
182
+ const { walletCommand } = require('./commands/wallet');
183
+ // Intercept argv so walletCommand receives 'stake' as the subcmd
184
+ const originalArgv = process.argv;
185
+ process.argv = [...originalArgv.slice(0, 2), 'wallet', 'stake', ...originalArgv.slice(3)];
186
+ walletCommand();
187
+ process.argv = originalArgv;
188
+ },
189
+ },
190
+ unstake: {
191
+ description: 'Unstake AETH — deactivate a stake account — aether unstake --account <stakeAcct> [--amount <aeth>]',
192
+ handler: () => {
193
+ const { walletCommand } = require('./commands/wallet');
194
+ const originalArgv = process.argv;
195
+ process.argv = [...originalArgv.slice(0, 2), 'wallet', 'unstake', ...originalArgv.slice(3)];
196
+ walletCommand();
197
+ process.argv = originalArgv;
198
+ },
199
+ },
200
+ transfer: {
201
+ description: 'Transfer AETH to another address — aether transfer --to <addr> --amount <aeth>',
202
+ handler: () => {
203
+ const { walletCommand } = require('./commands/wallet');
204
+ const originalArgv = process.argv;
205
+ process.argv = [...originalArgv.slice(0, 2), 'wallet', 'transfer', ...originalArgv.slice(3)];
206
+ walletCommand();
207
+ process.argv = originalArgv;
208
+ },
209
+ },
210
+ tx: {
211
+ description: 'Transaction history — aether tx history --address <addr> [--limit 20] [--json]',
212
+ handler: () => {
213
+ const { walletCommand } = require('./commands/wallet');
214
+ const originalArgv = process.argv;
215
+ process.argv = [...originalArgv.slice(0, 2), 'wallet', 'history', ...originalArgv.slice(3)];
216
+ walletCommand();
217
+ process.argv = originalArgv;
218
+ },
219
+ },
220
+ network: {
221
+ description: 'Aether network status — slot, block height, peers, TPS, epoch info',
222
+ handler: () => {
223
+ const { networkCommand } = require('./commands/network');
224
+ networkCommand();
225
+ },
226
+ },
227
+ history: {
228
+ description: 'Transaction history for an address — alias for tx history',
229
+ handler: () => {
230
+ const { walletCommand } = require('./commands/wallet');
231
+ const originalArgv = process.argv;
232
+ process.argv = [...originalArgv.slice(0, 2), 'wallet', 'history', ...originalArgv.slice(3)];
233
+ walletCommand();
234
+ process.argv = originalArgv;
235
+ },
236
+ },
237
+ validator: {
238
+ description: 'Validator node management',
239
+ handler: () => {
240
+ // Handle validator subcommands
241
+ const subcmd = process.argv[3];
242
+
243
+ if (!subcmd) {
244
+ console.log('Usage: aether-cli validator <command>');
245
+ console.log('');
246
+ console.log('Commands:');
247
+ console.log(' start Start the validator node');
248
+ console.log(' status Check validator status');
249
+ console.log('');
250
+ return;
251
+ }
252
+
253
+ switch (subcmd) {
254
+ case 'start':
255
+ validatorStart();
256
+ break;
257
+ case 'status':
258
+ validatorStatus();
259
+ break;
260
+ default:
261
+ console.error(`Unknown validator command: ${subcmd}`);
262
+ console.error('Valid commands: start, status');
263
+ process.exit(1);
264
+ }
265
+ },
266
+ },
267
+ delegations: {
268
+ description: 'List/claim stake delegations — aether delegations list --address <addr>',
269
+ handler: () => {
270
+ delegationsCommand();
271
+ },
272
+ },
273
+ rewards: {
274
+ description: 'View staking rewards — aether rewards list --address <addr> | rewards summary | rewards claim',
275
+ handler: () => {
276
+ rewardsCommand();
277
+ },
278
+ },
279
+ snapshot: {
280
+ description: 'Node sync status, snapshot slot info, and network slot comparison',
281
+ handler: () => {
282
+ const { snapshotCommand } = require('./commands/snapshot');
283
+ snapshotCommand();
284
+ },
285
+ },
286
+ validators: {
287
+ description: 'List active validators — aether validators list [--tier full|lite|observer] [--json]',
288
+ handler: () => {
289
+ validatorsListCommand();
290
+ },
291
+ },
292
+ emergency: {
293
+ description: 'Emergency response & network alerts — status, monitor, check, alert, failover, history',
294
+ handler: () => {
295
+ const { emergencyCommand } = require('./commands/emergency');
296
+ emergencyCommand();
297
+ },
298
+ },
299
+ help: {
300
+ description: 'Show this help message',
301
+ handler: showHelp,
302
+ },
303
+ version: {
304
+ description: 'Show version number',
305
+ handler: () => console.log(`aether-cli v${VERSION}`),
306
+ },
307
+ };
308
+
309
+ /**
310
+ * Display help message with ASCII art
311
+ */
312
+ function showHelp() {
313
+ const header = `
314
+ ███╗ ███╗██╗███████╗███████╗██╗ ██████╗ ███╗ ██╗
315
+ ████╗ ████║██║██╔════╝██╔════╝██║██╔═══██╗████╗ ██║
316
+ ██╔████╔██║██║███████╗███████╗██║██║ ██║██╔██╗ ██║
317
+ ██║╚██╔╝██║██║╚════██║╚════██║██║██║ ██║██║╚██╗██║
318
+ ██║ ╚═╝ ██║██║███████║███████║██║╚██████╔╝██║ ╚████║
319
+ ╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝
320
+
321
+ Validator CLI v${VERSION}
322
+ `.trim();
323
+
324
+ console.log(header);
325
+ console.log('\nUsage: aether-cli <command> [options]\n');
326
+ console.log('Commands:');
327
+ Object.entries(COMMANDS).forEach(([cmd, info]) => {
328
+ console.log(` ${cmd.padEnd(18)} ${info.description}`);
329
+ });
330
+ console.log('\nExamples:');
331
+ console.log(' aether-cli doctor # Check system requirements');
332
+ console.log(' aether-cli init # Start onboarding wizard');
333
+ console.log(' aether-cli monitor # Real-time validator dashboard');
334
+ console.log(' aether-cli validator start # Start validator node');
335
+ console.log(' aether-cli validator status # Check validator status');
336
+ console.log(' aether-cli wallet balance # Query AETH balance');
337
+ console.log(' aether-cli network # Network status, peers, slot info');
338
+ console.log(' aether-cli network --peers # Detailed peer list');
339
+ console.log(' aether-cli tx history # Show transaction history');
340
+ console.log(' aether-cli --version # Show version');
341
+ console.log('\nDocumentation: https://github.com/jelly-legs-ai/Jelly-legs-unsteady-workshop');
342
+ console.log('Spec: docs/MINING_VALIDATOR_TOOLS.md\n');
343
+ }
344
+
345
+ /**
346
+ * Parse command line arguments
347
+ */
348
+ function parseArgs() {
349
+ const args = process.argv.slice(2);
350
+
351
+ // Handle version flag
352
+ if (args.includes('--version') || args.includes('-v')) {
353
+ return 'version';
354
+ }
355
+
356
+ // No args → interactive menu
357
+ if (args.length === 0) {
358
+ return 'start';
359
+ }
360
+
361
+ // Handle multi-word commands (e.g., "validator start", "kyc generate")
362
+ if (args.length >= 2) {
363
+ const multiCmd = `${args[0]} ${args[1]}`;
364
+ if (COMMANDS[multiCmd]) {
365
+ return multiCmd;
366
+ }
367
+ }
368
+
369
+ // Single word command
370
+ return args[0] || 'help';
371
+ }
372
+
373
+ /**
374
+ * Main CLI entry point
375
+ */
376
+ function main() {
377
+ const command = parseArgs();
378
+
379
+ if (COMMANDS[command]) {
380
+ COMMANDS[command].handler();
381
+ } else {
382
+ console.error(`❌ Unknown command: ${command}`);
383
+ console.error('Run "aether-cli help" for usage.\n');
384
+ process.exit(1);
385
+ }
386
+ }
387
+
388
+ // Run CLI
389
+ main();