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.
- package/README.md +109 -0
- package/dist/commands/address.d.ts +2 -0
- package/dist/commands/address.d.ts.map +1 -0
- package/dist/commands/address.js +20 -0
- package/dist/commands/address.js.map +1 -0
- package/dist/commands/create.d.ts +8 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +57 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/install.d.ts +6 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +58 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/ascii.d.ts +29 -0
- package/dist/lib/ascii.d.ts.map +1 -0
- package/dist/lib/ascii.js +78 -0
- package/dist/lib/ascii.js.map +1 -0
- package/dist/lib/config.d.ts +23 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +49 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/wallet.d.ts +44 -0
- package/dist/lib/wallet.d.ts.map +1 -0
- package/dist/lib/wallet.js +118 -0
- package/dist/lib/wallet.js.map +1 -0
- package/fuego-cli-0.1.0.tgz +0 -0
- package/package.json +57 -0
- package/src/commands/address.ts +25 -0
- package/src/commands/create.ts +81 -0
- package/src/commands/install.ts +82 -0
- package/src/index.ts +53 -0
- package/src/lib/ascii.ts +94 -0
- package/src/lib/config.ts +74 -0
- package/src/lib/wallet.ts +189 -0
- package/tsconfig.json +20 -0
|
@@ -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":"AAAA,OAAO,EACL,OAAO,EACP,UAAU,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,gBAAgB,EACjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AA0BnF,MAAM,OAAO,WAAW;IACd,UAAU,CAAS;IACnB,OAAO,CAAW;IAE1B,YAAY,UAAmB;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,aAAa,EAAE,CAAC;IAClD,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAa;QACxB,0BAA0B;QAC1B,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAElD,uBAAuB;QACvB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;QAEpD,2DAA2D;QAC3D,MAAM,UAAU,GAAG;YACjB,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;SAC9C,CAAC;QAEF,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAEhD,sDAAsD;QACtD,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAEvC,yDAAyD;QACzD,gBAAgB,CAAC;YACf,SAAS;YACT,IAAI,EAAE,IAAI,IAAI,SAAS;YACvB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,OAAO,EAAE,OAAO;SACjB,CAAC,CAAC;QAEH,OAAO;YACL,SAAS;YACT,QAAQ,EAAE,SAAS;SACpB,CAAC;IACJ,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC;QAEtC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;QAE5E,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,YAAY;QACV,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;QAC3C,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,wEAAwE;QACxE,MAAM,UAAU,GAAG,mBAAmB,EAAE,CAAC;QACzC,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC;YAC3C,OAAO,MAAM,CAAC,SAAS,CAAC;QAC1B,CAAC;QAED,oCAAoC;QACpC,MAAM,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpD,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC;QACxE,OAAO,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAExC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEhE,iCAAiC;QAEjC,OAAO;YACL,GAAG,EAAE,QAAQ,GAAG,gBAAgB;YAChC,MAAM,EAAE,EAAE;SACX,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAKV;QACC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEtD,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAE3C,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,GAAG,gBAAgB,CAAC;YAElD,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC,GAAG,CACvC,aAAa,CAAC,QAAQ,CAAC;gBACrB,UAAU,EAAE,OAAO,CAAC,SAAS;gBAC7B,QAAQ,EAAE,SAAS;gBACnB,QAAQ;aACT,CAAC,CACH,CAAC;YAEF,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YAE3E,wBAAwB;YACxB,MAAM,UAAU,CAAC,kBAAkB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;YAE5D,OAAO;gBACL,SAAS;gBACT,YAAY,EAAE,WAAW;aAC1B,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,4BAA4B;YAC5B,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAa;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC;QAExC,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,uBAAuB,CACzD,OAAO,CAAC,SAAS,EACjB,EAAE,KAAK,EAAE,CACV,CAAC;QAEF,OAAO,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC5B,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,sDAAsD;YAC/F,MAAM,EAAE,GAAG,EAAE,4BAA4B;YACzC,KAAK,EAAE,KAAK;YACZ,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;SAC7D,CAAC,CAAC,CAAC;IACN,CAAC;IAEO,aAAa,CAAC,MAAe;QACnC,MAAM,QAAQ,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,qCAAqC,CAAC;QAC9F,OAAO,IAAI,UAAU,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC/C,CAAC;CACF"}
|
|
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
|
+
});
|
package/src/lib/ascii.ts
ADDED
|
@@ -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
|
+
}
|