@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 CHANGED
@@ -15,7 +15,7 @@ npm install -g @bankr/cli
15
15
  bankr login
16
16
 
17
17
  # Send a prompt
18
- bankr prompt "what's trending on base?"
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 prompt "swap 10 USDC to ETH on base"
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 prompt --continue "and what about SOL?"
70
- bankr prompt -c "compare them"
69
+ bankr agent --continue "and what about SOL?"
70
+ bankr agent -c "compare them"
71
71
 
72
72
  # Continue a specific thread
73
- bankr prompt --thread thr_ABC123 "tell me more"
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 (requests from other IPs will be blocked)")
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 (requests from other IPs will be blocked)")
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
- .action(async (text, opts) => {
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
- .action(async (text, opts) => {
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 (kept for backward compat) ──────────────────────
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
- .action(async (text, opts) => {
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(statusCommand);
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(cancelCommand);
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(profileDeleteCommand);
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();
@@ -484,7 +484,9 @@ export async function creditsAddCommand(amount, opts) {
484
484
  });
485
485
  spin.stop();
486
486
  if (res.status === 402) {
487
- output.error("Insufficient wallet balance. Add funds to your wallet first.");
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) {
@@ -7,7 +7,6 @@ export declare function loginCommand(opts: {
7
7
  keyName?: string;
8
8
  readWrite?: boolean;
9
9
  walletApi?: boolean;
10
- agentApi?: boolean;
11
10
  tokenLaunch?: boolean;
12
11
  llm?: boolean;
13
12
  llmKey?: string;
@@ -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}/generate-api-key`, {
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
- const enableAgent = opts.agentApi ??
267
- (headless
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 && !enableAgent) {
284
- output.warn("--read-write has no effect when both Wallet API and Agent API are disabled");
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: opts.agentApi ?? false,
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) => isIP(ip) === 0);
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
  });
@@ -1,6 +1,7 @@
1
1
  export interface PromptOptions {
2
2
  thread?: string;
3
3
  continue?: boolean;
4
+ model?: string;
4
5
  }
5
6
  export declare function promptCommand(text: string, options?: PromptOptions): Promise<void>;
6
7
  //# sourceMappingURL=prompt.d.ts.map
@@ -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
- output.error(err.message);
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 {
@@ -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 declare function submitPrompt(prompt: string, threadId?: string): Promise<PromptResponse>;
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 async function submitPrompt(prompt, threadId) {
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({ prompt, ...(threadId && { threadId }) }),
44
+ body: JSON.stringify({
45
+ prompt,
46
+ ...(threadId && { threadId }),
47
+ ...(maxMode && { maxMode }),
48
+ }),
37
49
  });
38
- return handleResponse(res);
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}`, {
@@ -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
@@ -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":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bankr/cli",
3
- "version": "0.2.9",
3
+ "version": "0.2.13",
4
4
  "description": "Official CLI for the Bankr AI agent platform",
5
5
  "type": "module",
6
6
  "bin": {