@bankr/cli 0.3.13 → 0.3.23

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
@@ -108,26 +108,44 @@ bankr agent cancel job_ABC123DEF456
108
108
  Launch Claude Code / OpenCode routed through the Bankr gateway:
109
109
 
110
110
  ```bash
111
- # Claude Code (auto-translates dotted model IDs to the Anthropic wire format)
112
- bankr llm claude --model claude-opus-4-8
111
+ # Claude Code — `bankr claude` is a top-level alias for `bankr llm claude`
112
+ # (auto-translates dotted model IDs to the Anthropic wire format)
113
+ bankr claude --model claude-opus-5
113
114
 
114
- # Or use dotted form — bankr llm claude rewrites it to claude-opus-4-8
115
- bankr llm claude --model claude-opus-4.8
115
+ # Or use dotted form — bankr claude rewrites it to claude-opus-4-8
116
+ bankr claude --model claude-opus-4.8
117
+
118
+ # The [1m] suffix is optional via the gateway, but MUST be quoted if used
119
+ # (zsh reads [1m] as a glob)
120
+ bankr claude --model "claude-opus-5[1m]"
116
121
 
117
122
  # OpenCode (use the bankr/ prefix with the gateway-canonical dotted form)
118
123
  bankr llm opencode -m bankr/claude-opus-4.8
119
124
  ```
120
125
 
121
- **Claude Code model format**: Claude Code's `--model` flag expects
122
- Anthropic-style dashed IDs (`claude-opus-4-8`, `claude-sonnet-4-6`,
123
- `claude-haiku-4-5`). If you pass the gateway-canonical dotted form
124
- (`claude-opus-4.8`), Claude Code silently falls back to its default —
125
- the flag appears honored but the real request is a different model.
126
+ Because `claude` is a command, it shadows the default prompt fallthrough:
127
+ `bankr claude ...` launches Claude Code rather than prompting the agent. Use
128
+ `bankr agent "..."` to send the agent a prompt starting with that word.
129
+
130
+ **Claude Code model format**: Claude Code's `--model` flag expects Anthropic
131
+ wire IDs, which use dashes rather than dots in the version (`claude-opus-5`,
132
+ `claude-sonnet-5`, `claude-opus-4-8`, `claude-haiku-4-5`). If you pass the
133
+ gateway-canonical dotted form (`claude-opus-4.8`), Claude Code silently falls
134
+ back to its default — the flag appears honored but the real request is a
135
+ different model.
126
136
 
127
- `bankr llm claude` translates dotted → dashed for you. If you use older
137
+ `bankr claude` translates dotted → dashed for you. If you use older
128
138
  versions of the CLI (or invoke `claude` directly via `ANTHROPIC_BASE_URL`),
129
139
  pass the dashed form explicitly.
130
140
 
141
+ **1M context tier**: the gateway strips Claude Code's `[1m]` suffix and enables
142
+ the 1M beta from the model's own context window, so it's **optional here** —
143
+ `claude-opus-5` and `claude-opus-5[1m]` send an identical upstream request. If
144
+ you do use it, **quote it**: in zsh (the macOS default) `[1m]` is a glob
145
+ character class, so an unquoted id aborts with `zsh: no matches found:
146
+ claude-opus-5[1m]` before the CLI ever runs. Bash passes it through literally,
147
+ so the same command can work on one machine and fail on another.
148
+
131
149
  ### Configuration
132
150
 
