decharge-scout 1.2.1 → 1.3.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/index.js +139 -37
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -20,12 +20,13 @@ import { Command } from 'commander';
|
|
|
20
20
|
import chalk from 'chalk';
|
|
21
21
|
import ora from 'ora';
|
|
22
22
|
import dotenv from 'dotenv';
|
|
23
|
-
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
23
|
+
import { readFileSync, writeFileSync, existsSync, readdirSync } from 'fs';
|
|
24
24
|
import { createInterface } from 'readline';
|
|
25
25
|
import path from 'path';
|
|
26
26
|
import { fileURLToPath } from 'url';
|
|
27
27
|
import { dirname } from 'path';
|
|
28
28
|
import { Keypair } from '@solana/web3.js';
|
|
29
|
+
import os from 'os';
|
|
29
30
|
|
|
30
31
|
// Load environment variables
|
|
31
32
|
dotenv.config();
|
|
@@ -68,6 +69,45 @@ function generateAgentName() {
|
|
|
68
69
|
return `Agent-${randomId}`;
|
|
69
70
|
}
|
|
70
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Search for existing Solana wallets in common locations
|
|
74
|
+
*/
|
|
75
|
+
function findExistingWallets() {
|
|
76
|
+
const wallets = [];
|
|
77
|
+
const searchPaths = [
|
|
78
|
+
// Current directory
|
|
79
|
+
path.join(process.cwd(), 'wallet.json'),
|
|
80
|
+
path.join(process.cwd(), 'id.json'),
|
|
81
|
+
// Home directory
|
|
82
|
+
path.join(os.homedir(), '.solana', 'id.json'),
|
|
83
|
+
path.join(os.homedir(), 'wallet.json'),
|
|
84
|
+
// Common wallet names in current dir
|
|
85
|
+
path.join(process.cwd(), 'solana-wallet.json'),
|
|
86
|
+
path.join(process.cwd(), 'keypair.json'),
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
for (const walletPath of searchPaths) {
|
|
90
|
+
if (existsSync(walletPath)) {
|
|
91
|
+
try {
|
|
92
|
+
const keyData = JSON.parse(readFileSync(walletPath, 'utf-8'));
|
|
93
|
+
if (Array.isArray(keyData) && keyData.length === 64) {
|
|
94
|
+
const keypair = Keypair.fromSecretKey(Uint8Array.from(keyData));
|
|
95
|
+
wallets.push({
|
|
96
|
+
path: walletPath,
|
|
97
|
+
publicKey: keypair.publicKey.toBase58(),
|
|
98
|
+
name: path.basename(walletPath),
|
|
99
|
+
location: path.dirname(walletPath)
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
// Skip invalid wallets
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return wallets;
|
|
109
|
+
}
|
|
110
|
+
|
|
71
111
|
/**
|
|
72
112
|
* Auto-create wallet if missing
|
|
73
113
|
*/
|
|
@@ -77,13 +117,72 @@ async function ensureWallet(walletPath) {
|
|
|
77
117
|
}
|
|
78
118
|
|
|
79
119
|
console.log(chalk.yellow(`\n⚠️ No wallet found at ${walletPath}`));
|
|
120
|
+
|
|
121
|
+
// Search for existing wallets
|
|
122
|
+
const existingWallets = findExistingWallets();
|
|
123
|
+
|
|
124
|
+
if (existingWallets.length > 0) {
|
|
125
|
+
console.log(chalk.green(`\n🔍 Found ${existingWallets.length} existing wallet(s):\n`));
|
|
126
|
+
|
|
127
|
+
existingWallets.forEach((wallet, index) => {
|
|
128
|
+
console.log(chalk.cyan(` ${index + 1}. ${wallet.name}`));
|
|
129
|
+
console.log(chalk.gray(` Path: ${wallet.path}`));
|
|
130
|
+
console.log(chalk.gray(` Public Key: ${wallet.publicKey}\n`));
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const useExisting = await question('Use an existing wallet? (Enter number, or press Enter to create new): ');
|
|
134
|
+
|
|
135
|
+
if (useExisting.trim() && !isNaN(useExisting)) {
|
|
136
|
+
const index = parseInt(useExisting.trim()) - 1;
|
|
137
|
+
if (index >= 0 && index < existingWallets.length) {
|
|
138
|
+
const selectedWallet = existingWallets[index];
|
|
139
|
+
console.log(chalk.green(`✓ Using wallet: ${selectedWallet.publicKey}`));
|
|
140
|
+
return selectedWallet.path;
|
|
141
|
+
} else {
|
|
142
|
+
console.log(chalk.yellow('Invalid selection, creating new wallet...'));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
80
147
|
const answer = await question('Create a new wallet? (Y/n): ');
|
|
81
148
|
|
|
82
149
|
if (answer.toLowerCase() === 'n') {
|
|
83
|
-
console.log(chalk.blue('\
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
150
|
+
console.log(chalk.blue('\n📥 Import existing wallet'));
|
|
151
|
+
const importAnswer = await question('Do you want to import an existing wallet private key? (Y/n): ');
|
|
152
|
+
|
|
153
|
+
if (importAnswer.toLowerCase() === 'n') {
|
|
154
|
+
console.log(chalk.blue('\nYou can create a wallet manually:'));
|
|
155
|
+
console.log(chalk.gray(' solana-keygen new --outfile ./wallet.json'));
|
|
156
|
+
console.log(chalk.gray(' Or run: node setup.js\n'));
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log(chalk.yellow('\n⚠️ Enter your Solana wallet private key'));
|
|
161
|
+
console.log(chalk.gray('Format: [1,2,3,...] (array of 64 numbers)'));
|
|
162
|
+
const privateKeyInput = await question('Private key: ');
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
// Parse the private key
|
|
166
|
+
const privateKey = JSON.parse(privateKeyInput.trim());
|
|
167
|
+
|
|
168
|
+
// Validate it's an array of numbers
|
|
169
|
+
if (!Array.isArray(privateKey) || privateKey.length !== 64) {
|
|
170
|
+
throw new Error('Invalid private key format');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Create keypair to validate
|
|
174
|
+
const keypair = Keypair.fromSecretKey(Uint8Array.from(privateKey));
|
|
175
|
+
|
|
176
|
+
// Save to file
|
|
177
|
+
writeFileSync(walletPath, JSON.stringify(privateKey));
|
|
178
|
+
|
|
179
|
+
console.log(chalk.green(`✓ Wallet imported: ${keypair.publicKey.toBase58()}`));
|
|
180
|
+
return walletPath;
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.log(chalk.red(`\n❌ Invalid private key: ${error.message}`));
|
|
183
|
+
console.log(chalk.gray('Expected format: [1,2,3,...] (array of 64 numbers)\n'));
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
87
186
|
}
|
|
88
187
|
|
|
89
188
|
console.log(chalk.blue('Generating new wallet...'));
|
|
@@ -124,7 +223,12 @@ async function ensureEnvironment() {
|
|
|
124
223
|
// Check for EIA API key
|
|
125
224
|
if (!process.env.EIA_API_KEY || process.env.EIA_API_KEY === 'your_eia_api_key_here') {
|
|
126
225
|
console.log(chalk.yellow('\n⚠️ EIA_API_KEY not configured'));
|
|
127
|
-
console.log(chalk.blue('
|
|
226
|
+
console.log(chalk.blue('\n📝 How to get a FREE EIA API key:'));
|
|
227
|
+
console.log(chalk.gray(' 1. Visit: https://www.eia.gov/opendata/register.php'));
|
|
228
|
+
console.log(chalk.gray(' 2. Fill out the registration form'));
|
|
229
|
+
console.log(chalk.gray(' 3. Check your email and verify your email address'));
|
|
230
|
+
console.log(chalk.gray(' 4. Your API key will be sent to your email'));
|
|
231
|
+
console.log(chalk.gray(' 5. Copy the API key and paste it below\n'));
|
|
128
232
|
|
|
129
233
|
const answer = await question('Enter your EIA API key (or press Enter to skip): ');
|
|
130
234
|
|
|
@@ -317,40 +421,38 @@ async function runQueryCycle(wallet, agentName, location, options) {
|
|
|
317
421
|
console.log(chalk.blue('\n📊 Dashboard Data Structure:'));
|
|
318
422
|
console.log(chalk.gray(JSON.stringify(submissionData, null, 2)));
|
|
319
423
|
|
|
320
|
-
//
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
424
|
+
// Submit to DeCharge Scout dashboard
|
|
425
|
+
try {
|
|
426
|
+
const dashboardSpinner = ora('Submitting to DeCharge Scout dashboard...').start();
|
|
427
|
+
const apiUrl = 'https://decharge-scout.vercel.app/api/agentone/submit';
|
|
428
|
+
|
|
429
|
+
console.log(chalk.blue(`\n🌐 Dashboard API URL: ${apiUrl}`));
|
|
430
|
+
console.log(chalk.gray(`📤 Submitting data...`));
|
|
431
|
+
|
|
432
|
+
const response = await fetch(apiUrl, {
|
|
433
|
+
method: 'POST',
|
|
434
|
+
headers: { 'Content-Type': 'application/json' },
|
|
435
|
+
body: JSON.stringify({
|
|
436
|
+
...submissionData,
|
|
437
|
+
wallet: wallet.publicKey.toBase58(),
|
|
438
|
+
run_number: totalRuns
|
|
439
|
+
})
|
|
440
|
+
});
|
|
325
441
|
|
|
326
|
-
|
|
327
|
-
|
|
442
|
+
const responseText = await response.text();
|
|
443
|
+
console.log(chalk.blue(`📥 API Response Status: ${response.status}`));
|
|
328
444
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
console.log(chalk.blue(`📥 API Response Status: ${response.status}`));
|
|
337
|
-
console.log(chalk.gray(`📥 API Response Body: ${responseText}`));
|
|
338
|
-
|
|
339
|
-
if (response.ok) {
|
|
340
|
-
dashboardSpinner.succeed(chalk.green('✅ Dashboard submission successful!'));
|
|
341
|
-
console.log(chalk.green(`🎉 Data should now appear at: https://decharge-scout.vercel.app/agentone`));
|
|
342
|
-
} else {
|
|
343
|
-
dashboardSpinner.warn(chalk.yellow(`⚠️ Dashboard API returned: ${response.status}`));
|
|
344
|
-
console.log(chalk.yellow(`Response: ${responseText}`));
|
|
345
|
-
}
|
|
346
|
-
} catch (error) {
|
|
347
|
-
// Silent fail for dashboard - it's optional
|
|
348
|
-
console.log(chalk.red(`❌ Dashboard API error: ${error.message}`));
|
|
349
|
-
console.log(chalk.gray(`Stack: ${error.stack}`));
|
|
445
|
+
if (response.ok) {
|
|
446
|
+
dashboardSpinner.succeed(chalk.green('✅ Dashboard submission successful!'));
|
|
447
|
+
console.log(chalk.green(`🎉 Data should now appear at: https://decharge-scout.vercel.app/agentone`));
|
|
448
|
+
console.log(chalk.gray(`Response: ${responseText}`));
|
|
449
|
+
} else {
|
|
450
|
+
dashboardSpinner.warn(chalk.yellow(`⚠️ Dashboard API returned: ${response.status}`));
|
|
451
|
+
console.log(chalk.yellow(`Response: ${responseText}`));
|
|
350
452
|
}
|
|
351
|
-
}
|
|
352
|
-
console.log(chalk.
|
|
353
|
-
console.log(chalk.gray(`
|
|
453
|
+
} catch (error) {
|
|
454
|
+
console.log(chalk.red(`❌ Dashboard submission failed: ${error.message}`));
|
|
455
|
+
console.log(chalk.gray(`This won't affect your oracle submission or points`));
|
|
354
456
|
}
|
|
355
457
|
|
|
356
458
|
// Award points
|