@alchemy/cli 0.7.2-alpha.21 → 0.7.2-alpha.29

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/dist/index.js CHANGED
@@ -2,18 +2,20 @@
2
2
  if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
3
  import {
4
4
  registerAuth
5
- } from "./chunk-LQXLZLCY.js";
5
+ } from "./chunk-XSN4XA5Z.js";
6
6
  import {
7
7
  openBrowser
8
- } from "./chunk-INVT5BV6.js";
8
+ } from "./chunk-C5HNQOLB.js";
9
9
  import {
10
+ SETUP_CAPABILITY_LABELS,
11
+ SETUP_CAPABILITY_ORDER,
10
12
  getSetupStatus,
11
13
  isSetupComplete,
12
14
  shouldRunOnboarding
13
- } from "./chunk-EZ2ZD7YO.js";
15
+ } from "./chunk-R4W44A6E.js";
14
16
  import {
15
17
  isInteractiveAllowed
16
- } from "./chunk-RE5HSYJJ.js";
18
+ } from "./chunk-64A5W4M2.js";
17
19
  import {
18
20
  adminClientFromFlags,
19
21
  clearSession,
@@ -41,12 +43,12 @@ import {
41
43
  resolveX402Client,
42
44
  saveSession,
43
45
  updateSession
44
- } from "./chunk-5LCA2B6S.js";
46
+ } from "./chunk-K6V3R7SH.js";
45
47
  import {
46
48
  getAvailableUpdate,
47
49
  getUpdateStatus,
48
50
  printUpdateNotice
49
- } from "./chunk-I5KTBL75.js";
51
+ } from "./chunk-NNPVKNB4.js";
50
52
  import {
51
53
  bold,
52
54
  brand,
@@ -70,7 +72,7 @@ import {
70
72
  weiToEth,
71
73
  withSpinner,
72
74
  yellow
73
- } from "./chunk-DGKUBK7G.js";
75
+ } from "./chunk-5IL2PMZ6.js";
74
76
  import {
75
77
  KEY_MAP,
76
78
  configDir,
@@ -81,7 +83,7 @@ import {
81
83
  save,
82
84
  toMap,
83
85
  validKeys
84
- } from "./chunk-BAZ4NGOD.js";
86
+ } from "./chunk-JUCUKTP3.js";
85
87
  import {
86
88
  CLIError,
87
89
  EXIT_CODES,
@@ -117,7 +119,7 @@ import {
117
119
  setFlags,
118
120
  setNoColor,
119
121
  verbose
120
- } from "./chunk-KLPWJFWP.js";
122
+ } from "./chunk-2BALTY22.js";
121
123
 
122
124
  // src/index.ts
123
125
  import { Command, Help } from "commander";
@@ -624,7 +626,7 @@ function registerConfig(program2) {
624
626
  printJSON(toMap(cfg));
625
627
  return;
626
628
  }
627
- const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-ZCR3YCHJ.js");
629
+ const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXT5ZCUK.js");
628
630
  const validToken = resolveAuthToken2(cfg);
629
631
  const authStatus = cfg.auth_token ? validToken ? `${green("\u2713")} authenticated${cfg.auth_token_expires_at ? ` ${dim(`(expires ${cfg.auth_token_expires_at})`)}` : ""}` : `${yellow("\u25C6")} expired${cfg.auth_token_expires_at ? ` ${dim(`(${cfg.auth_token_expires_at})`)}` : ""}` : dim("(not set) \u2014 run 'alchemy auth' to log in");
630
632
  const pairs = [
@@ -738,6 +740,15 @@ function registerConfig(program2) {
738
740
  console.log(` ${dim(`- ${command}`)}`);
739
741
  }
740
742
  }
743
+ console.log("");
744
+ console.log(` ${dim("Capabilities:")}`);
745
+ printKeyValue(
746
+ SETUP_CAPABILITY_ORDER.map((capability) => {
747
+ const capabilityStatus = status.capabilities[capability];
748
+ const value = capabilityStatus.complete ? `ready (${capabilityStatus.satisfiedBy})` : `missing ${capabilityStatus.missing.join(", ")}`;
749
+ return [SETUP_CAPABILITY_LABELS[capability], value];
750
+ })
751
+ );
741
752
  });
742
753
  }
743
754
 
@@ -2682,6 +2693,8 @@ function registerWallets(program2) {
2682
2693
  }
2683
2694
 
2684
2695
  // src/lib/rest.ts