133
151
  ```bash
package/dist/cli.js CHANGED
@@ -10,6 +10,8 @@ import { skillsCommand } from "./commands/capabilities.js";
10
10
  import { cancelCommand } from "./commands/cancel.js";
11
11
  import { configGetCommand, configSetCommand } from "./commands/config.js";
12
12
  import { setConfigPath } from "./lib/config.js";
13
+ import { getErrorMessage } from "./lib/errors.js";
14
+ import { passthroughArgs } from "./lib/passthrough.js";
13
15
  import { claudeCommand, creditsCommand, creditsAddCommand, creditsAutoCommand, modelsCommand, opencodeCommand, setupClaudeCodeCommand, setupCursorCommand, setupOpenclawCommand, setupOpenCodeCommand, } from "./commands/llm.js";
14
16
  import { feesCommand, feesClaimCommand, feesClaimWalletCommand, } from "./commands/fees.js";
15
17
  import { launchCommand } from "./commands/launch.js";
@@ -346,12 +348,14 @@ program
346
348
  .option("--symbol <symbol>", "Token symbol (default: auto-generated from name)")
347
349
  .option("--image <url>", "Token image URL")
348
350
  .option("--chain <chain>", "Chain to launch on: base, robinhood (default: base)")
351
+ .option("--no-vesting", "Turn off the default 15% creator vesting (sell 100% of supply into the pool)")
349
352
  .optionsGroup("Links")
350
353
  .option("--tweet <url>", "Associated tweet URL")
351
354
  .option("--website <url>", "Project website URL")
352
355
  .optionsGroup("Fees")
353
356
  .option("--fee <recipient>", "Fee recipient (username, ENS, or address)")
354
357
  .option("--fee-type <type>", "Fee recipient type: x, farcaster, ens, wallet (default: x)")
358
+ .option("--quote-only-fees", "Collect all creator fees in the pool's quote token (e.g. WETH) instead of a mix of your token and the quote token")
355
359
  .optionsGroup("")
356
360
  .option("-y, --yes", "Skip confirmation prompt")
357
361
  .option("--simulate", "Simulate the deploy without broadcasting a transaction")
@@ -361,10 +365,12 @@ program
361
365
  symbol: opts.symbol,
362
366
  image: opts.image,
363
367
  chain: opts.chain,
368
+ vesting: opts.vesting,
364
369
  tweet: opts.tweet,
365
370
  website: opts.website,
366
371
  fee: opts.fee,
367
372
  feeType: opts.feeType,
373
+ quoteOnlyFees: opts.quoteOnlyFees,
368
374
  yes: opts.yes,
369
375
  simulate: opts.simulate,
370
376
  });
@@ -471,6 +477,7 @@ llmCmd
471
477
  .command("models")
472
478
  .description("List available models")
473
479
  .option("--private", "Show only models that support private (:private) inference")
480
+ .option("--zdr", "Show only models that support zero data retention (:zdr)")
474
481
  .action(modelsCommand);
475
482
  const llmCreditsCmd = llmCmd
476
483
  .command("credits")
@@ -498,6 +505,7 @@ llmSetupCmd
498
505
  .command("openclaw")
499
506
  .description("OpenClaw config")
500
507
  .option("--install", "Write config to ~/.openclaw/openclaw.json")
508
+ .option("--images", "Also route image generation (gpt-image-2) through the gateway — takes over OpenClaw's 'openai' provider slot")
501
509
  .action(setupOpenclawCommand);
502
510
  llmSetupCmd
503
511
  .command("opencode")
@@ -512,25 +520,38 @@ llmSetupCmd
512
520
  .command("claude")
513
521
  .description("Claude Code config")
514
522
  .action(setupClaudeCodeCommand);
523
+ // `helpOption(false)` forwards `-h`/`--help` to the spawned tool instead of
524
+ // letting commander print ours — on a pure passthrough launcher the user
525
+ // almost always wants the tool's help. Use `bankr llm --help` for ours.
515
526
  llmCmd
516
527
  .command("claude")
517
528
  .description("Run Claude Code via gateway")
518
529
  .allowUnknownOption()
519
530
  .allowExcessArguments()
531
+ .helpOption(false)
520
532
  .action(async () => {
521
- const idx = process.argv.indexOf("claude");
522
- const args = idx >= 0 ? process.argv.slice(idx + 1) : [];
523
- await claudeCommand(args);
533
+ await claudeCommand(passthroughArgs("claude"));
524
534
  });
525
535
  llmCmd
526
536
  .command("opencode")
527
537
  .description("Run OpenCode via gateway")
528
538
  .allowUnknownOption()
529
539
  .allowExcessArguments()
540
+ .helpOption(false)
530
541
  .action(async () => {
531
- const idx = process.argv.indexOf("opencode");
532
- const args = idx >= 0 ? process.argv.slice(idx + 1) : [];
533
- await opencodeCommand(args);
542
+ await opencodeCommand(passthroughArgs("opencode"));
543
+ });
544
+ // Top-level shorthand for the most-used launcher. This shadows the default
545
+ // prompt fallthrough, so `bankr claude ...` launches Claude Code rather than
546
+ // prompting the agent about Claude — ask the agent via `bankr agent "..."`.
547
+ program
548
+ .command("claude")
549
+ .description("Run Claude Code via gateway (alias for `bankr llm claude`)")
550
+ .allowUnknownOption()
551
+ .allowExcessArguments()
552
+ .helpOption(false)
553
+ .action(async () => {
554
+ await claudeCommand(passthroughArgs("claude"));
534
555
  });
535
556
  // Token search and info
536
557
  program.commandsGroup("Tokens");
@@ -1048,7 +1069,7 @@ async function main() {
1048
1069
  console.log();
1049
1070
  process.exit(0);
1050
1071
  }
1051
- output.error(err.message);
1072
+ output.error(getErrorMessage(err));
1052
1073
  process.exit(1);
1053
1074
  }
1054
1075
  await checkForUpdate(pkg.version);
@@ -2,6 +2,7 @@ import chalk from "chalk";
2
2
  import { getBalances, } from "../lib/api.js";
3
3
  import * as output from "../lib/output.js";
4
4
  import { formatUsd, formatBalance } from "../lib/output.js";
5
+ import { getErrorMessage } from "../lib/errors.js";
5
6
  import { CHAIN_LABELS, VALID_CHAINS } from "../lib/chains.js";
6
7
  const BRAND = chalk.hex("#FF613D");
7
8
  const DIM = chalk.dim;
@@ -53,7 +54,7 @@ export async function balancesCommand(opts) {
53
54
  spin.succeed("Balances loaded");
54
55
  }
55
56
  catch (err) {
56
- spin.fail(`Failed to fetch balances: ${err.message}`);
57
+ spin.fail(`Failed to fetch balances: ${getErrorMessage(err)}`);
57
58
  process.exit(1);
58
59
  }
59
60
  // JSON output mode
@@ -1,6 +1,7 @@
1
1
  import { cancelJob } 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";
4
5
  export async function cancelCommand(jobId) {
5
6
  requireApiKey();
6
7
  const spin = output.spinner("Cancelling job...");
@@ -18,7 +19,7 @@ export async function cancelCommand(jobId) {
18
19
  }
19
20
  catch (err) {
20
21
  spin.fail("Failed to cancel job");
21
- output.error(err.message);
22
+ output.error(getErrorMessage(err));
22
23
  process.exit(1);
23
24
  }
24
25
  }
@@ -6,6 +6,7 @@ import { emitCESP } from "../lib/cesp/engine.js";
6
6
  import { requireApiKey } from "../lib/config.js";
7
7
  import { txExplorer } from "../lib/explorer.js";
8
8
  import * as output from "../lib/output.js";
9
+ import { getErrorMessage } from "../lib/errors.js";
9
10
  // ---------------------------------------------------------------------------
10
11
  // Constants
11
12
  // ---------------------------------------------------------------------------
@@ -283,28 +284,33 @@ function renderDashboard(data) {
283
284
  console.log(` ${BRAND_BOLD("\u2550".repeat(62))}`);
284
285
  console.log("");
285
286
  for (const token of data.tokens) {
286
- const wethIsToken0 = token.token0Label === "WETH";
287
- const claimableWeth = wethIsToken0
288
- ? token.claimable.token0
289
- : token.claimable.token1;
290
- const claimableToken = wethIsToken0
287
+ // Numeraire leg = the side whose label differs from the launched token's
288
+ // symbol \u2014 stock-paired launches label it with the stock ticker, not WETH.
289
+ const tokenIsToken0 = token.token0Label === token.symbol;
290
+ const numeraireLabel = tokenIsToken0
291
+ ? token.token1Label
292
+ : token.token0Label;
293
+ const claimableNumeraire = tokenIsToken0
291
294
  ? token.claimable.token1
292
295
  : token.claimable.token0;
293
- const claimedWeth = wethIsToken0
294
- ? token.claimed.token0
295
- : token.claimed.token1;
296
- const claimedToken = wethIsToken0
296
+ const claimableToken = tokenIsToken0
297
+ ? token.claimable.token0
298
+ : token.claimable.token1;
299
+ const claimedNumeraire = tokenIsToken0
297
300
  ? token.claimed.token1
298
301
  : token.claimed.token0;
299
- const tokenSymbol = wethIsToken0 ? token.token1Label : token.token0Label;
302
+ const claimedToken = tokenIsToken0
303
+ ? token.claimed.token0
304
+ : token.claimed.token1;
305
+ const tokenSymbol = tokenIsToken0 ? token.token0Label : token.token1Label;
300
306
  const sourceLabel = token.source === "clanker" ? DIM(" [Clanker]") : DIM(" [Doppler]");
301
307
  console.log(` ${BOLD(WHITE(token.name))} ${DIM("($" + token.symbol + ")")}${sourceLabel}`);
302
308
  const shareInfo = token.source === "clanker"
303
309
  ? `${DIM("Creator")} ${DIM("\u00b7 Token:")} ${DIM(token.tokenAddress)}`
304
310
  : `${DIM("Share:")} ${token.share} ${DIM("\u00b7 Token:")} ${DIM(token.tokenAddress)}`;
305
311
  console.log(` ${shareInfo}`);
306
- console.log(` ${DIM("Claimable:")} ${BRIGHT_GREEN(claimableWeth.padStart(12))} WETH ${DIM("|")} ${BRIGHT_GREEN(claimableToken.padStart(18))} ${tokenSymbol}`);
307
- console.log(` ${DIM("Claimed:")} ${WHITE(claimedWeth.padStart(12))} WETH ${DIM("|")} ${WHITE(claimedToken.padStart(18))} ${tokenSymbol} ${DIM(`(${token.claimed.count} claims)`)}`);
312
+ console.log(` ${DIM("Claimable:")} ${BRIGHT_GREEN(claimableNumeraire.padStart(12))} ${numeraireLabel} ${DIM("|")} ${BRIGHT_GREEN(claimableToken.padStart(18))} ${tokenSymbol}`);
313
+ console.log(` ${DIM("Claimed:")} ${WHITE(claimedNumeraire.padStart(12))} ${numeraireLabel} ${DIM("|")} ${WHITE(claimedToken.padStart(18))} ${tokenSymbol} ${DIM(`(${token.claimed.count} claims)`)}`);
308
314
  console.log("");
309
315
  }
310
316
  console.log(` ${BRAND_BOLD("\u2550".repeat(62))}`);
@@ -343,7 +349,7 @@ export async function feesCommand(address, opts) {
343
349
  catch (err) {
344
350
  spin.fail("Failed to fetch token fee data");
345
351
  emitCESP("task.error");
346
- output.error(err.message);
352
+ output.error(getErrorMessage(err));
347
353
  process.exit(1);
348
354
  }
349
355
  return;
@@ -365,7 +371,7 @@ export async function feesCommand(address, opts) {
365
371
  }
366
372
  catch (err) {
367
373
  spin.fail("Failed to fetch wallet info");
368
- output.error(err.message);
374
+ output.error(getErrorMessage(err));
369
375
  process.exit(1);
370
376
  }
371
377
  }
@@ -384,7 +390,7 @@ export async function feesCommand(address, opts) {
384
390
  catch (err) {
385
391
  spin.fail("Failed to fetch fee data");
386
392
  emitCESP("task.error");
387
- output.error(err.message);
393
+ output.error(getErrorMessage(err));
388
394
  process.exit(1);
389
395
  }
390
396
  }
@@ -445,7 +451,7 @@ export async function feesClaimCommand(tokenAddress, opts) {
445
451
  catch (err) {
446
452
  spin.fail("Claim submission failed");
447
453
  emitCESP("task.error");
448
- output.error(err.message);
454
+ output.error(getErrorMessage(err));
449
455
  process.exit(1);
450
456
  }
451
457
  }
@@ -550,42 +556,64 @@ export async function feesClaimWalletCommand(address, opts) {
550
556
  const result = await getBeneficiaryFeesStreaming(address, (progress) => {
551
557
  fetchSpin.text = `Scanning pools... ${progress.scanned}/${progress.total} (${progress.found ?? 0} with claimable fees)`;
552
558
  });
553
- fetchSpin.succeed(`Scanned ${result.totalLaunches} launches — ${result.poolsWithShares} pools with shares, ${result.tokens.length} with claimable fees`);
559
+ // A time-budget stop leaves `scanned` below `totalLaunches`; report the
560
+ // number actually scanned so this line can't contradict the warning below.
561
+ const scanned = result.scanned ?? result.totalLaunches;
562
+ fetchSpin.succeed(`Scanned ${scanned} launches — ${result.poolsWithShares} pools with shares, ${result.tokens.length} with claimable fees`);
563
+ if (result.truncated) {
564
+ output.warn(`Scan stopped early at ${scanned} launches — this wallet has more than the server scans in one request. Claimable fees beyond that are not listed.`);
565
+ }
554
566
  allTokens = result.tokens;
555
567
  }
556
568
  catch (err) {
557
569
  fetchSpin.fail("Failed to fetch fee data");
558
- output.error(err.message);
570
+ output.error(getErrorMessage(err));
559
571
  process.exit(1);
560
572
  }
561
573
  // Step 5: Filter to tokens with claimable fees (API already filters, but
562
574
  // double-check for any rounding edge cases)
563
575
  const parseAmount = (s) => parseFloat(s.replace(/^[<>]/, "")) || 0;
576
+ // Numeraire leg = the side whose label differs from the launched token's
577
+ // symbol — stock-paired launches label it with the stock ticker, not WETH.
578
+ const numeraireLegOf = (token) => {
579
+ const tokenIsToken0 = token.token0Label === token.symbol;
580
+ return {
581
+ label: tokenIsToken0 ? token.token1Label : token.token0Label,
582
+ claimable: tokenIsToken0
583
+ ? token.claimable.token1
584
+ : token.claimable.token0,
585
+ tokenClaimable: tokenIsToken0
586
+ ? token.claimable.token0
587
+ : token.claimable.token1,
588
+ };
589
+ };
564
590
  const claimableTokens = allTokens.filter((token) => {
565
- const wethIsToken0 = token.token0Label === "WETH";
566
- const claimableWeth = wethIsToken0
567
- ? token.claimable.token0
568
- : token.claimable.token1;
569
- const claimableToken = wethIsToken0
570
- ? token.claimable.token1
571
- : token.claimable.token0;
572
- return parseAmount(claimableWeth) > 0 || parseAmount(claimableToken) > 0;
591
+ const leg = numeraireLegOf(token);
592
+ return (parseAmount(leg.claimable) > 0 || parseAmount(leg.tokenClaimable) > 0);
573
593
  });
574
594
  if (claimableTokens.length === 0) {
575
595
  console.log();
576
596
  output.dim("No claimable fees found for this wallet.");
577
597
  return;
578
598
  }
579
- // Show total claimable WETH
599
+ // Show total claimable WETH — WETH legs only; stock-paired numeraires are a
600
+ // different unit and get their own per-ticker lines.
580
601
  const totalWeth = claimableTokens.reduce((sum, token) => {
581
- const wethIsToken0 = token.token0Label === "WETH";
582
- const wethStr = wethIsToken0
583
- ? token.claimable.token0
584
- : token.claimable.token1;
585
- return sum + parseAmount(wethStr);
602
+ const leg = numeraireLegOf(token);
603
+ return leg.label === "WETH" ? sum + parseAmount(leg.claimable) : sum;
586
604
  }, 0);
605
+ const nonWethTotals = new Map();
606
+ for (const token of claimableTokens) {
607
+ const leg = numeraireLegOf(token);
608
+ if (leg.label !== "WETH" && parseAmount(leg.claimable) > 0) {
609
+ nonWethTotals.set(leg.label, (nonWethTotals.get(leg.label) ?? 0) + parseAmount(leg.claimable));
610
+ }
611
+ }
587
612
  console.log();
588
613
  output.keyValue("Total claimable", `${totalWeth.toFixed(6)} WETH across ${claimableTokens.length} token${claimableTokens.length !== 1 ? "s" : ""}`);
614
+ for (const [label, amount] of nonWethTotals) {
615
+ output.keyValue("", `${amount.toFixed(6)} ${label} (stock-paired)`);
616
+ }
589
617
  // Step 6: Select tokens
590
618
  let selectedTokens;
591
619
  if (opts.all) {
@@ -593,12 +621,9 @@ export async function feesClaimWalletCommand(address, opts) {
593
621
  }
594
622
  else {
595
623
  const choices = claimableTokens.map((token) => {
596
- const wethIsToken0 = token.token0Label === "WETH";
597
- const claimableWeth = wethIsToken0
598
- ? token.claimable.token0
599
- : token.claimable.token1;
624
+ const leg = numeraireLegOf(token);
600
625
  return {
601
- name: `${token.name} ($${token.symbol}) - ${claimableWeth} WETH`,
626
+ name: `${token.name} ($${token.symbol}) - ${leg.claimable} ${leg.label}`,
602
627
  value: token.tokenAddress,
603
628
  checked: true,
604
629
  };
@@ -676,7 +701,7 @@ export async function feesClaimWalletCommand(address, opts) {
676
701
  return (gas * GAS_BUFFER) / 100n;
677
702
  }
678
703
  catch (err) {
679
- output.warn(`${token.symbol}: gas estimate failed — ${err.message}`);
704
+ output.warn(`${token.symbol}: gas estimate failed — ${getErrorMessage(err)}`);
680
705
  return null;
681
706
  }
682
707
  }));
@@ -737,7 +762,7 @@ export async function feesClaimWalletCommand(address, opts) {
737
762
  pendingTxs.push({ token: tx.token, hash });
738
763
  }
739
764
  catch (err) {
740
- sendSpin.fail(`${tx.token.symbol}: Send failed — ${err.message}`);
765
+ sendSpin.fail(`${tx.token.symbol}: Send failed — ${getErrorMessage(err)}`);
741
766
  emitCESP("task.error");
742
767
  failCount++;
743
768
  if (readyTxs.indexOf(tx) < readyTxs.length - 1) {
@@ -767,7 +792,7 @@ export async function feesClaimWalletCommand(address, opts) {
767
792
  token,
768
793
  hash,
769
794
  status: "failed",
770
- error: err.message,
795
+ error: getErrorMessage(err),
771
796
  };
772
797
  }
773
798
  }));
@@ -3,10 +3,14 @@ export interface LaunchOptions {
3
3
  symbol?: string;
4
4
  image?: string;
5
5
  chain?: string;
6
+ /** Commander --no-vesting flag: false = vesting explicitly turned off. */
7
+ vesting?: boolean;
6
8
  tweet?: string;
7
9
  website?: string;
8
10
  fee?: string;
9
11
  feeType?: string;
12
+ /** --quote-only-fees flag: collect all creator fees in the quote token. */
13
+ quoteOnlyFees?: boolean;
10
14
  yes?: boolean;
11
15
  simulate?: boolean;
12
16
  }
@@ -3,6 +3,7 @@ import { deployToken, } from "../lib/api.js";
3
3
  import { emitCESP } from "../lib/cesp/engine.js";
4
4
  import { requireApiKey } from "../lib/config.js";
5
5
  import * as output from "../lib/output.js";
6
+ import { getErrorMessage } from "../lib/errors.js";
6
7
  const VALID_FEE_TYPES = ["x", "farcaster", "ens", "wallet"];
7
8
  const VALID_CHAINS = ["base", "robinhood"];
8
9
  function chainLabel(chain) {
@@ -75,6 +76,34 @@ async function collectInteractive(options) {
75
76
  });
76
77
  }
77
78
  chain ?? (chain = "base");
79
+ // Vesting: --no-vesting wins; otherwise interactive select (default: keep
80
+ // the 15% creator vesting). Non-interactive runs keep vesting on.
81
+ let disableVesting = options.vesting === false;
82
+ if (!disableVesting && !output.isNonInteractive()) {
83
+ disableVesting = await select({
84
+ message: "Creator vesting? By default 15% of supply vests to the fee recipient over 1 year (30-day cliff).",
85
+ choices: [
86
+ { name: "15% vesting (default)", value: false },
87
+ { name: "No vesting — sell 100% into the pool", value: true },
88
+ ],
89
+ default: false,
90
+ theme: output.bankrTheme,
91
+ });
92
+ }
93
+ // Fee collection: --quote-only-fees wins; otherwise interactive select
94
+ // (default: in-kind). Non-interactive runs keep the in-kind default.
95
+ let quoteOnlyFees = options.quoteOnlyFees === true;
96
+ if (!quoteOnlyFees && !output.isNonInteractive()) {
97
+ quoteOnlyFees = await select({
98
+ message: "Fee collection? By default creator fees accrue as a mix of your token and the pool's quote token (e.g. WETH).",
99
+ choices: [
100
+ { name: "Both tokens (default)", value: false },
101
+ { name: "Quote token only", value: true },
102
+ ],
103
+ default: false,
104
+ theme: output.bankrTheme,
105
+ });
106
+ }
78
107
  const tweetUrl = options.tweet ??
79
108
  (await promptOrSkip("Associate with a tweet? Paste URL (press Enter to skip):"));
80
109
  const websiteUrl = options.website ??
@@ -94,9 +123,7 @@ async function collectInteractive(options) {
94
123
  theme: output.bankrTheme,
95
124
  });
96
125
  }
97
- if (!feeRecipient) {
98
- feeRecipient = "";
99
- }
126
+ feeRecipient || (feeRecipient = "");
100
127
  return {
101
128
  tokenName: tokenName.trim(),
102
129
  tokenSymbol: tokenSymbol.trim(),
@@ -106,6 +133,8 @@ async function collectInteractive(options) {
106
133
  websiteUrl: websiteUrl.trim(),
107
134
  feeRecipient: feeRecipient.trim(),
108
135
  feeRecipientType,
136
+ disableVesting,
137
+ quoteOnlyFees,
109
138
  };
110
139
  }
111
140
  export async function launchCommand(options) {
@@ -129,6 +158,12 @@ export async function launchCommand(options) {
129
158
  ? `${state.feeRecipient} (${feeTypeLabel(state.feeRecipientType)})`
130
159
  : "(self)");
131
160
  output.keyValue("Chain", chainLabel(state.chain));
161
+ output.keyValue("Vesting", state.disableVesting
162
+ ? "Off (100% of supply sold into the pool)"
163
+ : "15% to fee recipient over 1 year (default)");
164
+ output.keyValue("Fee collection", state.quoteOnlyFees
165
+ ? "Quote token only (e.g. WETH)"
166
+ : "Both tokens (default)");
132
167
  if (options.simulate) {
133
168
  output.keyValue("Mode", "Simulation (dry run)");
134
169
  }
@@ -161,6 +196,8 @@ export async function launchCommand(options) {
161
196
  ? { type: state.feeRecipientType, value: state.feeRecipient }
162
197
  : undefined,
163
198
  simulateOnly: options.simulate,
199
+ disableVesting: state.disableVesting || undefined,
200
+ quoteOnlyFees: state.quoteOnlyFees || undefined,
164
201
  });
165
202
  const elapsed = output.formatDuration(Date.now() - startTime);
166
203
  spin.succeed(result.simulated
@@ -187,12 +224,12 @@ export async function launchCommand(options) {
187
224
  }
188
225
  }
189
226
  console.log();
190
- output.dim(`View token: https://bankr.bot/launches/${result.tokenAddress}`);
227
+ output.dim(`View token: https://bankr.bot/terminal/trade?out=${result.tokenAddress}&chain=${result.chain}`);
191
228
  }
192
229
  catch (err) {
193
230
  spin.fail("Token launch failed");
194
231
  emitCESP("task.error");
195
- output.error(err.message);
232
+ output.error(getErrorMessage(err));
196
233
  process.exit(1);
197
234
  }
198
235
  }
@@ -1,5 +1,6 @@
1
1
  export declare function modelsCommand(opts?: {
2
2
  private?: boolean;
3
+ zdr?: boolean;
3
4
  }): Promise<void>;
4
5
  export declare function creditsCommand(): Promise<void>;
5
6
  export declare function creditsAddCommand(amount: string, opts: {
@@ -15,6 +16,7 @@ export declare function creditsAutoCommand(opts: {
15
16
  }): Promise<void>;
16
17
  export declare function setupOpenclawCommand(opts: {
17
18
  install?: boolean;
19
+ images?: boolean;
18
20
  }): Promise<void>;
19
21
  export declare function setupOpenCodeCommand(opts: {
20
22
  install?: boolean;