@alchemy/cli 0.6.2 → 0.7.0-alpha.5

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
@@ -67,7 +67,7 @@ Quick usage examples:
67
67
  alchemy
68
68
 
69
69
  # Agent/script-friendly command
70
- alchemy balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --json --no-interactive
70
+ alchemy evm data balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --json --no-interactive
71
71
 
72
72
  # Agent checks whether a newer CLI version is available
73
73
  alchemy update-check --json --no-interactive
@@ -91,56 +91,43 @@ Agents can also call `alchemy --json --no-interactive update-check` to retrieve
91
91
  Run commands as `alchemy <command>`.
92
92
  Use `alchemy help` or `alchemy help <command>` for generated command help.
93
93
 
94
- ### Node
94
+ ### EVM
95
95
 
96
96
  | Command | What it does | Example |
97
97
  |---|---|---|
98
- | `balance [address]` (`bal [address]`) | Gets ETH balance for an address | `alchemy bal 0x...` |
99
- | `tx [hash]` | Gets transaction + receipt by hash | `alchemy tx 0x...` |
100
- | `receipt [hash]` | Gets transaction receipt (status, gas, logs) | `alchemy receipt 0x...` |
101
- | `block <number>` | Gets block details (`latest`, decimal, or hex) | `alchemy block latest` |
102
- | `gas` | Gets current gas prices (base fee + priority fee) | `alchemy gas -n polygon-mainnet` |
103
- | `logs` | Queries event logs (`eth_getLogs`) | `alchemy logs --address 0x... --from-block 18000000 --to-block 18000010` |
104
- | `rpc <method> [params...]` | Makes raw JSON-RPC call | `alchemy rpc eth_blockNumber` |
105
- | `trace <method> [params...]` | Calls Trace API methods | `alchemy trace call '{"to":"0x..."}' '["trace"]' latest` |
106
- | `debug <method> [params...]` | Calls Debug API methods | `alchemy debug traceTransaction "0x..."` |
107
-
108
- ### Data
109
-
110
- | Command | What it does | Example |
111
- |---|---|---|
112
- | `tokens balances [address]` | Lists ERC-20 balances for an address | `alchemy tokens balances 0x...` |
113
- | `tokens metadata <contract>` | Gets ERC-20 metadata | `alchemy tokens metadata 0x...` |
114
- | `tokens allowance --owner --spender --contract` | Gets ERC-20 allowance | `alchemy tokens allowance --owner 0x... --spender 0x... --contract 0x...` |
115
- | `nfts [address]` | Lists NFTs owned by an address | `alchemy nfts 0x...` |
116
- | `nfts metadata --contract <addr> --token-id <id>` | Gets NFT metadata by contract/token | `alchemy nfts metadata --contract 0x... --token-id 1` |
117
- | `nfts contract <address>` | Gets NFT contract metadata | `alchemy nfts contract 0x...` |
118
- | `transfers [address]` | Gets transfer history (`alchemy_getAssetTransfers`) | `alchemy transfers 0x... --category erc20,erc721` |
119
- | `prices symbol <symbols>` | Gets current token prices by symbol | `alchemy prices symbol ETH,USDC` |
120
- | `prices address --addresses <json>` | Gets current token prices by address/network pairs | `alchemy prices address --addresses '[{"network":"eth-mainnet","address":"0x..."}]'` |
121
- | `prices historical --body <json>` | Gets historical prices | `alchemy prices historical --body '{"symbol":"ETH","startTime":"...","endTime":"..."}'` |
122
- | `portfolio tokens --body <json>` | Gets token portfolio data | `alchemy portfolio tokens --body '{...}'` |
123
- | `portfolio token-balances --body <json>` | Gets token balance snapshots | `alchemy portfolio token-balances --body '{...}'` |
124
- | `portfolio nfts --body <json>` | Gets NFT portfolio data | `alchemy portfolio nfts --body '{...}'` |
125
- | `portfolio nft-contracts --body <json>` | Gets NFT contract portfolio data | `alchemy portfolio nft-contracts --body '{...}'` |
126
- | `portfolio transactions --body <json>` | Gets portfolio transaction history | `alchemy portfolio transactions --body '{...}'` |
127
- | `simulate asset-changes --tx <json>` | Simulates asset changes | `alchemy simulate asset-changes --tx '{"from":"0x...","to":"0x..."}'` |
128
- | `simulate execution --tx <json>` | Simulates execution traces | `alchemy simulate execution --tx '{"from":"0x...","to":"0x..."}'` |
129
- | `simulate asset-changes-bundle --txs <json>` | Simulates bundle asset changes | `alchemy simulate asset-changes-bundle --txs '[{...}]'` |
130
- | `simulate execution-bundle --txs <json>` | Simulates bundle execution traces | `alchemy simulate execution-bundle --txs '[{...}]'` |
98
+ | `evm rpc <method> [params...]` | Makes raw Ethereum JSON-RPC calls | `alchemy evm rpc eth_blockNumber` |
99
+ | `evm data balance [address]` | Gets native token balance for an address | `alchemy evm data balance 0x...` |
100
+ | `evm data tokens balances [address]` | Lists ERC-20 balances for an address | `alchemy evm data tokens balances 0x...` |
101
+ | `evm data nfts [address]` | Lists NFTs owned by an address | `alchemy evm data nfts 0x...` |
102
+ | `evm data history [address]` | Gets transfer history (`alchemy_getAssetTransfers`) | `alchemy evm data history 0x... --category erc20,erc721` |
103
+ | `evm data price symbol <symbols>` | Gets current token prices by symbol | `alchemy evm data price symbol ETH,USDC` |
104
+ | `evm data portfolio tokens --body <json>` | Gets token portfolio data | `alchemy evm data portfolio tokens --body '{...}'` |
105
+ | `evm send <to> <amount>` | Sends native tokens or ERC-20 tokens | `alchemy evm send vitalik.eth 0.1 -n base-mainnet` |
106
+ | `evm contract read/call` | Reads or writes smart contracts | `alchemy evm contract read 0x... "balanceOf(address)(uint256)" --args '["0x..."]'` |
107
+ | `evm swap quote/execute` | Swaps tokens on the same chain | `alchemy evm swap quote --from 0xEeee... --to 0xA0b8... --amount 1` |
108
+ | `evm approve <spender_address>` | Approves an ERC-20 token allowance | `alchemy evm approve 0x... --token-address 0x... --amount 10` |
109
+ | `evm status [id]` | Checks transaction or operation status | `alchemy evm status 0x...` |
110
+ | `evm network list` | Lists RPC network IDs for use with `--network` | `alchemy evm network list --search base` |
111
+ | `evm tx/receipt/block/gas/logs` | Fetches common node resources | `alchemy evm block latest` |
112
+ | `evm trace/debug` | Calls Trace and Debug API methods | `alchemy evm trace call '{"to":"0x..."}' '["trace"]' latest` |
113
+ | `evm simulate *` | Calls simulation APIs | `alchemy evm simulate execution --tx '{"to":"0x..."}'` |
131
114
 