2696
+ var DATA_API_BASE_URL_ENV = "ALCHEMY_DATA_API_BASE_URL";
2697
+ var PRICES_API_BASE_URL_ENV = "ALCHEMY_PRICES_API_BASE_URL";
2685
2698
  function withQuery(url, query) {
2686
2699
  if (!query) return url;
2687
2700
  for (const [key, value] of Object.entries(query)) {
@@ -2715,13 +2728,15 @@ async function requestJSON(url, options) {
2715
2728
  }
2716
2729
  async function callApiData(apiKey, path, options = {}) {
2717
2730
  if (!apiKey) throw errAuthRequired();
2718
- const base2 = new URL(`https://api.g.${getBaseDomain()}/data/v1/${apiKey}/`);
2731
+ const override = parseBaseURLOverride(DATA_API_BASE_URL_ENV);
2732
+ const base2 = override ? new URL(`/data/v1/${apiKey}/`, override) : new URL(`https://api.g.${getBaseDomain()}/data/v1/${apiKey}/`);
2719
2733
  const url = withQuery(new URL(path.replace(/^\//, ""), base2), options.query);
2720
2734
  return requestJSON(url, { ...options, path });
2721
2735
  }
2722
2736
  async function callApiPrices(apiKey, path, options = {}) {
2723
2737
  if (!apiKey) throw errAuthRequired();
2724
- const base2 = new URL(`https://api.g.${getBaseDomain()}/prices/v1/${apiKey}/`);
2738
+ const override = parseBaseURLOverride(PRICES_API_BASE_URL_ENV);
2739
+ const base2 = override ? new URL(`/prices/v1/${apiKey}/`, override) : new URL(`https://api.g.${getBaseDomain()}/prices/v1/${apiKey}/`);
2725
2740
  const url = withQuery(new URL(path.replace(/^\//, ""), base2), options.query);
2726
2741
  return requestJSON(url, { ...options, path });
2727
2742
  }
@@ -3632,7 +3647,7 @@ async function performSolanaSend(program2, toArg, amountArg, tokenAddress, opts
3632
3647
  }
3633
3648
 
3634
3649
  // src/lib/smart-wallet.ts
3635
- import { createSmartWalletClient, alchemyWalletTransport } from "@alchemy/wallet-apis";
3650
+ import { createSmartWalletClient } from "@alchemy/wallet-apis";
3636
3651
  import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
3637
3652
 
3638
3653
  // src/lib/chains.ts
@@ -3971,6 +3986,17 @@ function createDelegatedAccount(args) {
3971
3986
  });
3972
3987
  }
3973
3988
 
3989
+ // src/lib/wallet-transport.ts
3990
+ import { alchemyWalletTransport } from "@alchemy/wallet-apis";
3991
+ var WALLET_RPC_BASE_URL_ENV = "ALCHEMY_WALLET_RPC_BASE_URL";
3992
+ function createAlchemyWalletTransport(apiKey) {
3993
+ const override = parseBaseURLOverride(WALLET_RPC_BASE_URL_ENV);
3994
+ return alchemyWalletTransport({
3995
+ apiKey,
3996
+ ...override ? { url: override.toString() } : {}
3997
+ });
3998
+ }
3999
+
3974
4000
  // src/lib/smart-wallet.ts
3975
4001
  function normalizeKey(key) {
3976
4002
  const trimmed = key.trim();
@@ -4069,7 +4095,7 @@ function buildWalletClient(program2, options = {}) {
4069
4095
  }
4070
4096
  const paymaster = gasSponsored && gasPolicyId ? { policyId: gasPolicyId } : void 0;
4071
4097
  const client = createSmartWalletClient({
4072
- transport: alchemyWalletTransport({ apiKey }),
4098
+ transport: createAlchemyWalletTransport(apiKey),
4073
4099
  chain,
4074
4100
  signer: signerConfig.signer,
4075
4101
  paymaster
@@ -4640,6 +4666,7 @@ var ERROR_RECOVERY = {
4640
4666
  RATE_LIMITED: "Wait and retry; consider upgrading your Alchemy plan",
4641
4667
  PAYMENT_REQUIRED: "Fund your x402 wallet or switch to API key auth",
4642
4668
  SETUP_REQUIRED: "Run preflight: alchemy --json --no-interactive config status, then follow nextCommands",
4669
+ QUOTE_FAILED: "Quote unavailable; check data.cause for the specific reason (INSUFFICIENT_BALANCE, INSUFFICIENT_LIQUIDITY, UNSUPPORTED_ROUTE, QUOTE_REVERTED, QUOTE_FAILED) and follow the hint",
4643
4670
  INTERNAL_ERROR: "Unexpected error; retry or report a bug"
4644
4671
  };
4645
4672
  function buildCommandSchema(cmd) {
@@ -4694,11 +4721,13 @@ function buildAgentPrompt(program2) {
4694
4721
  "For general capability and usage questions, prefer npx -y @alchemy/cli@latest --json --no-interactive agent-prompt so stale local installs or PATH shims do not hide new commands",
4695
4722
  "Use the user's installed alchemy binary only when executing commands against their local config or diagnosing their installed version",
4696
4723
  "If installed alchemy help contradicts latest npm help, compare alchemy --json --no-interactive version with npx -y @alchemy/cli@latest --json --no-interactive version and check command -v alchemy",
4697
- "Run alchemy --json --no-interactive update-check when you need to detect available CLI upgrades"
4724
+ "Run alchemy --json --no-interactive update-check when you need to detect available CLI upgrades",
4725
+ "For state-changing EVM commands, prefer preview flags such as --dry-run when available before asking the user to execute",
4726
+ "For large data reads, use output-size controls such as --limit or --summary when available"
4698
4727
  ],
4699
4728
  preflight: {
4700
4729
  command: "alchemy --json --no-interactive config status",
4701
- description: "Check auth readiness before first command. If complete is false, follow nextCommands in the response to configure auth."
4730
+ description: "Check auth readiness before first command. Use capabilities.rpc_data/admin_api/notify_webhooks/wallet_signing/x402 to scope setup to the intended command family."
4702
4731
  },
4703
4732
  runtimeDiscovery: {
4704
4733
  installed: {
@@ -4810,9 +4839,11 @@ function buildAgentPrompt(program2) {
4810
4839
  "ALCHEMY_ACCESS_KEY=ak_xxx alchemy --json --no-interactive app list",
4811
4840
  "alchemy --json --no-interactive evm rpc eth_blockNumber --api-key $ALCHEMY_API_KEY",
4812
4841
  "alchemy --json --no-interactive evm network list",
4813
- "alchemy --json --no-interactive evm send 0xRecipient 0.001 -n eth-sepolia",
4842
+ "alchemy --json --no-interactive evm send 0xRecipient 0.001 --dry-run -n eth-sepolia",
4814
4843
  `alchemy --json --no-interactive evm contract read 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 "balanceOf(address)(uint256)" --args '["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]' -n eth-mainnet`,
4815
- "alchemy --json --no-interactive evm swap quote --from 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE --to 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 --amount 1.0 -n eth-mainnet",
4844
+ "alchemy --json --no-interactive evm swap quote --from 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE --to 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 --amount 1.0 --from-address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 -n eth-mainnet",
4845
+ "alchemy --json --no-interactive evm logs --from-block latest --limit 25",
4846
+ "alchemy --json --no-interactive evm block latest --summary",
4816
4847
  "alchemy --json --no-interactive evm status 0xCallId -n eth-mainnet"
4817
4848
  ],
4818
4849
  docs: "https://www.alchemy.com/docs"
@@ -5154,15 +5185,26 @@ async function performApprove(program2, spenderArg, opts) {
5154
5185
  }
5155
5186
 
5156
5187
  // src/commands/block.ts
5188
+ function summarizeBlock(block) {
5189
+ return {
5190
+ number: block.number ?? null,
5191
+ hash: block.hash ?? null,
5192
+ timestamp: block.timestamp ?? null,
5193
+ transactionCount: Array.isArray(block.transactions) ? block.transactions.length : null,
5194
+ miner: block.miner ?? null,
5195
+ gasUsed: block.gasUsed ?? null,
5196
+ gasLimit: block.gasLimit ?? null
5197
+ };
5198
+ }
5157
5199
  function registerBlock(program2) {
5158
- program2.command("block").argument("<number>", "Block number, hex (0x...), or tag (latest, earliest, pending)").description("Get block details by number").addHelpText(
5200
+ program2.command("block").argument("<number>", "Block number, hex (0x...), or tag (latest, earliest, pending)").description("Get block details by number").option("--summary", "Return compact block summary in JSON mode").addHelpText(
5159
5201
  "after",
5160
5202
  `
5161
5203
  Examples:
5162
5204
  alchemy evm block latest
5163
5205
  alchemy evm block 17000000
5164
5206
  alchemy evm block 0x1`
5165
- ).action(async (blockId) => {
5207
+ ).action(async (blockId, opts) => {
5166
5208
  try {
5167
5209
  let blockParam;
5168
5210
  if (["latest", "earliest", "pending"].includes(blockId)) {
@@ -5189,7 +5231,7 @@ Examples:
5189
5231
  );
5190
5232
  if (!block) throw errNotFound(`block ${blockId}`);
5191
5233
  if (isJSONMode()) {
5192
- printJSON(block);
5234
+ printJSON(opts.summary ? summarizeBlock(block) : block);
5193
5235
  return;
5194
5236
  }
5195
5237
  const pairs = [];
@@ -6237,60 +6279,74 @@ async function runDataCall(program2, title, path, body) {
6237
6279
  () => x402 ? x402.callRest(`data/v1${path}`, { method: "POST", body }) : callApiData(resolveAPIKey(program2), path, { method: "POST", body })
6238
6280
  );
6239
6281
  }
6282
+ function limitPayload(value, limit) {
6283
+ if (limit === void 0) return value;
6284
+ if (Array.isArray(value)) {
6285
+ return value.slice(0, limit);
6286
+ }
6287
+ if (value && typeof value === "object") {
6288
+ return Object.fromEntries(
6289
+ Object.entries(value).map(([key, nested]) => [
6290
+ key,
6291
+ Array.isArray(nested) ? nested.slice(0, limit) : nested
6292
+ ])
6293
+ );
6294
+ }
6295
+ return value;
6296
+ }
6297
+ async function runPortfolioCommand(program2, title, path, opts) {
6298
+ const limit = parseOptionalInt(opts.limit, "--limit");
6299
+ const result = await runDataCall(program2, title, path, JSON.parse(opts.body));
6300
+ const output = limitPayload(result, limit);
6301
+ if (isJSONMode()) printJSON(output);
6302
+ else printSyntaxJSON(output);
6303
+ }
6240
6304
  function registerPortfolio(program2) {
6241
6305
  const cmd = program2.command("portfolio").description("Portfolio API wrappers");
6242
- cmd.command("tokens").description("Get token portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/tokens/by-address").action(async (opts) => {
6306
+ cmd.command("tokens").description("Get token portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/tokens/by-address").option("--limit <n>", "Limit arrays in output").action(async (opts) => {
6243
6307
  try {
6244
- const result = await runDataCall(
6308
+ await runPortfolioCommand(
6245
6309
  program2,
6246
6310
  "token portfolio",
6247
6311
  "/assets/tokens/by-address",
6248
- JSON.parse(opts.body)
6312
+ opts
6249
6313
  );
6250
- if (isJSONMode()) printJSON(result);
6251
- else printSyntaxJSON(result);
6252
6314
  } catch (err) {
6253
6315
  exitWithError(err);
6254
6316
  }
6255
6317
  });
6256
- cmd.command("token-balances").description("Get token balances by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/tokens/balances/by-address").action(async (opts) => {
6318
+ cmd.command("token-balances").description("Get token balances by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/tokens/balances/by-address").option("--limit <n>", "Limit arrays in output").action(async (opts) => {
6257
6319
  try {
6258
- const result = await runDataCall(
6320
+ await runPortfolioCommand(
6259
6321
  program2,
6260
6322
  "token balances",
6261
6323
  "/assets/tokens/balances/by-address",
6262
- JSON.parse(opts.body)
6324
+ opts
6263
6325
  );
6264
- if (isJSONMode()) printJSON(result);
6265
- else printSyntaxJSON(result);
6266
6326
  } catch (err) {
6267
6327
  exitWithError(err);
6268
6328
  }
6269
6329
  });
6270
- cmd.command("nfts").description("Get NFT portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/nfts/by-address").action(async (opts) => {
6330
+ cmd.command("nfts").description("Get NFT portfolio by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/nfts/by-address").option("--limit <n>", "Limit arrays in output").action(async (opts) => {
6271
6331
  try {
6272
- const result = await runDataCall(
6332
+ await runPortfolioCommand(
6273
6333
  program2,
6274
6334
  "NFT portfolio",
6275
6335
  "/assets/nfts/by-address",
6276
- JSON.parse(opts.body)
6336
+ opts
6277
6337
  );
6278
- if (isJSONMode()) printJSON(result);
6279
- else printSyntaxJSON(result);
6280
6338
  } catch (err) {
6281
6339
  exitWithError(err);
6282
6340
  }
6283
6341
  });
6284
- cmd.command("nft-contracts").description("Get NFT contracts by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/nfts/contracts/by-address").action(async (opts) => {
6342
+ cmd.command("nft-contracts").description("Get NFT contracts by address/network pairs").requiredOption("--body <json>", "JSON body for /assets/nfts/contracts/by-address").option("--limit <n>", "Limit arrays in output").action(async (opts) => {
6285
6343
  try {
6286
- const result = await runDataCall(
6344
+ await runPortfolioCommand(
6287
6345
  program2,
6288
6346
  "NFT contracts",
6289
6347
  "/assets/nfts/contracts/by-address",
6290
- JSON.parse(opts.body)
6348
+ opts
6291
6349
  );
6292
- if (isJSONMode()) printJSON(result);
6293
- else printSyntaxJSON(result);
6294
6350
  } catch (err) {
6295
6351
  exitWithError(err);
6296
6352
  }
@@ -6454,8 +6510,9 @@ Examples:
6454
6510
  alchemy evm logs --address 0xdAC17F958D2ee523a2206206994597C13D831ec7 --from-block 18000000 --to-block 18000010
6455
6511
  alchemy evm logs --address 0xdAC17F958D2ee523a2206206994597C13D831ec7 --topic 0xddf252ad...
6456
6512
  alchemy evm logs --from-block latest --json`
6457
- ).option("--address <address>", "Contract address to filter logs").option("--topic <topic...>", "Event topic(s) to filter (topic0, topic1, ...)").option("--from-block <block>", "Start block (number, hex, or tag)", "latest").option("--to-block <block>", "End block (number, hex, or tag)", "latest").action(async (opts) => {
6513
+ ).option("--address <address>", "Contract address to filter logs").option("--topic <topic...>", "Event topic(s) to filter (topic0, topic1, ...)").option("--from-block <block>", "Start block (number, hex, or tag)", "latest").option("--to-block <block>", "End block (number, hex, or tag)", "latest").option("--limit <n>", "Limit returned logs in output").action(async (opts) => {
6458
6514
  try {
6515
+ const outputLimit = parseOptionalInt(opts.limit, "--limit");
6459
6516
  const filter = {
6460
6517
  fromBlock: normalizeBlockParam(opts.fromBlock),
6461
6518
  toBlock: normalizeBlockParam(opts.toBlock)
@@ -6473,20 +6530,41 @@ Examples:
6473
6530
  () => client.call("eth_getLogs", [filter])
6474
6531
  );
6475
6532
  const network = resolveNetwork(program2);
6533
+ const displayedLogs = outputLimit === void 0 ? logs : logs.slice(0, outputLimit);
6476
6534
  if (isJSONMode()) {
6477
- printJSON({ logs, count: logs.length, network });
6535
+ printJSON({
6536
+ logs: displayedLogs,
6537
+ count: displayedLogs.length,
6538
+ network,
6539
+ ...outputLimit !== void 0 ? {
6540
+ totalCount: logs.length,
6541
+ truncated: displayedLogs.length < logs.length
6542
+ } : {}
6543
+ });
6478
6544
  return;
6479
6545
  }
6480
6546
  if (logs.length === 0) {
6481
6547
  console.log(dim("No logs found for the given filter."));
6482
6548
  return;
6483
6549
  }
6550
+ if (displayedLogs.length === 0) {
6551
+ console.log(dim(`Found ${logs.length} log${logs.length === 1 ? "" : "s"}; --limit 0 hides output.`));
6552
+ return;
6553
+ }
6484
6554
  const total = logs.length;
6485
6555
  const interactive = isInteractiveAllowed(program2);
6556
+ const limitSummary = displayedLogs.length < total ? `Showing ${displayedLogs.length} of ${total} logs on ${network}
6557
+ ` : `Found ${total} log${total === 1 ? "" : "s"} on ${network}
6558
+ `;
6559
+ if (outputLimit !== void 0) {
6560
+ console.log(limitSummary);
6561
+ printTable(TABLE_HEADERS2, formatLogRows(displayedLogs));
6562
+ return;
6563
+ }
6486
6564
  if (!interactive) {
6487
6565
  console.log(`Found ${total} log${total === 1 ? "" : "s"} on ${network}
6488
6566
  `);
6489
- printTable(TABLE_HEADERS2, formatLogRows(logs));
6567
+ printTable(TABLE_HEADERS2, formatLogRows(displayedLogs));
6490
6568
  } else {
6491
6569
  let offset = 0;
6492
6570
  const firstPage = logs.slice(0, PAGE_SIZE);
@@ -6616,8 +6694,15 @@ Examples:
6616
6694
  // src/commands/send-evm.ts
6617
6695
  import { encodeFunctionData as encodeFunctionData3, erc20Abi as erc20Abi2 } from "viem";
6618
6696
  var NATIVE_EVM_DECIMALS = 18;
6697
+ function formatCallPreview(call) {
6698
+ return {
6699
+ to: call.to,
6700
+ ...call.value !== void 0 ? { value: call.value.toString() } : {},
6701
+ ...call.data ? { data: call.data } : {}
6702
+ };
6703
+ }
6619
6704
  function registerEvmSend(program2) {
6620
- const sendCmd = program2.command("send").description("Send native tokens or ERC-20 tokens to an address").argument("<to>", "Recipient address (0x... or ENS name)").argument("<amount>", "Amount to send (human-readable, e.g. 1.5)").option("--token <address>", "ERC-20 token contract address (omit for native token)");
6705
+ const sendCmd = program2.command("send").description("Send native tokens or ERC-20 tokens to an address").argument("<to>", "Recipient address (0x... or ENS name)").argument("<amount>", "Amount to send (human-readable, e.g. 1.5)").option("--token <address>", "ERC-20 token contract address (omit for native token)").option("--dry-run", "Preview transaction without signing or sending");
6621
6706
  addSignerOption(sendCmd);
6622
6707
  sendCmd.option("--gas-sponsored", "Enable gas sponsorship (env: ALCHEMY_EVM_GAS_SPONSORED)").option("--gas-policy-id <id>", "Gas policy ID for sponsorship (env: ALCHEMY_EVM_GAS_POLICY_ID)").addHelpText(
6623
6708
  "after",
@@ -6626,16 +6711,18 @@ Examples:
6626
6711
  alchemy evm send 0xAbC...123 1.5 Send 1.5 ETH
6627
6712
  alchemy evm send vitalik.eth 0.1 -n base-mainnet Send 0.1 ETH on Base
6628
6713
  alchemy evm send 0xAbC...123 100 --token 0xA0b8...USDC Send 100 USDC
6714
+ alchemy evm send 0xAbC...123 1.5 --dry-run Preview without signing or sending
6629
6715
  alchemy evm send 0xAbC...123 1 --gas-sponsored --gas-policy-id <id>
6630
6716
  alchemy evm send 0xAbC...123 1.5 --signer local Force the local wallet`
6631
6717
  ).action(async (toArg, amountArg, _opts, cmd) => {
6632
6718
  try {
6633
6719
  const opts = cmd.opts();
6634
6720
  await performEvmSend(cmd, toArg, amountArg, opts.token, {
6635
- signer: parseSignerOpt(opts.signer)
6721
+ signer: parseSignerOpt(opts.signer),
6722
+ dryRun: opts.dryRun
6636
6723
  });
6637
6724
  } catch (err) {
6638
- const { exitWithError: exitWithError2 } = await import("./errors-J6HNGXVA.js");
6725
+ const { exitWithError: exitWithError2 } = await import("./errors-E2P6WHTX.js");
6639
6726
  exitWithError2(err);
6640
6727
  }
6641
6728
  });
@@ -6666,6 +6753,37 @@ async function performEvmSend(program2, toArg, amountArg, tokenAddress, opts = {
6666
6753
  args: [to, wei]
6667
6754
  })
6668
6755
  }] : [{ to, value: wei }];
6756
+ if (opts.dryRun) {
6757
+ const previewCalls = calls.map(formatCallPreview);
6758
+ if (isJSONMode()) {
6759
+ printJSON({
6760
+ dryRun: true,
6761
+ action: "evm-send",
6762
+ from,
6763
+ to,
6764
+ amount: amountArg,
6765
+ token: tokenAddress ?? symbol,
6766
+ tokenAddress: tokenAddress ?? null,
6767
+ network,
6768
+ sponsored: !!paymaster,
6769
+ calls: previewCalls
6770
+ });
6771
+ } else {
6772
+ const pairs = [
6773
+ ["Dry Run", "yes"],
6774
+ ["From", from],
6775
+ ["To", to],
6776
+ ["Amount", green(`${amountArg} ${symbol}`)],
6777
+ ["Network", network],
6778
+ ["Calls", String(previewCalls.length)]
6779
+ ];
6780
+ if (paymaster) {
6781
+ pairs.push(["Gas", green("Sponsored")]);
6782
+ }
6783
+ printKeyValue(pairs);
6784
+ }
6785
+ return;
6786
+ }
6669
6787
  const { id } = await withSpinner(
6670
6788
  "Sending transaction\u2026",
6671
6789
  "Transaction submitted",
@@ -6770,6 +6888,105 @@ function registerSimulate(program2) {
6770
6888
  import {
6771
6889
  swapActions
6772
6890
  } from "@alchemy/wallet-apis/experimental";
6891
+
6892
+ // src/lib/wallet-quote-client.ts
6893
+ import { createClient } from "viem";
6894
+ import { parseAccount } from "viem/accounts";
6895
+ function buildWalletQuoteClient(program2, address2) {
6896
+ const apiKey = resolveAPIKey(program2);
6897
+ if (!apiKey) throw errAuthRequired();
6898
+ const cfg = load();
6899
+ const network = resolveNetwork(program2, cfg);
6900
+ const chain = networkToChain(network);
6901
+ const client = createClient({
6902
+ account: parseAccount(address2),
6903
+ transport: createAlchemyWalletTransport(apiKey),
6904
+ chain,
6905
+ name: "alchemyQuoteClient"
6906
+ });
6907
+ if (typeof client.extend !== "function") {
6908
+ throw new Error("Quote client missing extend(); @alchemy/wallet-apis or viem may have changed.");
6909
+ }
6910
+ return {
6911
+ client,
6912
+ network,
6913
+ chain,
6914
+ address: address2,
6915
+ paymaster: void 0
6916
+ };
6917
+ }
6918
+
6919
+ // src/lib/quote-errors.ts
6920
+ function errorText(err) {
6921
+ if (err instanceof CLIError) {
6922
+ return [err.message, err.details].filter(Boolean).join(" ");
6923
+ }
6924
+ if (err instanceof Error) {
6925
+ return err.message;
6926
+ }
6927
+ return String(err);
6928
+ }
6929
+ function classifyQuoteFailure(text) {
6930
+ const lower = text.toLowerCase();
6931
+ if (/liquidity|no route|route not found|cannot find route|unable to find route|no quote/.test(lower)) {
6932
+ return "INSUFFICIENT_LIQUIDITY";
6933
+ }
6934
+ if (/insufficient (funds|balance)|exceeds balance|not enough (funds|balance)|balance too low/.test(lower)) {
6935
+ return "INSUFFICIENT_BALANCE";
6936
+ }
6937
+ if (/unsupported|not supported|unsupported route|unsupported token|unsupported chain|unsupported network/.test(lower)) {
6938
+ return "UNSUPPORTED_ROUTE";
6939
+ }
6940
+ if (/execution reverted|revert|call exception|internal json-rpc|rpc error|-32603/.test(lower)) {
6941
+ return "QUOTE_REVERTED";
6942
+ }
6943
+ return "QUOTE_FAILED";
6944
+ }
6945
+ function quoteMessage(flow, cause) {
6946
+ const label = flow === "swap" ? "Swap" : "Bridge";
6947
+ switch (cause) {
6948
+ case "INSUFFICIENT_BALANCE":
6949
+ return `${label} quote unavailable: insufficient balance for the requested amount.`;
6950
+ case "INSUFFICIENT_LIQUIDITY":
6951
+ return `${label} quote unavailable: no route or insufficient liquidity for this trade.`;
6952
+ case "UNSUPPORTED_ROUTE":
6953
+ return `${label} quote unavailable: unsupported token, chain, or route.`;
6954
+ case "QUOTE_REVERTED":
6955
+ return `${label} quote unavailable: quote simulation reverted.`;
6956
+ case "QUOTE_FAILED":
6957
+ return `${label} quote unavailable.`;
6958
+ }
6959
+ }
6960
+ function quoteHint(flow, cause) {
6961
+ switch (cause) {
6962
+ case "INSUFFICIENT_BALANCE":
6963
+ return "Lower --amount or quote from an address that holds enough source token.";
6964
+ case "INSUFFICIENT_LIQUIDITY":
6965
+ return flow === "swap" ? "Try a smaller --amount, different tokens, or a different mainnet." : "Try a smaller --amount, different tokens, or a different destination network.";
6966
+ case "UNSUPPORTED_ROUTE":
6967
+ return flow === "swap" ? "Check token addresses and use an EVM mainnet supported by swap." : "Check token addresses and source/destination EVM mainnets.";
6968
+ case "QUOTE_REVERTED":
6969
+ return "Try a smaller --amount or different route. Use --json for typed error details.";
6970
+ case "QUOTE_FAILED":
6971
+ return "Retry later or try a different amount, token, or network.";
6972
+ }
6973
+ }
6974
+ function normalizeQuoteError(err, flow) {
6975
+ if (err instanceof CLIError && err.code !== ErrorCode.RPC_ERROR && err.code !== ErrorCode.INTERNAL_ERROR) {
6976
+ return err;
6977
+ }
6978
+ const detail = errorText(err);
6979
+ const cause = classifyQuoteFailure(detail);
6980
+ return new CLIError(
6981
+ ErrorCode.QUOTE_FAILED,
6982
+ quoteMessage(flow, cause),
6983
+ quoteHint(flow, cause),
6984
+ detail || void 0,
6985
+ { cause }
6986
+ );
6987
+ }
6988
+
6989
+ // src/commands/swap.ts
6773
6990
  var NATIVE_TOKEN_ADDRESS2 = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
6774
6991
  var NATIVE_DECIMALS = 18;
6775
6992
  function isNativeToken2(address2) {
@@ -6792,11 +7009,12 @@ async function resolveTokenInfo(network, program2, tokenAddress) {
6792
7009
  throw errInvalidArgs(`Failed to resolve token info for ${tokenAddress}.${detail}`);
6793
7010
  }
6794
7011
  }
6795
- function createQuoteRequest(fromToken, toToken, fromAmount, slippagePercent, paymaster) {
7012
+ function createQuoteRequest(fromToken, toToken, fromAmount, slippagePercent, paymaster, account) {
6796
7013
  const request2 = {
6797
7014
  fromToken,
6798
7015
  toToken,
6799
7016
  fromAmount,
7017
+ ...account ? { account } : {},
6800
7018
  ...slippagePercent !== void 0 ? { slippage: slippagePercentToBasisPoints(slippagePercent) } : {},
6801
7019
  ...paymaster ? { capabilities: { paymaster } } : {}
6802
7020
  };
@@ -6843,7 +7061,7 @@ async function prepareQuoteForExecution(client, quote) {
6843
7061
  }
6844
7062
  function registerSwap(program2) {
6845
7063
  const cmd = program2.command("swap").description("Swap tokens on the same chain");
6846
- const quoteCmd = cmd.command("quote").description("Get a swap quote without executing").requiredOption("--from <token_address>", "Token address to swap from (use 0xEeee...EEeE for the native token)").requiredOption("--to <token_address>", "Token address to swap to (use 0xEeee...EEeE for the native token)").requiredOption("--amount <number>", "Amount to swap in decimal token units (for example, 1.5)").option("--slippage <percent>", "Max slippage percentage (omit to use the API default)");
7064
+ const quoteCmd = cmd.command("quote").description("Get a swap quote without executing").requiredOption("--from <token_address>", "Token address to swap from (use 0xEeee...EEeE for the native token)").requiredOption("--to <token_address>", "Token address to swap to (use 0xEeee...EEeE for the native token)").requiredOption("--amount <number>", "Amount to swap in decimal token units (for example, 1.5)").option("--from-address <address>", "Wallet/account address to quote from without changing signer selection").option("--slippage <percent>", "Max slippage percentage (omit to use the API default)");
6847
7065
  addSignerOption(quoteCmd);
6848
7066
  quoteCmd.addHelpText(
6849
7067
  "after",
@@ -6880,8 +7098,9 @@ async function performSwapQuote(program2, opts) {
6880
7098
  validateSwapNetwork(resolveNetwork(program2));
6881
7099
  validateAddress(opts.from);
6882
7100
  validateAddress(opts.to);
7101
+ if (opts.fromAddress) validateAddress(opts.fromAddress);
6883
7102
  const signer = parseSignerOpt(opts.signer);
6884
- const { client, network, paymaster } = buildWalletClient(program2, { signer });
7103
+ const { client, network, address: fromAddress, paymaster } = opts.fromAddress ? buildWalletQuoteClient(program2, opts.fromAddress) : buildWalletClient(program2, { signer });
6885
7104
  const swapClient = client.extend(swapActions);
6886
7105
  const fromInfo = await resolveTokenInfo(network, program2, opts.from);
6887
7106
  const rawAmount = parseAmount(opts.amount, fromInfo.decimals);
@@ -6889,17 +7108,23 @@ async function performSwapQuote(program2, opts) {
6889
7108
  if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
6890
7109
  throw errInvalidArgs("Slippage must be a number between 0 and 100.");
6891
7110
  }
6892
- const quote = await withSpinner(
6893
- "Fetching quote\u2026",
6894
- "Quote received",
6895
- () => swapClient.requestQuoteV0(createQuoteRequest(opts.from, opts.to, rawAmount, slippage, paymaster))
6896
- );
7111
+ let quote;
7112
+ try {
7113
+ quote = await withSpinner(
7114
+ "Fetching quote\u2026",
7115
+ "Quote received",
7116
+ () => swapClient.requestQuoteV0(createQuoteRequest(opts.from, opts.to, rawAmount, slippage, paymaster, fromAddress))
7117
+ );
7118
+ } catch (err) {
7119
+ throw normalizeQuoteError(err, "swap");
7120
+ }
6897
7121
  const toInfo = await resolveTokenInfo(network, program2, opts.to);
6898
7122
  const quoteData = extractQuoteData(quote);
6899
7123
  if (isJSONMode()) {
6900
7124
  printJSON({
6901
7125
  fromToken: opts.from,
6902
7126
  toToken: opts.to,
7127
+ fromAddress,
6903
7128
  fromAmount: opts.amount,
6904
7129
  fromSymbol: fromInfo.symbol,
6905
7130
  toSymbol: toInfo.symbol,
@@ -6918,6 +7143,7 @@ async function performSwapQuote(program2, opts) {
6918
7143
  pairs.push(["To", `${toInfo.symbol}`]);
6919
7144
  }
6920
7145
  pairs.push(
7146
+ ["Wallet", fromAddress],
6921
7147
  ["Slippage", slippage === void 0 ? "API default" : `${slippage}%`],
6922
7148
  ["Network", network]
6923
7149
  );
@@ -6937,11 +7163,16 @@ async function performSwapExecute(program2, opts) {
6937
7163
  if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
6938
7164
  throw errInvalidArgs("Slippage must be a number between 0 and 100.");
6939
7165
  }
6940
- const quote = await withSpinner(
6941
- "Fetching quote\u2026",
6942
- "Quote received",
6943
- () => swapClient.requestQuoteV0(createQuoteRequest(opts.from, opts.to, rawAmount, slippage, paymaster))
6944
- );
7166
+ let quote;
7167
+ try {
7168
+ quote = await withSpinner(
7169
+ "Fetching quote\u2026",
7170
+ "Quote received",
7171
+ () => swapClient.requestQuoteV0(createQuoteRequest(opts.from, opts.to, rawAmount, slippage, paymaster, from))
7172
+ );
7173
+ } catch (err) {
7174
+ throw normalizeQuoteError(err, "swap");
7175
+ }
6945
7176
  const preparedQuote = await prepareQuoteForExecution(client, quote);
6946
7177
  const { id } = await withSpinner(
6947
7178
  "Sending swap transaction\u2026",
@@ -7143,12 +7374,13 @@ async function resolveTokenInfo2(network, program2, tokenAddress) {
7143
7374
  throw errInvalidArgs(`Failed to resolve token info for ${tokenAddress}.${detail}`);
7144
7375
  }
7145
7376
  }
7146
- function createBridgeQuoteRequest(fromToken, toToken, fromAmount, toChainId, slippagePercent, paymaster) {
7377
+ function createBridgeQuoteRequest(fromToken, toToken, fromAmount, toChainId, slippagePercent, paymaster, account) {
7147
7378
  const request2 = {
7148
7379
  fromToken,
7149
7380
  toToken,
7150
7381
  fromAmount,
7151
7382
  toChainId,
7383
+ ...account ? { account } : {},
7152
7384
  ...slippagePercent !== void 0 ? { slippage: slippagePercentToBasisPoints2(slippagePercent) } : {},
7153
7385
  ...paymaster ? { capabilities: { paymaster } } : {}
7154
7386
  };
@@ -7214,7 +7446,7 @@ function extractQuoteData2(quote) {
7214
7446
  }
7215
7447
  function registerBridge(program2) {
7216
7448
  const cmd = program2.command("bridge").description("Bridge tokens from the source -n/--network to a destination --to-network");
7217
- const quoteCmd = cmd.command("quote").description("Get a bridge quote without executing").requiredOption("--from <token_address>", `Source token address (use ${NATIVE_TOKEN_ADDRESS3} for the native token)`).requiredOption("--to <token_address>", `Destination token address (use ${NATIVE_TOKEN_ADDRESS3} for the native token)`).requiredOption("--amount <number>", "Amount to bridge in decimal token units (for example, 1.5)").requiredOption("--to-network <network>", "Destination network (e.g. base-mainnet)").option("--slippage <percent>", "Max slippage percentage (omit to use the API default)");
7449
+ const quoteCmd = cmd.command("quote").description("Get a bridge quote without executing").requiredOption("--from <token_address>", `Source token address (use ${NATIVE_TOKEN_ADDRESS3} for the native token)`).requiredOption("--to <token_address>", `Destination token address (use ${NATIVE_TOKEN_ADDRESS3} for the native token)`).requiredOption("--amount <number>", "Amount to bridge in decimal token units (for example, 1.5)").requiredOption("--to-network <network>", "Destination network (e.g. base-mainnet)").option("--from-address <address>", "Wallet/account address to quote from without changing signer selection").option("--slippage <percent>", "Max slippage percentage (omit to use the API default)");
7218
7450
  addSignerOption(quoteCmd);
7219
7451
  quoteCmd.addHelpText(
7220
7452
  "after",
@@ -7256,8 +7488,9 @@ async function performBridgeQuote(program2, opts) {
7256
7488
  validateAddress(opts.from);
7257
7489
  const toChainId = bridgeDestinationChainId(opts.toNetwork);
7258
7490
  validateAddress(opts.to);
7491
+ if (opts.fromAddress) validateAddress(opts.fromAddress);
7259
7492
  const signer = parseSignerOpt(opts.signer);
7260
- const { client, network, paymaster } = buildWalletClient(program2, { signer });
7493
+ const { client, network, address: fromAddress, paymaster } = opts.fromAddress ? buildWalletQuoteClient(program2, opts.fromAddress) : buildWalletClient(program2, { signer });
7261
7494
  validateBridgeNetworks(network, opts.toNetwork);
7262
7495
  const swapClient = client.extend(swapActions2);
7263
7496
  const fromInfo = await resolveTokenInfo2(network, program2, opts.from);
@@ -7266,17 +7499,23 @@ async function performBridgeQuote(program2, opts) {
7266
7499
  if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
7267
7500
  throw errInvalidArgs("Slippage must be a number between 0 and 100.");
7268
7501
  }
7269
- const quote = await withSpinner(
7270
- "Fetching bridge quote\u2026",
7271
- "Quote received",
7272
- () => swapClient.requestQuoteV0(createBridgeQuoteRequest(opts.from, opts.to, rawAmount, toChainId, slippage, paymaster))
7273
- );
7502
+ let quote;
7503
+ try {
7504
+ quote = await withSpinner(
7505
+ "Fetching bridge quote\u2026",
7506
+ "Quote received",
7507
+ () => swapClient.requestQuoteV0(createBridgeQuoteRequest(opts.from, opts.to, rawAmount, toChainId, slippage, paymaster, fromAddress))
7508
+ );
7509
+ } catch (err) {
7510
+ throw normalizeQuoteError(err, "bridge");
7511
+ }
7274
7512
  const toInfo = await resolveTokenInfo2(opts.toNetwork, program2, opts.to);
7275
7513
  const quoteData = extractQuoteData2(quote);
7276
7514
  if (isJSONMode()) {
7277
7515
  printJSON({
7278
7516
  fromToken: opts.from,
7279
7517
  toToken: opts.to,
7518
+ fromAddress,
7280
7519
  fromAmount: opts.amount,
7281
7520
  fromSymbol: fromInfo.symbol,
7282
7521
  toSymbol: toInfo.symbol,
@@ -7296,6 +7535,7 @@ async function performBridgeQuote(program2, opts) {
7296
7535
  pairs.push(["To", toInfo.symbol]);
7297
7536
  }
7298
7537
  pairs.push(
7538
+ ["Wallet", fromAddress],
7299
7539
  ["Slippage", slippage === void 0 ? "API default" : `${slippage}%`],
7300
7540
  ["From Network", network],
7301
7541
  ["To Network", opts.toNetwork]
@@ -7317,11 +7557,16 @@ async function performBridgeExecute(program2, opts) {
7317
7557
  if (slippage !== void 0 && (isNaN(slippage) || slippage < 0 || slippage > 100)) {
7318
7558
  throw errInvalidArgs("Slippage must be a number between 0 and 100.");
7319
7559
  }
7320
- const quote = await withSpinner(
7321
- "Fetching bridge quote\u2026",
7322
- "Quote received",
7323
- () => swapClient.requestQuoteV0(createBridgeQuoteRequest(opts.from, opts.to, rawAmount, toChainId, slippage, paymaster))
7324
- );
7560
+ let quote;
7561
+ try {
7562
+ quote = await withSpinner(
7563
+ "Fetching bridge quote\u2026",
7564
+ "Quote received",
7565
+ () => swapClient.requestQuoteV0(createBridgeQuoteRequest(opts.from, opts.to, rawAmount, toChainId, slippage, paymaster, from))
7566
+ );
7567
+ } catch (err) {
7568
+ throw normalizeQuoteError(err, "bridge");
7569
+ }
7325
7570
  const preparedQuote = await prepareQuoteForExecution2(client, quote);
7326
7571
  const { id } = await withSpinner(
7327
7572
  "Sending bridge transaction\u2026",
@@ -7866,13 +8111,62 @@ function registerInstall(program2) {
7866
8111
  }
7867
8112
 
7868
8113
  // src/commands/doctor.ts
8114
+ var DOCTOR_SETUP_CAPABILITY_ORDER = SETUP_CAPABILITY_ORDER.filter(
8115
+ (capability) => capability !== "x402"
8116
+ );
8117
+ function removeX402SetupMissing(missing) {
8118
+ return missing.map(
8119
+ (item) => item.replace(" OR SIWx wallet", "").replace(" or x402 wallet", "")
8120
+ );
8121
+ }
8122
+ function removeX402NextCommands(commands) {
8123
+ return commands.filter((command) => !/x402|siwx/i.test(command));
8124
+ }
8125
+ function sanitizeCapabilityStatus(status) {
8126
+ if (status.satisfiedBy !== "x402_wallet") {
8127
+ return {
8128
+ ...status,
8129
+ missing: removeX402SetupMissing(status.missing),
8130
+ nextCommands: removeX402NextCommands(status.nextCommands)
8131
+ };
8132
+ }
8133
+ return {
8134
+ complete: false,
8135
+ satisfiedBy: null,
8136
+ missing: ["api-key"],
8137
+ nextCommands: ["alchemy config set app", "alchemy config set api-key <key>"]
8138
+ };
8139
+ }
8140
+ function doctorSetupStatus(setup) {
8141
+ const { x402: _x402, ...capabilities } = setup.capabilities;
8142
+ const sanitizedCapabilities = Object.fromEntries(
8143
+ Object.entries(capabilities).map(([capability, status]) => [
8144
+ capability,
8145
+ sanitizeCapabilityStatus(status)
8146
+ ])
8147
+ );
8148
+ const x402OnlySetup = setup.satisfiedBy === "x402_wallet";
8149
+ return {
8150
+ ...setup,
8151
+ complete: x402OnlySetup ? false : setup.complete,
8152
+ satisfiedBy: x402OnlySetup ? null : setup.satisfiedBy,
8153
+ missing: x402OnlySetup ? ["Provide one auth path: alchemy auth OR api-key OR ALCHEMY_ACCESS_KEY+app"] : removeX402SetupMissing(setup.missing),
8154
+ nextCommands: x402OnlySetup ? [
8155
+ "alchemy auth",
8156
+ "alchemy config set app",
8157
+ "alchemy config set access-key <key> && alchemy config set app <app-id>"
8158
+ ] : removeX402NextCommands(setup.nextCommands),
8159
+ capabilities: sanitizedCapabilities
8160
+ };
8161
+ }
7869
8162
  function registerDoctor(program2) {
7870
8163
  program2.command("doctor").description("Run readiness checks and print suggested fixes").action(() => {
7871
- const setup = getSetupStatus(load());
8164
+ const setup = doctorSetupStatus(getSetupStatus(load()));
7872
8165
  const payload = {
7873
8166
  ok: setup.complete,
7874
8167
  checks: {
7875
- setup
8168
+ setup,
8169
+ capabilities: setup.capabilities
7876
8170
  }
7877
8171
  };
7878
8172
  if (isJSONMode()) {
@@ -7891,6 +8185,15 @@ function registerDoctor(program2) {
7891
8185
  console.log(` ${command}`);
7892
8186
  }
7893
8187
  }
8188
+ console.log("");
8189
+ console.log(` ${dim("Capabilities:")}`);
8190
+ printKeyValue(
8191
+ DOCTOR_SETUP_CAPABILITY_ORDER.map((capability) => {
8192
+ const status = setup.capabilities[capability];
8193
+ const value = status.complete ? green(`ready${status.satisfiedBy ? ` (${status.satisfiedBy})` : ""}`) : dim(`missing ${status.missing.join(", ")}`);
8194
+ return [SETUP_CAPABILITY_LABELS[capability], value];
8195
+ })
8196
+ );
7894
8197
  });
7895
8198
  }
7896
8199
 
@@ -7987,9 +8290,15 @@ function resetUpdateNoticeState() {
7987
8290
  cachedAvailableUpdate = void 0;
7988
8291
  updateShownDuringInteractiveStartup = false;
7989
8292
  }
8293
+ async function flushProcessOutput() {
8294
+ await Promise.all([
8295
+ new Promise((resolve) => process.stdout.write("", () => resolve())),
8296
+ new Promise((resolve) => process.stderr.write("", () => resolve()))
8297
+ ]);
8298
+ }
7990
8299
  program.name("alchemy").description(
7991
8300
  "The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
7992
- ).version("0.7.2-alpha.21", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
8301
+ ).version("0.7.2-alpha.29", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
7993
8302
  "-n, --network <network>",
7994
8303
  "Target network (default: eth-mainnet) (env: ALCHEMY_NETWORK)"
7995
8304
  ).option("--x402", "Use x402 wallet-based gateway auth").option(
@@ -8176,17 +8485,17 @@ ${styledLine}`;
8176
8485
  "wallet"
8177
8486
  ];
8178
8487
  if (!skipAppPrompt.includes(cmdName) && isInteractiveAllowed(program) && !opts.apiKey && !process.env.ALCHEMY_API_KEY) {
8179
- const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-ZCR3YCHJ.js");
8488
+ const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXT5ZCUK.js");
8180
8489
  const authToken = resolveAuthToken2(cfg);
8181
8490
  const hasApiKey = Boolean(cfg.api_key?.trim() || cfg.app?.apiKey);
8182
8491
  if (authToken && !hasApiKey) {
8183
- const { selectAppAfterAuth } = await import("./auth-7QNYRHIK.js");
8492
+ const { selectAppAfterAuth } = await import("./auth-F2IXC6CM.js");
8184
8493
  console.log("");
8185
8494
  console.log(` No app selected. Please select an app to continue.`);
8186
8495
  await selectAppAfterAuth(authToken);
8187
8496
  }
8188
8497
  }
8189
- }).hook("postAction", () => {
8498
+ }).hook("postAction", async () => {
8190
8499
  if (!isJSONMode() && !quiet) {
8191
8500
  console.log("");
8192
8501
  if (!updateShownDuringInteractiveStartup) {
@@ -8196,6 +8505,7 @@ ${styledLine}`;
8196
8505
  }
8197
8506
  resetUpdateNoticeState();
8198
8507
  if (!isReplMode()) {
8508
+ await flushProcessOutput();
8199
8509
  process.exit(0);
8200
8510
  }
8201
8511
  }).action(async (_opts, cmd) => {
@@ -8214,7 +8524,7 @@ ${styledLine}`;
8214
8524
  if (isInteractiveAllowed(program)) {
8215
8525
  let latestForInteractiveStartup = null;
8216
8526
  if (shouldRunOnboarding(program, cfg)) {
8217
- const { runOnboarding } = await import("./onboarding-Y6HXW4CX.js");
8527
+ const { runOnboarding } = await import("./onboarding-CF24FH7O.js");
8218
8528
  const latest = getAvailableUpdateOnce();
8219
8529
  const completed = await runOnboarding(program, latest);
8220
8530
  updateShownDuringInteractiveStartup = Boolean(latest);
@@ -8228,7 +8538,7 @@ ${styledLine}`;
8228
8538
  latestForInteractiveStartup
8229
8539
  );
8230
8540
  }
8231
- const { startREPL } = await import("./interactive-OFBUWRE4.js");
8541
+ const { startREPL } = await import("./interactive-WRGKS7C5.js");
8232
8542
  program.exitOverride();
8233
8543
  program.configureOutput({
8234
8544
  writeErr: () => {