@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/dist/lib/api.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the BFunBot Agent API + LLM Gateway.
|
|
3
|
+
*
|
|
4
|
+
* Uses native fetch (Node 18+). Handles auth headers, error mapping,
|
|
5
|
+
* and --debug logging.
|
|
6
|
+
*/
|
|
7
|
+
import { readConfig, requireApiKey } from './config.js';
|
|
8
|
+
let debugEnabled = false;
|
|
9
|
+
export function enableDebug() {
|
|
10
|
+
debugEnabled = true;
|
|
11
|
+
}
|
|
12
|
+
// ─── Error Classes ───────────────────────────────────────
|
|
13
|
+
export class ApiError extends Error {
|
|
14
|
+
statusCode;
|
|
15
|
+
statusText;
|
|
16
|
+
body;
|
|
17
|
+
constructor(statusCode, statusText, body) {
|
|
18
|
+
const detail = body?.detail || body?.message || statusText;
|
|
19
|
+
super(detail);
|
|
20
|
+
this.statusCode = statusCode;
|
|
21
|
+
this.statusText = statusText;
|
|
22
|
+
this.body = body;
|
|
23
|
+
this.name = 'ApiError';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// ─── Friendly error messages ─────────────────────────────
|
|
27
|
+
function friendlyError(err) {
|
|
28
|
+
switch (err.statusCode) {
|
|
29
|
+
case 401:
|
|
30
|
+
return "Invalid or expired API key. Run 'bfunbot login' to re-authenticate.";
|
|
31
|
+
case 403:
|
|
32
|
+
return err.body?.detail || 'Access denied. Your API key may not have the required permissions.';
|
|
33
|
+
case 404:
|
|
34
|
+
return err.body?.detail || 'Not found.';
|
|
35
|
+
case 429: {
|
|
36
|
+
const detail = err.body?.detail;
|
|
37
|
+
if (typeof detail === 'object' && detail !== null && 'message' in detail)
|
|
38
|
+
return detail.message;
|
|
39
|
+
if (typeof detail === 'string')
|
|
40
|
+
return detail;
|
|
41
|
+
return 'Rate limited. Try again later.';
|
|
42
|
+
}
|
|
43
|
+
default: {
|
|
44
|
+
if (err.statusCode >= 500) {
|
|
45
|
+
return 'Server error. Try again later.';
|
|
46
|
+
}
|
|
47
|
+
const detail = err.body?.detail;
|
|
48
|
+
if (typeof detail === 'string')
|
|
49
|
+
return detail;
|
|
50
|
+
if (typeof detail === 'object' && detail !== null) {
|
|
51
|
+
const d = detail;
|
|
52
|
+
return d.message || d.error || JSON.stringify(detail);
|
|
53
|
+
}
|
|
54
|
+
return err.message || `HTTP ${err.statusCode}`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Print a friendly error message to stderr and exit.
|
|
60
|
+
*/
|
|
61
|
+
export function handleApiError(err) {
|
|
62
|
+
if (err instanceof ApiError) {
|
|
63
|
+
console.error(`Error: ${friendlyError(err)}`);
|
|
64
|
+
if (debugEnabled) {
|
|
65
|
+
console.error(` Status: ${err.statusCode} ${err.statusText}`);
|
|
66
|
+
if (err.body)
|
|
67
|
+
console.error(` Body: ${JSON.stringify(err.body)}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
else if (err instanceof TypeError && err.cause) {
|
|
71
|
+
console.error('Error: Could not reach BFunBot API. Check your connection.');
|
|
72
|
+
if (debugEnabled)
|
|
73
|
+
console.error(` ${err.message}`);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
77
|
+
}
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
async function request(path, opts = {}) {
|
|
81
|
+
const { method = 'GET', body, auth = true, baseLlm = false } = opts;
|
|
82
|
+
const config = readConfig();
|
|
83
|
+
const baseUrl = baseLlm
|
|
84
|
+
? (config.llmUrl || 'https://llm.bfun.bot/v1')
|
|
85
|
+
: (config.apiUrl || 'https://api.bfun.bot');
|
|
86
|
+
const url = `${baseUrl}${path}`;
|
|
87
|
+
const headers = {
|
|
88
|
+
'Accept': 'application/json',
|
|
89
|
+
};
|
|
90
|
+
if (auth) {
|
|
91
|
+
const apiKey = requireApiKey();
|
|
92
|
+
headers['X-API-Key'] = apiKey;
|
|
93
|
+
}
|
|
94
|
+
if (body) {
|
|
95
|
+
headers['Content-Type'] = 'application/json';
|
|
96
|
+
}
|
|
97
|
+
if (debugEnabled) {
|
|
98
|
+
console.error(`[debug] ${method} ${url}`);
|
|
99
|
+
if (body)
|
|
100
|
+
console.error(`[debug] Body: ${JSON.stringify(body)}`);
|
|
101
|
+
}
|
|
102
|
+
const response = await fetch(url, {
|
|
103
|
+
method,
|
|
104
|
+
headers,
|
|
105
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
106
|
+
});
|
|
107
|
+
if (debugEnabled) {
|
|
108
|
+
console.error(`[debug] Response: ${response.status} ${response.statusText}`);
|
|
109
|
+
}
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
let errorBody;
|
|
112
|
+
try {
|
|
113
|
+
errorBody = await response.json();
|
|
114
|
+
if (debugEnabled)
|
|
115
|
+
console.error(`[debug] Error body: ${JSON.stringify(errorBody)}`);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// non-JSON error response
|
|
119
|
+
}
|
|
120
|
+
throw new ApiError(response.status, response.statusText, errorBody);
|
|
121
|
+
}
|
|
122
|
+
// Handle 204 No Content (empty body)
|
|
123
|
+
if (response.status === 204) {
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
const data = await response.json();
|
|
127
|
+
if (debugEnabled) {
|
|
128
|
+
console.error(`[debug] Response body: ${JSON.stringify(data).slice(0, 500)}`);
|
|
129
|
+
}
|
|
130
|
+
return data;
|
|
131
|
+
}
|
|
132
|
+
// ─── Public API Methods ──────────────────────────────────
|
|
133
|
+
// Agent API (base: /agent/v1)
|
|
134
|
+
export const agent = {
|
|
135
|
+
me: () => request('/agent/v1/me'),
|
|
136
|
+
tokensCreated: (page = 1, pageSize = 20) => request(`/agent/v1/tokens/created?page=${page}&page_size=${pageSize}`),
|
|
137
|
+
tokenCreate: (body) => request('/agent/v1/token/create', {
|
|
138
|
+
method: 'POST',
|
|
139
|
+
body,
|
|
140
|
+
}),
|
|
141
|
+
tokenInfo: (address, chain) => {
|
|
142
|
+
const params = chain ? `?chain=${chain}` : '';
|
|
143
|
+
return request(`/agent/v1/token/${address}${params}`);
|
|
144
|
+
},
|
|
145
|
+
jobStatus: (jobId) => request(`/agent/v1/jobs/${jobId}`),
|
|
146
|
+
walletBalance: () => request('/agent/v1/balance/wallet'),
|
|
147
|
+
creditBalance: () => request('/agent/v1/balance/credits'),
|
|
148
|
+
reloadCredits: () => request('/agent/v1/balance/credits/reload', {
|
|
149
|
+
method: 'POST',
|
|
150
|
+
body: {},
|
|
151
|
+
}),
|
|
152
|
+
disableReload: () => request('/agent/v1/balance/credits/reload/disable', {
|
|
153
|
+
method: 'POST',
|
|
154
|
+
body: {},
|
|
155
|
+
}),
|
|
156
|
+
quota: () => request('/agent/v1/quota'),
|
|
157
|
+
skills: () => request('/agent/v1/skills', { auth: false }),
|
|
158
|
+
feesSummary: () => request('/agent/v1/fees/summary'),
|
|
159
|
+
feesEarnings: (chain) => request(`/agent/v1/fees/earnings?chain=${chain}`),
|
|
160
|
+
feesToken: (chain, platform, tokenAddress) => request(`/agent/v1/fees/token?chain=${chain}&platform=${platform}&token_address=${encodeURIComponent(tokenAddress)}`),
|
|
161
|
+
};
|
|
162
|
+
// LLM Gateway (base: /llm/v1)
|
|
163
|
+
export const llm = {
|
|
164
|
+
models: () => request('/models', {
|
|
165
|
+
baseLlm: true,
|
|
166
|
+
auth: false,
|
|
167
|
+
}),
|
|
168
|
+
openclawConfig: () => request('/models/openclaw', {
|
|
169
|
+
baseLlm: true,
|
|
170
|
+
auth: false,
|
|
171
|
+
}),
|
|
172
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BfunConfig } from '../types.js';
|
|
2
|
+
declare const CONFIG_DIR: string;
|
|
3
|
+
declare const CONFIG_PATH: string;
|
|
4
|
+
declare const DEFAULT_API_URL = "https://api.bfun.bot";
|
|
5
|
+
declare const DEFAULT_LLM_URL = "https://llm.bfun.bot/v1";
|
|
6
|
+
/**
|
|
7
|
+
* Read config from disk. Returns defaults for missing values.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readConfig(): BfunConfig;
|
|
10
|
+
/**
|
|
11
|
+
* Write config to disk. Merges with existing config.
|
|
12
|
+
* Creates ~/.bfunbot/ if needed. Sets file permissions to 0600.
|
|
13
|
+
*/
|
|
14
|
+
export declare function writeConfig(updates: Partial<BfunConfig>): void;
|
|
15
|
+
/**
|
|
16
|
+
* Delete config file (logout).
|
|
17
|
+
*/
|
|
18
|
+
export declare function clearConfig(): void;
|
|
19
|
+
/**
|
|
20
|
+
* Get a specific config value.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getConfigValue(key: keyof BfunConfig): string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Set a specific config value.
|
|
25
|
+
*/
|
|
26
|
+
export declare function setConfigValue(key: keyof BfunConfig, value: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Get the API key or throw a helpful error.
|
|
29
|
+
*/
|
|
30
|
+
export declare function requireApiKey(): string;
|
|
31
|
+
export { CONFIG_PATH, CONFIG_DIR, DEFAULT_API_URL, DEFAULT_LLM_URL };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config file management — read/write ~/.bfunbot/config.json
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync, mkdirSync, chmodSync, existsSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
const CONFIG_DIR = join(homedir(), '.bfunbot');
|
|
8
|
+
const CONFIG_PATH = join(CONFIG_DIR, 'config.json');
|
|
9
|
+
const DEFAULT_API_URL = 'https://api.bfun.bot';
|
|
10
|
+
const DEFAULT_LLM_URL = 'https://llm.bfun.bot/v1';
|
|
11
|
+
/**
|
|
12
|
+
* Read config from disk. Returns defaults for missing values.
|
|
13
|
+
*/
|
|
14
|
+
export function readConfig() {
|
|
15
|
+
try {
|
|
16
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
17
|
+
return { apiUrl: DEFAULT_API_URL, llmUrl: DEFAULT_LLM_URL };
|
|
18
|
+
}
|
|
19
|
+
const raw = readFileSync(CONFIG_PATH, 'utf-8');
|
|
20
|
+
const parsed = JSON.parse(raw);
|
|
21
|
+
return {
|
|
22
|
+
apiUrl: DEFAULT_API_URL,
|
|
23
|
+
llmUrl: DEFAULT_LLM_URL,
|
|
24
|
+
...parsed,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return { apiUrl: DEFAULT_API_URL, llmUrl: DEFAULT_LLM_URL };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Write config to disk. Merges with existing config.
|
|
33
|
+
* Creates ~/.bfunbot/ if needed. Sets file permissions to 0600.
|
|
34
|
+
*/
|
|
35
|
+
export function writeConfig(updates) {
|
|
36
|
+
const current = readConfig();
|
|
37
|
+
const merged = { ...current, ...updates };
|
|
38
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
39
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
42
|
+
chmodSync(CONFIG_PATH, 0o600);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Delete config file (logout).
|
|
46
|
+
*/
|
|
47
|
+
export function clearConfig() {
|
|
48
|
+
try {
|
|
49
|
+
if (existsSync(CONFIG_PATH)) {
|
|
50
|
+
writeFileSync(CONFIG_PATH, '{}\n', 'utf-8');
|
|
51
|
+
chmodSync(CONFIG_PATH, 0o600);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// ignore
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get a specific config value.
|
|
60
|
+
*/
|
|
61
|
+
export function getConfigValue(key) {
|
|
62
|
+
const config = readConfig();
|
|
63
|
+
return config[key];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Set a specific config value.
|
|
67
|
+
*/
|
|
68
|
+
export function setConfigValue(key, value) {
|
|
69
|
+
writeConfig({ [key]: value });
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get the API key or throw a helpful error.
|
|
73
|
+
*/
|
|
74
|
+
export function requireApiKey() {
|
|
75
|
+
// Env var takes precedence
|
|
76
|
+
const envKey = process.env['BFUN_API_KEY'];
|
|
77
|
+
if (envKey)
|
|
78
|
+
return envKey;
|
|
79
|
+
const config = readConfig();
|
|
80
|
+
if (!config.apiKey) {
|
|
81
|
+
console.error('Error: Not logged in. Run `bfunbot login` first.');
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
return config.apiKey;
|
|
85
|
+
}
|
|
86
|
+
export { CONFIG_PATH, CONFIG_DIR, DEFAULT_API_URL, DEFAULT_LLM_URL };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Print a key-value card.
|
|
3
|
+
*/
|
|
4
|
+
export declare function printCard(title: string, fields: [string, string | undefined][]): void;
|
|
5
|
+
/**
|
|
6
|
+
* Print a simple table with headers.
|
|
7
|
+
*/
|
|
8
|
+
export declare function printTable(headers: string[], rows: string[][]): void;
|
|
9
|
+
/**
|
|
10
|
+
* Truncate an address for display.
|
|
11
|
+
*/
|
|
12
|
+
export declare function shortAddr(addr: string | undefined | null, chars?: number): string;
|
|
13
|
+
/**
|
|
14
|
+
* Format a balance value.
|
|
15
|
+
*/
|
|
16
|
+
export declare function fmtBalance(value: string | undefined | null, symbol: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Format a USD value.
|
|
19
|
+
*/
|
|
20
|
+
export declare function fmtUsd(value: string | undefined | null): string;
|
|
21
|
+
/**
|
|
22
|
+
* Format a date string.
|
|
23
|
+
*/
|
|
24
|
+
export declare function fmtDate(dateStr: string | undefined | null): string;
|
|
25
|
+
/**
|
|
26
|
+
* Print a success message.
|
|
27
|
+
*/
|
|
28
|
+
export declare function success(msg: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Print an error message to stderr.
|
|
31
|
+
*/
|
|
32
|
+
export declare function error(msg: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Print a warning message.
|
|
35
|
+
*/
|
|
36
|
+
export declare function warn(msg: string): void;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal display helpers — tables, cards, formatting.
|
|
3
|
+
*/
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
/**
|
|
6
|
+
* Print a key-value card.
|
|
7
|
+
*/
|
|
8
|
+
export function printCard(title, fields) {
|
|
9
|
+
console.log();
|
|
10
|
+
console.log(chalk.bold.cyan(title));
|
|
11
|
+
console.log(chalk.dim('─'.repeat(40)));
|
|
12
|
+
for (const [key, value] of fields) {
|
|
13
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
14
|
+
console.log(` ${chalk.dim(key + ':')} ${value}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
console.log();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Print a simple table with headers.
|
|
21
|
+
*/
|
|
22
|
+
export function printTable(headers, rows) {
|
|
23
|
+
// Calculate column widths
|
|
24
|
+
const widths = headers.map((h, i) => {
|
|
25
|
+
const maxRow = rows.reduce((max, row) => Math.max(max, (row[i] || '').length), 0);
|
|
26
|
+
return Math.max(h.length, maxRow);
|
|
27
|
+
});
|
|
28
|
+
// Header
|
|
29
|
+
const headerLine = headers.map((h, i) => h.padEnd(widths[i])).join(' ');
|
|
30
|
+
console.log();
|
|
31
|
+
console.log(chalk.bold(headerLine));
|
|
32
|
+
console.log(chalk.dim(widths.map(w => '─'.repeat(w)).join(' ')));
|
|
33
|
+
// Rows
|
|
34
|
+
for (const row of rows) {
|
|
35
|
+
const line = row.map((cell, i) => (cell || '').padEnd(widths[i])).join(' ');
|
|
36
|
+
console.log(line);
|
|
37
|
+
}
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Truncate an address for display.
|
|
42
|
+
*/
|
|
43
|
+
export function shortAddr(addr, chars = 6) {
|
|
44
|
+
if (!addr)
|
|
45
|
+
return chalk.dim('—');
|
|
46
|
+
if (addr.length <= chars * 2 + 2)
|
|
47
|
+
return addr;
|
|
48
|
+
return `${addr.slice(0, chars + 2)}...${addr.slice(-chars)}`;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Format a balance value.
|
|
52
|
+
*/
|
|
53
|
+
export function fmtBalance(value, symbol) {
|
|
54
|
+
if (!value || value === '0' || value === '0.0')
|
|
55
|
+
return chalk.dim(`0 ${symbol}`);
|
|
56
|
+
// Trim trailing zeros after decimal
|
|
57
|
+
const num = parseFloat(value);
|
|
58
|
+
if (isNaN(num))
|
|
59
|
+
return chalk.dim(`0 ${symbol}`);
|
|
60
|
+
if (num === 0)
|
|
61
|
+
return chalk.dim(`0 ${symbol}`);
|
|
62
|
+
const formatted = num < 0.0001 ? num.toExponential(2) : num.toFixed(6).replace(/0+$/, '').replace(/\.$/, '');
|
|
63
|
+
return `${formatted} ${symbol}`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Format a USD value.
|
|
67
|
+
*/
|
|
68
|
+
export function fmtUsd(value) {
|
|
69
|
+
if (!value)
|
|
70
|
+
return chalk.dim('—');
|
|
71
|
+
const num = parseFloat(value);
|
|
72
|
+
if (isNaN(num) || num === 0)
|
|
73
|
+
return chalk.dim('—');
|
|
74
|
+
if (num >= 1)
|
|
75
|
+
return `$${num.toFixed(2)}`;
|
|
76
|
+
// For small numbers, show enough significant digits
|
|
77
|
+
const str = num.toFixed(10);
|
|
78
|
+
const match = str.match(/^0\.(0*)/);
|
|
79
|
+
const leadingZeros = match ? match[1].length : 0;
|
|
80
|
+
const sigFigs = Math.max(leadingZeros + 4, 2);
|
|
81
|
+
return `$${num.toFixed(sigFigs)}`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Format a date string.
|
|
85
|
+
*/
|
|
86
|
+
export function fmtDate(dateStr) {
|
|
87
|
+
if (!dateStr)
|
|
88
|
+
return chalk.dim('—');
|
|
89
|
+
try {
|
|
90
|
+
const d = new Date(dateStr);
|
|
91
|
+
return d.toLocaleDateString('en-US', {
|
|
92
|
+
year: 'numeric',
|
|
93
|
+
month: 'short',
|
|
94
|
+
day: 'numeric',
|
|
95
|
+
hour: '2-digit',
|
|
96
|
+
minute: '2-digit',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return dateStr;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Print a success message.
|
|
105
|
+
*/
|
|
106
|
+
export function success(msg) {
|
|
107
|
+
console.log(chalk.green('✓') + ' ' + msg);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Print an error message to stderr.
|
|
111
|
+
*/
|
|
112
|
+
export function error(msg) {
|
|
113
|
+
console.error(chalk.red('Error:') + ' ' + msg);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Print a warning message.
|
|
117
|
+
*/
|
|
118
|
+
export function warn(msg) {
|
|
119
|
+
console.log(chalk.yellow('⚠') + ' ' + msg);
|
|
120
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TypeScript types for the BFunBot CLI.
|
|
3
|
+
*/
|
|
4
|
+
export interface BfunConfig {
|
|
5
|
+
apiKey?: string;
|
|
6
|
+
apiUrl?: string;
|
|
7
|
+
llmUrl?: string;
|
|
8
|
+
[key: string]: string | undefined;
|
|
9
|
+
}
|
|
10
|
+
export interface ApiErrorResponse {
|
|
11
|
+
detail?: string | Record<string, unknown>;
|
|
12
|
+
message?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface MeResponse {
|
|
15
|
+
twitter_user_id: string;
|
|
16
|
+
twitter_username?: string;
|
|
17
|
+
profile_image_url?: string;
|
|
18
|
+
followers_count?: number;
|
|
19
|
+
joined_at?: string;
|
|
20
|
+
tos_accepted_at?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface TokenCreateRequest {
|
|
23
|
+
name: string;
|
|
24
|
+
symbol: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
image_url?: string;
|
|
27
|
+
source_url?: string;
|
|
28
|
+
chain: string;
|
|
29
|
+
platform: string;
|
|
30
|
+
twitter?: string;
|
|
31
|
+
telegram?: string;
|
|
32
|
+
website?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface TokenCreateResponse {
|
|
35
|
+
job_id: string;
|
|
36
|
+
status: string;
|
|
37
|
+
message?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface JobStatusResponse {
|
|
40
|
+
job_id: number;
|
|
41
|
+
status: string;
|
|
42
|
+
chain?: string;
|
|
43
|
+
token_address?: string;
|
|
44
|
+
error?: string;
|
|
45
|
+
created_at?: string;
|
|
46
|
+
completed_at?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface CreatedTokenItem {
|
|
49
|
+
token_address: string;
|
|
50
|
+
name: string;
|
|
51
|
+
symbol: string;
|
|
52
|
+
chain: string;
|
|
53
|
+
platform?: string;
|
|
54
|
+
created_at?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface CreatedTokensResponse {
|
|
57
|
+
tokens: CreatedTokenItem[];
|
|
58
|
+
total: number;
|
|
59
|
+
page: number;
|
|
60
|
+
page_size: number;
|
|
61
|
+
has_more: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface TokenInfoResponse {
|
|
64
|
+
address: string;
|
|
65
|
+
name: string;
|
|
66
|
+
symbol: string;
|
|
67
|
+
chain: string;
|
|
68
|
+
platform: string;
|
|
69
|
+
token_address?: string;
|
|
70
|
+
creator_twitter_username?: string;
|
|
71
|
+
created_at: string;
|
|
72
|
+
price_usd?: string;
|
|
73
|
+
market_cap_usd?: string;
|
|
74
|
+
volume_24h_usd?: string;
|
|
75
|
+
creator_reward_usd?: string;
|
|
76
|
+
[key: string]: unknown;
|
|
77
|
+
}
|
|
78
|
+
export interface WalletSlot {
|
|
79
|
+
address?: string;
|
|
80
|
+
balance_bnb?: string;
|
|
81
|
+
balance_usdt_bsc?: string;
|
|
82
|
+
bnb_error?: string | null;
|
|
83
|
+
usdt_bsc_error?: string | null;
|
|
84
|
+
}
|
|
85
|
+
export interface WalletBalanceResponse {
|
|
86
|
+
evm_main: WalletSlot;
|
|
87
|
+
evm_trading: WalletSlot;
|
|
88
|
+
}
|
|
89
|
+
export interface CreditBalanceResponse {
|
|
90
|
+
balance_usd: string;
|
|
91
|
+
agent_reload?: {
|
|
92
|
+
enabled: boolean;
|
|
93
|
+
amount_usd: number;
|
|
94
|
+
daily_limit_usd: number;
|
|
95
|
+
chains: string[];
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export interface AgentReloadResponse {
|
|
99
|
+
amount_usd: string;
|
|
100
|
+
tx_hash: string;
|
|
101
|
+
new_balance_usd?: string;
|
|
102
|
+
daily_used_usd: string;
|
|
103
|
+
daily_remaining_usd: string;
|
|
104
|
+
}
|
|
105
|
+
export interface ChainQuota {
|
|
106
|
+
chain: string;
|
|
107
|
+
free_used_today: number;
|
|
108
|
+
free_limit: number;
|
|
109
|
+
sponsored_remaining: number;
|
|
110
|
+
can_create_paid: boolean;
|
|
111
|
+
trading_wallet_balance?: string;
|
|
112
|
+
trading_wallet_address?: string;
|
|
113
|
+
}
|
|
114
|
+
export interface QuotaResponse {
|
|
115
|
+
chains: ChainQuota[];
|
|
116
|
+
}
|
|
117
|
+
export interface SkillItem {
|
|
118
|
+
name: string;
|
|
119
|
+
description: string;
|
|
120
|
+
example?: string;
|
|
121
|
+
}
|
|
122
|
+
export interface SkillsResponse {
|
|
123
|
+
skills: SkillItem[];
|
|
124
|
+
total: number;
|
|
125
|
+
}
|
|
126
|
+
export interface LlmModel {
|
|
127
|
+
id: string;
|
|
128
|
+
name?: string;
|
|
129
|
+
input?: number;
|
|
130
|
+
output?: number;
|
|
131
|
+
[key: string]: unknown;
|
|
132
|
+
}
|
|
133
|
+
export interface LlmModelsResponse {
|
|
134
|
+
models: string[];
|
|
135
|
+
}
|
|
136
|
+
export interface OpenclawConfigResponse {
|
|
137
|
+
baseUrl: string;
|
|
138
|
+
api: string;
|
|
139
|
+
models: LlmModel[];
|
|
140
|
+
}
|
|
141
|
+
export interface FeeSummaryBsc {
|
|
142
|
+
token_count: number;
|
|
143
|
+
total_earned_bnb: number;
|
|
144
|
+
}
|
|
145
|
+
export interface FeeSummaryResponse {
|
|
146
|
+
bsc: FeeSummaryBsc;
|
|
147
|
+
}
|
|
148
|
+
export interface FeeEarningsBsc {
|
|
149
|
+
chain: 'bsc';
|
|
150
|
+
flap: {
|
|
151
|
+
total_earned_bnb: number;
|
|
152
|
+
earning_token_count: number;
|
|
153
|
+
};
|
|
154
|
+
fourmeme: {
|
|
155
|
+
total_earned_bnb: number;
|
|
156
|
+
earning_token_count: number;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
export type FeeEarningsResponse = FeeEarningsBsc;
|
|
160
|
+
export interface FeeTokenBsc {
|
|
161
|
+
token_name: string;
|
|
162
|
+
token_symbol: string;
|
|
163
|
+
token_address: string;
|
|
164
|
+
platform: string;
|
|
165
|
+
chain: string;
|
|
166
|
+
earned_bnb: number;
|
|
167
|
+
}
|
|
168
|
+
export interface FeeTokenUnsupported {
|
|
169
|
+
supported: false;
|
|
170
|
+
message: string;
|
|
171
|
+
}
|
|
172
|
+
export type FeeTokenResponse = FeeTokenBsc | FeeTokenUnsupported;
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bfun-bot/cli",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "BFunBot CLI — deploy tokens, check balances, and manage your AI agent from the terminal",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"bfunbot": "./bin/bfunbot.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"bin",
|
|
14
|
+
"scripts"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsc --watch",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"bfunbot",
|
|
26
|
+
"bfunbot",
|
|
27
|
+
"token",
|
|
28
|
+
"meme",
|
|
29
|
+
"agent",
|
|
30
|
+
"cli",
|
|
31
|
+
"bsc",
|
|
32
|
+
"bnb"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"chalk": "^5.3.0",
|
|
37
|
+
"commander": "^12.1.0",
|
|
38
|
+
"ora": "^8.1.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.0.0",
|
|
42
|
+
"typescript": "^5.5.4"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const W = 43;
|
|
3
|
+
function pad(text) {
|
|
4
|
+
return text + ' '.repeat(Math.max(0, W - text.length));
|
|
5
|
+
}
|
|
6
|
+
let version = 'unknown';
|
|
7
|
+
try {
|
|
8
|
+
const pkg = require('../package.json');
|
|
9
|
+
version = pkg.version || 'unknown';
|
|
10
|
+
} catch {}
|
|
11
|
+
|
|
12
|
+
const lines = [
|
|
13
|
+
'',
|
|
14
|
+
' K I B I B O T',
|
|
15
|
+
'',
|
|
16
|
+
' Deploy tokens. Earn fees.',
|
|
17
|
+
' Power your AI agent.',
|
|
18
|
+
'',
|
|
19
|
+
` Version ${version}`,
|
|
20
|
+
' Website kibi.bot',
|
|
21
|
+
' Docs kibi.bot/docs/agent',
|
|
22
|
+
' GitHub github.com/KibiAgent',
|
|
23
|
+
'',
|
|
24
|
+
' Base · BSC · Solana',
|
|
25
|
+
'',
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
console.log();
|
|
29
|
+
console.log(` \x1b[36m╔${'═'.repeat(W)}╗\x1b[0m`);
|
|
30
|
+
for (const line of lines) {
|
|
31
|
+
console.log(` \x1b[36m║\x1b[0m${pad(line)}\x1b[36m║\x1b[0m`);
|
|
32
|
+
}
|
|
33
|
+
console.log(` \x1b[36m╚${'═'.repeat(W)}╝\x1b[0m`);
|
|
34
|
+
console.log();
|