@vultisig/cli 2.19.7 → 2.19.10

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/CHANGELOG.md +47 -0
  2. package/dist/index.js +276 -223
  3. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,52 @@
1
1
  # @vultisig/cli
2
2
 
3
+ ## 2.19.10
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1076](https://github.com/vultisig/vultisig-sdk/pull/1076) [`5179edd`](https://github.com/vultisig/vultisig-sdk/commit/5179edd9eb25b392941f9649a455e92bfd5bf8b5) Thanks [@neavra](https://github.com/neavra)! - fix(chains): validate `chains --add <chain>` against the registry before persisting
8
+
9
+ An invalid `chains --add fakechain` correctly reported INVALID_CHAIN but still wrote
10
+ "fakechain" to the vault's chain list (chain resolution falls back to the raw user
11
+ string when the name doesn't match the registry). Every subsequent address-deriving
12
+ command then re-derived the bogus chain and dumped a stack trace to stderr until it was
13
+ manually removed. The `--add` path now validates against the supported-chain registry
14
+ first and fails closed — nothing is persisted for an unsupported chain.
15
+
16
+ - [#1127](https://github.com/vultisig/vultisig-sdk/pull/1127) [`dea1efa`](https://github.com/vultisig/vultisig-sdk/commit/dea1efae6fbd2975de4ac5a26b2e8210999a0f4f) Thanks [@neavra](https://github.com/neavra)! - fix(cli): honor VULTISIG_CONFIG_DIR for vault storage
17
+
18
+ The documented `VULTISIG_CONFIG_DIR` env var was a no-op for vault storage: the
19
+ CLI constructed the SDK without a storage override, so vaults, the active-vault
20
+ pointer and cache always resolved to `~/.vultisig` even when the var pointed
21
+ elsewhere — only `config.json` and the agent journal honored it, producing a
22
+ split-brain config location that broke CI/container isolation and multi-tenant
23
+ use. The CLI now roots SDK vault storage at `getConfigDir()` via a shared
24
+ `createVaultStorage()` helper. When the var is unset it falls back to
25
+ `~/.vultisig`, so the default location is unchanged.
26
+
27
+ - [#1126](https://github.com/vultisig/vultisig-sdk/pull/1126) [`6054ff5`](https://github.com/vultisig/vultisig-sdk/commit/6054ff599e4133c9853f31e8ca2413ab52f606fb) Thanks [@neavra](https://github.com/neavra)! - fix(mpc): keep keygen tracing off stdout so `-o json` output stays parseable
28
+
29
+ The DKLS and Schnorr keygen/reshare/key-import ceremonies logged progress
30
+ (session ids, raw wire messages, "keygen complete", …) to stdout via ungated
31
+ `console.log`. stdout is the machine channel for the CLI's `-o json` mode, so
32
+ the documented `create fast … -o json` agent flow produced unparseable stdout
33
+ (`JSON.parse(stdout)` failed on the leading garbage) and leaked MPC internals
34
+ into terminals and CI logs.
35
+
36
+ Route that tracing through a gated logger that writes to stderr only when
37
+ `VULTISIG_DEBUG=1`, so stdout carries only the final JSON envelope while
38
+ the debug output stays available to humans on demand. No keygen behavior
39
+ changes — only the log sink moves off stdout.
40
+
41
+ - [#1077](https://github.com/vultisig/vultisig-sdk/pull/1077) [`5e5494c`](https://github.com/vultisig/vultisig-sdk/commit/5e5494cf103ea5c17431b6a6231b30931eb004bb) Thanks [@neavra](https://github.com/neavra)! - Tolerate a corrupt `activeVaultId.json` at startup. A truncated or unparseable
42
+ active-vault pointer used to throw during CLI initialization, which broke every
43
+ command — including `vultisig vaults`, the one you run to recover. The pointer
44
+ read now fails open (treated as "no active vault") and self-heals by clearing
45
+ the bad pointer, so vaults still list with none marked active.
46
+ - Updated dependencies [[`280956f`](https://github.com/vultisig/vultisig-sdk/commit/280956f1743564ea271a03c4735f70151b63f161), [`90070f3`](https://github.com/vultisig/vultisig-sdk/commit/90070f39be011821f7508c7ff094025861dce040), [`0e3f86d`](https://github.com/vultisig/vultisig-sdk/commit/0e3f86db82ed086b1e200a6f83434a638f593c17), [`6054ff5`](https://github.com/vultisig/vultisig-sdk/commit/6054ff599e4133c9853f31e8ca2413ab52f606fb), [`b37e726`](https://github.com/vultisig/vultisig-sdk/commit/b37e7264db3291adca1cb366f1311446d6add439), [`1b2636b`](https://github.com/vultisig/vultisig-sdk/commit/1b2636b535736a711fc537a87d2f51090fe6342d), [`2c9d34e`](https://github.com/vultisig/vultisig-sdk/commit/2c9d34e0837f68d92769c7aefa566ffb1c0c52c7), [`ffc75a6`](https://github.com/vultisig/vultisig-sdk/commit/ffc75a6e76af699a78b0fc3411ab052ce5000c91), [`fc595a1`](https://github.com/vultisig/vultisig-sdk/commit/fc595a17cb4901af1dfeac2521b93bb75823068f), [`776c539`](https://github.com/vultisig/vultisig-sdk/commit/776c5398764314f140f18ab4f86a1801fe9fdfe6)]:
47
+ - @vultisig/sdk@2.19.10
48
+ - @vultisig/core-chain@2.24.2
49
+
3
50
  ## 2.19.7
4
51
 
5
52
  ### Patch Changes
package/dist/index.js CHANGED
@@ -5899,234 +5899,33 @@ async function executePortfolio(ctx2, options = {}) {
5899
5899
  // src/commands/chains.ts
5900
5900
  import { SUPPORTED_CHAINS } from "@vultisig/sdk";
5901
5901
  import chalk3 from "chalk";
5902
- async function executeChains(ctx2, options = {}) {
5903
- const vault = await ctx2.ensureActiveVault();
5904
- if (options.addAll) {
5905
- const currentCount = vault.chains.length;
5906
- const spinner = createSpinner(`Adding all ${SUPPORTED_CHAINS.length} supported chains...`);
5907
- await vault.setChains([...SUPPORTED_CHAINS]);
5908
- const addedCount = SUPPORTED_CHAINS.length - currentCount;
5909
- spinner.succeed(`Added ${addedCount} chains (${SUPPORTED_CHAINS.length} total)`);
5910
- if (isJsonOutput()) {
5911
- outputJson({ chains: [...vault.chains], added: addedCount, total: SUPPORTED_CHAINS.length });
5912
- return;
5913
- }
5914
- info(chalk3.gray("\nAll supported chains are now enabled."));
5915
- return;
5916
- }
5917
- if (options.add) {
5918
- const alreadyActive = vault.chains.includes(options.add);
5919
- if (!alreadyActive) {
5920
- await vault.addChain(options.add);
5921
- }
5922
- const address = await vault.address(options.add);
5923
- if (isJsonOutput()) {
5924
- outputJson({ chain: options.add, alreadyActive, address, chains: [...vault.chains] });
5925
- return;
5926
- }
5927
- success(alreadyActive ? `
5928
- Chain already active: ${options.add}` : `
5929
- + Added chain: ${options.add}`);
5930
- info(`Address: ${address}`);
5931
- } else if (options.remove) {
5932
- await vault.removeChain(options.remove);
5933
- if (isJsonOutput()) {
5934
- outputJson({ chain: options.remove, removed: true, chains: [...vault.chains] });
5935
- return;
5936
- }
5937
- success(`
5938
- + Removed chain: ${options.remove}`);
5939
- } else {
5940
- const chains = vault.chains;
5941
- if (isJsonOutput()) {
5942
- outputJson({ chains: [...chains] });
5943
- return;
5944
- }
5945
- printResult(chalk3.cyan("\nActive Chains:\n"));
5946
- chains.forEach((chain) => {
5947
- printResult(` - ${chain}`);
5948
- });
5949
- info(chalk3.gray(`
5950
- ${chains.length} of ${SUPPORTED_CHAINS.length} chains enabled`));
5951
- info(chalk3.gray("Use --add <chain>, --add-all, or --remove <chain>"));
5952
- }
5953
- }
5954
- async function executeAddresses(ctx2) {
5955
- const vault = await ctx2.ensureActiveVault();
5956
- const spinner = createSpinner("Loading addresses...");
5957
- const addresses = await vault.addresses();
5958
- spinner.succeed("Addresses loaded");
5959
- if (isJsonOutput()) {
5960
- outputJson({ addresses });
5961
- return;
5962
- }
5963
- displayAddresses(addresses);
5964
- }
5965
5902
 
5966
- // src/commands/tokens.ts
5967
- import chalk4 from "chalk";
5968
- import inquirer3 from "inquirer";
5969
- async function executeTokens(ctx2, options) {
5970
- await ctx2.ensureActiveVault();
5971
- if (options.discover) {
5972
- await discoverTokens(ctx2, options.chain);
5973
- return;
5974
- }
5975
- if (options.add) {
5976
- let symbol = options.symbol;
5977
- let name = options.name;
5978
- let decimals = options.decimals;
5979
- const prompts = [];
5980
- if (!symbol) {
5981
- prompts.push({
5982
- type: "input",
5983
- name: "symbol",
5984
- message: "Enter token symbol (e.g., USDT):",
5985
- validate: (input) => input.trim() !== "" || "Symbol is required"
5986
- });
5987
- }
5988
- if (!name) {
5989
- prompts.push({
5990
- type: "input",
5991
- name: "name",
5992
- message: "Enter token name (e.g., Tether USD):",
5993
- validate: (input) => input.trim() !== "" || "Name is required"
5994
- });
5995
- }
5996
- if (decimals === void 0) {
5997
- prompts.push({
5998
- type: "number",
5999
- name: "decimals",
6000
- message: "Enter token decimals:",
6001
- default: 18,
6002
- validate: (input) => input >= 0 || "Decimals must be non-negative"
6003
- });
6004
- }
6005
- if (prompts.length > 0) {
6006
- requireInteractive("Provide --symbol, --name, and --decimals flags for non-interactive token addition.");
6007
- const answers = await inquirer3.prompt(prompts);
6008
- symbol = symbol || answers.symbol?.trim();
6009
- name = name || answers.name?.trim();
6010
- decimals = decimals ?? answers.decimals;
6011
- }
6012
- await addToken(ctx2, {
6013
- chain: options.chain,
6014
- contractAddress: options.add,
6015
- symbol,
6016
- name,
6017
- decimals
6018
- });
6019
- } else if (options.remove) {
6020
- await removeToken(ctx2, options.chain, options.remove);
6021
- } else {
6022
- await listTokens(ctx2, options.chain);
6023
- }
6024
- }
6025
- async function addToken(ctx2, options) {
6026
- const vault = await ctx2.ensureActiveVault();
6027
- await vault.addToken(options.chain, {
6028
- id: `${options.chain}-${options.contractAddress}`,
6029
- contractAddress: options.contractAddress,
6030
- symbol: options.symbol,
6031
- name: options.name,
6032
- decimals: options.decimals,
6033
- chainId: options.chain,
6034
- isNative: false
6035
- });
6036
- success(`
6037
- + Added token ${options.symbol} on ${options.chain}`);
6038
- }
6039
- async function removeToken(ctx2, chain, tokenId) {
6040
- const vault = await ctx2.ensureActiveVault();
6041
- await vault.removeToken(chain, tokenId);
6042
- success(`
6043
- + Removed token ${tokenId} from ${chain}`);
6044
- }
6045
- async function discoverTokens(ctx2, chain) {
6046
- const vault = await ctx2.ensureActiveVault();
6047
- const spinner = createSpinner(`Discovering tokens on ${chain}...`);
6048
- let discovered;
5903
+ // src/core/active-vault.ts
5904
+ var ACTIVE_VAULT_ID_KEY = "activeVaultId";
5905
+ async function loadActiveVaultSafely(sdk) {
5906
+ let activeId;
6049
5907
  try {
6050
- discovered = await vault.discoverTokens(chain);
5908
+ activeId = await sdk.storage.get(ACTIVE_VAULT_ID_KEY);
6051
5909
  } catch (err) {
6052
- spinner.fail(`Token discovery failed for ${chain}`);
6053
- throw err;
6054
- }
6055
- if (discovered.length === 0) {
6056
- spinner.succeed(`No new tokens found on ${chain}`);
6057
- if (isJsonOutput()) {
6058
- outputJson({ chain, discovered: [], count: 0 });
5910
+ process.stderr.write(
5911
+ `Warning: active vault pointer is unreadable and was ignored (no active vault). ${err?.message ?? ""}
5912
+ `
5913
+ );
5914
+ try {
5915
+ await sdk.setActiveVault(null);
5916
+ } catch {
6059
5917
  }
6060
- return;
6061
- }
6062
- const existingTokens = vault.getTokens(chain);
6063
- const existingAddresses = new Set(existingTokens.map((t) => t.contractAddress ?? t.id));
6064
- const newTokens = discovered.filter((d) => d.contractAddress && !existingAddresses.has(d.contractAddress));
6065
- for (const d of newTokens) {
6066
- await vault.addToken(chain, {
6067
- id: d.contractAddress,
6068
- symbol: d.ticker,
6069
- name: d.ticker,
6070
- decimals: d.decimals,
6071
- contractAddress: d.contractAddress,
6072
- chainId: chain,
6073
- isNative: false
6074
- });
5918
+ return { vault: null, corruptPointer: true };
6075
5919
  }
6076
- const allTokens = vault.getTokens(chain);
6077
- spinner.succeed(`Discovered ${newTokens.length} new token(s) on ${chain}`);
6078
- if (isJsonOutput()) {
6079
- outputJson({
6080
- chain,
6081
- discovered: newTokens.map((d) => ({
6082
- symbol: d.ticker,
6083
- contractAddress: d.contractAddress,
6084
- decimals: d.decimals
6085
- })),
6086
- count: newTokens.length
6087
- });
6088
- return;
5920
+ if (activeId === null || activeId === void 0) {
5921
+ return { vault: null, corruptPointer: false };
6089
5922
  }
6090
- for (const d of newTokens) {
6091
- printResult(` ${d.ticker} (${d.contractAddress})`);
6092
- }
6093
- info(chalk4.gray(`
6094
- ${allTokens.length} total token(s) tracked on ${chain}`));
5923
+ return { vault: await sdk.getVaultById(activeId), corruptPointer: false };
6095
5924
  }
6096
- async function listTokens(ctx2, chain) {
6097
- const vault = await ctx2.ensureActiveVault();
6098
- const spinner = createSpinner(`Loading tokens for ${chain}...`);
6099
- const tokens = vault.getTokens(chain);
6100
- spinner.succeed(`Tokens loaded for ${chain}`);
6101
- if (isJsonOutput()) {
6102
- outputJson({ chain, tokens: tokens || [] });
6103
- return;
6104
- }
6105
- if (!tokens || tokens.length === 0) {
6106
- warn(`
6107
- No tokens configured for ${chain}`);
6108
- info(chalk4.gray(`
6109
- Use --add <contractAddress> to add a token`));
6110
- } else {
6111
- printResult(chalk4.cyan(`
6112
- Tokens for ${chain}:
6113
- `));
6114
- const table = tokens.map((token) => ({
6115
- Symbol: token.symbol,
6116
- Name: token.name,
6117
- Contract: token.contractAddress || "N/A",
6118
- Decimals: token.decimals,
6119
- Native: token.isNative ? "Yes" : "No"
6120
- }));
6121
- printTable(table);
6122
- info(chalk4.gray(`
6123
- Use --add <contractAddress> to add or --remove <tokenId> to remove`));
6124
- }
5925
+ function shouldAutoSelectActiveVault(hasActiveVault, corruptPointer, vaultCount) {
5926
+ return !hasActiveVault && !corruptPointer && vaultCount > 0;
6125
5927
  }
6126
5928
 
6127
- // src/commands/transaction.ts
6128
- import { Chain, Vultisig as Vultisig2 } from "@vultisig/sdk";
6129
-
6130
5929
  // src/agent/broadcastJournal.ts
6131
5930
  import { createHash } from "node:crypto";
6132
5931
  import {
@@ -6703,7 +6502,242 @@ import { getConfigPath, loadConfig, saveConfig } from "@vultisig/client-shared";
6703
6502
  // src/core/vault-discovery.ts
6704
6503
  import { discoverVaultFiles, SEARCH_DIRS } from "@vultisig/client-shared";
6705
6504
 
6505
+ // src/commands/chains.ts
6506
+ async function executeChains(ctx2, options = {}) {
6507
+ const vault = await ctx2.ensureActiveVault();
6508
+ if (options.addAll) {
6509
+ const currentCount = vault.chains.length;
6510
+ const spinner = createSpinner(`Adding all ${SUPPORTED_CHAINS.length} supported chains...`);
6511
+ await vault.setChains([...SUPPORTED_CHAINS]);
6512
+ const addedCount = SUPPORTED_CHAINS.length - currentCount;
6513
+ spinner.succeed(`Added ${addedCount} chains (${SUPPORTED_CHAINS.length} total)`);
6514
+ if (isJsonOutput()) {
6515
+ outputJson({ chains: [...vault.chains], added: addedCount, total: SUPPORTED_CHAINS.length });
6516
+ return;
6517
+ }
6518
+ info(chalk3.gray("\nAll supported chains are now enabled."));
6519
+ return;
6520
+ }
6521
+ if (options.add) {
6522
+ if (!SUPPORTED_CHAINS.includes(options.add)) {
6523
+ throw new InvalidChainError(
6524
+ `Unsupported chain: "${options.add}"`,
6525
+ 'Run "vultisig chains" to see the supported chains, or check the spelling.',
6526
+ void 0,
6527
+ { chain: String(options.add) }
6528
+ );
6529
+ }
6530
+ const alreadyActive = vault.chains.includes(options.add);
6531
+ if (!alreadyActive) {
6532
+ await vault.addChain(options.add);
6533
+ }
6534
+ const address = await vault.address(options.add);
6535
+ if (isJsonOutput()) {
6536
+ outputJson({ chain: options.add, alreadyActive, address, chains: [...vault.chains] });
6537
+ return;
6538
+ }
6539
+ success(alreadyActive ? `
6540
+ Chain already active: ${options.add}` : `
6541
+ + Added chain: ${options.add}`);
6542
+ info(`Address: ${address}`);
6543
+ } else if (options.remove) {
6544
+ await vault.removeChain(options.remove);
6545
+ if (isJsonOutput()) {
6546
+ outputJson({ chain: options.remove, removed: true, chains: [...vault.chains] });
6547
+ return;
6548
+ }
6549
+ success(`
6550
+ + Removed chain: ${options.remove}`);
6551
+ } else {
6552
+ const chains = vault.chains;
6553
+ if (isJsonOutput()) {
6554
+ outputJson({ chains: [...chains] });
6555
+ return;
6556
+ }
6557
+ printResult(chalk3.cyan("\nActive Chains:\n"));
6558
+ chains.forEach((chain) => {
6559
+ printResult(` - ${chain}`);
6560
+ });
6561
+ info(chalk3.gray(`
6562
+ ${chains.length} of ${SUPPORTED_CHAINS.length} chains enabled`));
6563
+ info(chalk3.gray("Use --add <chain>, --add-all, or --remove <chain>"));
6564
+ }
6565
+ }
6566
+ async function executeAddresses(ctx2) {
6567
+ const vault = await ctx2.ensureActiveVault();
6568
+ const spinner = createSpinner("Loading addresses...");
6569
+ const addresses = await vault.addresses();
6570
+ spinner.succeed("Addresses loaded");
6571
+ if (isJsonOutput()) {
6572
+ outputJson({ addresses });
6573
+ return;
6574
+ }
6575
+ displayAddresses(addresses);
6576
+ }
6577
+
6578
+ // src/commands/tokens.ts
6579
+ import chalk4 from "chalk";
6580
+ import inquirer3 from "inquirer";
6581
+ async function executeTokens(ctx2, options) {
6582
+ await ctx2.ensureActiveVault();
6583
+ if (options.discover) {
6584
+ await discoverTokens(ctx2, options.chain);
6585
+ return;
6586
+ }
6587
+ if (options.add) {
6588
+ let symbol = options.symbol;
6589
+ let name = options.name;
6590
+ let decimals = options.decimals;
6591
+ const prompts = [];
6592
+ if (!symbol) {
6593
+ prompts.push({
6594
+ type: "input",
6595
+ name: "symbol",
6596
+ message: "Enter token symbol (e.g., USDT):",
6597
+ validate: (input) => input.trim() !== "" || "Symbol is required"
6598
+ });
6599
+ }
6600
+ if (!name) {
6601
+ prompts.push({
6602
+ type: "input",
6603
+ name: "name",
6604
+ message: "Enter token name (e.g., Tether USD):",
6605
+ validate: (input) => input.trim() !== "" || "Name is required"
6606
+ });
6607
+ }
6608
+ if (decimals === void 0) {
6609
+ prompts.push({
6610
+ type: "number",
6611
+ name: "decimals",
6612
+ message: "Enter token decimals:",
6613
+ default: 18,
6614
+ validate: (input) => input >= 0 || "Decimals must be non-negative"
6615
+ });
6616
+ }
6617
+ if (prompts.length > 0) {
6618
+ requireInteractive("Provide --symbol, --name, and --decimals flags for non-interactive token addition.");
6619
+ const answers = await inquirer3.prompt(prompts);
6620
+ symbol = symbol || answers.symbol?.trim();
6621
+ name = name || answers.name?.trim();
6622
+ decimals = decimals ?? answers.decimals;
6623
+ }
6624
+ await addToken(ctx2, {
6625
+ chain: options.chain,
6626
+ contractAddress: options.add,
6627
+ symbol,
6628
+ name,
6629
+ decimals
6630
+ });
6631
+ } else if (options.remove) {
6632
+ await removeToken(ctx2, options.chain, options.remove);
6633
+ } else {
6634
+ await listTokens(ctx2, options.chain);
6635
+ }
6636
+ }
6637
+ async function addToken(ctx2, options) {
6638
+ const vault = await ctx2.ensureActiveVault();
6639
+ await vault.addToken(options.chain, {
6640
+ id: `${options.chain}-${options.contractAddress}`,
6641
+ contractAddress: options.contractAddress,
6642
+ symbol: options.symbol,
6643
+ name: options.name,
6644
+ decimals: options.decimals,
6645
+ chainId: options.chain,
6646
+ isNative: false
6647
+ });
6648
+ success(`
6649
+ + Added token ${options.symbol} on ${options.chain}`);
6650
+ }
6651
+ async function removeToken(ctx2, chain, tokenId) {
6652
+ const vault = await ctx2.ensureActiveVault();
6653
+ await vault.removeToken(chain, tokenId);
6654
+ success(`
6655
+ + Removed token ${tokenId} from ${chain}`);
6656
+ }
6657
+ async function discoverTokens(ctx2, chain) {
6658
+ const vault = await ctx2.ensureActiveVault();
6659
+ const spinner = createSpinner(`Discovering tokens on ${chain}...`);
6660
+ let discovered;
6661
+ try {
6662
+ discovered = await vault.discoverTokens(chain);
6663
+ } catch (err) {
6664
+ spinner.fail(`Token discovery failed for ${chain}`);
6665
+ throw err;
6666
+ }
6667
+ if (discovered.length === 0) {
6668
+ spinner.succeed(`No new tokens found on ${chain}`);
6669
+ if (isJsonOutput()) {
6670
+ outputJson({ chain, discovered: [], count: 0 });
6671
+ }
6672
+ return;
6673
+ }
6674
+ const existingTokens = vault.getTokens(chain);
6675
+ const existingAddresses = new Set(existingTokens.map((t) => t.contractAddress ?? t.id));
6676
+ const newTokens = discovered.filter((d) => d.contractAddress && !existingAddresses.has(d.contractAddress));
6677
+ for (const d of newTokens) {
6678
+ await vault.addToken(chain, {
6679
+ id: d.contractAddress,
6680
+ symbol: d.ticker,
6681
+ name: d.ticker,
6682
+ decimals: d.decimals,
6683
+ contractAddress: d.contractAddress,
6684
+ chainId: chain,
6685
+ isNative: false
6686
+ });
6687
+ }
6688
+ const allTokens = vault.getTokens(chain);
6689
+ spinner.succeed(`Discovered ${newTokens.length} new token(s) on ${chain}`);
6690
+ if (isJsonOutput()) {
6691
+ outputJson({
6692
+ chain,
6693
+ discovered: newTokens.map((d) => ({
6694
+ symbol: d.ticker,
6695
+ contractAddress: d.contractAddress,
6696
+ decimals: d.decimals
6697
+ })),
6698
+ count: newTokens.length
6699
+ });
6700
+ return;
6701
+ }
6702
+ for (const d of newTokens) {
6703
+ printResult(` ${d.ticker} (${d.contractAddress})`);
6704
+ }
6705
+ info(chalk4.gray(`
6706
+ ${allTokens.length} total token(s) tracked on ${chain}`));
6707
+ }
6708
+ async function listTokens(ctx2, chain) {
6709
+ const vault = await ctx2.ensureActiveVault();
6710
+ const spinner = createSpinner(`Loading tokens for ${chain}...`);
6711
+ const tokens = vault.getTokens(chain);
6712
+ spinner.succeed(`Tokens loaded for ${chain}`);
6713
+ if (isJsonOutput()) {
6714
+ outputJson({ chain, tokens: tokens || [] });
6715
+ return;
6716
+ }
6717
+ if (!tokens || tokens.length === 0) {
6718
+ warn(`
6719
+ No tokens configured for ${chain}`);
6720
+ info(chalk4.gray(`
6721
+ Use --add <contractAddress> to add a token`));
6722
+ } else {
6723
+ printResult(chalk4.cyan(`
6724
+ Tokens for ${chain}:
6725
+ `));
6726
+ const table = tokens.map((token) => ({
6727
+ Symbol: token.symbol,
6728
+ Name: token.name,
6729
+ Contract: token.contractAddress || "N/A",
6730
+ Decimals: token.decimals,
6731
+ Native: token.isNative ? "Yes" : "No"
6732
+ }));
6733
+ printTable(table);
6734
+ info(chalk4.gray(`
6735
+ Use --add <contractAddress> to add or --remove <tokenId> to remove`));
6736
+ }
6737
+ }
6738
+
6706
6739
  // src/commands/transaction.ts
6740
+ import { Chain, Vultisig as Vultisig2 } from "@vultisig/sdk";
6707
6741
  async function executeSend(ctx2, params) {
6708
6742
  const vault = await ctx2.ensureActiveVault();
6709
6743
  if (!Object.values(Chain).includes(params.chain)) {
@@ -14534,7 +14568,7 @@ var cachedVersion = null;
14534
14568
  function getVersion() {
14535
14569
  if (cachedVersion) return cachedVersion;
14536
14570
  if (true) {
14537
- cachedVersion = "2.19.7";
14571
+ cachedVersion = "2.19.10";
14538
14572
  return cachedVersion;
14539
14573
  }
14540
14574
  try {
@@ -16150,7 +16184,7 @@ Error: ${error2.message}`));
16150
16184
  async loadAllVaults() {
16151
16185
  const spinner = createSpinner2("Loading vaults...").start();
16152
16186
  try {
16153
- const activeVault = await this.ctx.sdk.getActiveVault();
16187
+ const { vault: activeVault, corruptPointer } = await loadActiveVaultSafely(this.ctx.sdk);
16154
16188
  if (activeVault) {
16155
16189
  this.ctx.addVault(activeVault);
16156
16190
  await this.ctx.setActiveVault(activeVault);
@@ -16164,7 +16198,7 @@ Error: ${error2.message}`));
16164
16198
  this.eventBuffer.setupVaultListeners(vault);
16165
16199
  }
16166
16200
  });
16167
- if (!this.ctx.getActiveVault() && this.ctx.getVaults().size > 0) {
16201
+ if (shouldAutoSelectActiveVault(!!this.ctx.getActiveVault(), corruptPointer, this.ctx.getVaults().size)) {
16168
16202
  const firstVault = this.ctx.getVaults().values().next().value;
16169
16203
  await this.ctx.setActiveVault(firstVault);
16170
16204
  }
@@ -16174,6 +16208,11 @@ Error: ${error2.message}`));
16174
16208
  } else {
16175
16209
  spinner.succeed("No vaults found");
16176
16210
  }
16211
+ if (corruptPointer && !this.ctx.getActiveVault() && this.ctx.getVaults().size > 0) {
16212
+ console.log(
16213
+ chalk14.yellow('Active vault pointer was corrupt and has been reset. Use "vault <name>" to pick one.')
16214
+ );
16215
+ }
16177
16216
  } catch (error2) {
16178
16217
  if (this.ctx.getVaults().size > 0) {
16179
16218
  spinner.succeed(`Loaded ${this.ctx.getVaults().size} vault(s)`);
@@ -16522,6 +16561,18 @@ complete -c vsig -n "__fish_seen_subcommand_from import export" -a "(__fish_comp
16522
16561
  `.trim();
16523
16562
  }
16524
16563
 
16564
+ // src/lib/config.ts
16565
+ import { FileStorage } from "@vultisig/sdk/node";
16566
+ import { homedir as homedir6 } from "os";
16567
+ import { join as join6 } from "path";
16568
+ function getConfigDir() {
16569
+ const override = process.env.VULTISIG_CONFIG_DIR?.trim();
16570
+ return override ? override : join6(homedir6(), ".vultisig");
16571
+ }
16572
+ function createVaultStorage() {
16573
+ return new FileStorage({ basePath: getConfigDir() });
16574
+ }
16575
+
16525
16576
  // src/lib/errors.ts
16526
16577
  import chalk15 from "chalk";
16527
16578
 
@@ -16596,6 +16647,7 @@ async function init(vaultOverride, unlockPassword, passwordTTL) {
16596
16647
  const globalOptions = program.opts();
16597
16648
  const serverEndpoints = resolveServerEndpoints(globalOptions);
16598
16649
  const sdk = new Vultisig6({
16650
+ storage: createVaultStorage(),
16599
16651
  onPasswordRequired: createPasswordCallback(),
16600
16652
  ...serverEndpoints ? { serverEndpoints } : {},
16601
16653
  ...passwordTTL !== void 0 ? { passwordCache: { defaultTTL: passwordTTL } } : {}
@@ -16609,7 +16661,7 @@ async function init(vaultOverride, unlockPassword, passwordTTL) {
16609
16661
  throw new Error(`Vault not found: "${vaultSelector}"`);
16610
16662
  }
16611
16663
  } else {
16612
- vault = await sdk.getActiveVault();
16664
+ vault = (await loadActiveVaultSafely(sdk)).vault;
16613
16665
  }
16614
16666
  if (vault) {
16615
16667
  await ctx.setActiveVault(vault);
@@ -17440,6 +17492,7 @@ program.command("schema", { hidden: true }).description("Output machine-readable
17440
17492
  async function startInteractiveMode() {
17441
17493
  const serverEndpoints = resolveServerEndpoints(parseServerEndpointOverridesFromArgv(process.argv.slice(2)));
17442
17494
  const sdk = new Vultisig6({
17495
+ storage: createVaultStorage(),
17443
17496
  onPasswordRequired: createPasswordCallback(),
17444
17497
  ...serverEndpoints ? { serverEndpoints } : {}
17445
17498
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/cli",
3
- "version": "2.19.7",
3
+ "version": "2.19.10",
4
4
  "description": "The self-custody MPC wallet CLI for AI coding agents (Claude Code, Cursor, OpenCode). Natural-language agent mode, 36+ chains, DKLS23 threshold signatures. Seedless.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -74,9 +74,9 @@
74
74
  "@napi-rs/keyring": "^1.3.0",
75
75
  "@noble/hashes": "^2.2.0",
76
76
  "@vultisig/client-shared": "^0.2.17",
77
- "@vultisig/core-chain": "^2.24.0",
77
+ "@vultisig/core-chain": "^2.24.2",
78
78
  "@vultisig/rujira": "^52.0.0",
79
- "@vultisig/sdk": "^2.19.7",
79
+ "@vultisig/sdk": "^2.19.10",
80
80
  "chalk": "^5.6.2",
81
81
  "cli-table3": "^0.6.5",
82
82
  "commander": "^15.0.0",