@bankr/cli 0.2.9 → 0.2.13
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 +7 -7
- package/dist/cli.js +47 -20
- package/dist/commands/llm.js +3 -1
- package/dist/commands/login.d.ts +0 -1
- package/dist/commands/login.js +26 -15
- package/dist/commands/prompt.d.ts +1 -0
- package/dist/commands/prompt.js +56 -3
- package/dist/commands/x402.js +13 -0
- package/dist/lib/api.d.ts +19 -1
- package/dist/lib/api.js +22 -3
- package/dist/lib/output.d.ts +11 -0
- package/dist/lib/output.js +13 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ npm install -g @bankr/cli
|
|
|
15
15
|
bankr login
|
|
16
16
|
|
|
17
17
|
# Send a prompt
|
|
18
|
-
bankr
|
|
18
|
+
bankr agent "what's trending on base?"
|
|
19
19
|
|
|
20
20
|
# Or use the shorthand (no subcommand)
|
|
21
21
|
bankr "what is the price of ETH?"
|
|
@@ -60,17 +60,17 @@ bankr logout
|
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
62
|
# Send a prompt and wait for the response
|
|
63
|
-
bankr
|
|
63
|
+
bankr agent "swap 10 USDC to ETH on base"
|
|
64
64
|
|
|
65
65
|
# Shorthand — just pass the prompt directly
|
|
66
66
|
bankr "what are the top holders of VIRTUAL?"
|
|
67
67
|
|
|
68
68
|
# Continue the most recent conversation
|
|
69
|
-
bankr
|
|
70
|
-
bankr
|
|
69
|
+
bankr agent --continue "and what about SOL?"
|
|
70
|
+
bankr agent -c "compare them"
|
|
71
71
|
|
|
72
72
|
# Continue a specific thread
|
|
73
|
-
bankr
|
|
73
|
+
bankr agent --thread thr_ABC123 "tell me more"
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
### Token Launch
|
|
@@ -95,10 +95,10 @@ bankr launch --name "TESTCOIN" --fee "0x1234..." --fee-type wallet -y
|
|
|
95
95
|
|
|
96
96
|
```bash
|
|
97
97
|
# Check the status of a job
|
|
98
|
-
bankr status job_ABC123DEF456
|
|
98
|
+
bankr agent status job_ABC123DEF456
|
|
99
99
|
|
|
100
100
|
# Cancel a running job
|
|
101
|
-
bankr cancel job_ABC123DEF456
|
|
101
|
+
bankr agent cancel job_ABC123DEF456
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
### Configuration
|
package/dist/cli.js
CHANGED
|
@@ -119,10 +119,9 @@ loginCmd
|
|
|
119
119
|
.option("--key-name <name>", "API key name (default: CLI)")
|
|
120
120
|
.option("--read-write", "Disable read-only mode (allow transactions)")
|
|
121
121
|
.option("--no-wallet-api", "Disable Wallet API (enabled by default)")
|
|
122
|
-
.option("--agent-api", "Enable Agent API (AI prompts)")
|
|
123
122
|
.option("--no-token-launch", "Disable Token Launch API (enabled by default)")
|
|
124
123
|
.option("--llm", "Enable LLM gateway on the API key")
|
|
125
|
-
.option("--allowed-ips <ips>", "Comma-separated IP allowlist
|
|
124
|
+
.option("--allowed-ips <ips>", "Comma-separated IP/CIDR allowlist, e.g. 1.2.3.4,10.0.0.0/24")
|
|
126
125
|
.option("--allowed-recipients <addresses>", "Comma-separated EVM/Solana addresses (agent will only send funds to these)")
|
|
127
126
|
.action(async (address, opts, cmd) => {
|
|
128
127
|
const parentOpts = cmd.parent.opts();
|
|
@@ -135,7 +134,6 @@ loginCmd
|
|
|
135
134
|
keyName: opts.keyName,
|
|
136
135
|
readWrite: opts.readWrite,
|
|
137
136
|
walletApi: opts.walletApi,
|
|
138
|
-
agentApi: opts.agentApi,
|
|
139
137
|
tokenLaunch: opts.tokenLaunch,
|
|
140
138
|
llm: opts.llm,
|
|
141
139
|
allowedIps: opts.allowedIps,
|
|
@@ -150,9 +148,8 @@ loginCmd
|
|
|
150
148
|
.option("--key-name <name>", "API key name (default: SIWE-<date>)")
|
|
151
149
|
.option("--read-write", "Disable read-only mode (allow transactions)")
|
|
152
150
|
.option("--no-wallet-api", "Disable Wallet API (enabled by default)")
|
|
153
|
-
.option("--agent-api", "Enable Agent API (AI prompts)")
|
|
154
151
|
.option("--no-token-launch", "Disable Token Launch API (enabled by default)")
|
|
155
|
-
.option("--allowed-ips <ips>", "Comma-separated IP allowlist
|
|
152
|
+
.option("--allowed-ips <ips>", "Comma-separated IP/CIDR allowlist, e.g. 1.2.3.4,10.0.0.0/24")
|
|
156
153
|
.option("--allowed-recipients <addresses>", "Comma-separated EVM/Solana addresses (agent will only send funds to these)")
|
|
157
154
|
.action(async (opts, cmd) => {
|
|
158
155
|
const parentOpts = cmd.parent.opts();
|
|
@@ -164,7 +161,6 @@ loginCmd
|
|
|
164
161
|
keyName: opts.keyName,
|
|
165
162
|
readWrite: opts.readWrite,
|
|
166
163
|
walletApi: opts.walletApi,
|
|
167
|
-
agentApi: opts.agentApi,
|
|
168
164
|
tokenLaunch: opts.tokenLaunch,
|
|
169
165
|
allowedIps: opts.allowedIps,
|
|
170
166
|
allowedRecipients: opts.allowedRecipients,
|
|
@@ -274,7 +270,9 @@ const agentCmd = program
|
|
|
274
270
|
.description("AI agent commands (prompt, status, cancel, profile, skills)")
|
|
275
271
|
.option("--thread <id>", "Continue a specific conversation thread")
|
|
276
272
|
.option("-c, --continue", "Continue the most recent thread")
|
|
277
|
-
.
|
|
273
|
+
.option("-m, --model <model>", "Use Max Mode with a specific model (e.g. claude-opus-4.6)")
|
|
274
|
+
.action(async (text, opts, cmd) => {
|
|
275
|
+
opts.model ?? (opts.model = cmd.parent?.opts()?.model);
|
|
278
276
|
const joined = text.join(" ").trim();
|
|
279
277
|
if (!joined) {
|
|
280
278
|
agentCmd.help();
|
|
@@ -287,7 +285,11 @@ agentCmd
|
|
|
287
285
|
.description("Send a prompt to the Bankr AI agent")
|
|
288
286
|
.option("--thread <id>", "Continue a specific conversation thread")
|
|
289
287
|
.option("-c, --continue", "Continue the most recent thread")
|
|
290
|
-
.
|
|
288
|
+
.option("-m, --model <model>", "Use Max Mode with a specific model (e.g. claude-opus-4.6)")
|
|
289
|
+
.action(async (text, opts, cmd) => {
|
|
290
|
+
// Commander hoists --model to the parent when both define it;
|
|
291
|
+
// fall back to parent/grandparent opts so `bankr agent prompt --model` works.
|
|
292
|
+
opts.model ?? (opts.model = cmd.parent?.opts()?.model ?? cmd.parent?.parent?.opts()?.model);
|
|
291
293
|
const joined = text.join(" ").trim();
|
|
292
294
|
await promptCommand(joined || (await readPromptInput()), opts);
|
|
293
295
|
});
|
|
@@ -562,14 +564,19 @@ program
|
|
|
562
564
|
.command("logout")
|
|
563
565
|
.description("Clear stored credentials")
|
|
564
566
|
.action(logoutCommand);
|
|
565
|
-
// ── Deprecated aliases (
|
|
567
|
+
// ── Deprecated aliases (hidden from help, show runtime warning) ──────
|
|
568
|
+
function deprecatedCmd(oldCmd, newCmd) {
|
|
569
|
+
output.warn(`"bankr ${oldCmd}" is deprecated and will be removed in a future release. Use "bankr ${newCmd}" instead.`);
|
|
570
|
+
console.log();
|
|
571
|
+
}
|
|
566
572
|
program
|
|
567
|
-
.command("balances")
|
|
573
|
+
.command("balances", { hidden: true })
|
|
568
574
|
.description("Deprecated: use `bankr wallet portfolio` instead")
|
|
569
575
|
.option("--chain <chains>", "Chain(s) to fetch (comma-separated)")
|
|
570
576
|
.option("--json", "Output raw JSON")
|
|
571
577
|
.option("--low-value", "Include low-value tokens (under $1)")
|
|
572
578
|
.action(async (opts) => {
|
|
579
|
+
deprecatedCmd("balances", "wallet portfolio");
|
|
573
580
|
await balancesCommand({
|
|
574
581
|
chain: opts.chain,
|
|
575
582
|
json: opts.json,
|
|
@@ -577,27 +584,37 @@ program
|
|
|
577
584
|
});
|
|
578
585
|
});
|
|
579
586
|
program
|
|
580
|
-
.command("prompt [text...]")
|
|
587
|
+
.command("prompt [text...]", { hidden: true })
|
|
581
588
|
.description("Deprecated: use `bankr agent <prompt>` instead")
|
|
582
589
|
.option("--thread <id>")
|
|
583
590
|
.option("-c, --continue")
|
|
584
|
-
.
|
|
591
|
+
.option("-m, --model <model>")
|
|
592
|
+
.action(async (text, opts, cmd) => {
|
|
593
|
+
deprecatedCmd("prompt", "agent <prompt>");
|
|
594
|
+
opts.model ?? (opts.model = cmd.parent?.opts()?.model);
|
|
585
595
|
const joined = text.join(" ").trim();
|
|
586
596
|
await promptCommand(joined || (await readPromptInput()), opts);
|
|
587
597
|
});
|
|
588
598
|
program
|
|
589
|
-
.command("status <jobId>")
|
|
599
|
+
.command("status <jobId>", { hidden: true })
|
|
590
600
|
.description("Deprecated: use `bankr agent status` instead")
|
|
591
|
-
.action(
|
|
601
|
+
.action(async (jobId) => {
|
|
602
|
+
deprecatedCmd("status", "agent status");
|
|
603
|
+
await statusCommand(jobId);
|
|
604
|
+
});
|
|
592
605
|
program
|
|
593
|
-
.command("cancel <jobId>")
|
|
606
|
+
.command("cancel <jobId>", { hidden: true })
|
|
594
607
|
.description("Deprecated: use `bankr agent cancel` instead")
|
|
595
|
-
.action(
|
|
608
|
+
.action(async (jobId) => {
|
|
609
|
+
deprecatedCmd("cancel", "agent cancel");
|
|
610
|
+
await cancelCommand(jobId);
|
|
611
|
+
});
|
|
596
612
|
const profileAliasCmd = program
|
|
597
|
-
.command("profile")
|
|
613
|
+
.command("profile", { hidden: true })
|
|
598
614
|
.description("Deprecated: use `bankr agent profile` instead")
|
|
599
615
|
.option("--json", "Output raw JSON")
|
|
600
616
|
.action(async (opts) => {
|
|
617
|
+
deprecatedCmd("profile", "agent profile");
|
|
601
618
|
await profileViewCommand({ json: opts.json });
|
|
602
619
|
});
|
|
603
620
|
profileAliasCmd
|
|
@@ -609,6 +626,7 @@ profileAliasCmd
|
|
|
609
626
|
.option("--website <url>", "Project website URL")
|
|
610
627
|
.option("--json", "Output raw JSON")
|
|
611
628
|
.action(async (opts) => {
|
|
629
|
+
deprecatedCmd("profile create", "agent profile create");
|
|
612
630
|
await profileCreateCommand({
|
|
613
631
|
name: opts.name,
|
|
614
632
|
description: opts.description,
|
|
@@ -627,6 +645,7 @@ profileAliasCmd
|
|
|
627
645
|
.option("--website <url>", "Project website URL")
|
|
628
646
|
.option("--json", "Output raw JSON")
|
|
629
647
|
.action(async (opts) => {
|
|
648
|
+
deprecatedCmd("profile update", "agent profile update");
|
|
630
649
|
await profileUpdateCommand({
|
|
631
650
|
name: opts.name,
|
|
632
651
|
description: opts.description,
|
|
@@ -636,13 +655,17 @@ profileAliasCmd
|
|
|
636
655
|
json: opts.json,
|
|
637
656
|
});
|
|
638
657
|
});
|
|
639
|
-
profileAliasCmd.command("delete").action(
|
|
658
|
+
profileAliasCmd.command("delete").action(async () => {
|
|
659
|
+
deprecatedCmd("profile delete", "agent profile delete");
|
|
660
|
+
await profileDeleteCommand();
|
|
661
|
+
});
|
|
640
662
|
profileAliasCmd
|
|
641
663
|
.command("add-update")
|
|
642
664
|
.option("--title <title>", "Update title")
|
|
643
665
|
.option("--content <text>", "Update content")
|
|
644
666
|
.option("--json", "Output raw JSON")
|
|
645
667
|
.action(async (opts) => {
|
|
668
|
+
deprecatedCmd("profile add-update", "agent profile add-update");
|
|
646
669
|
await profileAddUpdateCommand({
|
|
647
670
|
title: opts.title,
|
|
648
671
|
content: opts.content,
|
|
@@ -650,13 +673,14 @@ profileAliasCmd
|
|
|
650
673
|
});
|
|
651
674
|
});
|
|
652
675
|
program
|
|
653
|
-
.command("sign")
|
|
676
|
+
.command("sign", { hidden: true })
|
|
654
677
|
.description("Deprecated: use `bankr wallet sign` instead")
|
|
655
678
|
.requiredOption("-t, --type <type>", "Signature type")
|
|
656
679
|
.option("-m, --message <message>", "Message to sign")
|
|
657
680
|
.option("--typed-data <json>", "EIP-712 typed data as JSON")
|
|
658
681
|
.option("--transaction <json>", "Transaction as JSON")
|
|
659
682
|
.action(async (opts) => {
|
|
683
|
+
deprecatedCmd("sign", "wallet sign");
|
|
660
684
|
await signCommand({
|
|
661
685
|
type: opts.type,
|
|
662
686
|
message: opts.message,
|
|
@@ -665,7 +689,7 @@ program
|
|
|
665
689
|
});
|
|
666
690
|
});
|
|
667
691
|
const submitAliasCmd = program
|
|
668
|
-
.command("submit")
|
|
692
|
+
.command("submit", { hidden: true })
|
|
669
693
|
.description("Deprecated: use `bankr wallet submit` instead");
|
|
670
694
|
submitAliasCmd
|
|
671
695
|
.command("tx")
|
|
@@ -682,6 +706,7 @@ submitAliasCmd
|
|
|
682
706
|
.option("-d, --description <text>", "Description")
|
|
683
707
|
.option("--no-wait", "Don't wait for confirmation")
|
|
684
708
|
.action(async (opts) => {
|
|
709
|
+
deprecatedCmd("submit tx", "wallet submit tx");
|
|
685
710
|
await submitCommand({
|
|
686
711
|
to: opts.to,
|
|
687
712
|
chainId: opts.chainId,
|
|
@@ -702,6 +727,7 @@ submitAliasCmd
|
|
|
702
727
|
.option("-d, --description <text>", "Description")
|
|
703
728
|
.option("--no-wait", "Don't wait for confirmation")
|
|
704
729
|
.action(async (transaction, opts) => {
|
|
730
|
+
deprecatedCmd("submit json", "wallet submit json");
|
|
705
731
|
await submitJsonCommand(transaction, {
|
|
706
732
|
noWait: !opts.wait,
|
|
707
733
|
description: opts.description,
|
|
@@ -794,6 +820,7 @@ program
|
|
|
794
820
|
.arguments("[text...]")
|
|
795
821
|
.option("--thread <id>", "Continue a specific conversation thread")
|
|
796
822
|
.option("-c, --continue", "Continue the most recent thread")
|
|
823
|
+
.option("-m, --model <model>", "Use Max Mode with a specific model (e.g. claude-opus-4.6)")
|
|
797
824
|
.action(async (text, opts) => {
|
|
798
825
|
if (text.length === 0) {
|
|
799
826
|
program.help();
|
package/dist/commands/llm.js
CHANGED
|
@@ -484,7 +484,9 @@ export async function creditsAddCommand(amount, opts) {
|
|
|
484
484
|
});
|
|
485
485
|
spin.stop();
|
|
486
486
|
if (res.status === 402) {
|
|
487
|
-
|
|
487
|
+
const errBody = (await res.json().catch(() => ({})));
|
|
488
|
+
output.error(errBody.error ??
|
|
489
|
+
"Insufficient wallet balance. Add funds to your wallet first.");
|
|
488
490
|
process.exit(1);
|
|
489
491
|
}
|
|
490
492
|
if (res.status === 403) {
|
package/dist/commands/login.d.ts
CHANGED
package/dist/commands/login.js
CHANGED
|
@@ -95,7 +95,7 @@ async function callAcceptTerms(apiUrl, identityToken) {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
async function callGenerateApiKey(apiUrl, identityToken, opts) {
|
|
98
|
-
const res = await fetch(`${apiUrl}/
|
|
98
|
+
const res = await fetch(`${apiUrl}/api-keys`, {
|
|
99
99
|
method: "POST",
|
|
100
100
|
headers: {
|
|
101
101
|
"Content-Type": "application/json",
|
|
@@ -263,14 +263,8 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
263
263
|
// Fine-grained API flags. walletApi and tokenLaunch default to enabled.
|
|
264
264
|
// --read-write only controls readOnly, not which APIs are enabled.
|
|
265
265
|
const enableWallet = opts.walletApi ?? true;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
? false
|
|
269
|
-
: await confirm({
|
|
270
|
-
message: "Enable Agent API? (AI prompts)",
|
|
271
|
-
default: false,
|
|
272
|
-
theme: output.bankrTheme,
|
|
273
|
-
}));
|
|
266
|
+
// Agent API must be enabled from the website (bankr.bot/api), not the CLI.
|
|
267
|
+
const enableAgent = false;
|
|
274
268
|
const enableTokenLaunch = opts.tokenLaunch ?? true;
|
|
275
269
|
const enableLlm = opts.llm ??
|
|
276
270
|
(headless
|
|
@@ -280,8 +274,8 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
280
274
|
default: false,
|
|
281
275
|
theme: output.bankrTheme,
|
|
282
276
|
}));
|
|
283
|
-
if (opts.readWrite && !enableWallet
|
|
284
|
-
output.warn("--read-write has no effect when
|
|
277
|
+
if (opts.readWrite && !enableWallet) {
|
|
278
|
+
output.warn("--read-write has no effect when Wallet API is disabled");
|
|
285
279
|
}
|
|
286
280
|
const keySpin = output.spinner("Generating API key...");
|
|
287
281
|
let apiKeyResult;
|
|
@@ -323,6 +317,7 @@ async function emailLoginFlow(apiUrl, opts) {
|
|
|
323
317
|
];
|
|
324
318
|
output.dim(` Recipients: ${parts.join(", ")}`);
|
|
325
319
|
}
|
|
320
|
+
output.dim(" Agent API: enable at bankr.bot/api");
|
|
326
321
|
output.dim(" Manage keys at bankr.bot/api");
|
|
327
322
|
return apiKeyResult.apiKey;
|
|
328
323
|
}
|
|
@@ -374,7 +369,7 @@ async function siweLoginFlow(apiUrl, opts) {
|
|
|
374
369
|
keyName: opts.keyName ?? `SIWE-${new Date().toISOString().slice(0, 10)}`,
|
|
375
370
|
readOnly: opts.readOnly ?? false,
|
|
376
371
|
walletApiEnabled: opts.walletApi ?? true,
|
|
377
|
-
agentApiEnabled:
|
|
372
|
+
agentApiEnabled: false,
|
|
378
373
|
tokenLaunchApiEnabled: opts.tokenLaunch ?? true,
|
|
379
374
|
allowedIps: opts.allowedIps,
|
|
380
375
|
allowedRecipients: opts.allowedRecipients,
|
|
@@ -435,14 +430,31 @@ async function validateApiKey(apiUrl, apiKey) {
|
|
|
435
430
|
}
|
|
436
431
|
}
|
|
437
432
|
// ── Main login command ──────────────────────────────────────────────
|
|
433
|
+
function isValidIpOrCidr(value) {
|
|
434
|
+
const slashIdx = value.indexOf("/");
|
|
435
|
+
if (slashIdx === -1)
|
|
436
|
+
return isIP(value) !== 0;
|
|
437
|
+
const ip = value.slice(0, slashIdx);
|
|
438
|
+
const prefix = Number(value.slice(slashIdx + 1));
|
|
439
|
+
if (!Number.isInteger(prefix) || prefix < 0)
|
|
440
|
+
return false;
|
|
441
|
+
const version = isIP(ip);
|
|
442
|
+
if (version === 0)
|
|
443
|
+
return false;
|
|
444
|
+
// ::ffff: mapped IPv4 addresses normalize to IPv4 at runtime,
|
|
445
|
+
// so validate prefix against IPv4 max (32) not IPv6 max (128)
|
|
446
|
+
const isV4Mapped = version === 6 && ip.toLowerCase().startsWith("::ffff:");
|
|
447
|
+
const maxPrefix = isV4Mapped ? 32 : version === 4 ? 32 : 128;
|
|
448
|
+
return prefix <= maxPrefix;
|
|
449
|
+
}
|
|
438
450
|
function parseAndValidateIps(raw) {
|
|
439
451
|
const ips = raw
|
|
440
452
|
.split(",")
|
|
441
453
|
.map((s) => s.trim())
|
|
442
454
|
.filter(Boolean);
|
|
443
|
-
const invalid = ips.filter((ip) =>
|
|
455
|
+
const invalid = ips.filter((ip) => !isValidIpOrCidr(ip));
|
|
444
456
|
if (invalid.length > 0) {
|
|
445
|
-
fatal(`Invalid IP address(es): ${invalid.join(", ")}`);
|
|
457
|
+
fatal(`Invalid IP address(es) or CIDR range(s): ${invalid.join(", ")}`);
|
|
446
458
|
}
|
|
447
459
|
return ips;
|
|
448
460
|
}
|
|
@@ -547,7 +559,6 @@ export async function loginCommand(opts) {
|
|
|
547
559
|
keyName: opts.keyName,
|
|
548
560
|
readOnly: !opts.readWrite,
|
|
549
561
|
walletApi: opts.walletApi,
|
|
550
|
-
agentApi: opts.agentApi,
|
|
551
562
|
tokenLaunch: opts.tokenLaunch,
|
|
552
563
|
...getParsedRestrictions(),
|
|
553
564
|
});
|
package/dist/commands/prompt.js
CHANGED
|
@@ -1,7 +1,39 @@
|
|
|
1
|
-
import { pollJob, submitPrompt } from "../lib/api.js";
|
|
1
|
+
import { ApiError, pollJob, submitPrompt } from "../lib/api.js";
|
|
2
2
|
import { emitCESP } from "../lib/cesp/engine.js";
|
|
3
3
|
import { getLastThreadId, requireApiKey, setLastThreadId, } from "../lib/config.js";
|
|
4
4
|
import * as output from "../lib/output.js";
|
|
5
|
+
/** Valid Max Mode model IDs — hardcoded because CLI is standalone (no monorepo imports).
|
|
6
|
+
* Must be manually kept in sync with models in the LLM gateway DB. */
|
|
7
|
+
const VALID_MAX_MODE_MODELS = new Set([
|
|
8
|
+
// Claude (Vertex AI)
|
|
9
|
+
"claude-opus-4.6",
|
|
10
|
+
"claude-opus-4.5",
|
|
11
|
+
"claude-sonnet-4.6",
|
|
12
|
+
"claude-sonnet-4.5",
|
|
13
|
+
"claude-haiku-4.5",
|
|
14
|
+
// Gemini (Vertex AI)
|
|
15
|
+
"gemini-3.1-pro",
|
|
16
|
+
"gemini-3-pro",
|
|
17
|
+
"gemini-2.5-pro",
|
|
18
|
+
// OpenAI (OpenRouter)
|
|
19
|
+
"gpt-5.4",
|
|
20
|
+
"gpt-5.4-mini",
|
|
21
|
+
"gpt-5.2",
|
|
22
|
+
"gpt-5-mini",
|
|
23
|
+
// Grok (OpenRouter)
|
|
24
|
+
"grok-4.1-fast",
|
|
25
|
+
// DeepSeek (OpenRouter)
|
|
26
|
+
"deepseek-v3.2",
|
|
27
|
+
// Qwen (OpenRouter)
|
|
28
|
+
"qwen3-coder",
|
|
29
|
+
"qwen3.5-plus",
|
|
30
|
+
// MiniMax (direct)
|
|
31
|
+
"minimax-m2.5",
|
|
32
|
+
"minimax-m2.7",
|
|
33
|
+
// Other (OpenRouter)
|
|
34
|
+
"kimi-k2.5",
|
|
35
|
+
"glm-5",
|
|
36
|
+
]);
|
|
5
37
|
export async function promptCommand(text, options = {}) {
|
|
6
38
|
requireApiKey();
|
|
7
39
|
// Resolve thread ID from flags
|
|
@@ -16,11 +48,20 @@ export async function promptCommand(text, options = {}) {
|
|
|
16
48
|
else if (options.thread) {
|
|
17
49
|
threadId = options.thread;
|
|
18
50
|
}
|
|
51
|
+
// Resolve Max Mode from --model flag
|
|
52
|
+
let maxMode;
|
|
53
|
+
if (options.model) {
|
|
54
|
+
if (!VALID_MAX_MODE_MODELS.has(options.model)) {
|
|
55
|
+
output.error(`Invalid model "${options.model}". Valid models: ${[...VALID_MAX_MODE_MODELS].join(", ")}`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
maxMode = { enabled: true, model: options.model };
|
|
59
|
+
}
|
|
19
60
|
let spin = output.spinner("Submitting prompt...");
|
|
20
61
|
let jobId;
|
|
21
62
|
let resolvedThreadId;
|
|
22
63
|
try {
|
|
23
|
-
const res = await submitPrompt(text, threadId);
|
|
64
|
+
const res = await submitPrompt(text, threadId, maxMode);
|
|
24
65
|
jobId = res.jobId;
|
|
25
66
|
resolvedThreadId = res.threadId;
|
|
26
67
|
spin.succeed("Prompt submitted");
|
|
@@ -34,7 +75,19 @@ export async function promptCommand(text, options = {}) {
|
|
|
34
75
|
}
|
|
35
76
|
catch (err) {
|
|
36
77
|
spin.fail("Failed to submit prompt");
|
|
37
|
-
|
|
78
|
+
if (err instanceof ApiError && err.body.remediation?.length) {
|
|
79
|
+
output.error(err.body.message);
|
|
80
|
+
if (process.stdout.isTTY) {
|
|
81
|
+
output.remediation(err.body.remediation);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
// Machine-readable JSON for AI agents / piped usage
|
|
85
|
+
console.log(JSON.stringify(err.body));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
output.error(err.message);
|
|
90
|
+
}
|
|
38
91
|
process.exit(1);
|
|
39
92
|
}
|
|
40
93
|
try {
|
package/dist/commands/x402.js
CHANGED
|
@@ -296,6 +296,18 @@ export async function x402ConfigureCommand(name) {
|
|
|
296
296
|
default: existing.methods?.[0] ?? "GET",
|
|
297
297
|
theme: output.bankrTheme,
|
|
298
298
|
});
|
|
299
|
+
const paymentScheme = await select({
|
|
300
|
+
message: "Payment scheme:",
|
|
301
|
+
choices: [
|
|
302
|
+
{ name: "exact — client pays exactly the listed price", value: "exact" },
|
|
303
|
+
{
|
|
304
|
+
name: "upto — client authorizes a max; server settles actual cost",
|
|
305
|
+
value: "upto",
|
|
306
|
+
},
|
|
307
|
+
],
|
|
308
|
+
default: existing.paymentScheme ?? "exact",
|
|
309
|
+
theme: output.bankrTheme,
|
|
310
|
+
});
|
|
299
311
|
config.services[name] = {
|
|
300
312
|
...existing,
|
|
301
313
|
description,
|
|
@@ -303,6 +315,7 @@ export async function x402ConfigureCommand(name) {
|
|
|
303
315
|
currency,
|
|
304
316
|
network,
|
|
305
317
|
methods: method === "*" ? undefined : [method],
|
|
318
|
+
paymentScheme,
|
|
306
319
|
};
|
|
307
320
|
saveConfigFile(root, config);
|
|
308
321
|
output.success(`Updated config for "${name}"`);
|
package/dist/lib/api.d.ts
CHANGED
|
@@ -43,7 +43,25 @@ export interface JobStatusResponse {
|
|
|
43
43
|
richData?: unknown[];
|
|
44
44
|
cancellable?: boolean;
|
|
45
45
|
}
|
|
46
|
-
export
|
|
46
|
+
export interface ApiErrorBody {
|
|
47
|
+
error: string;
|
|
48
|
+
message: string;
|
|
49
|
+
remediation?: Array<{
|
|
50
|
+
action: string;
|
|
51
|
+
label: string;
|
|
52
|
+
url?: string;
|
|
53
|
+
command?: string;
|
|
54
|
+
}>;
|
|
55
|
+
}
|
|
56
|
+
export declare class ApiError extends Error {
|
|
57
|
+
status: number;
|
|
58
|
+
body: ApiErrorBody;
|
|
59
|
+
constructor(status: number, body: ApiErrorBody);
|
|
60
|
+
}
|
|
61
|
+
export declare function submitPrompt(prompt: string, threadId?: string, maxMode?: {
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
model: string;
|
|
64
|
+
}): Promise<PromptResponse>;
|
|
47
65
|
export declare function getJobStatus(jobId: string): Promise<JobStatusResponse>;
|
|
48
66
|
export declare function cancelJob(jobId: string): Promise<JobStatusResponse>;
|
|
49
67
|
export declare function validateApiKey(): Promise<boolean>;
|
package/dist/lib/api.js
CHANGED
|
@@ -29,13 +29,32 @@ async function handleResponse(res) {
|
|
|
29
29
|
}
|
|
30
30
|
return res.json();
|
|
31
31
|
}
|
|
32
|
-
export
|
|
32
|
+
export class ApiError extends Error {
|
|
33
|
+
constructor(status, body) {
|
|
34
|
+
super(body.message);
|
|
35
|
+
this.name = "ApiError";
|
|
36
|
+
this.status = status;
|
|
37
|
+
this.body = body;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export async function submitPrompt(prompt, threadId, maxMode) {
|
|
33
41
|
const res = await fetch(`${getApiUrl()}/agent/prompt`, {
|
|
34
42
|
method: "POST",
|
|
35
43
|
headers: authHeaders(),
|
|
36
|
-
body: JSON.stringify({
|
|
44
|
+
body: JSON.stringify({
|
|
45
|
+
prompt,
|
|
46
|
+
...(threadId && { threadId }),
|
|
47
|
+
...(maxMode && { maxMode }),
|
|
48
|
+
}),
|
|
37
49
|
});
|
|
38
|
-
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
const body = (await res.json().catch(() => ({
|
|
52
|
+
error: res.statusText,
|
|
53
|
+
message: res.statusText,
|
|
54
|
+
})));
|
|
55
|
+
throw new ApiError(res.status, body);
|
|
56
|
+
}
|
|
57
|
+
return res.json();
|
|
39
58
|
}
|
|
40
59
|
export async function getJobStatus(jobId) {
|
|
41
60
|
const res = await fetch(`${getApiUrl()}/agent/job/${jobId}`, {
|
package/dist/lib/output.d.ts
CHANGED
|
@@ -33,5 +33,16 @@ export declare function maskApiKey(key: string): string;
|
|
|
33
33
|
export declare function formatDuration(ms: number): string;
|
|
34
34
|
export declare function formatUsd(value: string | number): string;
|
|
35
35
|
export declare function formatBalance(value: string | number, decimals?: number): string;
|
|
36
|
+
export interface RemediationStep {
|
|
37
|
+
action: string;
|
|
38
|
+
label: string;
|
|
39
|
+
url?: string;
|
|
40
|
+
command?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Display a structured remediation block with actionable fix steps.
|
|
44
|
+
* Used when the API returns a `remediation` array in error responses.
|
|
45
|
+
*/
|
|
46
|
+
export declare function remediation(steps: RemediationStep[]): void;
|
|
36
47
|
export declare function formatStatus(status: string): string;
|
|
37
48
|
//# sourceMappingURL=output.d.ts.map
|
package/dist/lib/output.js
CHANGED
|
@@ -92,6 +92,19 @@ export function formatBalance(value, decimals = 6) {
|
|
|
92
92
|
maximumFractionDigits: decimals,
|
|
93
93
|
});
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Display a structured remediation block with actionable fix steps.
|
|
97
|
+
* Used when the API returns a `remediation` array in error responses.
|
|
98
|
+
*/
|
|
99
|
+
export function remediation(steps) {
|
|
100
|
+
console.log();
|
|
101
|
+
console.log(` ${brandColorBold("Options:")}`);
|
|
102
|
+
for (const step of steps) {
|
|
103
|
+
const target = step.command ?? step.url ?? "";
|
|
104
|
+
console.log(` ${brandColor("→")} ${step.label.padEnd(40)} ${chalk.dim(target)}`);
|
|
105
|
+
}
|
|
106
|
+
console.log();
|
|
107
|
+
}
|
|
95
108
|
export function formatStatus(status) {
|
|
96
109
|
switch (status) {
|
|
97
110
|
case "completed":
|