132
115
  ### Wallets
133
116
 
117
+ `alchemy wallets` exposes a unified onchain-actions surface. The **session wallet** (Alchemy/Privy-managed, P-256 delegated signer) is the recommended flow; a **local wallet** (private key stored on disk) is supported as an alternative and is currently the only path for Solana.
118
+
134
119
  | Command | What it does | Example |
135
120
  |---|---|---|
136
- | `wallet generate` | Generates wallet for x402 and saves to config | `alchemy wallet generate` |
137
- | `wallet import <path>` | Imports wallet key file for x402 | `alchemy wallet import ./private-key.txt` |
138
- | `wallet address` | Prints configured wallet address | `alchemy wallet address` |
139
- | `bundler send-user-operation ...` | Sends ERC-4337 user op | `alchemy bundler send-user-operation --user-op '{...}' --entry-point 0x...` |
140
- | `bundler estimate-user-operation-gas ...` | Estimates ERC-4337 user op gas | `alchemy bundler estimate-user-operation-gas --user-op '{...}' --entry-point 0x...` |
141
- | `bundler get-user-operation-receipt ...` | Gets ERC-4337 user op receipt | `alchemy bundler get-user-operation-receipt --user-op-hash 0x...` |
142
- | `gas-manager request-gas-and-paymaster --body <json>` | Requests paymaster data | `alchemy gas-manager request-gas-and-paymaster --body '{...}'` |
143
- | `gas-manager request-paymaster-token-quote --body <json>` | Gets paymaster token quote | `alchemy gas-manager request-paymaster-token-quote --body '{...}'` |
121
+ | `wallets connect` | Interactive: choose a session wallet (recommended) or a local wallet. For scripts, pass `--mode <session\|local>`. | `alchemy wallets connect` |
122
+ | `wallets connect --mode local --chain evm` | Create a new local EVM key (non-interactive). `--chain` accepts `evm`, `solana`, or `both`. | `alchemy wallets connect --mode local --chain both` |
123
+ | `wallets connect --mode local --import <path>` | Import an existing EVM private key from a file. | `alchemy wallets connect --mode local --import ./key.txt` |
124
+ | `wallets status [--verify]` | Reports session, local EVM, local Solana, and the active signer. `--verify` reconciles the session with the backend. | `alchemy wallets status --verify` |
125
+ | `wallets address` | Prints addresses for every configured signer. | `alchemy wallets address` |
126
+ | `wallets use <session\|local>` | Selects which signer `evm send`, `evm swap`, `evm approve`, `xchain bridge`, and `evm contract call` use for EVM transactions. | `alchemy wallets use local` |
127
+ | `wallets disconnect` | Revokes the current session (local + backend). Clears `active_signer` if it pointed at the session. | `alchemy wallets disconnect` |
128
+ | `wallets qr [--type <evm\|solana>]` | Renders a configured address as a QR code. | `alchemy wallets qr --type evm` |
129
+
130
+ Per-command override: pass `--signer <session\|local>` to `evm send`, `evm approve`, `evm swap`, `xchain bridge`, or `evm contract call` to override the active signer for a single invocation.
144
131
  | `webhooks list` | Lists Notify webhooks | `alchemy webhooks list --webhook-api-key <key>` |
