@bfun-bot/cli 1.0.5
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 +93 -0
- package/bin/bfunbot.js +2 -0
- package/dist/commands/about.d.ts +5 -0
- package/dist/commands/about.js +62 -0
- package/dist/commands/balances.d.ts +5 -0
- package/dist/commands/balances.js +48 -0
- package/dist/commands/config.d.ts +5 -0
- package/dist/commands/config.js +53 -0
- package/dist/commands/fees.d.ts +7 -0
- package/dist/commands/fees.js +99 -0
- package/dist/commands/llm.d.ts +5 -0
- package/dist/commands/llm.js +216 -0
- package/dist/commands/login.d.ts +5 -0
- package/dist/commands/login.js +109 -0
- package/dist/commands/quota.d.ts +5 -0
- package/dist/commands/quota.js +28 -0
- package/dist/commands/skills.d.ts +5 -0
- package/dist/commands/skills.js +32 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.js +33 -0
- package/dist/commands/token.d.ts +5 -0
- package/dist/commands/token.js +150 -0
- package/dist/commands/tokens.d.ts +5 -0
- package/dist/commands/tokens.js +45 -0
- package/dist/commands/whoami.d.ts +5 -0
- package/dist/commands/whoami.js +25 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +86 -0
- package/dist/lib/api.d.ts +32 -0
- package/dist/lib/api.js +172 -0
- package/dist/lib/config.d.ts +31 -0
- package/dist/lib/config.js +86 -0
- package/dist/lib/display.d.ts +36 -0
- package/dist/lib/display.js +120 -0
- package/dist/types.d.ts +172 -0
- package/dist/types.js +4 -0
- package/package.json +44 -0
- package/scripts/postinstall.js +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# BFunBot CLI
|
|
2
|
+
|
|
3
|
+
Deploy tokens, check balances, and manage your AI agent from the terminal.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @bfun_bot/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Authenticate
|
|
15
|
+
bfunbot login
|
|
16
|
+
|
|
17
|
+
# Create a token
|
|
18
|
+
bfunbot token create --name "My Token" --symbol MYT
|
|
19
|
+
|
|
20
|
+
# Check balances
|
|
21
|
+
bfunbot balances
|
|
22
|
+
|
|
23
|
+
# Check fee earnings
|
|
24
|
+
bfunbot fees
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Commands
|
|
28
|
+
|
|
29
|
+
| Command | Description |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `bfunbot login` | Authenticate with your BFunBot API key |
|
|
32
|
+
| `bfunbot logout` | Clear stored credentials |
|
|
33
|
+
| `bfunbot whoami` | Show current user info |
|
|
34
|
+
| `bfunbot token create` | Create a new token |
|
|
35
|
+
| `bfunbot token info <address>` | Get token details |
|
|
36
|
+
| `bfunbot tokens created` | List tokens you've created |
|
|
37
|
+
| `bfunbot status <jobId>` | Check job status |
|
|
38
|
+
| `bfunbot balances` | Show wallet balances (BSC) |
|
|
39
|
+
| `bfunbot quota` | Show daily API quota |
|
|
40
|
+
| `bfunbot fees` | Check fee earnings summary |
|
|
41
|
+
| `bfunbot fees --platform flap` | Per-platform fee breakdown |
|
|
42
|
+
| `bfunbot llm models` | List available LLM models |
|
|
43
|
+
| `bfunbot llm credits` | Check BFun.bot Credits balance |
|
|
44
|
+
| `bfunbot llm reload` | Reload credits from trading wallet |
|
|
45
|
+
| `bfunbot llm setup openclaw` | Configure OpenClaw integration |
|
|
46
|
+
| `bfunbot skills` | List agent capabilities |
|
|
47
|
+
| `bfunbot config get` | Show current config |
|
|
48
|
+
| `bfunbot config set` | Set a config value |
|
|
49
|
+
| `bfunbot about` | About BFunBot CLI |
|
|
50
|
+
|
|
51
|
+
## Authentication
|
|
52
|
+
|
|
53
|
+
Get your API key at [bfun.bot/settings/api-keys](https://bfun.bot/settings/api-keys).
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bfunbot login --api-key bfbot_...
|
|
57
|
+
# or open browser
|
|
58
|
+
bfunbot login --url
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Config is stored at `~/.bfunbot/config.json` (permissions: 0600).
|
|
62
|
+
|
|
63
|
+
You can also set `BFUN_API_KEY` environment variable instead of storing a key.
|
|
64
|
+
|
|
65
|
+
## Networks
|
|
66
|
+
|
|
67
|
+
BSC (BNB Chain) only — flap and fourmeme platforms.
|
|
68
|
+
|
|
69
|
+
## LLM Gateway
|
|
70
|
+
|
|
71
|
+
The BFun LLM Gateway gives your agent access to frontier AI models (Claude, GPT, Gemini), billed from your BFun.bot Credits balance.
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Set up OpenClaw integration
|
|
75
|
+
bfunbot llm setup openclaw --install
|
|
76
|
+
|
|
77
|
+
# Check credit balance
|
|
78
|
+
bfunbot llm credits
|
|
79
|
+
|
|
80
|
+
# Reload credits from trading wallet
|
|
81
|
+
bfunbot llm reload
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Global Options
|
|
85
|
+
|
|
86
|
+
- `--json` — Machine-readable JSON output
|
|
87
|
+
- `--debug` — Verbose HTTP request/response logging
|
|
88
|
+
|
|
89
|
+
## Links
|
|
90
|
+
|
|
91
|
+
- Website: [bfun.bot](https://bfun.bot)
|
|
92
|
+
- Docs: [bfun.bot/docs/agent](https://bfun.bot/docs/agent)
|
|
93
|
+
- GitHub: [github.com/BFunBot](https://github.com/BFunBot)
|
package/bin/bfunbot.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { readFileSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { join, dirname } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { homedir } from 'node:os';
|
|
6
|
+
function getVersion() {
|
|
7
|
+
try {
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf-8'));
|
|
10
|
+
return pkg.version || 'unknown';
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return 'unknown';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function registerAbout(program) {
|
|
17
|
+
program
|
|
18
|
+
.command('about')
|
|
19
|
+
.description('About BFunBot CLI')
|
|
20
|
+
.action(() => {
|
|
21
|
+
const version = getVersion();
|
|
22
|
+
const W = 43; // inner width between ║ borders
|
|
23
|
+
function pad(text, displayWidth) {
|
|
24
|
+
const dw = displayWidth ?? text.length;
|
|
25
|
+
const padding = W - dw;
|
|
26
|
+
return text + ' '.repeat(Math.max(0, padding));
|
|
27
|
+
}
|
|
28
|
+
const lines = [
|
|
29
|
+
'',
|
|
30
|
+
' B F U N . B O T',
|
|
31
|
+
'',
|
|
32
|
+
' Deploy tokens. Earn fees.',
|
|
33
|
+
' Self-fund your AI agent.',
|
|
34
|
+
'',
|
|
35
|
+
` Version ${version}`,
|
|
36
|
+
' Website bfun.bot',
|
|
37
|
+
' Docs bfun.bot/docs/agent',
|
|
38
|
+
' GitHub github.com/BFunBot',
|
|
39
|
+
'',
|
|
40
|
+
' BSC',
|
|
41
|
+
'',
|
|
42
|
+
];
|
|
43
|
+
console.log();
|
|
44
|
+
console.log(chalk.cyan(` ╔${'═'.repeat(W)}╗`));
|
|
45
|
+
for (const line of lines) {
|
|
46
|
+
console.log(chalk.cyan(' ║') + pad(line) + chalk.cyan('║'));
|
|
47
|
+
}
|
|
48
|
+
console.log(chalk.cyan(` ╚${'═'.repeat(W)}╝`));
|
|
49
|
+
console.log();
|
|
50
|
+
// Mark as welcomed
|
|
51
|
+
try {
|
|
52
|
+
const bfunDir = join(homedir(), '.bfunbot');
|
|
53
|
+
const marker = join(bfunDir, '.welcomed');
|
|
54
|
+
if (!existsSync(marker)) {
|
|
55
|
+
if (!existsSync(bfunDir))
|
|
56
|
+
mkdirSync(bfunDir, { recursive: true });
|
|
57
|
+
writeFileSync(marker, new Date().toISOString());
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch { }
|
|
61
|
+
});
|
|
62
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { agent, handleApiError } from '../lib/api.js';
|
|
3
|
+
import { fmtBalance, shortAddr } from '../lib/display.js';
|
|
4
|
+
function printWallet(label, slot) {
|
|
5
|
+
if (!slot.address) {
|
|
6
|
+
console.log(` ${chalk.dim(label + ':')} ${chalk.dim('Not configured')}`);
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
console.log(` ${chalk.bold(label)} ${chalk.dim(shortAddr(slot.address))}`);
|
|
10
|
+
const balances = [
|
|
11
|
+
['BNB (BSC)', slot.balance_bnb, slot.bnb_error],
|
|
12
|
+
['USDT (BSC)', slot.balance_usdt_bsc, slot.usdt_bsc_error],
|
|
13
|
+
];
|
|
14
|
+
for (const [name, value, error] of balances) {
|
|
15
|
+
if (error) {
|
|
16
|
+
console.log(` ${name.padEnd(14)} ${chalk.red('error')}`);
|
|
17
|
+
}
|
|
18
|
+
else if (name === 'BNB (BSC)' || (value && parseFloat(value) > 0)) {
|
|
19
|
+
const symbol = name.split(' ')[0];
|
|
20
|
+
console.log(` ${name.padEnd(14)} ${fmtBalance(value, symbol)}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
console.log();
|
|
24
|
+
}
|
|
25
|
+
export function registerBalances(program) {
|
|
26
|
+
program
|
|
27
|
+
.command('balances')
|
|
28
|
+
.description('Show wallet balances (BSC)')
|
|
29
|
+
.action(async (_, cmd) => {
|
|
30
|
+
try {
|
|
31
|
+
const res = await agent.walletBalance();
|
|
32
|
+
const isJson = cmd.optsWithGlobals().json;
|
|
33
|
+
if (isJson) {
|
|
34
|
+
console.log(JSON.stringify(res, null, 2));
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
console.log();
|
|
38
|
+
console.log(chalk.bold.cyan('Wallet Balances'));
|
|
39
|
+
console.log(chalk.dim('─'.repeat(40)));
|
|
40
|
+
console.log();
|
|
41
|
+
printWallet('EVM Main', res.evm_main);
|
|
42
|
+
printWallet('EVM Trading', res.evm_trading);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
handleApiError(err);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { readConfig, setConfigValue, CONFIG_PATH } from '../lib/config.js';
|
|
3
|
+
const VALID_KEYS = ['apiKey'];
|
|
4
|
+
function maskKey(key) {
|
|
5
|
+
if (key.length <= 8)
|
|
6
|
+
return '***';
|
|
7
|
+
return key.slice(0, 6) + '...' + key.slice(-4);
|
|
8
|
+
}
|
|
9
|
+
export function registerConfig(program) {
|
|
10
|
+
const configCmd = program
|
|
11
|
+
.command('config')
|
|
12
|
+
.description('Read or write CLI configuration');
|
|
13
|
+
configCmd
|
|
14
|
+
.command('get [key]')
|
|
15
|
+
.description('Show config values')
|
|
16
|
+
.action((key) => {
|
|
17
|
+
const config = readConfig();
|
|
18
|
+
if (key) {
|
|
19
|
+
if (!VALID_KEYS.includes(key)) {
|
|
20
|
+
console.error(`Error: Unknown key '${key}'. Valid keys: ${VALID_KEYS.join(', ')}`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
const value = config[key];
|
|
24
|
+
if (value) {
|
|
25
|
+
console.log(key === 'apiKey' ? maskKey(value) : value);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
console.log(chalk.dim('(not set)'));
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Show all
|
|
33
|
+
console.log();
|
|
34
|
+
console.log(chalk.bold.cyan('Configuration'));
|
|
35
|
+
console.log(chalk.dim('─'.repeat(40)));
|
|
36
|
+
console.log(` ${chalk.dim('File:')} ${CONFIG_PATH}`);
|
|
37
|
+
console.log(` ${chalk.dim('apiKey:')} ${config.apiKey ? maskKey(config.apiKey) : chalk.dim('(not set)')}`);
|
|
38
|
+
console.log(` ${chalk.dim('apiUrl:')} ${'https://api.bfun.bot'}`);
|
|
39
|
+
console.log(` ${chalk.dim('llmUrl:')} ${'https://llm.bfun.bot/v1'}`);
|
|
40
|
+
console.log();
|
|
41
|
+
});
|
|
42
|
+
configCmd
|
|
43
|
+
.command('set <key> <value>')
|
|
44
|
+
.description('Set a config value (apiKey)')
|
|
45
|
+
.action((key, value) => {
|
|
46
|
+
if (!VALID_KEYS.includes(key)) {
|
|
47
|
+
console.error(`Error: Unknown key '${key}'. Valid keys: ${VALID_KEYS.join(', ')}`);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
setConfigValue(key, value);
|
|
51
|
+
console.log(chalk.green('✓') + ` ${key} updated`);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { agent, handleApiError } from '../lib/api.js';
|
|
3
|
+
import { fmtBalance, printTable } from '../lib/display.js';
|
|
4
|
+
const VALID_PLATFORMS = ['flap', 'fourmeme'];
|
|
5
|
+
// ─── Display Helpers ─────────────────────────────────────
|
|
6
|
+
function printSummary(res) {
|
|
7
|
+
console.log();
|
|
8
|
+
console.log(chalk.bold.cyan('Fee Earnings Summary'));
|
|
9
|
+
console.log(chalk.dim('─'.repeat(44)));
|
|
10
|
+
console.log();
|
|
11
|
+
console.log(` ${chalk.bold('BSC (BNB Chain)')} ${chalk.dim(res.bsc.token_count + ' tokens')}`);
|
|
12
|
+
console.log(` ${'Total Earned'.padEnd(22)} ${fmtBalance(res.bsc.total_earned_bnb.toString(), 'BNB')}`);
|
|
13
|
+
console.log();
|
|
14
|
+
}
|
|
15
|
+
function printEarnings(res) {
|
|
16
|
+
console.log();
|
|
17
|
+
console.log(chalk.bold.cyan(`Fee Earnings · BSC`));
|
|
18
|
+
console.log(chalk.dim('─'.repeat(44)));
|
|
19
|
+
console.log();
|
|
20
|
+
printTable(['Platform', 'Earned', 'Tokens'], [
|
|
21
|
+
['flap', fmtBalance(res.flap.total_earned_bnb.toString(), 'BNB'), res.flap.earning_token_count.toString()],
|
|
22
|
+
['fourmeme', fmtBalance(res.fourmeme.total_earned_bnb.toString(), 'BNB'), res.fourmeme.earning_token_count.toString()],
|
|
23
|
+
]);
|
|
24
|
+
}
|
|
25
|
+
function printToken(res) {
|
|
26
|
+
if ('supported' in res && res.supported === false) {
|
|
27
|
+
console.log();
|
|
28
|
+
console.log(chalk.yellow('⚠') + ' ' + res.message);
|
|
29
|
+
console.log();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const bsc = res;
|
|
33
|
+
console.log();
|
|
34
|
+
console.log(chalk.bold.cyan('Token Fee Earnings'));
|
|
35
|
+
console.log(chalk.dim('─'.repeat(44)));
|
|
36
|
+
console.log();
|
|
37
|
+
console.log(` ${'Token'.padEnd(14)} ${bsc.token_name} (${bsc.token_symbol})`);
|
|
38
|
+
console.log(` ${'Address'.padEnd(14)} ${chalk.dim(bsc.token_address)}`);
|
|
39
|
+
console.log(` ${'Platform'.padEnd(14)} ${bsc.platform}`);
|
|
40
|
+
console.log(` ${'Earned'.padEnd(14)} ${fmtBalance(bsc.earned_bnb.toString(), 'BNB')}`);
|
|
41
|
+
console.log();
|
|
42
|
+
}
|
|
43
|
+
// ─── Command Registration ─────────────────────────────────
|
|
44
|
+
export function registerFees(program) {
|
|
45
|
+
program
|
|
46
|
+
.command('fees')
|
|
47
|
+
.description('Check fee earnings (summary, per-platform, or per-token)')
|
|
48
|
+
.option('--platform <platform>', 'Platform: flap or fourmeme')
|
|
49
|
+
.option('--token <address>', 'Token contract address')
|
|
50
|
+
.action(async (opts, cmd) => {
|
|
51
|
+
const isJson = cmd.optsWithGlobals().json;
|
|
52
|
+
try {
|
|
53
|
+
// Per-token: requires --platform and --token
|
|
54
|
+
if (opts.token) {
|
|
55
|
+
const platform = opts.platform;
|
|
56
|
+
if (!platform) {
|
|
57
|
+
console.error(chalk.red('Error:') + ' --platform is required with --token. Use: bfunbot fees --platform flap --token <address>');
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
if (!VALID_PLATFORMS.includes(platform)) {
|
|
61
|
+
console.error(chalk.red('Error:') + ` Platform must be one of: ${VALID_PLATFORMS.join(', ')}`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
const res = await agent.feesToken('bsc', platform, opts.token);
|
|
65
|
+
if (isJson) {
|
|
66
|
+
console.log(JSON.stringify(res, null, 2));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
printToken(res);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// Per-platform breakdown
|
|
73
|
+
if (opts.platform) {
|
|
74
|
+
if (!VALID_PLATFORMS.includes(opts.platform)) {
|
|
75
|
+
console.error(chalk.red('Error:') + ` Platform must be one of: ${VALID_PLATFORMS.join(', ')}`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
// Show full breakdown (both platforms) — the platform flag is for future filtering
|
|
79
|
+
const res = await agent.feesEarnings('bsc');
|
|
80
|
+
if (isJson) {
|
|
81
|
+
console.log(JSON.stringify(res, null, 2));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
printEarnings(res);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Default: summary
|
|
88
|
+
const res = await agent.feesSummary();
|
|
89
|
+
if (isJson) {
|
|
90
|
+
console.log(JSON.stringify(res, null, 2));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
printSummary(res);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
handleApiError(err);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { agent, llm, handleApiError } from '../lib/api.js';
|
|
4
|
+
import { readConfig } from '../lib/config.js';
|
|
5
|
+
import { printCard, success } from '../lib/display.js';
|
|
6
|
+
export function registerLlm(program) {
|
|
7
|
+
const llmCmd = program
|
|
8
|
+
.command('llm')
|
|
9
|
+
.description('LLM Gateway commands');
|
|
10
|
+
// ── llm models ────────────────────────────────────────
|
|
11
|
+
llmCmd
|
|
12
|
+
.command('models')
|
|
13
|
+
.description('List available LLM models')
|
|
14
|
+
.action(async (_, cmd) => {
|
|
15
|
+
try {
|
|
16
|
+
const res = await llm.models();
|
|
17
|
+
const isJson = cmd.optsWithGlobals().json;
|
|
18
|
+
if (isJson) {
|
|
19
|
+
console.log(JSON.stringify(res, null, 2));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const models = res.models || [];
|
|
23
|
+
if (models.length === 0) {
|
|
24
|
+
console.log('\nNo models available.\n');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
console.log();
|
|
28
|
+
console.log(chalk.bold.cyan(`Available Models (${models.length})`));
|
|
29
|
+
console.log(chalk.dim('─'.repeat(40)));
|
|
30
|
+
for (const modelId of models) {
|
|
31
|
+
console.log(` ${chalk.bold(modelId)}`);
|
|
32
|
+
}
|
|
33
|
+
console.log();
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
handleApiError(err);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
// ── llm credits ───────────────────────────────────────
|
|
40
|
+
llmCmd
|
|
41
|
+
.command('credits')
|
|
42
|
+
.description('Check your BFun.bot Credits balance')
|
|
43
|
+
.action(async (_, cmd) => {
|
|
44
|
+
try {
|
|
45
|
+
const res = await agent.creditBalance();
|
|
46
|
+
const isJson = cmd.optsWithGlobals().json;
|
|
47
|
+
if (isJson) {
|
|
48
|
+
console.log(JSON.stringify(res, null, 2));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
printCard('BFun.bot Credits', [
|
|
52
|
+
['Balance', `$${res.balance_usd}`],
|
|
53
|
+
]);
|
|
54
|
+
// Show agent reload config
|
|
55
|
+
if (res.agent_reload) {
|
|
56
|
+
const r = res.agent_reload;
|
|
57
|
+
console.log();
|
|
58
|
+
if (r.enabled) {
|
|
59
|
+
console.log(` ${chalk.dim('Agent Reload:')} ${chalk.green('ON')}`);
|
|
60
|
+
console.log(` ${chalk.dim('Amount:')} $${r.amount_usd.toFixed(2)}`);
|
|
61
|
+
console.log(` ${chalk.dim('Daily Limit:')} $${r.daily_limit_usd.toFixed(2)}`);
|
|
62
|
+
console.log(` ${chalk.dim('Chains:')} ${r.chains.join(', ')}`);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
console.log(` ${chalk.dim('Agent Reload:')} ${chalk.dim('OFF')}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
handleApiError(err);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
// ── llm reload ────────────────────────────────────────
|
|
74
|
+
llmCmd
|
|
75
|
+
.command('reload')
|
|
76
|
+
.description('Reload BFun.bot Credits from trading wallet')
|
|
77
|
+
.option('--disable', 'Emergency disable agent reload')
|
|
78
|
+
.action(async (opts, cmd) => {
|
|
79
|
+
try {
|
|
80
|
+
if (opts.disable) {
|
|
81
|
+
await agent.disableReload();
|
|
82
|
+
const isJson = cmd.optsWithGlobals().json;
|
|
83
|
+
if (isJson) {
|
|
84
|
+
console.log(JSON.stringify({ disabled: true }));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
success('Agent reload disabled. Re-enable from your BFunBot dashboard.');
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const isJson = cmd.optsWithGlobals().json;
|
|
92
|
+
const spinner = ora('Reloading BFun.bot Credits from trading wallet...').start();
|
|
93
|
+
const res = await agent.reloadCredits();
|
|
94
|
+
if (isJson) {
|
|
95
|
+
spinner.stop();
|
|
96
|
+
console.log(JSON.stringify(res, null, 2));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
spinner.succeed('Reload complete!');
|
|
100
|
+
printCard('BFun.bot Credit Reload', [
|
|
101
|
+
['Amount', `$${res.amount_usd}`],
|
|
102
|
+
['Tx Hash', res.tx_hash],
|
|
103
|
+
['New Balance', res.new_balance_usd ? `$${res.new_balance_usd}` : undefined],
|
|
104
|
+
['Daily Used', `$${res.daily_used_usd} / $${res.daily_remaining_usd} remaining`],
|
|
105
|
+
]);
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
handleApiError(err);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
// ── llm setup ─────────────────────────────────────────
|
|
112
|
+
llmCmd
|
|
113
|
+
.command('setup <target>')
|
|
114
|
+
.description('Generate config for OpenClaw')
|
|
115
|
+
.option('--install', 'Write config directly to ~/.openclaw/openclaw.json')
|
|
116
|
+
.action(async (target, opts, cmd) => {
|
|
117
|
+
const config = readConfig();
|
|
118
|
+
const apiKey = config.apiKey || process.env['BFUN_API_KEY'];
|
|
119
|
+
if (!apiKey) {
|
|
120
|
+
console.error("Error: Not logged in. Run 'bfunbot login' first.");
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
switch (target.toLowerCase()) {
|
|
124
|
+
case 'openclaw': {
|
|
125
|
+
// Fetch model catalog from API — always up-to-date
|
|
126
|
+
let apiConfig;
|
|
127
|
+
try {
|
|
128
|
+
apiConfig = await llm.openclawConfig();
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
console.error('Error: Could not fetch model catalog from BFunBot API.');
|
|
132
|
+
if (err instanceof Error)
|
|
133
|
+
console.error(` ${err.message}`);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
// Build allowlist from fetched models
|
|
137
|
+
const allowlist = {};
|
|
138
|
+
for (const m of apiConfig.models) {
|
|
139
|
+
allowlist[`bfunbot/${m.id}`] = { alias: m.id };
|
|
140
|
+
}
|
|
141
|
+
const openclawConfig = {
|
|
142
|
+
models: {
|
|
143
|
+
mode: 'merge',
|
|
144
|
+
providers: {
|
|
145
|
+
bfunbot: {
|
|
146
|
+
baseUrl: apiConfig.baseUrl,
|
|
147
|
+
apiKey: apiKey,
|
|
148
|
+
api: apiConfig.api,
|
|
149
|
+
models: apiConfig.models.map(({ input, ...rest }) => rest),
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
agents: {
|
|
154
|
+
defaults: {
|
|
155
|
+
models: allowlist,
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
if (opts.install) {
|
|
160
|
+
try {
|
|
161
|
+
const { readFileSync, writeFileSync, existsSync, mkdirSync } = await import('node:fs');
|
|
162
|
+
const { join } = await import('node:path');
|
|
163
|
+
const { homedir } = await import('node:os');
|
|
164
|
+
const configDir = join(homedir(), '.openclaw');
|
|
165
|
+
const configPath = join(configDir, 'openclaw.json');
|
|
166
|
+
let existing = {};
|
|
167
|
+
if (existsSync(configPath)) {
|
|
168
|
+
try {
|
|
169
|
+
existing = JSON.parse(readFileSync(configPath, 'utf-8'));
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
existing = {};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
mkdirSync(configDir, { recursive: true });
|
|
177
|
+
}
|
|
178
|
+
// Deep merge providers
|
|
179
|
+
existing.models = existing.models || {};
|
|
180
|
+
existing.models.mode = 'merge';
|
|
181
|
+
existing.models.providers = existing.models.providers || {};
|
|
182
|
+
existing.models.providers.bfunbot = openclawConfig.models.providers.bfunbot;
|
|
183
|
+
// Deep merge agents.defaults.models (allowlist + aliases)
|
|
184
|
+
existing.agents = existing.agents || {};
|
|
185
|
+
existing.agents.defaults = existing.agents.defaults || {};
|
|
186
|
+
existing.agents.defaults.models = existing.agents.defaults.models || {};
|
|
187
|
+
Object.assign(existing.agents.defaults.models, openclawConfig.agents.defaults.models);
|
|
188
|
+
writeFileSync(configPath, JSON.stringify(existing, null, 2) + '\n', 'utf-8');
|
|
189
|
+
success(`BFunBot provider added to ${configPath}`);
|
|
190
|
+
console.log(chalk.dim(' Restart OpenClaw: openclaw gateway restart'));
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
console.error(`Error: Failed to write config — ${err instanceof Error ? err.message : err}`);
|
|
194
|
+
process.exit(1);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
console.log();
|
|
199
|
+
console.log(chalk.bold.cyan('OpenClaw Configuration'));
|
|
200
|
+
console.log(chalk.dim('─'.repeat(40)));
|
|
201
|
+
console.log();
|
|
202
|
+
console.log('Add this to your ~/.openclaw/openclaw.json:');
|
|
203
|
+
console.log();
|
|
204
|
+
console.log(JSON.stringify(openclawConfig, null, 2));
|
|
205
|
+
console.log();
|
|
206
|
+
console.log(chalk.dim('Or run: bfunbot llm setup openclaw --install'));
|
|
207
|
+
console.log();
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
default:
|
|
212
|
+
console.error(`Error: Unknown target '${target}'. Supported: openclaw`);
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
}
|