@bankr/cli 0.3.23 → 0.3.35
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 +15 -5
- package/dist/cli.js +20 -14
- package/dist/commands/balances.js +1 -2
- package/dist/commands/cancel.js +1 -4
- package/dist/commands/club.js +6 -16
- package/dist/commands/config.js +1 -2
- package/dist/commands/fees.js +19 -29
- package/dist/commands/files.js +17 -39
- package/dist/commands/launch.d.ts +5 -0
- package/dist/commands/launch.js +98 -22
- package/dist/commands/launchQuotes.d.ts +7 -0
- package/dist/commands/launchQuotes.js +49 -0
- package/dist/commands/llm.d.ts +8 -0
- package/dist/commands/llm.js +308 -68
- package/dist/commands/login.js +20 -31
- package/dist/commands/portfolio.js +1 -2
- package/dist/commands/prompt.js +28 -29
- package/dist/commands/sign.js +8 -16
- package/dist/commands/sounds.js +6 -16
- package/dist/commands/status.js +1 -4
- package/dist/commands/submit.js +12 -24
- package/dist/commands/swap.js +2 -4
- package/dist/commands/tokens.js +1 -2
- package/dist/commands/transfer.js +2 -4
- package/dist/commands/update.js +1 -2
- package/dist/commands/webhooks.js +21 -65
- package/dist/commands/whoami.js +1 -2
- package/dist/commands/x402.js +36 -100
- package/dist/lib/api.d.ts +42 -2
- package/dist/lib/api.js +10 -2
- package/dist/lib/chains.js +4 -0
- package/dist/lib/explorer.js +1 -0
- package/dist/lib/output.d.ts +4 -0
- package/dist/lib/output.js +12 -0
- package/dist/lib/quoteTokens.d.ts +15 -0
- package/dist/lib/quoteTokens.js +53 -0
- package/package.json +1 -1
package/dist/commands/login.js
CHANGED
|
@@ -8,10 +8,6 @@ import { getErrorMessage } from "../lib/errors.js";
|
|
|
8
8
|
const DEFAULT_DASHBOARD_URL = "https://bankr.bot/api-keys";
|
|
9
9
|
const MAX_OTP_ATTEMPTS = 3;
|
|
10
10
|
const INVALID_CODE_STATUSES = [400, 401, 422];
|
|
11
|
-
function fatal(message) {
|
|
12
|
-
output.error(message);
|
|
13
|
-
process.exit(1);
|
|
14
|
-
}
|
|
15
11
|
function deriveDashboardUrl(apiUrl) {
|
|
16
12
|
if (apiUrl === DEFAULT_API_URL) {
|
|
17
13
|
return DEFAULT_DASHBOARD_URL;
|
|
@@ -114,7 +110,7 @@ async function callGenerateApiKey(apiUrl, tokens, opts) {
|
|
|
114
110
|
async function fetchPrivyConfigOrFail(apiUrl) {
|
|
115
111
|
const config = await fetchPrivyConfig(apiUrl).catch(() => null);
|
|
116
112
|
if (!config) {
|
|
117
|
-
fatal("Could not connect to Bankr API. Check your connection and try again.");
|
|
113
|
+
output.fatal("Could not connect to Bankr API. Check your connection and try again.");
|
|
118
114
|
}
|
|
119
115
|
return config;
|
|
120
116
|
}
|
|
@@ -125,8 +121,7 @@ async function sendOtpWithSpinner(privyConfig, email) {
|
|
|
125
121
|
spin.succeed(`Verification code sent to ${email}`);
|
|
126
122
|
}
|
|
127
123
|
catch (err) {
|
|
128
|
-
|
|
129
|
-
fatal(getErrorMessage(err));
|
|
124
|
+
output.failWith(spin, "Failed to send verification code", err);
|
|
130
125
|
}
|
|
131
126
|
}
|
|
132
127
|
async function verifyOtpWithSpinner(privyConfig, email, code) {
|
|
@@ -139,7 +134,7 @@ async function verifyOtpWithSpinner(privyConfig, email, code) {
|
|
|
139
134
|
catch (err) {
|
|
140
135
|
const errMsg = getErrorMessage(err);
|
|
141
136
|
spin.fail("Verification failed");
|
|
142
|
-
fatal(errMsg === "INVALID_CODE" ? "Invalid verification code." : errMsg);
|
|
137
|
+
output.fatal(errMsg === "INVALID_CODE" ? "Invalid verification code." : errMsg);
|
|
143
138
|
}
|
|
144
139
|
}
|
|
145
140
|
// ── Email authentication flow ───────────────────────────────────────
|
|
@@ -197,13 +192,13 @@ async function authenticateWithEmail(apiUrl, providedEmail, providedCode) {
|
|
|
197
192
|
continue;
|
|
198
193
|
}
|
|
199
194
|
verifySpin.fail("Invalid code");
|
|
200
|
-
fatal("Too many invalid attempts. Please restart login.");
|
|
195
|
+
output.fatal("Too many invalid attempts. Please restart login.");
|
|
201
196
|
}
|
|
202
197
|
verifySpin.fail("Verification failed");
|
|
203
|
-
fatal(errMsg);
|
|
198
|
+
output.fatal(errMsg);
|
|
204
199
|
}
|
|
205
200
|
}
|
|
206
|
-
fatal("Verification failed. Please try again.");
|
|
201
|
+
output.fatal("Verification failed. Please try again.");
|
|
207
202
|
}
|
|
208
203
|
// ── Email login flow ────────────────────────────────────────────────
|
|
209
204
|
async function emailLoginFlow(apiUrl, opts) {
|
|
@@ -217,8 +212,7 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
217
212
|
walletSpin.stop();
|
|
218
213
|
}
|
|
219
214
|
catch (err) {
|
|
220
|
-
|
|
221
|
-
fatal(getErrorMessage(err));
|
|
215
|
+
output.failWith(walletSpin, "Wallet setup failed", err);
|
|
222
216
|
}
|
|
223
217
|
// Show wallet info
|
|
224
218
|
output.blank();
|
|
@@ -248,7 +242,7 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
248
242
|
theme: output.bankrTheme,
|
|
249
243
|
}));
|
|
250
244
|
if (!accepted) {
|
|
251
|
-
fatal("Terms must be accepted to continue.");
|
|
245
|
+
output.fatal("Terms must be accepted to continue.");
|
|
252
246
|
}
|
|
253
247
|
const termsSpin = output.spinner("Accepting terms...");
|
|
254
248
|
try {
|
|
@@ -256,8 +250,7 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
256
250
|
termsSpin.succeed("Terms accepted");
|
|
257
251
|
}
|
|
258
252
|
catch (err) {
|
|
259
|
-
|
|
260
|
-
fatal(getErrorMessage(err));
|
|
253
|
+
output.failWith(termsSpin, "Failed to accept terms", err);
|
|
261
254
|
}
|
|
262
255
|
}
|
|
263
256
|
// Step 4: Generate API key
|
|
@@ -305,8 +298,7 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
305
298
|
keySpin.stop();
|
|
306
299
|
}
|
|
307
300
|
catch (err) {
|
|
308
|
-
|
|
309
|
-
fatal(getErrorMessage(err));
|
|
301
|
+
output.failWith(keySpin, "Failed to generate API key", err);
|
|
310
302
|
}
|
|
311
303
|
// Show result
|
|
312
304
|
output.blank();
|
|
@@ -345,7 +337,7 @@ async function siweLoginFlow(apiUrl, opts) {
|
|
|
345
337
|
});
|
|
346
338
|
if (!nonceRes.ok) {
|
|
347
339
|
nonceSpinner.fail("Failed to fetch nonce");
|
|
348
|
-
fatal(`Nonce request failed (${nonceRes.status})`);
|
|
340
|
+
output.fatal(`Nonce request failed (${nonceRes.status})`);
|
|
349
341
|
}
|
|
350
342
|
const { nonce } = (await nonceRes.json());
|
|
351
343
|
nonceSpinner.succeed("Nonce received");
|
|
@@ -389,7 +381,7 @@ async function siweLoginFlow(apiUrl, opts) {
|
|
|
389
381
|
if (!verifyRes.ok) {
|
|
390
382
|
verifySpinner.fail("SIWE verification failed");
|
|
391
383
|
const body = (await verifyRes.json().catch(() => ({})));
|
|
392
|
-
fatal(body.message || `Verification failed (${verifyRes.status})`);
|
|
384
|
+
output.fatal(body.message || `Verification failed (${verifyRes.status})`);
|
|
393
385
|
}
|
|
394
386
|
const result = (await verifyRes.json());
|
|
395
387
|
verifySpinner.succeed("Wallet created");
|
|
@@ -417,13 +409,11 @@ async function validateApiKey(apiUrl, apiKey) {
|
|
|
417
409
|
const errorType = body.error ?? "";
|
|
418
410
|
if (errorType === "Authentication required") {
|
|
419
411
|
spin.fail("API key is not linked to a wallet");
|
|
420
|
-
output.
|
|
421
|
-
process.exit(1);
|
|
412
|
+
output.fatal("This API key is not associated with a wallet. Generate a new key at https://bankr.bot/api-keys");
|
|
422
413
|
}
|
|
423
414
|
else {
|
|
424
415
|
spin.fail("Invalid Bankr API key");
|
|
425
|
-
output.
|
|
426
|
-
process.exit(1);
|
|
416
|
+
output.fatal("The provided API key is invalid or inactive. Generate a new key at https://bankr.bot/api-keys");
|
|
427
417
|
}
|
|
428
418
|
}
|
|
429
419
|
else {
|
|
@@ -461,7 +451,7 @@ function parseAndValidateIps(raw) {
|
|
|
461
451
|
.filter(Boolean);
|
|
462
452
|
const invalid = ips.filter((ip) => !isValidIpOrCidr(ip));
|
|
463
453
|
if (invalid.length > 0) {
|
|
464
|
-
fatal(`Invalid IP address(es) or CIDR range(s): ${invalid.join(", ")}`);
|
|
454
|
+
output.fatal(`Invalid IP address(es) or CIDR range(s): ${invalid.join(", ")}`);
|
|
465
455
|
}
|
|
466
456
|
return ips;
|
|
467
457
|
}
|
|
@@ -493,14 +483,14 @@ function parseAndValidateRecipients(raw) {
|
|
|
493
483
|
}
|
|
494
484
|
}
|
|
495
485
|
if (invalid.length > 0) {
|
|
496
|
-
fatal(`Invalid address(es): ${invalid.join(", ")}`);
|
|
486
|
+
output.fatal(`Invalid address(es): ${invalid.join(", ")}`);
|
|
497
487
|
}
|
|
498
488
|
return { evm, solana };
|
|
499
489
|
}
|
|
500
490
|
export async function loginCommand(opts) {
|
|
501
491
|
// Fail fast if flags were passed with empty values
|
|
502
492
|
if (opts.apiKey !== undefined && !opts.apiKey.trim()) {
|
|
503
|
-
fatal("--api-key requires a non-empty value");
|
|
493
|
+
output.fatal("--api-key requires a non-empty value");
|
|
504
494
|
}
|
|
505
495
|
// Non-interactive mode requires a headless flag combo. Without one, the
|
|
506
496
|
// command would hang on a prompt — fail fast with the available paths.
|
|
@@ -512,8 +502,7 @@ export async function loginCommand(opts) {
|
|
|
512
502
|
(opts.siwe && opts.privateKey) ||
|
|
513
503
|
(opts.email && opts.email.trim());
|
|
514
504
|
if (!hasHeadlessFlag) {
|
|
515
|
-
output.
|
|
516
|
-
process.exit(1);
|
|
505
|
+
output.fatal("Non-interactive login requires one of: --api-key <key>, login siwe --private-key <key>, or login email <address> [--code <otp>]");
|
|
517
506
|
}
|
|
518
507
|
}
|
|
519
508
|
const config = readConfig();
|
|
@@ -573,7 +562,7 @@ export async function loginCommand(opts) {
|
|
|
573
562
|
// --siwe: SIWE login flow (headless agent onboarding)
|
|
574
563
|
if (opts.siwe) {
|
|
575
564
|
if (!opts.privateKey) {
|
|
576
|
-
fatal("--private-key is required with --siwe");
|
|
565
|
+
output.fatal("--private-key is required with --siwe");
|
|
577
566
|
}
|
|
578
567
|
const { apiKey } = await siweLoginFlow(apiUrl, {
|
|
579
568
|
privateKey: opts.privateKey,
|
|
@@ -604,7 +593,7 @@ export async function loginCommand(opts) {
|
|
|
604
593
|
if (opts.apiKey) {
|
|
605
594
|
const apiKey = opts.apiKey.trim();
|
|
606
595
|
if (!apiKey.startsWith("bk_")) {
|
|
607
|
-
fatal('Invalid format. Bankr API keys start with "bk_".');
|
|
596
|
+
output.fatal('Invalid format. Bankr API keys start with "bk_".');
|
|
608
597
|
}
|
|
609
598
|
await validateApiKey(apiUrl, apiKey);
|
|
610
599
|
saveCredentials(apiKey, opts.llmKey);
|
|
@@ -54,8 +54,7 @@ export async function portfolioCommand(opts) {
|
|
|
54
54
|
if (chains) {
|
|
55
55
|
const invalid = chains.filter((c) => !VALID_CHAINS.has(c));
|
|
56
56
|
if (invalid.length > 0) {
|
|
57
|
-
output.
|
|
58
|
-
process.exit(1);
|
|
57
|
+
output.fatal(`Invalid chain${invalid.length > 1 ? "s" : ""}: ${invalid.join(", ")}. Valid chains: ${[...VALID_CHAINS].join(", ")}`);
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
const includePnl = opts.pnl || opts.all;
|
package/dist/commands/prompt.js
CHANGED
|
@@ -4,57 +4,59 @@ import { getLastThreadId, requireApiKey, setLastThreadId, } from "../lib/config.
|
|
|
4
4
|
import * as output from "../lib/output.js";
|
|
5
5
|
import { getErrorMessage } from "../lib/errors.js";
|
|
6
6
|
/** Valid Max Mode model IDs — hardcoded because CLI is standalone (no monorepo imports).
|
|
7
|
-
* Must be manually kept in sync with models in the LLM gateway DB.
|
|
7
|
+
* Must be manually kept in sync with models in the LLM gateway DB.
|
|
8
|
+
*
|
|
9
|
+
* Only the two newest releases of each vendor tier are listed, and only the
|
|
10
|
+
* frontier / flagship / balanced ranks — matching what the web picker shows.
|
|
11
|
+
* Older generations and `light` lines still run on the gateway, but the CLI
|
|
12
|
+
* stops steering people onto them. Superseding a model here means DROPPING
|
|
13
|
+
* the one it pushes out of the tier, not just adding the new id. */
|
|
8
14
|
const VALID_MAX_MODE_MODELS = new Set([
|
|
9
15
|
// Claude (Vertex AI)
|
|
16
|
+
"claude-fable-5.1",
|
|
10
17
|
"claude-fable-5",
|
|
11
18
|
"claude-opus-5",
|
|
12
19
|
"claude-opus-4.8",
|
|
13
|
-
"claude-opus-4.7",
|
|
14
|
-
"claude-opus-4.6",
|
|
15
|
-
"claude-opus-4.5",
|
|
16
20
|
"claude-sonnet-5",
|
|
17
21
|
"claude-sonnet-4.6",
|
|
18
|
-
"claude-sonnet-4.5",
|
|
19
|
-
"claude-haiku-4.5",
|
|
20
22
|
// Gemini (Vertex AI) — gemini-3-pro deliberately absent: removed 2026-03-09,
|
|
21
|
-
// both provider slugs retired.
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
// both provider slugs retired. The Flash Lite tier likewise: 3.5 and 3.1
|
|
24
|
+
// deprecated 2026-09-09 (replaced by gemini-3.8-flash). Don't re-add on a
|
|
25
|
+
// sync pass.
|
|
26
|
+
"gemini-3.8-flash",
|
|
27
|
+
"gemini-3.7-flash",
|
|
24
28
|
"gemini-3.1-pro",
|
|
25
29
|
"gemini-2.5-pro",
|
|
26
30
|
// OpenAI (OpenRouter)
|
|
31
|
+
"gpt-6-astra",
|
|
27
32
|
"gpt-5.6-sol",
|
|
28
|
-
"gpt-5.6-terra",
|
|
29
|
-
"gpt-5.6-luna",
|
|
30
33
|
"gpt-5.5",
|
|
31
|
-
"gpt-5.
|
|
32
|
-
"gpt-5.
|
|
33
|
-
"gpt-5.2",
|
|
34
|
-
"gpt-5-mini",
|
|
34
|
+
"gpt-5.6-terra",
|
|
35
|
+
"gpt-5.2-codex",
|
|
35
36
|
// Grok (OpenRouter)
|
|
36
37
|
"grok-4.6",
|
|
37
38
|
"grok-4.5",
|
|
38
|
-
|
|
39
|
-
//
|
|
40
|
-
"deepseek-
|
|
39
|
+
// DeepSeek (OpenRouter) — v4.1-flash is its own tier at `balanced`
|
|
40
|
+
// ($0.30/$1.20, 3.3x under the V4 Pro card), not the `light` flash line.
|
|
41
|
+
"deepseek-v4-pro-0813",
|
|
42
|
+
"deepseek-v4-pro",
|
|
43
|
+
"deepseek-v4.1-flash",
|
|
41
44
|
// Qwen (OpenRouter)
|
|
42
|
-
"qwen3-coder",
|
|
43
45
|
"qwen3.8-max",
|
|
44
46
|
"qwen3.7-max",
|
|
45
47
|
"qwen3.7-plus",
|
|
46
|
-
"qwen3.7-flash",
|
|
47
48
|
"qwen3.5-plus",
|
|
48
49
|
// MiniMax (direct)
|
|
49
|
-
"minimax-
|
|
50
|
+
"minimax-m3",
|
|
50
51
|
"minimax-m2.7",
|
|
52
|
+
"minimax-m2.7-highspeed",
|
|
51
53
|
// Other (OpenRouter)
|
|
52
54
|
"kimi-k3",
|
|
53
55
|
"kimi-k2.7-code",
|
|
54
56
|
"kimi-k2.6",
|
|
55
|
-
"kimi-k2.5",
|
|
56
|
-
"glm-5",
|
|
57
57
|
"glm-5.2",
|
|
58
|
+
"glm-5.3",
|
|
59
|
+
"glm-5-turbo",
|
|
58
60
|
]);
|
|
59
61
|
export async function promptCommand(text, options = {}) {
|
|
60
62
|
requireApiKey();
|
|
@@ -63,8 +65,7 @@ export async function promptCommand(text, options = {}) {
|
|
|
63
65
|
if (options.continue) {
|
|
64
66
|
threadId = getLastThreadId();
|
|
65
67
|
if (!threadId) {
|
|
66
|
-
output.
|
|
67
|
-
process.exit(1);
|
|
68
|
+
output.fatal("No previous thread found. Run a prompt first.");
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
71
|
else if (options.thread) {
|
|
@@ -74,8 +75,7 @@ export async function promptCommand(text, options = {}) {
|
|
|
74
75
|
let maxMode;
|
|
75
76
|
if (options.model) {
|
|
76
77
|
if (!VALID_MAX_MODE_MODELS.has(options.model)) {
|
|
77
|
-
output.
|
|
78
|
-
process.exit(1);
|
|
78
|
+
output.fatal(`Invalid model "${options.model}". Valid models: ${[...VALID_MAX_MODE_MODELS].join(", ")}`);
|
|
79
79
|
}
|
|
80
80
|
maxMode = { enabled: true, model: options.model };
|
|
81
81
|
}
|
|
@@ -154,8 +154,7 @@ export async function promptCommand(text, options = {}) {
|
|
|
154
154
|
catch (err) {
|
|
155
155
|
spin.fail("Error while polling");
|
|
156
156
|
emitCESP("resource.limit");
|
|
157
|
-
output.
|
|
158
|
-
process.exit(1);
|
|
157
|
+
output.fatal(getErrorMessage(err));
|
|
159
158
|
}
|
|
160
159
|
}
|
|
161
160
|
//# sourceMappingURL=prompt.js.map
|
package/dist/commands/sign.js
CHANGED
|
@@ -10,40 +10,34 @@ export async function signCommand(opts) {
|
|
|
10
10
|
switch (opts.type) {
|
|
11
11
|
case "personal_sign":
|
|
12
12
|
if (!opts.message) {
|
|
13
|
-
output.
|
|
14
|
-
process.exit(1);
|
|
13
|
+
output.fatal("--message is required for personal_sign");
|
|
15
14
|
}
|
|
16
15
|
request.message = opts.message;
|
|
17
16
|
break;
|
|
18
17
|
case "eth_signTypedData_v4":
|
|
19
18
|
if (!opts.typedData) {
|
|
20
|
-
output.
|
|
21
|
-
process.exit(1);
|
|
19
|
+
output.fatal("--typed-data is required for eth_signTypedData_v4");
|
|
22
20
|
}
|
|
23
21
|
try {
|
|
24
22
|
request.typedData = JSON.parse(opts.typedData);
|
|
25
23
|
}
|
|
26
24
|
catch {
|
|
27
|
-
output.
|
|
28
|
-
process.exit(1);
|
|
25
|
+
output.fatal("--typed-data must be valid JSON");
|
|
29
26
|
}
|
|
30
27
|
break;
|
|
31
28
|
case "eth_signTransaction":
|
|
32
29
|
if (!opts.transaction) {
|
|
33
|
-
output.
|
|
34
|
-
process.exit(1);
|
|
30
|
+
output.fatal("--transaction is required for eth_signTransaction");
|
|
35
31
|
}
|
|
36
32
|
try {
|
|
37
33
|
request.transaction = JSON.parse(opts.transaction);
|
|
38
34
|
}
|
|
39
35
|
catch {
|
|
40
|
-
output.
|
|
41
|
-
process.exit(1);
|
|
36
|
+
output.fatal("--transaction must be valid JSON");
|
|
42
37
|
}
|
|
43
38
|
break;
|
|
44
39
|
default:
|
|
45
|
-
output.
|
|
46
|
-
process.exit(1);
|
|
40
|
+
output.fatal(`Invalid signature type: ${opts.type}. Must be one of: personal_sign, eth_signTypedData_v4, eth_signTransaction`);
|
|
47
41
|
}
|
|
48
42
|
// Execute signing with spinner
|
|
49
43
|
const spinner = output.spinner("Signing...");
|
|
@@ -51,8 +45,7 @@ export async function signCommand(opts) {
|
|
|
51
45
|
const result = await sign(request);
|
|
52
46
|
spinner.stop();
|
|
53
47
|
if (!result.success) {
|
|
54
|
-
output.
|
|
55
|
-
process.exit(1);
|
|
48
|
+
output.fatal(result.error || "Signing failed");
|
|
56
49
|
}
|
|
57
50
|
output.success("Signed successfully");
|
|
58
51
|
emitCESP("task.complete");
|
|
@@ -64,8 +57,7 @@ export async function signCommand(opts) {
|
|
|
64
57
|
catch (err) {
|
|
65
58
|
spinner.stop();
|
|
66
59
|
emitCESP("task.error");
|
|
67
|
-
output.
|
|
68
|
-
process.exit(1);
|
|
60
|
+
output.fatal(getErrorMessage(err));
|
|
69
61
|
}
|
|
70
62
|
}
|
|
71
63
|
//# sourceMappingURL=sign.js.map
|
package/dist/commands/sounds.js
CHANGED
|
@@ -6,7 +6,6 @@ import { tmpdir } from "node:os";
|
|
|
6
6
|
import { readConfig, writeConfig } from "../lib/config.js";
|
|
7
7
|
import { DEFAULT_SOUND_CONFIG, emitCESP, getPacksDir, listInstalledPacks, } from "../lib/cesp/engine.js";
|
|
8
8
|
import * as output from "../lib/output.js";
|
|
9
|
-
import { getErrorMessage } from "../lib/errors.js";
|
|
10
9
|
const execFileAsync = promisify(execFile);
|
|
11
10
|
const REGISTRY_URL = "https://peonping.github.io/registry/index.json";
|
|
12
11
|
function getSoundConfig() {
|
|
@@ -71,8 +70,7 @@ export async function soundsUseCommand(packName) {
|
|
|
71
70
|
const packs = listInstalledPacks();
|
|
72
71
|
const match = packs.find((p) => p.name === packName);
|
|
73
72
|
if (!match) {
|
|
74
|
-
output.
|
|
75
|
-
process.exit(1);
|
|
73
|
+
output.fatal(`Pack "${packName}" not found. Run: bankr sounds list`);
|
|
76
74
|
}
|
|
77
75
|
const sound = getSoundConfig();
|
|
78
76
|
sound.activePack = packName;
|
|
@@ -87,8 +85,7 @@ export async function soundsVolumeCommand(level) {
|
|
|
87
85
|
}
|
|
88
86
|
const vol = parseFloat(level);
|
|
89
87
|
if (isNaN(vol) || vol < 0 || vol > 1) {
|
|
90
|
-
output.
|
|
91
|
-
process.exit(1);
|
|
88
|
+
output.fatal("Volume must be a number between 0.0 and 1.0");
|
|
92
89
|
}
|
|
93
90
|
sound.volume = vol;
|
|
94
91
|
saveSoundConfig(sound);
|
|
@@ -109,8 +106,7 @@ export async function soundsUnmuteCommand() {
|
|
|
109
106
|
export async function soundsTestCommand(category) {
|
|
110
107
|
const sound = getSoundConfig();
|
|
111
108
|
if (!sound.activePack) {
|
|
112
|
-
output.
|
|
113
|
-
process.exit(1);
|
|
109
|
+
output.fatal("No active sound pack. Run: bankr sounds use <pack>");
|
|
114
110
|
}
|
|
115
111
|
const cat = category ?? "task.complete";
|
|
116
112
|
output.dim(`Playing "${cat}" from ${sound.activePack}...`);
|
|
@@ -164,9 +160,7 @@ export async function soundsInstallCommand(packName) {
|
|
|
164
160
|
spin.succeed(`Found ${entry.display_name} (${entry.sound_count} sounds, ${formatSize(entry.total_size_bytes)})`);
|
|
165
161
|
}
|
|
166
162
|
catch (err) {
|
|
167
|
-
|
|
168
|
-
output.error(getErrorMessage(err));
|
|
169
|
-
process.exit(1);
|
|
163
|
+
output.failWith(spin, "Failed to fetch registry", err);
|
|
170
164
|
}
|
|
171
165
|
// Download and extract
|
|
172
166
|
const tarballUrl = `https://github.com/${entry.source_repo}/archive/refs/tags/${entry.source_ref}.tar.gz`;
|
|
@@ -218,9 +212,7 @@ export async function soundsInstallCommand(packName) {
|
|
|
218
212
|
}
|
|
219
213
|
}
|
|
220
214
|
catch (err) {
|
|
221
|
-
|
|
222
|
-
output.error(getErrorMessage(err));
|
|
223
|
-
process.exit(1);
|
|
215
|
+
output.failWith(spin2, "Install failed", err);
|
|
224
216
|
}
|
|
225
217
|
}
|
|
226
218
|
// -- Search command --
|
|
@@ -232,9 +224,7 @@ export async function soundsSearchCommand(query) {
|
|
|
232
224
|
spin.stop();
|
|
233
225
|
}
|
|
234
226
|
catch (err) {
|
|
235
|
-
|
|
236
|
-
output.error(getErrorMessage(err));
|
|
237
|
-
process.exit(1);
|
|
227
|
+
output.failWith(spin, "Failed to fetch registry", err);
|
|
238
228
|
}
|
|
239
229
|
// Filter by query if provided
|
|
240
230
|
let results = registry;
|
package/dist/commands/status.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getJobStatus } from "../lib/api.js";
|
|
2
2
|
import { requireApiKey } from "../lib/config.js";
|
|
3
3
|
import * as output from "../lib/output.js";
|
|
4
|
-
import { getErrorMessage } from "../lib/errors.js";
|
|
5
4
|
export async function statusCommand(jobId) {
|
|
6
5
|
requireApiKey();
|
|
7
6
|
const spin = output.spinner("Fetching job status...");
|
|
@@ -38,9 +37,7 @@ export async function statusCommand(jobId) {
|
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
39
|
catch (err) {
|
|
41
|
-
|
|
42
|
-
output.error(getErrorMessage(err));
|
|
43
|
-
process.exit(1);
|
|
40
|
+
output.failWith(spin, "Failed to fetch job status", err);
|
|
44
41
|
}
|
|
45
42
|
}
|
|
46
43
|
//# sourceMappingURL=status.js.map
|
package/dist/commands/submit.js
CHANGED
|
@@ -28,24 +28,20 @@ function displayResult(result) {
|
|
|
28
28
|
export async function submitCommand(opts) {
|
|
29
29
|
// Validate required fields
|
|
30
30
|
if (!opts.to) {
|
|
31
|
-
output.
|
|
32
|
-
process.exit(1);
|
|
31
|
+
output.fatal("--to is required");
|
|
33
32
|
}
|
|
34
33
|
if (!opts.chainId) {
|
|
35
|
-
output.
|
|
36
|
-
process.exit(1);
|
|
34
|
+
output.fatal("--chain-id is required");
|
|
37
35
|
}
|
|
38
36
|
const chainId = parseInt(opts.chainId, 10);
|
|
39
37
|
if (isNaN(chainId)) {
|
|
40
|
-
output.
|
|
41
|
-
process.exit(1);
|
|
38
|
+
output.fatal("--chain-id must be a number");
|
|
42
39
|
}
|
|
43
40
|
let nonce;
|
|
44
41
|
if (opts.nonce) {
|
|
45
42
|
nonce = parseInt(opts.nonce, 10);
|
|
46
43
|
if (isNaN(nonce)) {
|
|
47
|
-
output.
|
|
48
|
-
process.exit(1);
|
|
44
|
+
output.fatal("--nonce must be a number");
|
|
49
45
|
}
|
|
50
46
|
}
|
|
51
47
|
const request = {
|
|
@@ -74,8 +70,7 @@ export async function submitCommand(opts) {
|
|
|
74
70
|
}
|
|
75
71
|
catch (err) {
|
|
76
72
|
spinner.stop();
|
|
77
|
-
output.
|
|
78
|
-
process.exit(1);
|
|
73
|
+
output.fatal(getErrorMessage(err));
|
|
79
74
|
}
|
|
80
75
|
}
|
|
81
76
|
// Alternative: submit from JSON
|
|
@@ -85,32 +80,26 @@ export async function submitJsonCommand(json, opts) {
|
|
|
85
80
|
transaction = JSON.parse(json);
|
|
86
81
|
}
|
|
87
82
|
catch {
|
|
88
|
-
output.
|
|
89
|
-
process.exit(1);
|
|
83
|
+
output.fatal("Invalid JSON. Expected: {to, chainId, value?, data?}");
|
|
90
84
|
}
|
|
91
85
|
if (!transaction ||
|
|
92
86
|
typeof transaction !== "object" ||
|
|
93
87
|
Array.isArray(transaction)) {
|
|
94
|
-
output.
|
|
95
|
-
process.exit(1);
|
|
88
|
+
output.fatal("Invalid JSON. Expected object: {to, chainId, value?, data?}");
|
|
96
89
|
}
|
|
97
90
|
// Validate required fields
|
|
98
91
|
if (!transaction.to) {
|
|
99
|
-
output.
|
|
100
|
-
process.exit(1);
|
|
92
|
+
output.fatal("Transaction must have 'to' field");
|
|
101
93
|
}
|
|
102
94
|
if (transaction.chainId === undefined) {
|
|
103
|
-
output.
|
|
104
|
-
process.exit(1);
|
|
95
|
+
output.fatal("Transaction must have 'chainId' field");
|
|
105
96
|
}
|
|
106
97
|
if (typeof transaction.chainId !== "number" || isNaN(transaction.chainId)) {
|
|
107
|
-
output.
|
|
108
|
-
process.exit(1);
|
|
98
|
+
output.fatal("Transaction 'chainId' must be a number");
|
|
109
99
|
}
|
|
110
100
|
if (transaction.nonce !== undefined &&
|
|
111
101
|
(typeof transaction.nonce !== "number" || isNaN(transaction.nonce))) {
|
|
112
|
-
output.
|
|
113
|
-
process.exit(1);
|
|
102
|
+
output.fatal("Transaction 'nonce' must be a number");
|
|
114
103
|
}
|
|
115
104
|
const request = {
|
|
116
105
|
transaction,
|
|
@@ -128,8 +117,7 @@ export async function submitJsonCommand(json, opts) {
|
|
|
128
117
|
}
|
|
129
118
|
catch (err) {
|
|
130
119
|
spinner.stop();
|
|
131
|
-
output.
|
|
132
|
-
process.exit(1);
|
|
120
|
+
output.fatal(getErrorMessage(err));
|
|
133
121
|
}
|
|
134
122
|
}
|
|
135
123
|
//# sourceMappingURL=submit.js.map
|
package/dist/commands/swap.js
CHANGED
|
@@ -24,16 +24,14 @@ async function resolveSwapToken(tokenInput, chain) {
|
|
|
24
24
|
export async function swapCommand(opts) {
|
|
25
25
|
const chain = opts.chain ?? "base";
|
|
26
26
|
if (!VALID_CHAINS.has(chain) || chain === "solana") {
|
|
27
|
-
output.
|
|
28
|
-
process.exit(1);
|
|
27
|
+
output.fatal(`Unsupported chain "${chain}". Swaps support EVM chains: base, polygon, mainnet, unichain, worldchain, arbitrum, bnb.`);
|
|
29
28
|
}
|
|
30
29
|
// Validate amount client-side so a bad value gives a clear error instead of a
|
|
31
30
|
// generic 500 from the API's parseUnits(amount, decimals). Number() alone
|
|
32
31
|
// accepts "1e-3" / "0x10" / "Infinity" that parseUnits rejects, so require a
|
|
33
32
|
// plain decimal string.
|
|
34
33
|
if (!/^\d*\.?\d+$/.test(opts.amount) || Number(opts.amount) <= 0) {
|
|
35
|
-
output.
|
|
36
|
-
process.exit(1);
|
|
34
|
+
output.fatal(`Invalid amount "${opts.amount}". Provide a positive decimal number, e.g. --amount 0.5.`);
|
|
37
35
|
}
|
|
38
36
|
// Resolve from/to tokens (symbol → address, native → zero address)
|
|
39
37
|
let fromToken;
|
package/dist/commands/tokens.js
CHANGED
|
@@ -38,8 +38,7 @@ export async function tokensInfoCommand(address, opts) {
|
|
|
38
38
|
const token = res.tokens.find((t) => t.address.toLowerCase() === addressLower) ??
|
|
39
39
|
res.tokens[0];
|
|
40
40
|
if (!token) {
|
|
41
|
-
output.
|
|
42
|
-
process.exit(1);
|
|
41
|
+
output.fatal("Token not found. Check the address and try again.");
|
|
43
42
|
}
|
|
44
43
|
console.log();
|
|
45
44
|
output.label("Name", token.name);
|
|
@@ -14,8 +14,7 @@ async function resolveTransferRecipient(raw) {
|
|
|
14
14
|
return { address: value, label: value };
|
|
15
15
|
}
|
|
16
16
|
if (!looksLikeEnsName(value)) {
|
|
17
|
-
output.
|
|
18
|
-
process.exit(1);
|
|
17
|
+
output.fatal(`Invalid recipient "${value}". Expected a 0x address or an ENS name (e.g. vitalik.eth, name.base.eth, name.cb.id).`);
|
|
19
18
|
}
|
|
20
19
|
const spin = output.spinner(`Resolving ENS name "${value}"...`);
|
|
21
20
|
try {
|
|
@@ -39,8 +38,7 @@ export async function transferCommand(opts) {
|
|
|
39
38
|
const isNative = opts.native ?? false;
|
|
40
39
|
const chain = opts.chain ?? "base";
|
|
41
40
|
if (!isNative && !opts.token) {
|
|
42
|
-
output.
|
|
43
|
-
process.exit(1);
|
|
41
|
+
output.fatal("Token required for ERC20 transfers. Use --token <symbol or address> or --native.");
|
|
44
42
|
}
|
|
45
43
|
const recipient = await resolveTransferRecipient(opts.to);
|
|
46
44
|
const recipientAddress = recipient.address;
|
package/dist/commands/update.js
CHANGED