145
132
  | `webhooks create --body <json>` | Creates Notify webhook | `alchemy webhooks create --body '{...}' --webhook-api-key <key>` |
146
133
  | `webhooks update --body <json>` | Updates Notify webhook | `alchemy webhooks update --body '{...}' --webhook-api-key <key>` |
@@ -150,9 +137,10 @@ Use `alchemy help` or `alchemy help <command>` for generated command help.
150
137
 
151
138
  | Command | What it does | Example |
152
139
  |---|---|---|
153
- | `network list` | Lists RPC network IDs for use with `--network` (e.g. `eth-mainnet`) | `alchemy network list --search ethereum` |
154
140
  | `solana rpc <method> [params...]` | Calls Solana JSON-RPC methods | `alchemy solana rpc getBalance '"<pubkey>"'` |
155
141
  | `solana das <method> [params...]` | Calls Solana DAS methods | `alchemy solana das getAssetsByOwner '{"ownerAddress":"<pubkey>"}'` |
142
+ | `solana network list` | Lists networks from the Solana namespace | `alchemy solana network list --search solana` |
143
+ | `xchain bridge quote/execute` | Bridges tokens across chains | `alchemy xchain bridge quote --from 0xEeee... --to 0xEeee... --amount 0.1 --to-network base-mainnet -n eth-mainnet` |
156
144
 
157
145
  ### CLI Admin
158
146
 
@@ -172,7 +160,9 @@ Use `alchemy help` or `alchemy help <command>` for generated command help.
172
160
  | `apps address-allowlist <id>` | Updates app address allowlist | `alchemy apps address-allowlist <app-id> --addresses 0xabc,0xdef` |
173
161
  | `apps origin-allowlist <id>` | Updates app origin allowlist | `alchemy apps origin-allowlist <app-id> --origins https://example.com` |
174
162
  | `apps ip-allowlist <id>` | Updates app IP allowlist | `alchemy apps ip-allowlist <app-id> --ips 1.2.3.4,5.6.7.8` |
175
- | `setup status` | Shows setup status + next commands | `alchemy setup status` |
163
+ | `doctor` | Runs readiness checks and suggestions | `alchemy doctor` |
164
+ | `install mcp` | Installs Alchemy's remote MCP server config | `alchemy install mcp --client claude --dry-run` |
165
+ | `install skills` | Installs bundled Alchemy skills | `alchemy install skills --client cursor --dry-run` |
176
166
  | `update-check` | Checks whether a newer CLI version is available | `alchemy update-check --json --no-interactive` |
