fuego-cli 0.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.
@@ -0,0 +1,118 @@
1
+ import { Keypair, Connection, PublicKey, Transaction, SystemProgram, LAMPORTS_PER_SOL } from '@solana/web3.js';
2
+ import fs from 'fs-extra';
3
+ import path from 'path';
4
+ import { getWalletPath, getWalletConfigPath, saveWalletConfig } from './config.js';
5
+ export class FuegoWallet {
6
+ walletPath;
7
+ keypair;
8
+ constructor(walletPath) {
9
+ this.walletPath = walletPath || getWalletPath();
10
+ }
11
+ exists() {
12
+ return fs.existsSync(this.walletPath);
13
+ }
14
+ async create(name) {
15
+ // Ensure directory exists
16
+ await fs.ensureDir(path.dirname(this.walletPath));
17
+ // Generate new keypair
18
+ this.keypair = Keypair.generate();
19
+ const publicKey = this.keypair.publicKey.toBase58();
20
+ // Save wallet.json with ONLY the keypair (minimal, secure)
21
+ const walletData = {
22
+ secretKey: Array.from(this.keypair.secretKey)
23
+ };
24
+ await fs.writeJson(this.walletPath, walletData);
25
+ // Set restrictive permissions (owner read/write only)
26
+ await fs.chmod(this.walletPath, 0o600);
27
+ // Save wallet-config.json with metadata (safe to modify)
28
+ saveWalletConfig({
29
+ publicKey,
30
+ name: name || 'default',
31
+ createdAt: new Date().toISOString(),
32
+ version: '0.1.0'
33
+ });
34
+ return {
35
+ publicKey,
36
+ mnemonic: undefined
37
+ };
38
+ }
39
+ load() {
40
+ if (this.keypair)
41
+ return this.keypair;
42
+ if (!this.exists()) {
43
+ throw new Error('Wallet not found. Run "fuego init" first.');
44
+ }
45
+ const walletData = fs.readJsonSync(this.walletPath);
46
+ this.keypair = Keypair.fromSecretKey(Uint8Array.from(walletData.secretKey));
47
+ return this.keypair;
48
+ }
49
+ getPublicKey() {
50
+ if (this.keypair) {
51
+ return this.keypair.publicKey.toBase58();
52
+ }
53
+ if (!this.exists()) {
54
+ throw new Error('Wallet not found. Run "fuego init" first.');
55
+ }
56
+ // Read from wallet-config.json if available, otherwise from wallet.json
57
+ const configPath = getWalletConfigPath();
58
+ if (fs.existsSync(configPath)) {
59
+ const config = fs.readJsonSync(configPath);
60
+ return config.publicKey;
61
+ }
62
+ // Fallback: derive from wallet.json
63
+ const walletData = fs.readJsonSync(this.walletPath);
64
+ const kp = Keypair.fromSecretKey(Uint8Array.from(walletData.secretKey));
65
+ return kp.publicKey.toBase58();
66
+ }
67
+ async getBalance() {
68
+ const keypair = this.load();
69
+ const connection = this.getConnection();
70
+ const lamports = await connection.getBalance(keypair.publicKey);
71
+ // TODO: Fetch SPL token balances
72
+ return {
73
+ sol: lamports / LAMPORTS_PER_SOL,
74
+ tokens: []
75
+ };
76
+ }
77
+ async send(params) {
78
+ const keypair = this.load();
79
+ const connection = this.getConnection(params.network);
80
+ const recipient = new PublicKey(params.to);
81
+ if (params.token === 'SOL') {
82
+ const lamports = params.amount * LAMPORTS_PER_SOL;
83
+ const transaction = new Transaction().add(SystemProgram.transfer({
84
+ fromPubkey: keypair.publicKey,
85
+ toPubkey: recipient,
86
+ lamports
87
+ }));
88
+ const signature = await connection.sendTransaction(transaction, [keypair]);
89
+ // Wait for confirmation
90
+ await connection.confirmTransaction(signature, 'confirmed');
91
+ return {
92
+ signature,
93
+ confirmation: 'confirmed'
94
+ };
95
+ }
96
+ else {
97
+ // TODO: SPL token transfers
98
+ throw new Error('SPL token transfers coming in v0.2');
99
+ }
100
+ }
101
+ async getHistory(limit) {
102
+ const keypair = this.load();
103
+ const connection = this.getConnection();
104
+ const signatures = await connection.getSignaturesForAddress(keypair.publicKey, { limit });
105
+ return signatures.map(sig => ({
106
+ signature: sig.signature,
107
+ type: sig.err ? 'outgoing' : 'incoming', // Simplified - actual logic needs transaction parsing
108
+ amount: '0', // TODO: Parse actual amount
109
+ token: 'SOL',
110
+ timestamp: sig.blockTime ? sig.blockTime * 1000 : Date.now(),
111
+ }));
112
+ }
113
+ getConnection(rpcUrl) {
114
+ const endpoint = rpcUrl || process.env.FUEGO_RPC_URL || 'https://api.mainnet-beta.solana.com';
115
+ return new Connection(endpoint, 'confirmed');
116
+ }
117
+ }
118
+ //# sourceMappingURL=wallet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wallet.js","sourceRoot":"","sources":["../../src/lib/wallet.ts"],"names":[],"mappings":"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"}
Binary file
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "fuego-cli",
3
+ "version": "0.1.0",
4
+ "description": "Command-line interface for Fuego - the sovereign Solana wallet for AI agents",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "fuego": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "npx tsc",
12
+ "dev": "npx tsc --watch",
13
+ "start": "node dist/index.js",
14
+ "test": "node --test dist/**/*.test.js",
15
+ "lint": "eslint src/**/*.ts",
16
+ "format": "prettier --write src/**/*.ts"
17
+ },
18
+ "keywords": [
19
+ "solana",
20
+ "wallet",
21
+ "cli",
22
+ "ai-agent",
23
+ "cryptocurrency",
24
+ "blockchain",
25
+ "fuego"
26
+ ],
27
+ "author": "Will McDeezy <will@yatori.io>",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/willmcdeezy/fuego-cli.git"
32
+ },
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ },
36
+ "dependencies": {
37
+ "@solana/web3.js": "^1.98.0",
38
+ "boxen": "^8.0.1",
39
+ "chalk": "^5.4.1",
40
+ "commander": "^13.1.0",
41
+ "conf": "^13.1.0",
42
+ "figlet": "^1.8.0",
43
+ "fs-extra": "^11.3.0",
44
+ "gradient-string": "^3.0.0",
45
+ "inquirer": "^12.4.2",
46
+ "ora": "^8.2.0"
47
+ },
48
+ "devDependencies": {
49
+ "@types/fs-extra": "^11.0.4",
50
+ "@types/node": "^22.13.5",
51
+ "@typescript-eslint/eslint-plugin": "^8.25.0",
52
+ "@typescript-eslint/parser": "^8.25.0",
53
+ "eslint": "^10.0.1",
54
+ "prettier": "^3.5.2",
55
+ "typescript": "^5.7.3"
56
+ }
57
+ }
@@ -0,0 +1,25 @@
1
+ import chalk from 'chalk';
2
+ import { loadWalletConfig } from '../lib/config.js';
3
+ import { showInfo, formatPublicKey, flameDivider } from '../lib/ascii.js';
4
+
5
+ export async function addressCommand(): Promise<void> {
6
+ console.log(); // spacer
7
+
8
+ const config = loadWalletConfig();
9
+
10
+ if (!config) {
11
+ console.log(chalk.red('❌ No wallet found. Run "fuego create" first.'));
12
+ process.exit(1);
13
+ }
14
+
15
+ showInfo('📍 Your Fuego Address', [
16
+ `Name: ${chalk.cyan(config.name || 'default')}`,
17
+ `Public Key: ${formatPublicKey(config.publicKey)}`
18
+ ]);
19
+
20
+ // Also show plain for easy copying
21
+ console.log(chalk.gray('\nPlain text (for copying):'));
22
+ console.log(chalk.white(config.publicKey));
23
+
24
+ flameDivider();
25
+ }
@@ -0,0 +1,81 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { FuegoWallet } from '../lib/wallet.js';
4
+ import { getWalletPath, getConfigPath } from '../lib/config.js';
5
+ import { showSuccess, showWarning, showInfo, formatPublicKey, flameDivider } from '../lib/ascii.js';
6
+ import fs from 'fs-extra';
7
+
8
+ interface CreateOptions {
9
+ force?: boolean;
10
+ directory?: string;
11
+ name?: string;
12
+ }
13
+
14
+ export async function createCommand(options: CreateOptions): Promise<void> {
15
+ console.log(); // spacer
16
+
17
+ const spinner = ora({
18
+ text: 'Checking for existing wallet...',
19
+ color: 'yellow'
20
+ }).start();
21
+
22
+ try {
23
+ const walletPath = options.directory
24
+ ? `${options.directory}/wallet.json`
25
+ : getWalletPath();
26
+
27
+ const wallet = new FuegoWallet(walletPath);
28
+
29
+ if (wallet.exists() && !options.force) {
30
+ spinner.stop();
31
+ showWarning('Wallet already exists.\n\nUse --force to overwrite.\n⚠️ Warning: Overwriting will destroy your current wallet!');
32
+ return;
33
+ }
34
+
35
+ spinner.text = 'Generating new Solana keypair...';
36
+ spinner.color = 'red';
37
+
38
+ const { publicKey, mnemonic } = await wallet.create(options.name);
39
+
40
+ // Create config.json with defaults
41
+ const configPath = options.directory
42
+ ? `${options.directory}/config.json`
43
+ : getConfigPath();
44
+
45
+ if (!fs.existsSync(configPath)) {
46
+ fs.writeJsonSync(configPath, {
47
+ network: 'mainnet',
48
+ rpcUrl: 'https://api.mainnet-beta.solana.com',
49
+ version: '0.1.0'
50
+ }, { spaces: 2 });
51
+ }
52
+
53
+ spinner.stop();
54
+
55
+ // Success display
56
+ showSuccess(
57
+ '🔥 Wallet Created Successfully!',
58
+ `Name: ${chalk.cyan(options.name || 'default')}\nPublic Key: ${formatPublicKey(publicKey)}`
59
+ );
60
+
61
+ if (mnemonic) {
62
+ showWarning(
63
+ 'IMPORTANT: Save this recovery phrase!\n' +
64
+ chalk.white(mnemonic) +
65
+ '\n\n' + chalk.red('Never share this phrase with anyone!')
66
+ );
67
+ }
68
+
69
+ // File locations
70
+ showInfo('📁 Wallet Files', [
71
+ 'Keypair: ~/.fuego/wallet.json',
72
+ 'Config: ~/.fuego/wallet-config.json'
73
+ ]);
74
+
75
+ flameDivider();
76
+
77
+ } catch (error: any) {
78
+ spinner.fail(chalk.red(`Failed to create wallet: ${error.message}`));
79
+ process.exit(1);
80
+ }
81
+ }
@@ -0,0 +1,82 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { execSync } from 'child_process';
4
+ import fs from 'fs-extra';
5
+ import path from 'path';
6
+ import os from 'os';
7
+ import { showSuccess, showWarning, showInfo, flameDivider } from '../lib/ascii.js';
8
+
9
+ interface InstallOptions {
10
+ path?: string;
11
+ }
12
+
13
+ export async function installCommand(options: InstallOptions): Promise<void> {
14
+ console.log(); // spacer
15
+
16
+ // Determine default path: use openclaw workspace if it exists, otherwise current directory
17
+ const openclawWorkspace = path.join(os.homedir(), '.openclaw', 'workspace');
18
+ const hasOpenclaw = fs.existsSync(openclawWorkspace);
19
+
20
+ const defaultPath = hasOpenclaw
21
+ ? path.join(openclawWorkspace, 'fuego')
22
+ : path.join(process.cwd(), 'fuego');
23
+
24
+ const installPath = options.path || defaultPath;
25
+
26
+ const spinner = ora({
27
+ text: 'Checking installation path...',
28
+ color: 'yellow'
29
+ }).start();
30
+
31
+ try {
32
+ // Check if already exists
33
+ if (fs.existsSync(installPath)) {
34
+ spinner.stop();
35
+ showWarning(
36
+ `Fuego already installed at:\n${chalk.cyan(installPath)}\n\nUse --path to install elsewhere, or delete the existing installation.`
37
+ );
38
+ return;
39
+ }
40
+
41
+ spinner.text = 'Creating directory...';
42
+ spinner.color = 'cyan';
43
+ await fs.ensureDir(path.dirname(installPath));
44
+
45
+ spinner.text = 'Cloning Fuego repository...';
46
+ spinner.color = 'red';
47
+
48
+ // Clone the main Fuego repo
49
+ const repoUrl = 'https://github.com/willmcdeezy/fuego.git';
50
+ execSync(`git clone ${repoUrl} "${installPath}"`, { stdio: 'pipe' });
51
+
52
+ spinner.stop();
53
+
54
+ // Show contextual next steps
55
+ const relativePath = path.relative(process.cwd(), installPath);
56
+ const cdPath = relativePath.startsWith('..') ? installPath : relativePath;
57
+ const safeCdPath = cdPath.includes(' ') ? `"${cdPath}"` : cdPath;
58
+
59
+ showSuccess(
60
+ '🔥 Fuego Installed Successfully!',
61
+ `Location: ${chalk.cyan(installPath)}`
62
+ );
63
+
64
+ showInfo('🚀 Next Steps', [
65
+ `cd ${safeCdPath}`,
66
+ 'npm install',
67
+ 'npm run start'
68
+ ]);
69
+
70
+ flameDivider();
71
+
72
+ } catch (error: any) {
73
+ spinner.fail(chalk.red(`Installation failed: ${error.message}`));
74
+
75
+ // Cleanup on failure
76
+ if (fs.existsSync(installPath)) {
77
+ fs.removeSync(installPath);
78
+ }
79
+
80
+ process.exit(1);
81
+ }
82
+ }
package/src/index.ts ADDED
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import { createCommand } from './commands/create.js';
6
+ import { installCommand } from './commands/install.js';
7
+ import { addressCommand } from './commands/address.js';
8
+ import { showBanner } from './lib/ascii.js';
9
+
10
+ async function main() {
11
+ // Show banner for help and when no args provided
12
+ const args = process.argv.slice(2);
13
+ if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
14
+ showBanner();
15
+ }
16
+
17
+ const program = new Command();
18
+
19
+ program
20
+ .name('fuego')
21
+ .description('🔥 Fuego CLI - Sovereign Solana wallet for AI agents')
22
+ .version('0.1.0')
23
+ .configureOutput({
24
+ outputError: (str, write) => write(chalk.red(str))
25
+ });
26
+
27
+ program
28
+ .command('create')
29
+ .description('Create a new Fuego wallet')
30
+ .option('-f, --force', 'Overwrite existing wallet')
31
+ .option('-d, --directory <path>', 'Custom config directory')
32
+ .option('-n, --name <name>', 'Wallet name', 'default')
33
+ .action(createCommand);
34
+
35
+ program
36
+ .command('install')
37
+ .description('Install the main Fuego project (for agents)')
38
+ .option('-p, --path <path>', 'Installation path (default: ~/.openclaw/workspace/fuego if exists, else ./fuego)')
39
+ .action(installCommand);
40
+
41
+ program
42
+ .command('address')
43
+ .alias('addr')
44
+ .description('Show your wallet address')
45
+ .action(addressCommand);
46
+
47
+ await program.parseAsync(process.argv);
48
+ }
49
+
50
+ main().catch((error) => {
51
+ console.error(chalk.red(`\n❌ Error: ${error.message}`));
52
+ process.exit(1);
53
+ });
@@ -0,0 +1,94 @@
1
+ import figlet from 'figlet';
2
+ import gradient from 'gradient-string';
3
+ import boxen from 'boxen';
4
+ import chalk from 'chalk';
5
+
6
+ // Fire gradient for Fuego branding
7
+ const fireGradient = gradient(['#ff6b35', '#f7931e', '#ffd23f']);
8
+
9
+ /**
10
+ * Display the Fuego ASCII banner
11
+ */
12
+ export function showBanner(): void {
13
+ const banner = figlet.textSync('FUEGO', {
14
+ font: 'Big',
15
+ horizontalLayout: 'default',
16
+ verticalLayout: 'default'
17
+ });
18
+
19
+ console.log(fireGradient.multiline(banner));
20
+ console.log(chalk.gray(' Sovereign Solana wallet for AI agents\n'));
21
+ }
22
+
23
+ /**
24
+ * Display a success message in a box
25
+ */
26
+ export function showSuccess(title: string, message: string): void {
27
+ const content = `${chalk.bold.green(title)}\n\n${message}`;
28
+ console.log(
29
+ boxen(content, {
30
+ padding: 1,
31
+ margin: { top: 1, bottom: 1 },
32
+ borderStyle: 'round',
33
+ borderColor: 'green',
34
+ backgroundColor: '#0a0a0a'
35
+ })
36
+ );
37
+ }
38
+
39
+ /**
40
+ * Display an error message in a box
41
+ */
42
+ export function showError(message: string): void {
43
+ console.log(
44
+ boxen(chalk.red(message), {
45
+ padding: 1,
46
+ margin: { top: 1, bottom: 1 },
47
+ borderStyle: 'bold',
48
+ borderColor: 'red'
49
+ })
50
+ );
51
+ }
52
+
53
+ /**
54
+ * Display a warning message in a box
55
+ */
56
+ export function showWarning(message: string): void {
57
+ console.log(
58
+ boxen(chalk.yellow(message), {
59
+ padding: 1,
60
+ margin: { top: 0, bottom: 1 },
61
+ borderStyle: 'round',
62
+ borderColor: 'yellow'
63
+ })
64
+ );
65
+ }
66
+
67
+ /**
68
+ * Display info in a subtle box
69
+ */
70
+ export function showInfo(title: string, lines: string[]): void {
71
+ const content = chalk.bold.cyan(title) + '\n\n' + lines.map(l => chalk.white(l)).join('\n');
72
+ console.log(
73
+ boxen(content, {
74
+ padding: 1,
75
+ margin: { top: 0, bottom: 1 },
76
+ borderStyle: 'single',
77
+ borderColor: 'cyan'
78
+ })
79
+ );
80
+ }
81
+
82
+ /**
83
+ * Format a public key with fire styling
84
+ */
85
+ export function formatPublicKey(key: string): string {
86
+ return fireGradient(key);
87
+ }
88
+
89
+ /**
90
+ * Show a flame divider
91
+ */
92
+ export function flameDivider(): void {
93
+ console.log(fireGradient('━'.repeat(50)));
94
+ }
@@ -0,0 +1,74 @@
1
+ import fs from 'fs-extra';
2
+ import path from 'path';
3
+ import os from 'os';
4
+
5
+ const CONFIG_DIR = path.join(os.homedir(), '.fuego');
6
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
7
+ const WALLET_FILE = path.join(CONFIG_DIR, 'wallet.json');
8
+ const WALLET_CONFIG_FILE = path.join(CONFIG_DIR, 'wallet-config.json');
9
+
10
+ interface Config {
11
+ rpcUrl?: string;
12
+ network?: 'mainnet' | 'devnet' | 'testnet';
13
+ defaultToken?: string;
14
+ [key: string]: string | undefined;
15
+ }
16
+
17
+ interface WalletConfig {
18
+ publicKey: string;
19
+ name?: string;
20
+ label?: string;
21
+ createdAt: string;
22
+ version: string;
23
+ }
24
+
25
+ export function getWalletPath(): string {
26
+ return WALLET_FILE;
27
+ }
28
+
29
+ export function getWalletConfigPath(): string {
30
+ return WALLET_CONFIG_FILE;
31
+ }
32
+
33
+ export function getConfigPath(): string {
34
+ return CONFIG_FILE;
35
+ }
36
+
37
+ export function loadWalletConfig(): WalletConfig | null {
38
+ if (!fs.existsSync(WALLET_CONFIG_FILE)) {
39
+ return null;
40
+ }
41
+ return fs.readJsonSync(WALLET_CONFIG_FILE);
42
+ }
43
+
44
+ export function saveWalletConfig(config: WalletConfig): void {
45
+ fs.ensureDirSync(CONFIG_DIR);
46
+ fs.writeJsonSync(WALLET_CONFIG_FILE, config, { spaces: 2 });
47
+ }
48
+
49
+ function loadConfig(): Config {
50
+ if (!fs.existsSync(CONFIG_FILE)) {
51
+ return {};
52
+ }
53
+ return fs.readJsonSync(CONFIG_FILE);
54
+ }
55
+
56
+ function saveConfig(config: Config): void {
57
+ fs.ensureDirSync(CONFIG_DIR);
58
+ fs.writeJsonSync(CONFIG_FILE, config, { spaces: 2 });
59
+ }
60
+
61
+ export function getConfig(key: string): string | undefined {
62
+ const config = loadConfig();
63
+ return config[key];
64
+ }
65
+
66
+ export function setConfig(key: string, value: string): void {
67
+ const config = loadConfig();
68
+ config[key] = value;
69
+ saveConfig(config);
70
+ }
71
+
72
+ export function listConfig(): Config {
73
+ return loadConfig();
74
+ }