@zoralabs/cli 0.3.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +17 -16
  2. package/dist/index.js +456 -172
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@ A command-line tool for interacting with the [Zora](https://zora.co) protocol. E
6
6
 
7
7
  ## Install
8
8
 
9
- Requires **Node.js 24+**.
9
+ Requires **Node.js 20+**.
10
10
 
11
11
  ```bash
12
12
  npm install -g @zoralabs/cli
@@ -15,6 +15,9 @@ npm install -g @zoralabs/cli
15
15
  ## Quick start
16
16
 
17
17
  ```bash
18
+ # Guided first-time setup — wallet, API key, and deposit instructions
19
+ zora setup
20
+
18
21
  # Browse trending coins
19
22
  zora explore
20
23
 
@@ -31,41 +34,39 @@ All commands support `--json` for machine-readable output. Commands with live da
31
34
 
32
35
  | Command | Description | Wallet required |
33
36
  | --------------- | --------------------------------------------------------- | --------------- |
37
+ | `setup` | Guided first-time setup (wallet + API key + deposit info) | — |
34
38
  | `explore` | Browse top, new, and highest volume coins | No |
35
39
  | `get` | Look up a coin by address or name | No |
36
40
  | `price-history` | Display price history for a coin | No |
37
41
  | `auth` | Configure or check API key status | No |
38
42
  | `profile` | View creator or user profiles | No |
39
- | `setup` | Set up a wallet (generate or import private key) | — |
40
43
  | `buy` | Buy a coin | Yes |
41
44
  | `sell` | Sell a coin | Yes |
42
45
  | `balance` | Show wallet balances (ETH, USDC, ZORA) and coin positions | Yes |
43
- | `wallet` | Show wallet address, storage location, or export key | Yes |
46
+ | `wallet` | Show wallet address, export key, or configure wallet | Yes |
44
47
  | `send` | Send tokens to another address | Yes |
45
48
 
46
49
  Run `zora --help` or `zora <command> --help` for detailed usage.
47
50
 
48
- ## Wallet setup
51
+ ## Setup
49
52
 
50
- Commands that sign transactions require a wallet. Set one up with:
53
+ `zora setup` walks through three steps: wallet configuration, API key (optional), and deposit instructions. It is re-runnable — existing configuration is detected and can be kept or overwritten.
51
54
 
52
55
  ```bash
53
- zora setup # interactive create or import a key
54
- zora setup --create # generate a new key non-interactively
56
+ zora setup # interactive 3-step flow
57
+ zora setup --create # skip wallet prompt, generate a new key
58
+ zora setup --yes # non-interactive, accept all defaults
59
+ zora setup --force # overwrite existing wallet and API key
55
60
  ```
56
61
 
57
- The private key is stored locally at `~/.config/zora/wallet.json` with restricted permissions. Alternatively, set the `ZORA_PRIVATE_KEY` environment variable.
58
-
59
- ## API key (optional)
62
+ The private key is stored locally at `~/.config/zora/wallet.json` with restricted permissions. `ZORA_PRIVATE_KEY` and `ZORA_API_KEY` environment variables take precedence over saved config files.
60
63
 
61
- Read-only commands work without an API key but may be rate-limited. To get a key, create an account at [zora.co](https://zora.co) and generate one at [zora.co/settings/developer](https://zora.co/settings/developer), then:
64
+ ### Advanced
62
65
 
63
- ```bash
64
- zora auth configure # save the key
65
- zora auth status # check current config
66
- ```
66
+ To configure wallet or API key individually (without running the full setup flow). All commands work without an API key but may be rate-limited:
67
67
 
68
- The `ZORA_API_KEY` environment variable takes precedence over the saved config.
68
+ - `zora wallet configure` create or import a wallet (`--create`, `--force`)
69
+ - `zora auth configure` — save an API key; `zora auth status` — check current config
69
70
 
70
71
  ## Documentation
71
72
 
package/dist/index.js CHANGED
@@ -285,6 +285,10 @@ var passwordOrFail = async (json, opts, nonInteractive) => {
285
285
  }
286
286
  return password(opts);
287
287
  };
288
+ var passwordOrSkip = async (opts, nonInteractive) => {
289
+ if (nonInteractive) return "";
290
+ return password(opts);
291
+ };
288
292
 
289
293
  // src/lib/analytics.ts
290
294
  import { PostHog } from "posthog-node";
@@ -437,7 +441,7 @@ var getClient = () => {
437
441
  return client;
438
442
  };
439
443
  var commonProperties = () => ({
440
- cli_version: true ? "0.3.1" : "development",
444
+ cli_version: true ? "1.0.0" : "development",
441
445
  os: process.platform,
442
446
  arch: process.arch,
443
447
  node_version: process.version
@@ -500,7 +504,9 @@ var shutdownAnalytics = async () => {
500
504
  // src/commands/auth.ts
501
505
  var authCommand = new Command("auth").description(
502
506
  "Manage API key authentication.\nAPI key is optional \u2014 without one, requests are rate-limited.\nGet a key at https://zora.co/settings/developer"
503
- );
507
+ ).action(function() {
508
+ this.outputHelp();
509
+ });
504
510
  authCommand.command("configure").description("Set your Zora API key").option("--yes", "Skip interactive prompt and execute directly").action(async function() {
505
511
  const json = getJson(this);
506
512
  const nonInteractive = getYes(this);
@@ -747,6 +753,13 @@ var formatAmountDisplay = (amount, decimals) => {
747
753
  maximumFractionDigits: 2
748
754
  }).format(Number(formatted));
749
755
  };
756
+ function computeMarketCapChange24h(marketCap, marketCapDelta24h) {
757
+ if (marketCap === null || marketCapDelta24h === null || marketCap - marketCapDelta24h === 0)
758
+ return null;
759
+ return Number(
760
+ (marketCapDelta24h / (marketCap - marketCapDelta24h) * 100).toFixed(4)
761
+ );
762
+ }
750
763
  var truncateAddress = (address) => `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
751
764
 
752
765
  // src/lib/balance-format.ts
@@ -1166,11 +1179,10 @@ var formatBalanceJson = (balance, rank) => {
1166
1179
  const totalVolume = balance.coin?.totalVolume ? Number(balance.coin.totalVolume) : null;
1167
1180
  const priceUsdValue = priceUsd ? Number(priceUsd) : null;
1168
1181
  const usdValue = priceUsdValue !== null ? Number((parseRawBalance(balance.balance) * priceUsdValue).toFixed(6)) : null;
1169
- const marketCapChange24h = marketCap !== null && marketCapDelta24h !== null && marketCap - marketCapDelta24h !== 0 ? Number(
1170
- (marketCapDelta24h / (marketCap - marketCapDelta24h) * 100).toFixed(
1171
- 4
1172
- )
1173
- ) : null;
1182
+ const marketCapChange24h = computeMarketCapChange24h(
1183
+ marketCap,
1184
+ marketCapDelta24h
1185
+ );
1174
1186
  return {
1175
1187
  rank,
1176
1188
  name: balance.coin?.name ?? null,
@@ -1193,13 +1205,9 @@ var formatBalanceJson = (balance, rank) => {
1193
1205
  function resolveContext(json) {
1194
1206
  const account = resolveAccount(json);
1195
1207
  const apiKey = getApiKey();
1196
- if (!apiKey) {
1197
- outputErrorAndExit(
1198
- json,
1199
- "Not authenticated. Run 'zora auth configure' to set your API key."
1200
- );
1208
+ if (apiKey) {
1209
+ setApiKey(apiKey);
1201
1210
  }
1202
- setApiKey(apiKey);
1203
1211
  return account;
1204
1212
  }
1205
1213
  function renderWallet(json, walletResult) {
@@ -1674,7 +1682,9 @@ var printQuote = (json, info) => {
1674
1682
  Buy \x1B[1m${info.coinName}\x1B[0m`);
1675
1683
  console.log(` ${info.coinType} \xB7 ${info.address}
1676
1684
  `);
1677
- console.log(` Amount ${spendFormatted} ${info.inputTokenSymbol}`);
1685
+ console.log(
1686
+ ` Amount ${spendFormatted} ${info.inputTokenSymbol}${info.amountUsd ? ` (${info.amountUsd})` : ""}`
1687
+ );
1678
1688
  console.log(` You get ~${coinsFormatted} ${info.coinSymbol}`);
1679
1689
  console.log(` Slippage ${info.slippagePct}%
1680
1690
  `);
@@ -1708,7 +1718,9 @@ var printTradeResult = (json, info) => {
1708
1718
  Bought \x1B[1m${info.coinName}\x1B[0m`);
1709
1719
  console.log(` ${info.coinType} \xB7 ${info.address}
1710
1720
  `);
1711
- console.log(` Spent ${spentFormatted} ${info.inputTokenSymbol}`);
1721
+ console.log(
1722
+ ` Spent ${spentFormatted} ${info.inputTokenSymbol}${info.amountUsd ? ` (${info.amountUsd})` : ""}`
1723
+ );
1712
1724
  console.log(` Received ${receivedFormatted} ${info.coinSymbol}`);
1713
1725
  console.log(` Tx ${info.txHash}
1714
1726
  `);
@@ -2150,8 +2162,9 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
2150
2162
  amountOut,
2151
2163
  slippagePct
2152
2164
  };
2165
+ const amountUsd = swapAmountUsd != null && inputToken.fixedPriceUsd == null ? `${amountMode === "usd" ? "" : "~"}${formatUsd(swapAmountUsd)}` : void 0;
2153
2166
  if (opts.quote) {
2154
- printQuote(json, quoteInfo);
2167
+ printQuote(json, { ...quoteInfo, amountUsd });
2155
2168
  track("cli_buy", {
2156
2169
  action: "quote",
2157
2170
  coin_address: coinAddress,
@@ -2167,7 +2180,7 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
2167
2180
  return;
2168
2181
  }
2169
2182
  if (!opts.yes) {
2170
- printQuote(false, quoteInfo);
2183
+ printQuote(false, { ...quoteInfo, amountUsd });
2171
2184
  const ok = await confirm2({
2172
2185
  message: "Confirm?",
2173
2186
  default: false
@@ -2226,6 +2239,7 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
2226
2239
  coinSymbol,
2227
2240
  coinType,
2228
2241
  address: coinAddress,
2242
+ amountUsd,
2229
2243
  amountIn,
2230
2244
  inputTokenSymbol: inputToken.symbol,
2231
2245
  inputTokenDecimals: inputToken.decimals,
@@ -2548,6 +2562,47 @@ var ExploreView = ({
2548
2562
 
2549
2563
  // src/commands/explore.tsx
2550
2564
  import { jsx as jsx5 } from "react/jsx-runtime";
2565
+ var formatExploreCoinJson = (node) => {
2566
+ const marketCap = node.marketCap ? Number(node.marketCap) : null;
2567
+ const marketCapDelta24h = node.marketCapDelta24h ? Number(node.marketCapDelta24h) : null;
2568
+ const marketCapChange24h = computeMarketCapChange24h(
2569
+ marketCap,
2570
+ marketCapDelta24h
2571
+ );
2572
+ const priceUsd = node.tokenPrice?.priceInUsdc ? Number(node.tokenPrice.priceInUsdc) : null;
2573
+ const coinType = node.coinType ? COIN_TYPE_DISPLAY[node.coinType] ?? node.coinType : null;
2574
+ const socials = node.creatorProfile?.socialAccounts;
2575
+ const socialAccounts = socials ? {
2576
+ instagram: socials.instagram ?? null,
2577
+ tiktok: socials.tiktok ?? null,
2578
+ twitter: socials.twitter ?? null,
2579
+ farcaster: socials.farcaster ?? null
2580
+ } : null;
2581
+ return {
2582
+ name: node.name ?? null,
2583
+ description: node.description ?? null,
2584
+ symbol: node.symbol ?? null,
2585
+ coinType,
2586
+ chainId: node.chainId ?? null,
2587
+ address: node.address ?? null,
2588
+ platformBlocked: node.platformBlocked ?? false,
2589
+ totalSupply: node.totalSupply ?? null,
2590
+ creatorAddress: node.creatorAddress ?? null,
2591
+ creatorHandle: node.creatorProfile?.handle ?? null,
2592
+ socialAccounts,
2593
+ mediaContentMimeType: node.mediaContent?.mimeType ?? null,
2594
+ mediaContentOriginalUri: node.mediaContent?.originalUri ?? null,
2595
+ previewImage: node.mediaContent?.previewImage?.medium ?? null,
2596
+ priceUsd,
2597
+ marketCap,
2598
+ marketCapDelta24h,
2599
+ marketCapChange24h,
2600
+ volume24h: node.volume24h ? Number(node.volume24h) : null,
2601
+ totalVolume: node.totalVolume ? Number(node.totalVolume) : null,
2602
+ uniqueHolders: node.uniqueHolders ?? null,
2603
+ createdAt: node.createdAt ?? null
2604
+ };
2605
+ };
2551
2606
  var QUERY_MAP = {
2552
2607
  mcap: {
2553
2608
  all: getMostValuableAll,
@@ -2659,7 +2714,10 @@ var exploreCommand = new Command4("explore").description("Browse top, new, and h
2659
2714
  outputErrorAndExit(json, `API error: ${msg}`);
2660
2715
  }
2661
2716
  const edges = response.data?.exploreList?.edges ?? [];
2662
- const coins = edges.map((e) => e.node);
2717
+ const rawNodes = edges.map((e) => e.node);
2718
+ const coins = rawNodes.map(
2719
+ (node, i) => formatExploreCoinJson(node)
2720
+ );
2663
2721
  const pageInfo = response.data?.exploreList?.pageInfo;
2664
2722
  outputJson({ coins, pageInfo: pageInfo ?? null });
2665
2723
  track("cli_explore", {
@@ -3243,7 +3301,7 @@ function printSellQuote(output, info) {
3243
3301
  `);
3244
3302
  console.log(` Amount ${info.soldFormatted} ${info.coinSymbol}`);
3245
3303
  console.log(
3246
- ` You get ~${info.receivedFormatted} ${info.outputSymbol}`
3304
+ ` You get ~${info.receivedFormatted} ${info.outputSymbol}${info.receivedUsd ? ` (${info.receivedUsd})` : ""}`
3247
3305
  );
3248
3306
  console.log(` Slippage ${info.slippagePct}%
3249
3307
  `);
@@ -3283,7 +3341,7 @@ function printSellResult(output, info) {
3283
3341
  `);
3284
3342
  console.log(` Sold ${info.soldFormatted} ${info.coinSymbol}`);
3285
3343
  console.log(
3286
- ` Received ${info.receivedSource === "quote" ? "~" : ""}${receivedFormatted} ${info.outputSymbol}`
3344
+ ` Received ${info.receivedSource === "quote" ? "~" : ""}${receivedFormatted} ${info.outputSymbol}${info.receivedUsd ? ` (${info.receivedUsd})` : ""}`
3287
3345
  );
3288
3346
  if (info.receivedSource === "quote") {
3289
3347
  console.log(" Note based on quote");
@@ -3409,22 +3467,22 @@ var sellCommand = new Command7("sell").description("Sell a coin").argument(
3409
3467
  );
3410
3468
  return;
3411
3469
  }
3412
- const coinPriceUsd = await fetchTokenPriceUsd(coinAddress);
3413
- if (coinPriceUsd === null || coinPriceUsd <= 0) {
3470
+ const coinPriceUsd2 = await fetchTokenPriceUsd(coinAddress);
3471
+ if (coinPriceUsd2 === null || coinPriceUsd2 <= 0) {
3414
3472
  outputErrorAndExit(
3415
3473
  json,
3416
3474
  `Failed to fetch ${coinSymbol} price for USD conversion.`
3417
3475
  );
3418
3476
  return;
3419
3477
  }
3420
- const coinAmount = usdVal / coinPriceUsd;
3478
+ const coinAmount = usdVal / coinPriceUsd2;
3421
3479
  amountIn = parseUnits2(coinAmount.toFixed(coinDecimals), coinDecimals);
3422
3480
  if (amountIn === 0n) {
3423
3481
  outputErrorAndExit(json, "Calculated amount is zero. USD too small.");
3424
3482
  }
3425
3483
  if (debug) {
3426
3484
  console.error(
3427
- `[debug] $${usdVal} USD = ${formatUnits5(amountIn, coinDecimals)} ${coinSymbol} (coin price: $${coinPriceUsd})`
3485
+ `[debug] $${usdVal} USD = ${formatUnits5(amountIn, coinDecimals)} ${coinSymbol} (coin price: $${coinPriceUsd2})`
3428
3486
  );
3429
3487
  }
3430
3488
  } else if (amountMode === "amount") {
@@ -3472,18 +3530,19 @@ var sellCommand = new Command7("sell").description("Sell a coin").argument(
3472
3530
  }
3473
3531
  }
3474
3532
  }
3533
+ const needsCoinPrice = amountMode !== "usd";
3534
+ const needsOutputPrice = outputToken.fixedPriceUsd == null;
3535
+ const [coinPriceUsd, outputPriceUsd] = await Promise.all([
3536
+ needsCoinPrice ? fetchTokenPriceUsd(coinAddress) : Promise.resolve(null),
3537
+ needsOutputPrice ? fetchTokenPriceUsd(outputToken.priceAddress) : Promise.resolve(null)
3538
+ ]);
3475
3539
  let swapAmountUsd;
3476
3540
  if (amountMode === "usd") {
3477
3541
  swapAmountUsd = parsePercentageLikeValue(opts.usd);
3478
- } else {
3479
- const coinPriceUsd = await fetchTokenPriceUsd(coinAddress);
3480
- if (coinPriceUsd !== null && coinPriceUsd > 0) {
3481
- swapAmountUsd = Number(
3482
- (Number(formatUnits5(amountIn, coinDecimals)) * coinPriceUsd).toFixed(
3483
- 2
3484
- )
3485
- );
3486
- }
3542
+ } else if (coinPriceUsd !== null && coinPriceUsd > 0) {
3543
+ swapAmountUsd = Number(
3544
+ (Number(formatUnits5(amountIn, coinDecimals)) * coinPriceUsd).toFixed(2)
3545
+ );
3487
3546
  }
3488
3547
  const tradeParameters = {
3489
3548
  sell: { type: "erc20", address: coinAddress },
@@ -3541,6 +3600,13 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
3541
3600
  BigInt(quoteAmountOut),
3542
3601
  outputToken.decimals
3543
3602
  );
3603
+ let receivedUsd;
3604
+ if (outputPriceUsd != null) {
3605
+ const outAmount = Number(
3606
+ formatUnits5(BigInt(quoteAmountOut), outputToken.decimals)
3607
+ );
3608
+ receivedUsd = `~${formatUsd(outAmount * outputPriceUsd)}`;
3609
+ }
3544
3610
  if (opts.quote) {
3545
3611
  printSellQuote(output, {
3546
3612
  coinName,
@@ -3554,7 +3620,8 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
3554
3620
  quoteAmountOut,
3555
3621
  outputSymbol: outputToken.symbol,
3556
3622
  outputDecimals: outputToken.decimals,
3557
- slippagePct
3623
+ slippagePct,
3624
+ receivedUsd
3558
3625
  });
3559
3626
  track("cli_sell", {
3560
3627
  action: "quote",
@@ -3584,7 +3651,8 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
3584
3651
  quoteAmountOut,
3585
3652
  outputSymbol: outputToken.symbol,
3586
3653
  outputDecimals: outputToken.decimals,
3587
- slippagePct
3654
+ slippagePct,
3655
+ receivedUsd
3588
3656
  });
3589
3657
  const ok = await confirm3({
3590
3658
  message: "Confirm?",
@@ -3641,6 +3709,12 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
3641
3709
  } catch {
3642
3710
  }
3643
3711
  }
3712
+ if (outputPriceUsd != null) {
3713
+ const actualAmount = Number(
3714
+ formatUnits5(receivedAmountOut, outputToken.decimals)
3715
+ );
3716
+ receivedUsd = `~${formatUsd(actualAmount * outputPriceUsd)}`;
3717
+ }
3644
3718
  printSellResult(output, {
3645
3719
  coinName,
3646
3720
  coinSymbol,
@@ -3653,7 +3727,8 @@ ${err instanceof Error ? err.stack || err.message : String(err)}
3653
3727
  outputSymbol: outputToken.symbol,
3654
3728
  outputDecimals: outputToken.decimals,
3655
3729
  receivedSource,
3656
- txHash
3730
+ txHash,
3731
+ receivedUsd
3657
3732
  });
3658
3733
  track("cli_sell", {
3659
3734
  action: "trade",
@@ -3867,15 +3942,11 @@ var extractErrorMessage2 = (error) => {
3867
3942
  }
3868
3943
  return JSON.stringify(error);
3869
3944
  };
3870
- var resolveApiKey = (json) => {
3945
+ var resolveApiKey = () => {
3871
3946
  const apiKey = getApiKey();
3872
- if (!apiKey) {
3873
- outputErrorAndExit(
3874
- json,
3875
- "Not authenticated. Run 'zora auth configure' to set your API key."
3876
- );
3947
+ if (apiKey) {
3948
+ setApiKey7(apiKey);
3877
3949
  }
3878
- setApiKey7(apiKey);
3879
3950
  };
3880
3951
  var formatPostJson = (post, rank) => ({
3881
3952
  rank,
@@ -3951,7 +4022,7 @@ var profileCommand = new Command8("profile").description("View profile activity
3951
4022
  ).action(async function(identifierArg) {
3952
4023
  const output = getOutputMode(this, "live");
3953
4024
  const json = output === "json";
3954
- resolveApiKey(json);
4025
+ resolveApiKey();
3955
4026
  const { live, intervalSeconds } = getLiveConfig(this, output);
3956
4027
  let identifier = identifierArg;
3957
4028
  if (!identifier) {
@@ -4520,32 +4591,33 @@ var sendCommand = new Command9("send").description("Send coins or ETH to an addr
4520
4591
  }
4521
4592
  });
4522
4593
 
4523
- // src/commands/setup.ts
4594
+ // src/commands/setup.tsx
4524
4595
  import { Command as Command10 } from "commander";
4525
- import { generatePrivateKey, privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
4596
+ import { Text as Text9, Box as Box9 } from "ink";
4526
4597
 
4527
4598
  // src/lib/strings.ts
4528
- var DEPOSIT_INSTRUCTIONS = "Deposit ETH or USDC to this address on Base to start trading.\n\n You can do this from:\n - Coinbase \u2014 withdraw directly to Base\n - Another wallet (MetaMask, Rainbow, etc.) \u2014 send on Base network\n - Bridge from other chains \u2014 use https://superbridge.app/base";
4599
+ var DEPOSIT_SOURCES = "Deposit from:\n- Coinbase \u2014 withdraw directly to Base\n- Another wallet (MetaMask, Rainbow, etc.) \u2014 send on Base network\n- Bridge from other chains \u2014 use https://superbridge.app/base";
4529
4600
  var NO_WALLET_CONFIGURED = "No wallet configured.";
4530
4601
  var NO_WALLET_SUGGESTION = "Run 'zora setup' to create or import one.";
4531
4602
  var SAVE_ERROR_HINT = "Check that the directory exists and is writable.";
4532
- var BACKUP_WARNING = "Back up this file \u2014 it's the only copy of your key.";
4603
+ var BACKUP_WARNING = "Back up this file \u2014 it's the only copy of your key. Zora is not responsible for any loss of funds.";
4533
4604
 
4534
- // src/commands/setup.ts
4605
+ // src/lib/wallet-setup.ts
4606
+ import { generatePrivateKey, privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
4535
4607
  var isValidPrivateKey = (key) => /^(0x)?[0-9a-fA-F]{64}$/.test(key);
4536
4608
  var toAccount = (json, key, errorPrefix) => {
4537
4609
  try {
4538
4610
  return privateKeyToAccount4(normalizeKey(key));
4539
4611
  } catch {
4540
- outputErrorAndExit(
4612
+ return outputErrorAndExit(
4541
4613
  json,
4542
4614
  `\u2717 ${errorPrefix} isn't a valid private key.`
4543
4615
  );
4544
4616
  }
4545
4617
  };
4546
- var setupCommand = new Command10("setup").description("Set up your Zora wallet").option("--create", "Create a new wallet without prompting").option("--force", "Overwrite existing wallet without prompting").option("--yes", "Skip interactive prompt and execute directly").action(async function(options) {
4547
- const json = getJson(this);
4548
- const nonInteractive = getYes(this);
4618
+ var walletExistsWarning = (truncated) => `Wallet already configured: ${truncated}. Make sure your wallet is backed up \u2014 Zora is not responsible for any loss of funds.`;
4619
+ async function configureWallet(opts) {
4620
+ const { json, nonInteractive, promptOverwrite } = opts;
4549
4621
  const envKey = process.env.ZORA_PRIVATE_KEY;
4550
4622
  if (envKey !== void 0) {
4551
4623
  if (!isValidPrivateKey(envKey)) {
@@ -4555,25 +4627,11 @@ var setupCommand = new Command10("setup").description("Set up your Zora wallet")
4555
4627
  "Fix it and run zora setup again."
4556
4628
  );
4557
4629
  }
4558
- const account = toAccount(json, envKey, "ZORA_PRIVATE_KEY");
4559
- outputData(json, {
4560
- json: { source: "env", address: account.address },
4561
- render: () => {
4562
- console.log(" Using wallet from ZORA_PRIVATE_KEY.\n");
4563
- console.log(` Address: ${account.address}
4564
- `);
4565
- console.log(` ${DEPOSIT_INSTRUCTIONS}`);
4566
- }
4567
- });
4568
- track("cli_setup", {
4569
- action: "env_detected",
4570
- source: "env",
4571
- output_format: json ? "json" : "text"
4572
- });
4573
- return;
4630
+ const account2 = toAccount(json, envKey, "ZORA_PRIVATE_KEY");
4631
+ return { action: "env_detected", address: account2.address };
4574
4632
  }
4575
4633
  let existing;
4576
- if (!options.force) {
4634
+ if (!opts.force) {
4577
4635
  try {
4578
4636
  existing = getPrivateKey();
4579
4637
  } catch (err) {
@@ -4585,20 +4643,33 @@ var setupCommand = new Command10("setup").description("Set up your Zora wallet")
4585
4643
  }
4586
4644
  }
4587
4645
  if (existing) {
4588
- const account = toAccount(json, existing, "Stored private key");
4589
- const truncated = truncateAddress(account.address);
4590
- console.log(` Wallet already configured: ${truncated}
4591
- `);
4592
- if (!options.force) {
4593
- outputErrorAndExit(
4594
- json,
4595
- "Wallet already exists.",
4596
- "Use --force to overwrite."
4646
+ const account2 = toAccount(json, existing, "Stored private key");
4647
+ const truncated = `${account2.address.slice(0, 6)}\u2026${account2.address.slice(-4)}`;
4648
+ const warning = walletExistsWarning(truncated);
4649
+ if (promptOverwrite) {
4650
+ if (nonInteractive) {
4651
+ return { action: "skipped", address: account2.address, warning };
4652
+ }
4653
+ const overwrite = await confirmOrDefault(
4654
+ { message: "Overwrite wallet configuration?", default: false },
4655
+ false
4597
4656
  );
4657
+ if (!overwrite) {
4658
+ return { action: "skipped", address: account2.address, warning };
4659
+ }
4660
+ } else {
4661
+ if (!opts.force) {
4662
+ outputErrorAndExit(
4663
+ json,
4664
+ `${warning}
4665
+ Wallet already exists.`,
4666
+ "Use --force to overwrite."
4667
+ );
4668
+ }
4598
4669
  }
4599
4670
  }
4600
4671
  let choice;
4601
- if (options.create) {
4672
+ if (opts.create) {
4602
4673
  choice = "create";
4603
4674
  } else {
4604
4675
  choice = await selectOrDefault(
@@ -4632,7 +4703,7 @@ var setupCommand = new Command10("setup").description("Set up your Zora wallet")
4632
4703
  );
4633
4704
  }
4634
4705
  }
4635
- const account = toAccount(json, importedKey, "Imported key");
4706
+ const account2 = toAccount(json, importedKey, "Imported key");
4636
4707
  try {
4637
4708
  savePrivateKey(importedKey);
4638
4709
  } catch {
@@ -4642,64 +4713,201 @@ var setupCommand = new Command10("setup").description("Set up your Zora wallet")
4642
4713
  SAVE_ERROR_HINT
4643
4714
  );
4644
4715
  }
4645
- outputData(json, {
4646
- json: {
4647
- action: "imported",
4648
- address: account.address,
4649
- path: getWalletPath()
4650
- },
4651
- render: () => {
4652
- console.log("\n\u2713 Wallet imported\n");
4653
- console.log(` Address: ${account.address}`);
4654
- console.log(` Private key: saved to ${getWalletPath()}
4716
+ return {
4717
+ action: "imported",
4718
+ address: account2.address,
4719
+ path: getWalletPath()
4720
+ };
4721
+ }
4722
+ const privateKey = generatePrivateKey();
4723
+ const account = toAccount(json, privateKey, "Generated key");
4724
+ try {
4725
+ savePrivateKey(privateKey);
4726
+ } catch {
4727
+ outputErrorAndExit(
4728
+ json,
4729
+ `\u2717 Couldn't save to ${getWalletPath()}.`,
4730
+ SAVE_ERROR_HINT
4731
+ );
4732
+ }
4733
+ return {
4734
+ action: "created",
4735
+ address: account.address,
4736
+ path: getWalletPath()
4737
+ };
4738
+ }
4739
+
4740
+ // src/lib/ansi.ts
4741
+ var DIM = "\x1B[2m";
4742
+ var BOLD = "\x1B[1m";
4743
+ var YELLOW = "\x1B[33m";
4744
+ var RESET = "\x1B[0m";
4745
+ var useAnsi = () => process.stdout.isTTY && !process.env.NO_COLOR;
4746
+
4747
+ // src/lib/warning-box.ts
4748
+ function warningBox(text) {
4749
+ if (!useAnsi()) {
4750
+ console.log(`\u26A0 ${text}
4655
4751
  `);
4656
- console.log(` ${BACKUP_WARNING}
4752
+ return;
4753
+ }
4754
+ console.log(`${YELLOW}\u26A0 ${text}${RESET}
4755
+ `);
4756
+ }
4757
+
4758
+ // src/commands/setup.tsx
4759
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
4760
+ function stepLine(step, total, title) {
4761
+ const cols = (process.stdout.columns || 80) - 4;
4762
+ if (!useAnsi()) {
4763
+ console.log(`
4764
+ [${step}/${total}] ${title}`);
4765
+ console.log(`${"\u2500".repeat(Math.max(cols, 20))}
4657
4766
  `);
4658
- console.log(` ${DEPOSIT_INSTRUCTIONS}`);
4659
- }
4660
- });
4661
- track("cli_setup", {
4662
- action: "imported",
4663
- source: "file",
4664
- output_format: json ? "json" : "text"
4665
- });
4666
4767
  return;
4667
4768
  }
4668
- if (choice === "create") {
4669
- const privateKey = generatePrivateKey();
4670
- const account = toAccount(json, privateKey, "Generated key");
4671
- try {
4672
- savePrivateKey(privateKey);
4673
- } catch {
4674
- outputErrorAndExit(
4675
- json,
4676
- `\u2717 Couldn't save to ${getWalletPath()}.`,
4677
- SAVE_ERROR_HINT
4678
- );
4679
- }
4680
- outputData(json, {
4681
- json: {
4682
- action: "created",
4683
- address: account.address,
4684
- path: getWalletPath()
4685
- },
4686
- render: () => {
4687
- console.log("\n\u2713 Wallet created\n");
4688
- console.log(` Address: ${account.address}`);
4689
- console.log(` Private key: saved to ${getWalletPath()}
4769
+ console.log(
4770
+ `
4771
+ ${BOLD}${DIM}[${step}/${total}]${RESET} ${BOLD}${title}${RESET}`
4772
+ );
4773
+ console.log(`${DIM}${"\u2500".repeat(Math.max(cols, 20))}${RESET}
4690
4774
  `);
4691
- console.log(` ${BACKUP_WARNING}
4775
+ }
4776
+ var setupCommand = new Command10("setup").description("Guided first-time setup").option("--create", "Create a new wallet without prompting").option("--force", "Overwrite existing wallet without prompting").option("--yes", "Skip interactive prompt and execute directly").action(async function(options) {
4777
+ const json = getJson(this);
4778
+ const nonInteractive = getYes(this);
4779
+ if (!json) stepLine(1, 3, "Set up wallet");
4780
+ const walletResult = await configureWallet({
4781
+ json,
4782
+ nonInteractive,
4783
+ create: options.create,
4784
+ force: options.force,
4785
+ promptOverwrite: true
4786
+ });
4787
+ if (!json) {
4788
+ if (walletResult.action === "env_detected") {
4789
+ console.log("Using wallet from ZORA_PRIVATE_KEY.");
4790
+ console.log(`Address: ${walletResult.address}
4692
4791
  `);
4693
- console.log(` ${DEPOSIT_INSTRUCTIONS}`);
4792
+ } else if (walletResult.action === "skipped") {
4793
+ warningBox(walletResult.warning);
4794
+ console.log(`${DIM}Keeping existing wallet.${RESET}
4795
+ `);
4796
+ } else {
4797
+ const verb = walletResult.action === "created" ? "created" : "imported";
4798
+ console.log(`\u2713 Wallet ${verb}`);
4799
+ console.log(`Address: ${walletResult.address}`);
4800
+ console.log(`Private key: saved to ${walletResult.path}
4801
+ `);
4802
+ warningBox(BACKUP_WARNING);
4803
+ }
4804
+ }
4805
+ if (!json) stepLine(2, 3, "Set up API key (optional)");
4806
+ let apiKeyStatus;
4807
+ const envApiKey = getEnvApiKey();
4808
+ if (envApiKey) {
4809
+ apiKeyStatus = "env_override";
4810
+ if (!json) {
4811
+ console.log("API key is set via ZORA_API_KEY environment variable.\n");
4812
+ }
4813
+ } else {
4814
+ const existingKey = getApiKey();
4815
+ if (existingKey && !options.force) {
4816
+ if (nonInteractive) {
4817
+ apiKeyStatus = "already_set";
4818
+ if (!json) {
4819
+ console.log(
4820
+ `API key already configured: ${maskKey(existingKey)}
4821
+ `
4822
+ );
4823
+ }
4824
+ } else {
4825
+ if (!json) console.log(`Current key: ${maskKey(existingKey)}`);
4826
+ const overwrite = await confirmOrDefault(
4827
+ { message: "Overwrite API key?", default: false },
4828
+ false
4829
+ );
4830
+ if (!overwrite) {
4831
+ apiKeyStatus = "already_set";
4832
+ if (!json) console.log("");
4833
+ } else {
4834
+ apiKeyStatus = await promptAndSaveApiKey(json);
4835
+ }
4694
4836
  }
4695
- });
4696
- track("cli_setup", {
4697
- action: "created",
4698
- source: "file",
4699
- output_format: json ? "json" : "text"
4700
- });
4837
+ } else {
4838
+ apiKeyStatus = await promptAndSaveApiKey(json, nonInteractive);
4839
+ }
4701
4840
  }
4841
+ if (!json) stepLine(3, 3, "Deposit");
4842
+ if (!json) {
4843
+ renderOnce(
4844
+ /* @__PURE__ */ jsxs9(
4845
+ Box9,
4846
+ {
4847
+ flexDirection: "column",
4848
+ borderStyle: "single",
4849
+ borderDimColor: true,
4850
+ paddingX: 1,
4851
+ paddingY: 1,
4852
+ children: [
4853
+ /* @__PURE__ */ jsxs9(Text9, { children: [
4854
+ "Your address: ",
4855
+ /* @__PURE__ */ jsx12(Text9, { bold: true, children: walletResult.address })
4856
+ ] }),
4857
+ /* @__PURE__ */ jsxs9(Text9, { children: [
4858
+ "Deposit",
4859
+ " ",
4860
+ /* @__PURE__ */ jsx12(Text9, { bold: true, color: "blue", children: "ETH or USDC on Base" }),
4861
+ " ",
4862
+ "to start trading."
4863
+ ] })
4864
+ ]
4865
+ }
4866
+ )
4867
+ );
4868
+ console.log(`
4869
+ ${DEPOSIT_SOURCES}
4870
+ `);
4871
+ }
4872
+ outputData(json, {
4873
+ json: { wallet: walletResult, apiKey: apiKeyStatus },
4874
+ render: () => {
4875
+ }
4876
+ });
4877
+ track("cli_setup", {
4878
+ wallet_action: walletResult.action,
4879
+ api_key_status: apiKeyStatus,
4880
+ output_format: json ? "json" : "text"
4881
+ });
4702
4882
  });
4883
+ async function promptAndSaveApiKey(json, nonInteractive = false) {
4884
+ if (!json && !nonInteractive) {
4885
+ console.log(
4886
+ "Optional. An API key unlocks higher rate limits for frequent trading."
4887
+ );
4888
+ console.log("Get your API key from: https://zora.co/settings/developer\n");
4889
+ }
4890
+ const apiKey = await passwordOrSkip(
4891
+ { message: "Paste your API key (Enter to skip):" },
4892
+ nonInteractive
4893
+ );
4894
+ const trimmed = apiKey.trim();
4895
+ if (!trimmed) {
4896
+ if (!json) console.log("Skipped API key configuration.\n");
4897
+ return "skipped";
4898
+ }
4899
+ try {
4900
+ saveApiKey(trimmed);
4901
+ if (!json) console.log(`API key saved to ${getConfigPath()}
4902
+ `);
4903
+ return "saved";
4904
+ } catch (err) {
4905
+ outputErrorAndExit(
4906
+ json,
4907
+ `Failed to save API key: ${fsErrorMessage(err, getConfigPath())}`
4908
+ );
4909
+ }
4910
+ }
4703
4911
 
4704
4912
  // src/commands/wallet.ts
4705
4913
  import { Command as Command11 } from "commander";
@@ -4715,9 +4923,9 @@ var resolvePrivateKey = () => {
4715
4923
  }
4716
4924
  return void 0;
4717
4925
  };
4718
- var walletCommand = new Command11("wallet").description(
4719
- "Manage your Zora wallet"
4720
- );
4926
+ var walletCommand = new Command11("wallet").description("Manage your Zora wallet").action(function() {
4927
+ this.outputHelp();
4928
+ });
4721
4929
  walletCommand.command("info").description("Show wallet address and storage location").action(function() {
4722
4930
  const json = getJson(this);
4723
4931
  const resolved = resolvePrivateKey();
@@ -4773,21 +4981,69 @@ walletCommand.command("export").description("Print the raw private key to stdout
4773
4981
  output_format: json ? "json" : "text"
4774
4982
  });
4775
4983
  });
4984
+ walletCommand.command("configure").description("Create or import a wallet").option("--create", "Create a new wallet without prompting").option("--force", "Overwrite existing wallet without prompting").option("--yes", "Skip interactive prompt and execute directly").action(async function(options) {
4985
+ const json = getJson(this);
4986
+ const nonInteractive = getYes(this);
4987
+ const result = await configureWallet({
4988
+ json,
4989
+ nonInteractive,
4990
+ create: options.create,
4991
+ force: options.force,
4992
+ promptOverwrite: false
4993
+ });
4994
+ outputData(json, {
4995
+ json: result,
4996
+ render: () => {
4997
+ if (result.action === "env_detected") {
4998
+ console.log(" Using wallet from ZORA_PRIVATE_KEY.\n");
4999
+ console.log(` Address: ${result.address}
5000
+ `);
5001
+ console.log(
5002
+ ` Deposit ETH or USDC on Base to start trading.
5003
+
5004
+ ${DEPOSIT_SOURCES}`
5005
+ );
5006
+ } else if (result.action === "created" || result.action === "imported") {
5007
+ const verb = result.action === "created" ? "created" : "imported";
5008
+ console.log(`
5009
+ \u2713 Wallet ${verb}
5010
+ `);
5011
+ console.log(` Address: ${result.address}`);
5012
+ console.log(` Private key: saved to ${result.path}
5013
+ `);
5014
+ console.log(` ${BACKUP_WARNING}
5015
+ `);
5016
+ console.log(
5017
+ ` Deposit ETH or USDC on Base to start trading.
5018
+
5019
+ ${DEPOSIT_SOURCES}`
5020
+ );
5021
+ } else if (result.action === "skipped") {
5022
+ console.log(` Wallet already configured: ${result.address}
5023
+ `);
5024
+ }
5025
+ }
5026
+ });
5027
+ track("cli_wallet_config", {
5028
+ action: result.action,
5029
+ output_format: json ? "json" : "text"
5030
+ });
5031
+ });
4776
5032
 
4777
5033
  // src/components/StyledHelp.tsx
4778
- import { Text as Text10, Box as Box10 } from "ink";
5034
+ import { Text as Text11, Box as Box11 } from "ink";
4779
5035
 
4780
5036
  // src/components/KeyValueTable.tsx
4781
- import { Text as Text9, Box as Box9 } from "ink";
4782
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
5037
+ import { Text as Text10, Box as Box10 } from "ink";
5038
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
4783
5039
  function KeyValueTable({
4784
5040
  rows,
4785
5041
  labelWidth
4786
5042
  }) {
4787
5043
  const pad = labelWidth ?? Math.max(0, ...rows.map((r) => r.label.length)) + 2;
4788
- return /* @__PURE__ */ jsx12(Box9, { flexDirection: "column", children: rows.map((row, i) => /* @__PURE__ */ jsxs9(Text9, { children: [
4789
- /* @__PURE__ */ jsx12(Text9, { bold: true, children: row.label.padEnd(pad) }),
4790
- /* @__PURE__ */ jsx12(Text9, { dimColor: true, children: row.value })
5044
+ return /* @__PURE__ */ jsx13(Box10, { flexDirection: "column", children: rows.map((row, i) => /* @__PURE__ */ jsxs10(Text10, { children: [
5045
+ /* @__PURE__ */ jsx13(Text10, { bold: true, children: row.label.padEnd(pad) }),
5046
+ /* @__PURE__ */ jsx13(Text10, { dimColor: true, children: row.value })
4791
5047
  ] }, i)) });
4792
5048
  }
4793
5049
 
@@ -4828,14 +5084,18 @@ function parseHelpSections(text) {
4828
5084
  }
4829
5085
 
4830
5086
  // src/components/StyledHelp.tsx
4831
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
5087
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
4832
5088
  function StyledHelp({
4833
5089
  sections,
4834
5090
  header
4835
5091
  }) {
4836
5092
  const descriptionColumnOffset = getDescriptionColumnOffset(sections);
4837
- return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", gap: 1, children: [
5093
+ return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", gap: 1, children: [
4838
5094
  header,
5095
+ /* @__PURE__ */ jsxs11(Box11, { paddingX: 1, children: [
5096
+ /* @__PURE__ */ jsx14(Text11, { color: "yellow", children: "\u26A0 Beta:" }),
5097
+ /* @__PURE__ */ jsx14(Text11, { children: " This CLI is in beta and should be used with caution." })
5098
+ ] }),
4839
5099
  sections.map((section, i) => {
4840
5100
  const hasTwoColumns = TWO_COLUMN_REGEX.test(section.content);
4841
5101
  const rows = hasTwoColumns ? section.content.split("\n").map((line) => {
@@ -4847,8 +5107,8 @@ function StyledHelp({
4847
5107
  };
4848
5108
  return { label: "", value: line.trimStart() };
4849
5109
  }) : null;
4850
- return /* @__PURE__ */ jsxs10(
4851
- Box10,
5110
+ return /* @__PURE__ */ jsxs11(
5111
+ Box11,
4852
5112
  {
4853
5113
  flexDirection: "column",
4854
5114
  borderStyle: "single",
@@ -4856,8 +5116,8 @@ function StyledHelp({
4856
5116
  paddingX: 1,
4857
5117
  paddingY: 1,
4858
5118
  children: [
4859
- /* @__PURE__ */ jsx13(Text10, { bold: true, children: section.title }),
4860
- rows ? /* @__PURE__ */ jsx13(KeyValueTable, { rows, labelWidth: descriptionColumnOffset }) : /* @__PURE__ */ jsx13(Text10, { children: section.content })
5119
+ /* @__PURE__ */ jsx14(Text11, { bold: true, children: section.title }),
5120
+ rows ? /* @__PURE__ */ jsx14(KeyValueTable, { rows, labelWidth: descriptionColumnOffset }) : /* @__PURE__ */ jsx14(Text11, { children: section.content })
4861
5121
  ]
4862
5122
  },
4863
5123
  i
@@ -4867,10 +5127,10 @@ function StyledHelp({
4867
5127
  }
4868
5128
 
4869
5129
  // src/components/StyledHelpHeader.tsx
4870
- import { Text as Text12, Box as Box12 } from "ink";
5130
+ import { Text as Text13, Box as Box13 } from "ink";
4871
5131
 
4872
5132
  // src/components/Zorb.tsx
4873
- import { Text as Text11, Box as Box11 } from "ink";
5133
+ import { Text as Text12, Box as Box12 } from "ink";
4874
5134
 
4875
5135
  // src/lib/zorb-pixels.ts
4876
5136
  function supportsTruecolor() {
@@ -5015,7 +5275,7 @@ function generateZorbPixels(size) {
5015
5275
  }
5016
5276
 
5017
5277
  // src/components/Zorb.tsx
5018
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
5278
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
5019
5279
  var LOWER_HALF_BLOCK = "\u2584";
5020
5280
  var UPPER_HALF_BLOCK = "\u2580";
5021
5281
  function rgbString([r, g, b]) {
@@ -5038,19 +5298,19 @@ function Zorb({ size = 20 }) {
5038
5298
  const topIsBlack = isBlack(top);
5039
5299
  const bottomIsBlack = isBlack(bottom);
5040
5300
  if (topIsBlack && bottomIsBlack) {
5041
- cells.push(/* @__PURE__ */ jsx14(Text11, { children: " " }, x));
5301
+ cells.push(/* @__PURE__ */ jsx15(Text12, { children: " " }, x));
5042
5302
  } else if (topIsBlack) {
5043
5303
  cells.push(
5044
- /* @__PURE__ */ jsx14(Text11, { color: rgbString(bottom), children: LOWER_HALF_BLOCK }, x)
5304
+ /* @__PURE__ */ jsx15(Text12, { color: rgbString(bottom), children: LOWER_HALF_BLOCK }, x)
5045
5305
  );
5046
5306
  } else if (bottomIsBlack) {
5047
5307
  cells.push(
5048
- /* @__PURE__ */ jsx14(Text11, { color: rgbString(top), children: UPPER_HALF_BLOCK }, x)
5308
+ /* @__PURE__ */ jsx15(Text12, { color: rgbString(top), children: UPPER_HALF_BLOCK }, x)
5049
5309
  );
5050
5310
  } else {
5051
5311
  cells.push(
5052
- /* @__PURE__ */ jsx14(
5053
- Text11,
5312
+ /* @__PURE__ */ jsx15(
5313
+ Text12,
5054
5314
  {
5055
5315
  backgroundColor: rgbString(top),
5056
5316
  color: rgbString(bottom),
@@ -5061,23 +5321,23 @@ function Zorb({ size = 20 }) {
5061
5321
  );
5062
5322
  }
5063
5323
  }
5064
- rows.push(/* @__PURE__ */ jsx14(Text11, { children: cells }, y));
5324
+ rows.push(/* @__PURE__ */ jsx15(Text12, { children: cells }, y));
5065
5325
  }
5066
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
5067
- /* @__PURE__ */ jsx14(Text11, { children: " " }),
5326
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
5327
+ /* @__PURE__ */ jsx15(Text12, { children: " " }),
5068
5328
  rows,
5069
- /* @__PURE__ */ jsx14(Text11, { children: " " })
5329
+ /* @__PURE__ */ jsx15(Text12, { children: " " })
5070
5330
  ] });
5071
5331
  }
5072
5332
 
5073
5333
  // src/components/StyledHelpHeader.tsx
5074
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
5334
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
5075
5335
  function StyledHelpHeader({
5076
5336
  sections
5077
5337
  }) {
5078
5338
  const descriptionColumnOffset = getDescriptionColumnOffset(sections);
5079
- return /* @__PURE__ */ jsxs12(
5080
- Box12,
5339
+ return /* @__PURE__ */ jsxs13(
5340
+ Box13,
5081
5341
  {
5082
5342
  flexDirection: "row",
5083
5343
  borderStyle: "single",
@@ -5085,19 +5345,36 @@ function StyledHelpHeader({
5085
5345
  paddingX: 1,
5086
5346
  paddingY: 1,
5087
5347
  children: [
5088
- /* @__PURE__ */ jsx15(Box12, { flexShrink: 0, width: descriptionColumnOffset, children: /* @__PURE__ */ jsx15(Zorb, { size: 20 }) }),
5089
- /* @__PURE__ */ jsx15(Box12, { flexDirection: "column", flexGrow: 1, justifyContent: "center", children: /* @__PURE__ */ jsx15(Text12, { bold: true, children: "Zora CLI" }) })
5348
+ /* @__PURE__ */ jsx16(Box13, { flexShrink: 0, width: descriptionColumnOffset, children: /* @__PURE__ */ jsx16(Zorb, { size: 20 }) }),
5349
+ /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", flexGrow: 1, justifyContent: "center", children: [
5350
+ /* @__PURE__ */ jsx16(Text13, { bold: true, children: /* @__PURE__ */ jsxs13(Text13, { backgroundColor: "#3fff00", color: "black", children: [
5351
+ " ",
5352
+ "Zora CLI",
5353
+ " "
5354
+ ] }) }),
5355
+ /* @__PURE__ */ jsxs13(Text13, { children: [
5356
+ /* @__PURE__ */ jsx16(Text13, { dimColor: true, children: "Trade what's trending. Run" }),
5357
+ " ",
5358
+ /* @__PURE__ */ jsxs13(Text13, { backgroundColor: "#3fff00", color: "black", children: [
5359
+ " ",
5360
+ "zora setup",
5361
+ " "
5362
+ ] }),
5363
+ " ",
5364
+ /* @__PURE__ */ jsx16(Text13, { dimColor: true, children: "to get started." })
5365
+ ] })
5366
+ ] })
5090
5367
  ]
5091
5368
  }
5092
5369
  );
5093
5370
  }
5094
5371
 
5095
5372
  // src/index.tsx
5096
- import { jsx as jsx16 } from "react/jsx-runtime";
5373
+ import { jsx as jsx17 } from "react/jsx-runtime";
5097
5374
  if (process.env.ZORA_API_TARGET) {
5098
5375
  setApiBaseUrl(process.env.ZORA_API_TARGET);
5099
5376
  }
5100
- var version = true ? "0.3.1" : JSON.parse(
5377
+ var version = true ? "1.0.0" : JSON.parse(
5101
5378
  readFileSync2(new URL("../package.json", import.meta.url), "utf-8")
5102
5379
  ).version;
5103
5380
  function styledHelpWriteOut(showHeader) {
@@ -5105,18 +5382,27 @@ function styledHelpWriteOut(showHeader) {
5105
5382
  if (supportsTruecolor()) {
5106
5383
  const sections = parseHelpSections(str);
5107
5384
  if (sections.length > 0) {
5108
- const header = showHeader ? /* @__PURE__ */ jsx16(StyledHelpHeader, { sections }) : void 0;
5109
- renderOnce(/* @__PURE__ */ jsx16(StyledHelp, { sections, header }));
5385
+ const header = showHeader ? /* @__PURE__ */ jsx17(StyledHelpHeader, { sections }) : void 0;
5386
+ renderOnce(/* @__PURE__ */ jsx17(StyledHelp, { sections, header }));
5110
5387
  return;
5111
5388
  }
5112
5389
  }
5113
5390
  process.stdout.write(str);
5391
+ process.stdout.write(
5392
+ "\n\x1B[33m\u26A0 Beta:\x1B[0m This CLI is in beta and should be used with caution.\n"
5393
+ );
5114
5394
  };
5115
5395
  }
5116
5396
  var buildProgram = () => {
5117
- const program2 = new Command12().name("zora").description("A developer CLI for the Zora platform").version(version).option("--json", "Output as JSON (for scripts and automation)", false);
5397
+ const program2 = new Command12().name("zora").description("Trade what's trending. Run `zora setup` to get started.").version(version).option("--json", "Output as JSON (for scripts and automation)", false);
5118
5398
  const helpWidth = (process.stdout.columns || 80) - 4;
5119
- program2.configureHelp({ helpWidth });
5399
+ program2.configureHelp({
5400
+ helpWidth,
5401
+ commandDescription: (cmd) => {
5402
+ if (!cmd.parent && supportsTruecolor()) return "";
5403
+ return cmd.description();
5404
+ }
5405
+ });
5120
5406
  program2.configureOutput({ writeOut: styledHelpWriteOut(true) });
5121
5407
  program2.action(() => {
5122
5408
  program2.outputHelp();
@@ -5140,9 +5426,10 @@ var buildProgram = () => {
5140
5426
  }
5141
5427
  };
5142
5428
  applyToSubcommands(program2);
5429
+ const argOptionalCommands = /* @__PURE__ */ new Set(["profile"]);
5143
5430
  program2.hook("preAction", (_thisCommand, actionCommand) => {
5144
5431
  const expected = actionCommand.registeredArguments.length;
5145
- if (expected > 0 && actionCommand.args.length === 0) {
5432
+ if (expected > 0 && actionCommand.args.length === 0 && !argOptionalCommands.has(actionCommand.name())) {
5146
5433
  actionCommand.outputHelp();
5147
5434
  process.exit(1);
5148
5435
  }
@@ -5151,9 +5438,6 @@ var buildProgram = () => {
5151
5438
  };
5152
5439
  var program = buildProgram();
5153
5440
  if (!process.env.VITEST) {
5154
- console.warn(
5155
- "\x1B[33m\u26A0 Beta:\x1B[0m This CLI is in beta and should be used with caution."
5156
- );
5157
5441
  identify();
5158
5442
  try {
5159
5443
  await program.parseAsync();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zoralabs/cli",
3
- "version": "0.3.1",
3
+ "version": "1.0.0",
4
4
  "description": "Zora CLI tool",
5
5
  "type": "module",
6
6
  "bin": {