177
167
  | `config set ...` | Sets config values | `alchemy config set api-key <key>` |
178
168
  | `config get <key>` | Gets one config value | `alchemy config get network` |
@@ -229,20 +219,16 @@ Additional env vars:
229
219
  | Command | Flags |
230
220
  |---|---|
231
221
  | `auth login` | `--force`, `-y, --yes` |
232
- | `nfts` | `--limit <n>`, `--page-key <key>` |
233
- | `nfts metadata` | `--contract <address>` (required), `--token-id <id>` (required) |
234
- | `tokens` | `--page-key <key>` |
235
- | `tokens allowance` | `--owner <address>` (required), `--spender <address>` (required), `--contract <address>` (required) |
236
- | `transfers` | `--from-address <address>`, `--to-address <address>`, `--from-block <block>`, `--to-block <block>`, `--category <list>`, `--max-count <n>`, `--page-key <key>` |
237
- | `prices address` | `--addresses <json>` (required) |
238
- | `prices historical` | `--body <json>` (required) |
239
- | `portfolio *` | `--body <json>` (required per subcommand) |
240
- | `simulate *` | `--tx <json>` or `--txs <json>` (required) |
222
+ | `evm data nfts` | `--limit <n>`, `--page-key <key>` |
223
+ | `evm data nfts metadata` | `--contract <address>` (required), `--token-id <id>` (required) |
224
+ | `evm data tokens balances` | `--page-key <key>` |
225
+ | `evm data tokens allowance` | `--owner <address>` (required), `--spender <address>` (required), `--contract <address>` (required) |
226
+ | `evm data history` | `--from-address <address>`, `--to-address <address>`, `--from-block <block>`, `--to-block <block>`, `--category <list>`, `--max-count <n>`, `--page-key <key>` |
227
+ | `evm data price address` | `--addresses <json>` (required) |
228
+ | `evm data price historical` | `--body <json>` (required) |
229
+ | `evm data portfolio *` | `--body <json>` (required per subcommand) |
230
+ | `evm simulate *` | `--tx <json>` or `--txs <json>` (required) |
241
231
  | `webhooks *` | `--webhook-api-key <key>` (or `ALCHEMY_WEBHOOK_API_KEY`, `ALCHEMY_NOTIFY_AUTH_TOKEN`, config `webhook-api-key`, or app webhook key) |
242
- | `bundler send-user-operation` | `--user-op <json>` (required), `--entry-point <address>` (required) |
243
- | `bundler estimate-user-operation-gas` | `--user-op <json>` (required), `--entry-point <address>` (required), `--state-override <json>` |
244
- | `bundler get-user-operation-receipt` | `--user-op-hash <hash>` (required) |
245
- | `gas-manager *` | `--body <json>` (required) |
246
232
  | `apps list` | `--cursor <cursor>`, `--limit <n>`, `--all`, `--search <query>`, `--id <appId>` |
247
233
  | `apps create` | `--name <name>` (required), `--networks <networks>` (required), `--description <desc>`, `--products <products>`, `--dry-run` |
248
234
  | `apps update` | `--name <name>`, `--description <desc>`, `--dry-run` |
@@ -251,7 +237,9 @@ Additional env vars:
251
237
  | `apps address-allowlist` | `--addresses <addrs>` (required), `--dry-run` |
252
238
  | `apps origin-allowlist` | `--origins <origins>` (required), `--dry-run` |
253
239
  | `apps ip-allowlist` | `--ips <ips>` (required), `--dry-run` |
254
- | `network list` | `--mainnet-only`, `--testnet-only`, `--search <term>` |
240
+ | `install mcp` | `--client <claude,cursor,codex,other,all>`, `--dry-run` |
241
+ | `install skills` | `--client <claude,cursor,codex,all>`, `--dry-run` |
242
+ | `evm network list` | `--mainnet-only`, `--testnet-only`, `--search <term>` |
255
243
  | `config reset` | `-y, --yes` |
256
244
 
257
245
  ## Authentication Reference
@@ -284,8 +272,8 @@ Run `alchemy` with no command in an interactive terminal:
284
272
 
