@bankr/cli 0.1.0-beta.6 → 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 +27 -1
- package/dist/cli.js +222 -4
- package/dist/commands/balances.d.ts +5 -0
- package/dist/commands/balances.js +113 -0
- package/dist/commands/fees.d.ts +18 -0
- package/dist/commands/fees.js +793 -0
- package/dist/commands/launch.d.ts +13 -0
- package/dist/commands/launch.js +174 -0
- package/dist/commands/llm.d.ts +11 -0
- package/dist/commands/llm.js +319 -3
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.js +464 -147
- package/dist/commands/profile.d.ts +26 -0
- package/dist/commands/profile.js +183 -0
- package/dist/commands/prompt.js +5 -0
- package/dist/commands/sign.js +3 -0
- package/dist/commands/sounds.d.ts +12 -0
- package/dist/commands/sounds.js +262 -0
- package/dist/commands/submit.js +14 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/lib/api.d.ts +213 -0
- package/dist/lib/api.js +177 -3
- package/dist/lib/cesp/engine.d.ts +13 -0
- package/dist/lib/cesp/engine.js +132 -0
- package/dist/lib/cesp/player.d.ts +6 -0
- package/dist/lib/cesp/player.js +50 -0
- package/dist/lib/cesp/types.d.ts +38 -0
- package/dist/lib/cesp/types.js +2 -0
- package/dist/lib/config.d.ts +4 -0
- package/dist/lib/config.js +1 -0
- package/dist/lib/output.d.ts +1 -0
- package/dist/lib/output.js +3 -0
- package/package.json +4 -2
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/cancel.d.ts.map +0 -1
- package/dist/commands/cancel.js.map +0 -1
- package/dist/commands/capabilities.d.ts.map +0 -1
- package/dist/commands/capabilities.js.map +0 -1
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/llm.d.ts.map +0 -1
- package/dist/commands/llm.js.map +0 -1
- package/dist/commands/login.d.ts.map +0 -1
- package/dist/commands/login.js.map +0 -1
- package/dist/commands/logout.d.ts.map +0 -1
- package/dist/commands/logout.js.map +0 -1
- package/dist/commands/prompt.d.ts.map +0 -1
- package/dist/commands/prompt.js.map +0 -1
- package/dist/commands/sign.d.ts.map +0 -1
- package/dist/commands/sign.js.map +0 -1
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/submit.d.ts.map +0 -1
- package/dist/commands/submit.js.map +0 -1
- package/dist/commands/whoami.d.ts.map +0 -1
- package/dist/commands/whoami.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/api.d.ts.map +0 -1
- package/dist/lib/api.js.map +0 -1
- package/dist/lib/config.d.ts.map +0 -1
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/output.d.ts.map +0 -1
- package/dist/lib/output.js.map +0 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface LaunchOptions {
|
|
2
|
+
name?: string;
|
|
3
|
+
symbol?: string;
|
|
4
|
+
image?: string;
|
|
5
|
+
tweet?: string;
|
|
6
|
+
website?: string;
|
|
7
|
+
fee?: string;
|
|
8
|
+
feeType?: string;
|
|
9
|
+
yes?: boolean;
|
|
10
|
+
simulate?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function launchCommand(options: LaunchOptions): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=launch.d.ts.map
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { confirm, input, select } from "@inquirer/prompts";
|
|
2
|
+
import { deployToken } from "../lib/api.js";
|
|
3
|
+
import { emitCESP } from "../lib/cesp/engine.js";
|
|
4
|
+
import { requireApiKey } from "../lib/config.js";
|
|
5
|
+
import * as output from "../lib/output.js";
|
|
6
|
+
const VALID_FEE_TYPES = ["x", "farcaster", "ens", "wallet"];
|
|
7
|
+
function parseFeeType(value) {
|
|
8
|
+
if (!value)
|
|
9
|
+
return "x";
|
|
10
|
+
const lower = value.toLowerCase();
|
|
11
|
+
if (VALID_FEE_TYPES.includes(lower))
|
|
12
|
+
return lower;
|
|
13
|
+
output.warn(`Unknown fee type "${value}". Valid types: ${VALID_FEE_TYPES.join(", ")}. Defaulting to "x".`);
|
|
14
|
+
return "x";
|
|
15
|
+
}
|
|
16
|
+
function feeTypeLabel(type) {
|
|
17
|
+
switch (type) {
|
|
18
|
+
case "x":
|
|
19
|
+
return "X";
|
|
20
|
+
case "farcaster":
|
|
21
|
+
return "Farcaster";
|
|
22
|
+
case "ens":
|
|
23
|
+
return "ENS";
|
|
24
|
+
case "wallet":
|
|
25
|
+
return "Wallet";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function collectInteractive(options) {
|
|
29
|
+
const tokenName = options.name ??
|
|
30
|
+
(await input({
|
|
31
|
+
message: "What do you want to call your token?",
|
|
32
|
+
theme: output.bankrTheme,
|
|
33
|
+
required: true,
|
|
34
|
+
}));
|
|
35
|
+
const tokenSymbol = options.symbol ??
|
|
36
|
+
(await input({
|
|
37
|
+
message: "Token symbol (press Enter to auto-generate from name):",
|
|
38
|
+
theme: output.bankrTheme,
|
|
39
|
+
}));
|
|
40
|
+
const imageUrl = options.image ??
|
|
41
|
+
(await input({
|
|
42
|
+
message: "Image URL for your token (press Enter to skip):",
|
|
43
|
+
theme: output.bankrTheme,
|
|
44
|
+
}));
|
|
45
|
+
const tweetUrl = options.tweet ??
|
|
46
|
+
(await input({
|
|
47
|
+
message: "Associate with a tweet? Paste URL (press Enter to skip):",
|
|
48
|
+
theme: output.bankrTheme,
|
|
49
|
+
}));
|
|
50
|
+
const websiteUrl = options.website ??
|
|
51
|
+
(await input({
|
|
52
|
+
message: "Project website URL (press Enter to skip):",
|
|
53
|
+
theme: output.bankrTheme,
|
|
54
|
+
}));
|
|
55
|
+
let feeRecipient = options.fee ??
|
|
56
|
+
(await input({
|
|
57
|
+
message: "Direct fees to someone? Enter username, ENS, or address (press Enter to skip):",
|
|
58
|
+
theme: output.bankrTheme,
|
|
59
|
+
}));
|
|
60
|
+
let feeRecipientType = parseFeeType(options.feeType);
|
|
61
|
+
if (feeRecipient && !options.feeType) {
|
|
62
|
+
feeRecipientType = await select({
|
|
63
|
+
message: "What type of identifier is this?",
|
|
64
|
+
choices: [
|
|
65
|
+
{ name: "X (Twitter)", value: "x" },
|
|
66
|
+
{ name: "Farcaster", value: "farcaster" },
|
|
67
|
+
{ name: "ENS", value: "ens" },
|
|
68
|
+
{ name: "Wallet address", value: "wallet" },
|
|
69
|
+
],
|
|
70
|
+
theme: output.bankrTheme,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
if (!feeRecipient) {
|
|
74
|
+
feeRecipient = "";
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
tokenName: tokenName.trim(),
|
|
78
|
+
tokenSymbol: tokenSymbol.trim(),
|
|
79
|
+
imageUrl: imageUrl.trim(),
|
|
80
|
+
tweetUrl: tweetUrl.trim(),
|
|
81
|
+
websiteUrl: websiteUrl.trim(),
|
|
82
|
+
feeRecipient: feeRecipient.trim(),
|
|
83
|
+
feeRecipientType,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
export async function launchCommand(options) {
|
|
87
|
+
requireApiKey();
|
|
88
|
+
// Collect token details
|
|
89
|
+
const state = await collectInteractive(options);
|
|
90
|
+
if (!state.tokenName) {
|
|
91
|
+
output.error("Token name is required.");
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
// Display summary
|
|
95
|
+
console.log();
|
|
96
|
+
output.brandBold(" Token launch summary");
|
|
97
|
+
console.log();
|
|
98
|
+
output.keyValue("Name", state.tokenName);
|
|
99
|
+
output.keyValue("Symbol", state.tokenSymbol || "(auto)");
|
|
100
|
+
output.keyValue("Image", state.imageUrl || "(none)");
|
|
101
|
+
output.keyValue("Tweet", state.tweetUrl || "(none)");
|
|
102
|
+
output.keyValue("Website", state.websiteUrl || "(none)");
|
|
103
|
+
output.keyValue("Fee recipient", state.feeRecipient
|
|
104
|
+
? `${state.feeRecipient} (${feeTypeLabel(state.feeRecipientType)})`
|
|
105
|
+
: "(self)");
|
|
106
|
+
output.keyValue("Chain", "Base");
|
|
107
|
+
if (options.simulate) {
|
|
108
|
+
output.keyValue("Mode", "Simulation (dry run)");
|
|
109
|
+
}
|
|
110
|
+
console.log();
|
|
111
|
+
// Confirm unless --yes
|
|
112
|
+
if (!options.yes) {
|
|
113
|
+
const proceed = await confirm({
|
|
114
|
+
message: options.simulate
|
|
115
|
+
? "Simulate this token launch?"
|
|
116
|
+
: "Launch this token?",
|
|
117
|
+
default: true,
|
|
118
|
+
theme: output.bankrTheme,
|
|
119
|
+
});
|
|
120
|
+
if (!proceed) {
|
|
121
|
+
output.dim("Launch cancelled.");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Deploy directly via REST endpoint (no LLM agent)
|
|
126
|
+
const spin = output.spinner(options.simulate ? "Simulating token deploy..." : "Deploying your token...");
|
|
127
|
+
const startTime = Date.now();
|
|
128
|
+
try {
|
|
129
|
+
const result = await deployToken({
|
|
130
|
+
tokenName: state.tokenName,
|
|
131
|
+
tokenSymbol: state.tokenSymbol || undefined,
|
|
132
|
+
image: state.imageUrl || undefined,
|
|
133
|
+
tweetUrl: state.tweetUrl || undefined,
|
|
134
|
+
websiteUrl: state.websiteUrl || undefined,
|
|
135
|
+
feeRecipient: state.feeRecipient
|
|
136
|
+
? { type: state.feeRecipientType, value: state.feeRecipient }
|
|
137
|
+
: undefined,
|
|
138
|
+
simulateOnly: options.simulate,
|
|
139
|
+
});
|
|
140
|
+
const elapsed = output.formatDuration(Date.now() - startTime);
|
|
141
|
+
spin.succeed(result.simulated
|
|
142
|
+
? `Simulation complete in ${elapsed}`
|
|
143
|
+
: `Token deployed in ${elapsed}`);
|
|
144
|
+
emitCESP("task.complete");
|
|
145
|
+
console.log();
|
|
146
|
+
output.keyValue("Token Address", result.tokenAddress);
|
|
147
|
+
output.keyValue("Pool ID", result.poolId);
|
|
148
|
+
if (result.txHash) {
|
|
149
|
+
output.keyValue("Transaction", result.txHash);
|
|
150
|
+
}
|
|
151
|
+
output.keyValue("Chain", result.chain);
|
|
152
|
+
if (result.feeDistribution) {
|
|
153
|
+
console.log();
|
|
154
|
+
output.brandBold(" Fee distribution");
|
|
155
|
+
console.log();
|
|
156
|
+
for (const [role, info] of Object.entries(result.feeDistribution)) {
|
|
157
|
+
const pct = (info.bps / 100).toFixed(1);
|
|
158
|
+
const label = role === "alt"
|
|
159
|
+
? "Ecosystem"
|
|
160
|
+
: role.charAt(0).toUpperCase() + role.slice(1);
|
|
161
|
+
output.keyValue(` ${label} (${pct}%)`, info.address);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
console.log();
|
|
165
|
+
output.dim(`View token: https://bankr.bot/launches/${result.tokenAddress}`);
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
spin.fail("Token launch failed");
|
|
169
|
+
emitCESP("task.error");
|
|
170
|
+
output.error(err.message);
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=launch.js.map
|
package/dist/commands/llm.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
export declare function modelsCommand(): Promise<void>;
|
|
2
2
|
export declare function creditsCommand(): Promise<void>;
|
|
3
|
+
export declare function creditsAddCommand(amount: string, opts: {
|
|
4
|
+
token?: string;
|
|
5
|
+
yes?: boolean;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
export declare function creditsAutoCommand(opts: {
|
|
8
|
+
enable?: boolean;
|
|
9
|
+
disable?: boolean;
|
|
10
|
+
amount?: string;
|
|
11
|
+
threshold?: string;
|
|
12
|
+
tokens?: string;
|
|
13
|
+
}): Promise<void>;
|
|
3
14
|
export declare function setupOpenclawCommand(opts: {
|
|
4
15
|
install?: boolean;
|
|
5
16
|
}): Promise<void>;
|
package/dist/commands/llm.js
CHANGED
|
@@ -2,8 +2,11 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
|
2
2
|
import { homedir } from "os";
|
|
3
3
|
import { dirname, join } from "path";
|
|
4
4
|
import { spawn } from "child_process";
|
|
5
|
-
import { getLlmKey, getLlmUrl } from "../lib/config.js";
|
|
5
|
+
import { CLI_USER_AGENT, getApiUrl, getLlmKey, getLlmUrl, requireApiKey, } from "../lib/config.js";
|
|
6
|
+
import { getBalances } from "../lib/api.js";
|
|
6
7
|
import * as output from "../lib/output.js";
|
|
8
|
+
import { bankrTheme } from "../lib/output.js";
|
|
9
|
+
const ERR_LLM_NOT_ENABLED = "LLM Gateway not enabled on this API key. Enable at bankr.bot/api";
|
|
7
10
|
/**
|
|
8
11
|
* Fallback model catalog — used when the gateway is unreachable or unauthenticated.
|
|
9
12
|
* resolveModels() fetches live data from GET /v1/models; this list is the offline safety net.
|
|
@@ -22,6 +25,12 @@ const GATEWAY_MODELS = [
|
|
|
22
25
|
owned_by: "anthropic",
|
|
23
26
|
cost: { input: 15.0, output: 75.0, cacheRead: 1.5, cacheWrite: 18.75 },
|
|
24
27
|
},
|
|
28
|
+
{
|
|
29
|
+
id: "claude-sonnet-4.6",
|
|
30
|
+
name: "Claude Sonnet 4.6",
|
|
31
|
+
owned_by: "anthropic",
|
|
32
|
+
cost: { input: 3.0, output: 15.0, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
33
|
+
},
|
|
25
34
|
{
|
|
26
35
|
id: "claude-sonnet-4.5",
|
|
27
36
|
name: "Claude Sonnet 4.5",
|
|
@@ -105,7 +114,7 @@ async function resolveModels() {
|
|
|
105
114
|
return { models: GATEWAY_MODELS, live: false };
|
|
106
115
|
try {
|
|
107
116
|
const res = await fetch(`${getLlmUrl()}/v1/models`, {
|
|
108
|
-
headers: { "X-API-Key": llmKey },
|
|
117
|
+
headers: { "X-API-Key": llmKey, "User-Agent": CLI_USER_AGENT },
|
|
109
118
|
signal: AbortSignal.timeout(5000),
|
|
110
119
|
});
|
|
111
120
|
if (!res.ok)
|
|
@@ -195,7 +204,7 @@ export async function creditsCommand() {
|
|
|
195
204
|
const spin = output.spinner("Fetching credit balance…");
|
|
196
205
|
try {
|
|
197
206
|
const res = await fetch(`${llmUrl}/v1/credits`, {
|
|
198
|
-
headers: { "X-API-Key": llmKey },
|
|
207
|
+
headers: { "X-API-Key": llmKey, "User-Agent": CLI_USER_AGENT },
|
|
199
208
|
signal: AbortSignal.timeout(10000),
|
|
200
209
|
});
|
|
201
210
|
spin.stop();
|
|
@@ -228,6 +237,313 @@ export async function creditsCommand() {
|
|
|
228
237
|
process.exit(1);
|
|
229
238
|
}
|
|
230
239
|
}
|
|
240
|
+
/* ─────────────────────── bankr llm credits add ──────────────────────────── */
|
|
241
|
+
export async function creditsAddCommand(amount, opts) {
|
|
242
|
+
const apiKey = requireApiKey();
|
|
243
|
+
const apiUrl = getApiUrl();
|
|
244
|
+
const llmKey = getLlmKey();
|
|
245
|
+
const llmUrl = getLlmUrl();
|
|
246
|
+
// Validate amount
|
|
247
|
+
const amountUsd = Number(amount);
|
|
248
|
+
if (Number.isNaN(amountUsd) || amountUsd < 1 || amountUsd > 1000) {
|
|
249
|
+
output.error("Amount must be between $1 and $1,000");
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
// Fetch current balance for display (skip when --yes since user won't see it)
|
|
253
|
+
let currentBalance = "unknown";
|
|
254
|
+
if (llmKey && !opts.yes) {
|
|
255
|
+
const balSpin = output.spinner("Fetching balance…");
|
|
256
|
+
try {
|
|
257
|
+
const balRes = await fetch(`${llmUrl}/v1/credits`, {
|
|
258
|
+
headers: { "X-API-Key": llmKey, "User-Agent": CLI_USER_AGENT },
|
|
259
|
+
signal: AbortSignal.timeout(10000),
|
|
260
|
+
});
|
|
261
|
+
balSpin.stop();
|
|
262
|
+
if (balRes.ok) {
|
|
263
|
+
const bal = (await balRes.json());
|
|
264
|
+
currentBalance = `$${bal.balanceUsd.toFixed(2)}`;
|
|
265
|
+
}
|
|
266
|
+
else if (balRes.status === 402) {
|
|
267
|
+
currentBalance = "$0.00";
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
balSpin.stop();
|
|
272
|
+
// Non-fatal — proceed without balance display
|
|
273
|
+
output.dim(` (Could not fetch balance: ${err.message})`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
// Show confirmation
|
|
277
|
+
console.log();
|
|
278
|
+
output.label("Add Credits", `$${amountUsd.toFixed(2)}`);
|
|
279
|
+
output.keyValue("Source token", opts.token ?? "USDC (default)");
|
|
280
|
+
output.keyValue("Current balance", currentBalance);
|
|
281
|
+
console.log();
|
|
282
|
+
if (!opts.yes) {
|
|
283
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
284
|
+
const proceed = await confirm({
|
|
285
|
+
message: "Proceed?",
|
|
286
|
+
default: true,
|
|
287
|
+
theme: bankrTheme,
|
|
288
|
+
});
|
|
289
|
+
if (!proceed) {
|
|
290
|
+
output.dim("Cancelled.");
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const spin = output.spinner("Adding credits…");
|
|
295
|
+
try {
|
|
296
|
+
const body = { amountUsd };
|
|
297
|
+
if (opts.token) {
|
|
298
|
+
body.sourceToken = opts.token;
|
|
299
|
+
}
|
|
300
|
+
const res = await fetch(`${apiUrl}/llm/credits/topup`, {
|
|
301
|
+
method: "POST",
|
|
302
|
+
headers: {
|
|
303
|
+
"X-API-Key": apiKey,
|
|
304
|
+
"Content-Type": "application/json",
|
|
305
|
+
"User-Agent": CLI_USER_AGENT,
|
|
306
|
+
},
|
|
307
|
+
body: JSON.stringify(body),
|
|
308
|
+
signal: AbortSignal.timeout(60000),
|
|
309
|
+
});
|
|
310
|
+
spin.stop();
|
|
311
|
+
if (res.status === 402) {
|
|
312
|
+
output.error("Insufficient wallet balance. Add funds to your wallet first.");
|
|
313
|
+
process.exit(1);
|
|
314
|
+
}
|
|
315
|
+
if (res.status === 403) {
|
|
316
|
+
output.error(ERR_LLM_NOT_ENABLED);
|
|
317
|
+
process.exit(1);
|
|
318
|
+
}
|
|
319
|
+
if (res.status === 502) {
|
|
320
|
+
output.error("Token swap failed. Try USDC or a different token.");
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
if (!res.ok) {
|
|
324
|
+
const errBody = (await res.json().catch(() => ({})));
|
|
325
|
+
output.error(errBody.error ?? `Failed to add credits (HTTP ${res.status})`);
|
|
326
|
+
process.exit(1);
|
|
327
|
+
}
|
|
328
|
+
const result = (await res.json());
|
|
329
|
+
console.log();
|
|
330
|
+
output.success(`Added $${result.creditsGranted.toFixed(2)} credits`);
|
|
331
|
+
output.label("New Balance", `$${result.newBalance.toFixed(2)}`);
|
|
332
|
+
if (result.txHash) {
|
|
333
|
+
output.keyValue("Transaction", `https://basescan.org/tx/${result.txHash}`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
catch (err) {
|
|
337
|
+
spin.stop();
|
|
338
|
+
output.error(`Failed to add credits: ${err.message}`);
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function formatTimeAgo(dateStr) {
|
|
343
|
+
if (!dateStr)
|
|
344
|
+
return "never";
|
|
345
|
+
const diff = Date.now() - new Date(dateStr).getTime();
|
|
346
|
+
const mins = Math.floor(diff / 60000);
|
|
347
|
+
if (mins < 60)
|
|
348
|
+
return `${mins}m ago`;
|
|
349
|
+
const hours = Math.floor(mins / 60);
|
|
350
|
+
if (hours < 24)
|
|
351
|
+
return `${hours}h ago`;
|
|
352
|
+
const days = Math.floor(hours / 24);
|
|
353
|
+
return `${days}d ago`;
|
|
354
|
+
}
|
|
355
|
+
function displayAutoTopUpConfig(config) {
|
|
356
|
+
output.keyValue("Status", config.enabled ? "Enabled" : "Disabled");
|
|
357
|
+
output.keyValue("Amount", `$${config.amountUsd.toFixed(2)}`);
|
|
358
|
+
output.keyValue("Threshold", `$${config.thresholdUsd.toFixed(2)}`);
|
|
359
|
+
output.keyValue("Tokens", config.tokens.length > 0
|
|
360
|
+
? config.tokens.map((t) => t.symbol).join(" → ")
|
|
361
|
+
: "none configured");
|
|
362
|
+
}
|
|
363
|
+
export async function creditsAutoCommand(opts) {
|
|
364
|
+
const apiKey = requireApiKey();
|
|
365
|
+
const apiUrl = getApiUrl();
|
|
366
|
+
const isUpdate = opts.enable || opts.disable || opts.amount || opts.threshold || opts.tokens;
|
|
367
|
+
if (!isUpdate) {
|
|
368
|
+
// GET current config
|
|
369
|
+
const spin = output.spinner("Fetching auto top-up config…");
|
|
370
|
+
try {
|
|
371
|
+
const res = await fetch(`${apiUrl}/llm/credits/auto-topup`, {
|
|
372
|
+
headers: {
|
|
373
|
+
"X-API-Key": apiKey,
|
|
374
|
+
"User-Agent": CLI_USER_AGENT,
|
|
375
|
+
},
|
|
376
|
+
signal: AbortSignal.timeout(10000),
|
|
377
|
+
});
|
|
378
|
+
spin.stop();
|
|
379
|
+
if (res.status === 403) {
|
|
380
|
+
output.error(ERR_LLM_NOT_ENABLED);
|
|
381
|
+
process.exit(1);
|
|
382
|
+
}
|
|
383
|
+
if (!res.ok) {
|
|
384
|
+
output.error(`Failed to fetch config (HTTP ${res.status})`);
|
|
385
|
+
process.exit(1);
|
|
386
|
+
}
|
|
387
|
+
const { config } = (await res.json());
|
|
388
|
+
output.brandBold("Bankr LLM Gateway — Auto Top-Up");
|
|
389
|
+
console.log();
|
|
390
|
+
displayAutoTopUpConfig(config);
|
|
391
|
+
output.keyValue("Last top-up", formatTimeAgo(config.lastTopUpAt));
|
|
392
|
+
if (config.lastError) {
|
|
393
|
+
output.keyValue("Last error", config.lastError.message);
|
|
394
|
+
}
|
|
395
|
+
console.log();
|
|
396
|
+
output.dim(" Update: bankr llm credits auto --amount 25 --tokens USDC");
|
|
397
|
+
}
|
|
398
|
+
catch (err) {
|
|
399
|
+
spin.stop();
|
|
400
|
+
output.error(`Failed to fetch config: ${err.message}`);
|
|
401
|
+
process.exit(1);
|
|
402
|
+
}
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
// POST update config
|
|
406
|
+
if (opts.enable && opts.disable) {
|
|
407
|
+
output.error("Cannot use --enable and --disable together");
|
|
408
|
+
process.exit(1);
|
|
409
|
+
}
|
|
410
|
+
const body = {};
|
|
411
|
+
if (opts.disable) {
|
|
412
|
+
body.enabled = false;
|
|
413
|
+
}
|
|
414
|
+
else if (opts.enable) {
|
|
415
|
+
body.enabled = true;
|
|
416
|
+
}
|
|
417
|
+
else if (opts.amount || opts.threshold || opts.tokens) {
|
|
418
|
+
// Setting config values implicitly enables
|
|
419
|
+
body.enabled = true;
|
|
420
|
+
}
|
|
421
|
+
if (opts.amount) {
|
|
422
|
+
const amt = Number(opts.amount);
|
|
423
|
+
if (Number.isNaN(amt) || amt < 1 || amt > 1000) {
|
|
424
|
+
output.error("Amount must be between $1 and $1,000");
|
|
425
|
+
process.exit(1);
|
|
426
|
+
}
|
|
427
|
+
body.amountUsd = amt;
|
|
428
|
+
}
|
|
429
|
+
if (opts.threshold) {
|
|
430
|
+
const thr = Number(opts.threshold);
|
|
431
|
+
if (Number.isNaN(thr) || thr < 1 || thr > 500) {
|
|
432
|
+
output.error("Threshold must be between $1 and $500");
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
body.thresholdUsd = thr;
|
|
436
|
+
}
|
|
437
|
+
const missing = [];
|
|
438
|
+
if (opts.tokens) {
|
|
439
|
+
// Accepts symbols (USDC) or addresses (0x...), comma-separated
|
|
440
|
+
const inputs = opts.tokens
|
|
441
|
+
.split(",")
|
|
442
|
+
.map((s) => s.trim())
|
|
443
|
+
.filter(Boolean);
|
|
444
|
+
if (inputs.length === 0 || inputs.length > 3) {
|
|
445
|
+
output.error("Provide 1-3 comma-separated token symbols or addresses");
|
|
446
|
+
process.exit(1);
|
|
447
|
+
}
|
|
448
|
+
const resolved = [];
|
|
449
|
+
// Fetch balances to resolve both symbols and addresses
|
|
450
|
+
const spin = output.spinner("Resolving tokens…");
|
|
451
|
+
let baseTokens = [];
|
|
452
|
+
let hasNativeEth = false;
|
|
453
|
+
try {
|
|
454
|
+
const balData = await getBalances(["base"]);
|
|
455
|
+
const baseChain = balData.balances.base;
|
|
456
|
+
baseTokens = baseChain?.tokenBalances ?? [];
|
|
457
|
+
hasNativeEth = !!baseChain && parseFloat(baseChain.nativeBalance) > 0;
|
|
458
|
+
}
|
|
459
|
+
catch {
|
|
460
|
+
output.warn("Could not fetch balances for token resolution");
|
|
461
|
+
}
|
|
462
|
+
spin.stop();
|
|
463
|
+
for (const input of inputs) {
|
|
464
|
+
const isAddress = input.startsWith("0x");
|
|
465
|
+
const sym = isAddress ? null : input.toUpperCase();
|
|
466
|
+
// Native ETH
|
|
467
|
+
if (sym === "ETH" && hasNativeEth) {
|
|
468
|
+
resolved.push({
|
|
469
|
+
address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
470
|
+
chain: "base",
|
|
471
|
+
symbol: "ETH",
|
|
472
|
+
name: "Ethereum",
|
|
473
|
+
decimals: 18,
|
|
474
|
+
});
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
const tb = baseTokens.find((t) => isAddress
|
|
478
|
+
? t.token.baseToken.address.toLowerCase() === input.toLowerCase()
|
|
479
|
+
: t.token.baseToken.symbol.toUpperCase() === sym);
|
|
480
|
+
if (tb) {
|
|
481
|
+
resolved.push({
|
|
482
|
+
address: tb.token.baseToken.address,
|
|
483
|
+
chain: "base",
|
|
484
|
+
symbol: tb.token.baseToken.symbol,
|
|
485
|
+
name: tb.token.baseToken.name,
|
|
486
|
+
decimals: tb.token.baseToken.decimals,
|
|
487
|
+
imageUrl: tb.token.baseToken.imgUrl,
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
missing.push(input);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
if (resolved.length === 0) {
|
|
495
|
+
output.error("No valid tokens resolved. Check your token symbols.");
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
body.tokens = resolved;
|
|
499
|
+
}
|
|
500
|
+
// Collect warnings to show after success output
|
|
501
|
+
const warnings = [];
|
|
502
|
+
if (missing.length > 0) {
|
|
503
|
+
warnings.push(`Token(s) not found in wallet: ${missing.join(", ")} — skipped`);
|
|
504
|
+
}
|
|
505
|
+
const spin = output.spinner("Updating auto top-up…");
|
|
506
|
+
try {
|
|
507
|
+
const res = await fetch(`${apiUrl}/llm/credits/auto-topup`, {
|
|
508
|
+
method: "POST",
|
|
509
|
+
headers: {
|
|
510
|
+
"X-API-Key": apiKey,
|
|
511
|
+
"Content-Type": "application/json",
|
|
512
|
+
"User-Agent": CLI_USER_AGENT,
|
|
513
|
+
},
|
|
514
|
+
body: JSON.stringify(body),
|
|
515
|
+
signal: AbortSignal.timeout(10000),
|
|
516
|
+
});
|
|
517
|
+
spin.stop();
|
|
518
|
+
if (res.status === 403) {
|
|
519
|
+
output.error(ERR_LLM_NOT_ENABLED);
|
|
520
|
+
process.exit(1);
|
|
521
|
+
}
|
|
522
|
+
if (!res.ok) {
|
|
523
|
+
const errBody = (await res.json().catch(() => ({})));
|
|
524
|
+
output.error(errBody.error ?? `Failed to update config (HTTP ${res.status})`);
|
|
525
|
+
process.exit(1);
|
|
526
|
+
}
|
|
527
|
+
output.success(opts.disable ? "Auto top-up disabled" : "Auto top-up settings updated");
|
|
528
|
+
// Show config from POST response (avoids extra GET round-trip)
|
|
529
|
+
const resBody = (await res.json());
|
|
530
|
+
if (resBody.config) {
|
|
531
|
+
console.log();
|
|
532
|
+
displayAutoTopUpConfig(resBody.config);
|
|
533
|
+
}
|
|
534
|
+
if (warnings.length > 0) {
|
|
535
|
+
console.log();
|
|
536
|
+
for (const w of warnings) {
|
|
537
|
+
output.warn(w);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
catch (err) {
|
|
542
|
+
spin.stop();
|
|
543
|
+
output.error(`Failed to update config: ${err.message}`);
|
|
544
|
+
process.exit(1);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
231
547
|
/* ──────────────────────── bankr llm setup openclaw ────────────────────────── */
|
|
232
548
|
export async function setupOpenclawCommand(opts) {
|
|
233
549
|
const llmKey = getLlmKey();
|
package/dist/commands/login.d.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
export declare function loginCommand(opts: {
|
|
2
2
|
apiUrl?: string;
|
|
3
3
|
apiKey?: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
code?: string;
|
|
6
|
+
acceptTerms?: boolean;
|
|
7
|
+
keyName?: string;
|
|
8
|
+
readWrite?: boolean;
|
|
9
|
+
llm?: boolean;
|
|
4
10
|
llmKey?: string;
|
|
5
11
|
url?: boolean;
|
|
12
|
+
siwe?: boolean;
|
|
13
|
+
privateKey?: string;
|
|
14
|
+
partnerKey?: string;
|
|
6
15
|
}): Promise<void>;
|
|
7
16
|
//# sourceMappingURL=login.d.ts.map
|