285
273
  ```bash
286
274
  alchemy
287
- alchemy ◆ balance 0x...
288
- alchemy ◆ block latest
275
+ alchemy ◆ evm data balance 0x...
276
+ alchemy ◆ evm block latest
289
277
  alchemy ◆ exit
290
278
  ```
291
279
 
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
+ import {
4
+ registerAuth,
5
+ selectAppAfterAuth
6
+ } from "./chunk-NT3G6BKD.js";
7
+ import "./chunk-HSKKIATB.js";
8
+ import "./chunk-HYCRHNPX.js";
9
+ import "./chunk-PKAN5FKD.js";
10
+ import "./chunk-A6L3WCJN.js";
11
+ import "./chunk-B3R6PRAL.js";
12
+ import "./chunk-QEDAULQ2.js";
13
+ export {
14
+ registerAuth,
15
+ selectAppAfterAuth
16
+ };
@@ -2,24 +2,26 @@
2
2
  if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
3
  import {
4
4
  AUTH_PORT,
5
- OAUTH_CLIENT_ID,
5
+ DEFAULT_EXPIRES_IN_SECONDS,
6
+ completeLogin,
6
7
  exchangeCodeForToken,
7
- getAuthorizeUrl,
8
+ getLoginUrl,
8
9
  openBrowser,
9
10
  performBrowserLogin,
10
- prepareBrowserLogin,
11
+ prepareLogin,
11
12
  revokeToken,
12
13
  waitForCallback
13
- } from "./chunk-FFMNT74F.js";
14
- import "./chunk-56ZVYB4G.js";
14
+ } from "./chunk-HSKKIATB.js";
15
+ import "./chunk-QEDAULQ2.js";
15
16
  export {
16
17
  AUTH_PORT,
17
- OAUTH_CLIENT_ID,
18
+ DEFAULT_EXPIRES_IN_SECONDS,
19
+ completeLogin,
18
20
  exchangeCodeForToken,
19
- getAuthorizeUrl,
21
+ getLoginUrl,
20
22
  openBrowser,
21
23
  performBrowserLogin,
22
- prepareBrowserLogin,
24
+ prepareLogin,
23
25
  revokeToken,
24
26
  waitForCallback
25
27
  };
@@ -2,10 +2,10 @@
2
2
  if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
3
  import {
4
4
  configPath
5
- } from "./chunk-BAAQ7ELR.js";
5
+ } from "./chunk-B3R6PRAL.js";
6
6
  import {
7
7
  esc
8
- } from "./chunk-56ZVYB4G.js";
8
+ } from "./chunk-QEDAULQ2.js";
9
9
 
10
10
  // src/lib/update-check.ts
11
11
  import { execFileSync } from "child_process";
@@ -53,7 +53,7 @@ function semverLT(a, b) {
53
53
  return false;
54
54
  }
55
55
  function currentVersion() {
56
- return true ? "0.6.2" : "0.0.0";
56
+ return true ? "0.7.0-alpha.5" : "0.0.0";
57
57
  }
58
58
  function toUpdateStatus(latestVersion, checkedAt) {
59
59
  const current = currentVersion();
@@ -5,7 +5,7 @@ import {
5
5
  isJSONMode,
6
6
  quiet,
7
7
  rgb
8
- } from "./chunk-56ZVYB4G.js";
8
+ } from "./chunk-QEDAULQ2.js";
9
9
 
10
10
  // src/lib/terminal-ui.ts
11
11
  import * as readline from "readline";
@@ -48,6 +48,9 @@ function suspendStdinKeypressListeners() {
48
48
  }
49
49
  async function runListPrompt(opts) {
50
50
  if (!stdin.isTTY || !stdout.isTTY) {
51
+ if (opts.allowMultiple) {
52
+ return { value: opts.initialValues ?? [], cancelled: false };
53
+ }
51
54
  const initial = opts.initialValue ?? opts.options.find((o) => !o.disabled)?.value ?? null;
52
55
  return { value: initial, cancelled: false };
53
56
  }
@@ -61,7 +64,7 @@ async function runListPrompt(opts) {
61
64
  0,
62
65
  opts.options.findIndex((o) => o.value === opts.initialValue && !o.disabled)
63
66
  );
64
- const selected = /* @__PURE__ */ new Set();
67
+ const selected = new Set(opts.initialValues ?? []);
65
68
  const maxVisible = 8;
66
69
  let renderedLines = 0;
67
70
  const getFiltered = () => {
@@ -104,10 +107,11 @@ async function runListPrompt(opts) {
104
107
  const active = start + i === cursor;
105
108
  const disabled = option.disabled === true;
106
109
  const selectedMark = opts.allowMultiple ? selected.has(option.value) ? ansi.green("\u25C6") : ansi.dim("\u25C7") : active ? ansi.cyan("\u25C6") : ansi.dim("\u25C7");
110
+ const activeMark = active ? ansi.cyan("\u203A") : " ";
107
111
  const label = optionLabel(option);
108
112
  const value = disabled ? ansi.dim(label) : label;
109
113
  const hint = option.hint ? ` ${ansi.dim(`\u2014 ${option.hint}`)}` : "";
110
- lines.push(` ${ansi.dim(FLOW_PIPE)} ${selectedMark} ${value}${hint}`);
114
+ lines.push(` ${ansi.dim(FLOW_PIPE)} ${activeMark} ${selectedMark} ${value}${hint}`);
111
115
  }
112
116
  if (filtered.length > maxVisible) {
113
117
  lines.push(` ${ansi.dim(FLOW_PIPE)} ${ansi.dim(`${filtered.length} options`)}`);
@@ -217,16 +221,26 @@ async function promptText(opts) {
217
221
  const question = ` ${ansi.cyan("\u25C6")} ${opts.message}${opts.placeholder ? ` ${ansi.dim(`(${opts.placeholder})`)}` : ""}: `;
218
222
  const previousRawMode = stdin.isRaw;
219
223
  if (previousRawMode) stdin.setRawMode(false);
224
+ const ABORTED = /* @__PURE__ */ Symbol("aborted");
220
225
  const value = await new Promise((resolve) => {
221
226
  rl.on("SIGINT", () => resolve(null));
222
227
  rl.question(question, (answer) => resolve(answer));
228
+ if (opts.abortSignal) {
229
+ const onAbort = () => resolve(ABORTED);
230
+ if (opts.abortSignal.aborted) {
231
+ onAbort();
232
+ } else {
233
+ opts.abortSignal.addEventListener("abort", onAbort, { once: true });
234
+ }
235
+ }
223
236
  });
224
237
  rl.close();
225
238
  restoreKeypressListeners();
226
239
  if (previousRawMode) stdin.setRawMode(true);
227
- if (opts.clearAfterSubmit) {
240
+ if (opts.clearAfterSubmit || value === ABORTED) {
228
241
  clearRenderedLines(2);
229
242
  }
243
+ if (value === ABORTED) return "";
230
244
  if (value === null) {
231
245
  printCancel(opts.cancelMessage);
232
246
  return null;
@@ -281,6 +295,7 @@ async function promptMultiselect(opts) {
281
295
  const result = await runListPrompt({
282
296
  message: opts.message,
283
297
  options: opts.options,
298
+ initialValues: opts.initialValues,
284
299
  allowMultiple: true,
285
300
  required: opts.required,
286
301
  commitLabel: "Selected"
@@ -362,29 +377,24 @@ async function withSpinner(label, doneLabel, fn) {
362
377
  if (isJSONMode() || quiet) return fn();
363
378
  return runWithSpinner(label, doneLabel, fn);
364
379
  }
365
- function printKeyValueBox(pairs) {
380
+ function printKeyValue(pairs, withBottomPadding = true) {
366
381
  if (isJSONMode()) return;
382
+ console.log("");
367
383
  if (pairs.length === 0) {
368
- console.log(` ${ansi2.brand("\u250C\u2500\u2500\u2510")}`);
369
- console.log(` ${ansi2.brand("\u2514\u2500\u2500\u2518")}`);
384
+ if (withBottomPadding) {
385
+ console.log("");
386
+ }
370
387
  return;
371
388
  }
372
- const keyWidth = Math.max(...pairs.map(([k]) => stripAnsi(k).length));
373
- const contentRows = pairs.map(([key, value]) => {
389
+ const maxLen = Math.max(...pairs.map(([k]) => stripAnsi(k).length));
390
+ for (const [key, value] of pairs) {
374
391
  const visibleKeyLen = stripAnsi(key).length;
375
- const paddedKey = key + " ".repeat(Math.max(0, keyWidth - visibleKeyLen));
376
- return `${ansi2.dim(paddedKey)} ${value}`;
377
- });
378
- const contentWidth = Math.max(...contentRows.map((row) => stripAnsi(row).length));
379
- const top = `\u250C${"\u2500".repeat(contentWidth + 2)}\u2510`;
380
- const bottom = `\u2514${"\u2500".repeat(contentWidth + 2)}\u2518`;
381
- console.log(` ${ansi2.dim(top)}`);
382
- for (const row of contentRows) {
383
- const visibleLen = stripAnsi(row).length;
384
- const padded = row + " ".repeat(Math.max(0, contentWidth - visibleLen));
385
- console.log(` ${ansi2.dim("\u2502")} ${padded} ${ansi2.dim("\u2502")}`);
392
+ const paddedKey = key + " ".repeat(Math.max(0, maxLen - visibleKeyLen));
393
+ console.log(` ${ansi2.dim(paddedKey)} ${value}`);
394
+ }
395
+ if (withBottomPadding) {
396
+ console.log("");
386
397
  }
387
- console.log(` ${ansi2.dim(bottom)}`);
388
398
  }
389
399
  function emptyState(message) {
390
400
  if (isJSONMode()) return;
@@ -543,7 +553,7 @@ export {
543
553
  successBadge,
544
554
  failBadge,
545
555
  withSpinner,
546
- printKeyValueBox,
556
+ printKeyValue,
547
557
  emptyState,
548
558
  printSyntaxJSON,
549
559
  printTable,
@@ -2,7 +2,7 @@
2
2
  if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
3
  import {
4
4
  isRevealMode
5
- } from "./chunk-56ZVYB4G.js";
5
+ } from "./chunk-QEDAULQ2.js";
6
6
 
7
7
  // src/lib/secrets.ts
8
8
  function maskSecret(value) {
@@ -35,7 +35,23 @@ var KEY_MAP = {
35
35
  "auth-token": "auth_token",
36
36
  auth_token: "auth_token",
37
37
  "auth-token-expires-at": "auth_token_expires_at",
38
- auth_token_expires_at: "auth_token_expires_at"
38
+ auth_token_expires_at: "auth_token_expires_at",
39
+ "solana-wallet-key-file": "solana_wallet_key_file",
40
+ solana_wallet_key_file: "solana_wallet_key_file",
41
+ "solana-wallet-address": "solana_wallet_address",
42
+ solana_wallet_address: "solana_wallet_address",
43
+ "evm-gas-sponsored": "evm_gas_sponsored",
44
+ evm_gas_sponsored: "evm_gas_sponsored",
45
+ "evm-gas-policy-id": "evm_gas_policy_id",
46
+ evm_gas_policy_id: "evm_gas_policy_id",
47
+ "solana-fee-sponsored": "solana_fee_sponsored",
48
+ solana_fee_sponsored: "solana_fee_sponsored",
49
+ "solana-fee-policy-id": "solana_fee_policy_id",
50
+ solana_fee_policy_id: "solana_fee_policy_id",
51
+ "delegated-wallet": "delegated_wallet",
52
+ delegated_wallet: "delegated_wallet",
53
+ "active-signer": "active_signer",
54
+ active_signer: "active_signer"
39
55
  };
40
56
  var SAFE_ID_RE = /^[A-Za-z0-9:_-]{1,128}$/;
41
57
  var SAFE_NETWORK_RE = /^[A-Za-z0-9:_-]{1,128}$/;
@@ -63,7 +79,15 @@ var configSchema = z.object({
63
79
  auth_token: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
64
80
  auth_token_expires_at: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
65
81
  siwe_token: safeTextSchema(MAX_PATH_LEN).optional().catch(void 0),
66
- siwe_token_expires_at: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0)
82
+ siwe_token_expires_at: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
83
+ solana_wallet_key_file: safeTextSchema(MAX_PATH_LEN).optional().catch(void 0),
84
+ solana_wallet_address: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
85
+ evm_gas_sponsored: z.boolean().optional().catch(void 0),
86
+ evm_gas_policy_id: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
87
+ solana_fee_sponsored: z.boolean().optional().catch(void 0),
88
+ solana_fee_policy_id: safeTextSchema(MAX_SECRET_LEN).optional().catch(void 0),
89
+ delegated_wallet: z.boolean().optional().catch(void 0),
90
+ active_signer: z.enum(["session", "local"]).optional().catch(void 0)
67
91
  }).strip();
68
92
  function sanitizeConfig(input) {
69
93
  const parsed = configSchema.safeParse(input);
@@ -72,6 +96,13 @@ function sanitizeConfig(input) {
72
96
  }
73
97
  return parsed.data;
74
98
  }
99
+ function applyLegacyMigration(cfg) {
100
+ if (cfg.active_signer === void 0 && cfg.delegated_wallet === true) {
101
+ const { delegated_wallet: _, ...rest } = cfg;
102
+ return { ...rest, active_signer: "session" };
103
+ }
104
+ return cfg;
105
+ }
75
106
  function getHome() {
76
107
  return process.env.HOME || homedir();
77
108
  }
@@ -88,7 +119,7 @@ function load() {
88
119
  if (!existsSync(p)) return {};
89
120
  try {
90
121
  const data = readFileSync(p, "utf-8");
91
- return sanitizeConfig(JSON.parse(data));
122
+ return applyLegacyMigration(sanitizeConfig(JSON.parse(data)));
92
123
  } catch {
93
124
  console.error(`warning: could not parse config file at ${p} \u2014 using defaults`);
94
125
  return {};
@@ -97,6 +128,7 @@ function load() {
97
128
  function save(cfg) {
98
129
  const p = configPath();
99
130
  const sanitized = sanitizeConfig(cfg);
131
+ delete sanitized.delegated_wallet;
100
132
  mkdirSync(dirname(p), { recursive: true, mode: 493 });
101
133
  writeFileSync(p, JSON.stringify(sanitized, null, 2) + "\n", {
102
134
  mode: 384
@@ -115,6 +147,21 @@ function get(cfg, key) {
115
147
  if (typeof value === "string") return value;
116
148
  return void 0;
117
149
  }
150
+ function validKeys() {
151
+ return [
152
+ "api-key",
153
+ "access-key",
154
+ "webhook-api-key",
155
+ "network",
156
+ "verbose",
157
+ "wallet-key-file",
158
+ "x402",
159
+ "evm-gas-sponsored",
160
+ "evm-gas-policy-id",
161
+ "solana-fee-sponsored",
162
+ "solana-fee-policy-id"
163
+ ];
164
+ }
118
165
  function toMap(cfg) {
119
166
  const m = {};
120
167
  if (cfg.api_key) m["api-key"] = maskIf(cfg.api_key);
@@ -128,6 +175,13 @@ function toMap(cfg) {
128
175
  if (cfg.x402 !== void 0) m["x402"] = String(cfg.x402);
129
176
  if (cfg.auth_token) m["auth-token"] = maskIf(cfg.auth_token);
130
177
  if (cfg.auth_token_expires_at) m["auth-token-expires-at"] = cfg.auth_token_expires_at;
178
+ if (cfg.solana_wallet_key_file) m["solana-wallet-key-file"] = cfg.solana_wallet_key_file;
179
+ if (cfg.solana_wallet_address) m["solana-wallet-address"] = cfg.solana_wallet_address;
180
+ if (cfg.evm_gas_sponsored !== void 0) m["evm-gas-sponsored"] = String(cfg.evm_gas_sponsored);
181
+ if (cfg.evm_gas_policy_id) m["evm-gas-policy-id"] = cfg.evm_gas_policy_id;
182
+ if (cfg.solana_fee_sponsored !== void 0) m["solana-fee-sponsored"] = String(cfg.solana_fee_sponsored);
183
+ if (cfg.solana_fee_policy_id) m["solana-fee-policy-id"] = cfg.solana_fee_policy_id;
184
+ if (cfg.active_signer !== void 0) m["active-signer"] = cfg.active_signer;
131
185
  return m;
132
186
  }
133
187
 
@@ -139,5 +193,6 @@ export {
139
193
  load,
140
194
  save,
141
195
  get,
196
+ validKeys,
142
197
  toMap
143
198
  };