@vultisig/cli 0.1.1-alpha.2 → 0.2.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/index.js +139 -116
  3. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @vultisig/cli
2
2
 
3
+ ## 0.2.0-alpha.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [#57](https://github.com/vultisig/vultisig-sdk/pull/57) [`6137bc6`](https://github.com/vultisig/vultisig-sdk/commit/6137bc65bdf06ea5f6ede009ac72ec58b7cac7d1) Thanks [@bornslippynuxx](https://github.com/bornslippynuxx)! - Optimize SDK bundling configuration
8
+ - Add terser minification (~60% bundle size reduction)
9
+ - Add clean script to remove stale dist files before builds
10
+ - Centralize duplicated onwarn handler in rollup config
11
+ - Add package.json exports for react-native and electron platforms
12
+
13
+ - Updated dependencies [[`6137bc6`](https://github.com/vultisig/vultisig-sdk/commit/6137bc65bdf06ea5f6ede009ac72ec58b7cac7d1), [`c75f442`](https://github.com/vultisig/vultisig-sdk/commit/c75f442ce4e34521aa8d0f704c415f63c24dba8f)]:
14
+ - @vultisig/sdk@0.2.0-alpha.5
15
+
16
+ ## 0.2.0-alpha.3
17
+
18
+ ### Patch Changes
19
+
20
+ - [#55](https://github.com/vultisig/vultisig-sdk/pull/55) [`95ba10b`](https://github.com/vultisig/vultisig-sdk/commit/95ba10baf2dc2dc4ba8e48825f10f34ec275a73c) Thanks [@bornslippynuxx](https://github.com/bornslippynuxx)! - Replace development command references (`npm run wallet`) with production CLI name (`vultisig`) in all user-facing messages.
21
+
22
+ - [#55](https://github.com/vultisig/vultisig-sdk/pull/55) [`95ba10b`](https://github.com/vultisig/vultisig-sdk/commit/95ba10baf2dc2dc4ba8e48825f10f34ec275a73c) Thanks [@bornslippynuxx](https://github.com/bornslippynuxx)! - Fix interactive shell prompts by replacing REPL with readline to prevent stdin conflicts with inquirer
23
+
24
+ - [#55](https://github.com/vultisig/vultisig-sdk/pull/55) [`95ba10b`](https://github.com/vultisig/vultisig-sdk/commit/95ba10baf2dc2dc4ba8e48825f10f34ec275a73c) Thanks [@bornslippynuxx](https://github.com/bornslippynuxx)! - Update browser example and CLI for new fast vault creation API
25
+ - Updated to use new `createFastVault()` that returns just the vaultId
26
+ - Updated to use new `verifyVault()` that returns the FastVault
27
+ - Removed `code` from CLI `CreateVaultOptions` (verification code always prompted interactively)
28
+ - Removed `--code` option from CLI create command
29
+
30
+ - [#55](https://github.com/vultisig/vultisig-sdk/pull/55) [`95ba10b`](https://github.com/vultisig/vultisig-sdk/commit/95ba10baf2dc2dc4ba8e48825f10f34ec275a73c) Thanks [@bornslippynuxx](https://github.com/bornslippynuxx)! - Add inline verification code retry during vault creation. When entering an incorrect code, users can now retry, resend the verification email, or abort gracefully instead of being kicked back to the main menu.
31
+
32
+ - Updated dependencies [[`95ba10b`](https://github.com/vultisig/vultisig-sdk/commit/95ba10baf2dc2dc4ba8e48825f10f34ec275a73c), [`95ba10b`](https://github.com/vultisig/vultisig-sdk/commit/95ba10baf2dc2dc4ba8e48825f10f34ec275a73c)]:
33
+ - @vultisig/sdk@0.2.0-alpha.3
34
+
3
35
  ## 0.1.1-alpha.2
4
36
 
5
37
  ### Patch Changes
package/dist/index.js CHANGED
@@ -860,7 +860,7 @@ async function executeCreate(ctx2, options = { type: "fast" }) {
860
860
  email = emailAnswer.email;
861
861
  }
862
862
  const spinner = createSpinner("Creating vault...");
863
- const result = await ctx2.sdk.createFastVault({
863
+ const vaultId = await ctx2.sdk.createFastVault({
864
864
  name,
865
865
  password,
866
866
  email,
@@ -868,46 +868,76 @@ async function executeCreate(ctx2, options = { type: "fast" }) {
868
868
  spinner.text = `${step.message} (${step.progress}%)`;
869
869
  }
870
870
  });
871
- setupVaultEvents(result.vault);
872
- await ctx2.setActiveVault(result.vault);
873
- spinner.succeed(`Vault created: ${name}`);
874
- if (result.verificationRequired) {
875
- let code = options.code;
876
- if (!code) {
877
- warn("\nA verification code has been sent to your email.");
878
- info("Please check your inbox and enter the code.");
879
- const codeAnswer = await inquirer4.prompt([
871
+ spinner.succeed(`Vault keys generated: ${name}`);
872
+ warn("\nA verification code has been sent to your email.");
873
+ info("Please check your inbox and enter the code.");
874
+ const MAX_VERIFY_ATTEMPTS = 5;
875
+ let attempts = 0;
876
+ while (attempts < MAX_VERIFY_ATTEMPTS) {
877
+ attempts++;
878
+ const codeAnswer = await inquirer4.prompt([
879
+ {
880
+ type: "input",
881
+ name: "code",
882
+ message: `Verification code sent to ${email}. Enter code:`,
883
+ validate: (input) => /^\d{4,6}$/.test(input) || "Code must be 4-6 digits"
884
+ }
885
+ ]);
886
+ const verifySpinner = createSpinner("Verifying email code...");
887
+ try {
888
+ const vault = await ctx2.sdk.verifyVault(vaultId, codeAnswer.code);
889
+ verifySpinner.succeed("Email verified successfully!");
890
+ setupVaultEvents(vault);
891
+ await ctx2.setActiveVault(vault);
892
+ success("\n+ Vault created!");
893
+ info("\nYour vault is ready. Run the following commands:");
894
+ printResult(chalk5.cyan(" vultisig balance ") + "- View balances");
895
+ printResult(chalk5.cyan(" vultisig addresses ") + "- View addresses");
896
+ printResult(chalk5.cyan(" vultisig portfolio ") + "- View portfolio value");
897
+ return vault;
898
+ } catch (err) {
899
+ verifySpinner.fail("Verification failed");
900
+ error(`
901
+ \u2717 ${err.message || "Invalid verification code"}`);
902
+ if (attempts >= MAX_VERIFY_ATTEMPTS) {
903
+ warn("\nMaximum attempts reached.");
904
+ warn("\nTo retry verification later, use:");
905
+ info(` vultisig verify ${vaultId}`);
906
+ err.exitCode = 1;
907
+ throw err;
908
+ }
909
+ const { action } = await inquirer4.prompt([
880
910
  {
881
- type: "input",
882
- name: "code",
883
- message: `Verification code sent to ${email}. Enter code:`,
884
- validate: (input) => /^\d{4,6}$/.test(input) || "Code must be 4-6 digits"
911
+ type: "list",
912
+ name: "action",
913
+ message: `What would you like to do? (${MAX_VERIFY_ATTEMPTS - attempts} attempts remaining)`,
914
+ choices: [
915
+ { name: "Enter a different code", value: "retry" },
916
+ { name: "Resend verification email (rate limited)", value: "resend" },
917
+ { name: "Abort and verify later", value: "abort" }
918
+ ]
885
919
  }
886
920
  ]);
887
- code = codeAnswer.code;
888
- }
889
- const verifySpinner = createSpinner("Verifying email code...");
890
- const verified = await ctx2.sdk.verifyVault(result.vaultId, code);
891
- if (verified) {
892
- verifySpinner.succeed("Email verified successfully!");
893
- } else {
894
- verifySpinner.fail("Invalid verification code");
895
- error("\nx Verification failed. Please check the code and try again.");
896
- warn("\nTo retry verification, use:");
897
- info(` npm run wallet verify ${result.vaultId}`);
898
- warn("\nTo resend the verification email:");
899
- info(` npm run wallet verify ${result.vaultId} --resend`);
900
- const err = new Error("Verification failed");
901
- err.exitCode = 1;
902
- throw err;
921
+ if (action === "abort") {
922
+ warn("\nVault creation paused. To complete verification, use:");
923
+ info(` vultisig verify ${vaultId}`);
924
+ warn("\nNote: The pending vault is stored in memory only and will be lost if you exit.");
925
+ return void 0;
926
+ }
927
+ if (action === "resend") {
928
+ const resendSpinner = createSpinner("Resending verification email...");
929
+ try {
930
+ await ctx2.sdk.resendVaultVerification(vaultId);
931
+ resendSpinner.succeed("Verification email sent!");
932
+ info("Check your inbox for the new code. Note: There may be a ~3 minute cooldown between resends.");
933
+ } catch (resendErr) {
934
+ resendSpinner.fail("Failed to resend");
935
+ warn(resendErr.message || "Could not resend email. You may need to wait a few minutes.");
936
+ }
937
+ }
903
938
  }
904
939
  }
905
- success("\n+ Vault created!");
906
- info("\nYour vault is ready. Run the following commands:");
907
- printResult(chalk5.cyan(" npm run wallet balance ") + "- View balances");
908
- printResult(chalk5.cyan(" npm run wallet addresses ") + "- View addresses");
909
- printResult(chalk5.cyan(" npm run wallet portfolio ") + "- View portfolio value");
910
- return result.vault;
940
+ throw new Error("Verification loop exited unexpectedly");
911
941
  } else {
912
942
  let threshold = options.threshold;
913
943
  let totalShares = options.shares;
@@ -982,7 +1012,7 @@ async function executeImport(ctx2, file) {
982
1012
  await ctx2.setActiveVault(vault);
983
1013
  spinner.succeed(`Vault imported: ${vault.name}`);
984
1014
  success("\n+ Vault imported successfully!");
985
- info('\nRun "npm run wallet balance" to view balances');
1015
+ info('\nRun "vultisig balance" to view balances');
986
1016
  return vault;
987
1017
  }
988
1018
  async function executeVerify(ctx2, vaultId, options = {}) {
@@ -1005,15 +1035,20 @@ async function executeVerify(ctx2, vaultId, options = {}) {
1005
1035
  code = codeAnswer.code;
1006
1036
  }
1007
1037
  const spinner = createSpinner("Verifying email code...");
1008
- const verified = await ctx2.sdk.verifyVault(vaultId, code);
1009
- if (verified) {
1038
+ try {
1039
+ const vault = await ctx2.sdk.verifyVault(vaultId, code);
1010
1040
  spinner.succeed("Vault verified successfully!");
1041
+ setupVaultEvents(vault);
1042
+ await ctx2.setActiveVault(vault);
1043
+ success(`
1044
+ + Vault "${vault.name}" is now ready to use!`);
1011
1045
  return true;
1012
- } else {
1013
- spinner.fail("Invalid verification code");
1014
- error("\nx Verification failed. Please check the code and try again.");
1046
+ } catch (err) {
1047
+ spinner.fail("Verification failed");
1048
+ error(`
1049
+ \u2717 ${err.message || "Verification failed. Please check the code and try again."}`);
1015
1050
  warn("\nTip: Use --resend to get a new verification code:");
1016
- info(` npm run wallet verify ${vaultId} --resend`);
1051
+ info(` vultisig verify ${vaultId} --resend`);
1017
1052
  return false;
1018
1053
  }
1019
1054
  }
@@ -1076,7 +1111,7 @@ async function executeVaults(ctx2) {
1076
1111
  }
1077
1112
  const activeVault = ctx2.getActiveVault();
1078
1113
  displayVaultsList(vaults, activeVault);
1079
- info(chalk5.gray('\nUse "npm run wallet switch <id>" to switch active vault'));
1114
+ info(chalk5.gray('\nUse "vultisig switch <id>" to switch active vault'));
1080
1115
  return vaults;
1081
1116
  }
1082
1117
  async function executeSwitch(ctx2, vaultId) {
@@ -1303,7 +1338,7 @@ async function executeCurrency(ctx2, newCurrency) {
1303
1338
  printResult(` ${chalk6.green(currentCurrency.toUpperCase())} - ${currencyName2}`);
1304
1339
  info(chalk6.gray(`
1305
1340
  Supported currencies: ${fiatCurrencies2.join(", ")}`));
1306
- info(chalk6.gray('Use "npm run wallet currency <code>" to change'));
1341
+ info(chalk6.gray('Use "vultisig currency <code>" to change'));
1307
1342
  return currentCurrency;
1308
1343
  }
1309
1344
  const currency = newCurrency.toLowerCase();
@@ -1745,7 +1780,7 @@ var EventBuffer = class {
1745
1780
  import { fiatCurrencies as fiatCurrencies3 } from "@vultisig/sdk";
1746
1781
  import chalk9 from "chalk";
1747
1782
  import ora3 from "ora";
1748
- import * as repl from "repl";
1783
+ import * as readline from "readline";
1749
1784
 
1750
1785
  // src/interactive/shell-commands.ts
1751
1786
  import chalk8 from "chalk";
@@ -2028,7 +2063,7 @@ function createShellContext(sdk, options) {
2028
2063
  }
2029
2064
 
2030
2065
  // src/interactive/session.ts
2031
- function createReplSafeSpinner(text) {
2066
+ function createSpinner2(text) {
2032
2067
  return ora3({
2033
2068
  text,
2034
2069
  hideCursor: false,
@@ -2040,7 +2075,6 @@ function createReplSafeSpinner(text) {
2040
2075
  var ShellSession = class {
2041
2076
  ctx;
2042
2077
  eventBuffer;
2043
- replServer;
2044
2078
  constructor(sdk, options) {
2045
2079
  this.ctx = createShellContext(sdk, options);
2046
2080
  this.eventBuffer = new EventBuffer();
@@ -2055,56 +2089,61 @@ var ShellSession = class {
2055
2089
  console.log(chalk9.cyan.bold("==============================================\n"));
2056
2090
  await this.loadAllVaults();
2057
2091
  this.displayVaultList();
2058
- console.log(chalk9.gray('Type "help" for available commands, ".exit" to quit\n'));
2059
- this.replServer = repl.start({
2060
- prompt: this.getPrompt(),
2061
- eval: this.evalCommand.bind(this),
2062
- ignoreUndefined: true,
2063
- terminal: true,
2064
- useColors: true,
2065
- completer: createCompleter(this.ctx)
2092
+ console.log(chalk9.gray('Type "help" for available commands, "exit" to quit\n'));
2093
+ this.promptLoop().catch(() => {
2066
2094
  });
2067
- this.setupReplCommands();
2068
2095
  }
2069
2096
  /**
2070
- * Custom eval function for command processing
2097
+ * Main prompt loop - creates fresh readline for each command
2071
2098
  */
2072
- async evalCommand(cmd, _context, _filename, callback) {
2073
- const input = cmd.trim();
2074
- if (!input) {
2075
- callback(null);
2076
- return;
2099
+ async promptLoop() {
2100
+ while (true) {
2101
+ const line = await this.readLine(this.getPrompt());
2102
+ await this.processLine(line);
2077
2103
  }
2104
+ }
2105
+ /**
2106
+ * Read a single line with tab completion, then close readline
2107
+ */
2108
+ readLine(prompt) {
2109
+ return new Promise((resolve) => {
2110
+ const rl = readline.createInterface({
2111
+ input: process.stdin,
2112
+ output: process.stdout,
2113
+ completer: (line, cb) => {
2114
+ cb(null, createCompleter(this.ctx)(line));
2115
+ },
2116
+ terminal: true
2117
+ });
2118
+ rl.question(prompt, (answer) => {
2119
+ rl.close();
2120
+ resolve(answer);
2121
+ });
2122
+ rl.on("SIGINT", () => {
2123
+ rl.close();
2124
+ console.log(chalk9.yellow("\nGoodbye!"));
2125
+ this.ctx.dispose();
2126
+ process.exit(0);
2127
+ });
2128
+ });
2129
+ }
2130
+ /**
2131
+ * Process a line of input
2132
+ */
2133
+ async processLine(line) {
2134
+ const input = line.trim();
2135
+ if (!input) return;
2078
2136
  const [command, ...args] = input.split(/\s+/);
2079
2137
  try {
2080
2138
  this.eventBuffer.startCommand();
2081
2139
  await this.executeCommand(command.toLowerCase(), args);
2082
2140
  this.eventBuffer.endCommand();
2083
- this.replServer.setPrompt(this.getPrompt());
2084
- callback(null);
2085
- this.restoreTerminalState();
2086
2141
  } catch (error2) {
2087
2142
  this.eventBuffer.endCommand();
2088
2143
  console.error(chalk9.red(`
2089
- x Error: ${error2.message}`));
2090
- this.replServer.setPrompt(this.getPrompt());
2091
- callback(null);
2092
- this.restoreTerminalState();
2144
+ Error: ${error2.message}`));
2093
2145
  }
2094
2146
  }
2095
- /**
2096
- * Restore terminal state after commands that may have altered it.
2097
- * Some libraries (like ora spinners) pause stdin and disable raw mode.
2098
- */
2099
- restoreTerminalState() {
2100
- if (process.stdin.isPaused()) {
2101
- process.stdin.resume();
2102
- }
2103
- if (process.stdin.isTTY && !process.stdin.isRaw) {
2104
- process.stdin.setRawMode(true);
2105
- }
2106
- this.replServer.displayPrompt();
2107
- }
2108
2147
  /**
2109
2148
  * Execute a command
2110
2149
  */
@@ -2193,11 +2232,22 @@ x Error: ${error2.message}`));
2193
2232
  case "?":
2194
2233
  showHelp();
2195
2234
  break;
2235
+ // Clear screen
2236
+ case "clear":
2237
+ console.clear();
2238
+ this.displayVaultList();
2239
+ break;
2240
+ // Exit
2241
+ case "exit":
2242
+ case "quit":
2243
+ console.log(chalk9.yellow("\nGoodbye!"));
2244
+ this.ctx.dispose();
2245
+ process.exit(0);
2246
+ break;
2247
+ // eslint requires break even after process.exit
2196
2248
  default:
2197
- if (command && !command.startsWith(".")) {
2198
- console.log(chalk9.yellow(`Unknown command: ${command}`));
2199
- console.log(chalk9.gray('Type "help" for available commands'));
2200
- }
2249
+ console.log(chalk9.yellow(`Unknown command: ${command}`));
2250
+ console.log(chalk9.gray('Type "help" for available commands'));
2201
2251
  break;
2202
2252
  }
2203
2253
  }
@@ -2414,34 +2464,8 @@ x Error: ${error2.message}`));
2414
2464
  await executeAddressBook(this.ctx, { add, remove, chain });
2415
2465
  }
2416
2466
  // ===== Setup =====
2417
- setupReplCommands() {
2418
- this.replServer.defineCommand("help", {
2419
- help: "Show available commands",
2420
- action: () => {
2421
- showHelp();
2422
- this.replServer.displayPrompt();
2423
- }
2424
- });
2425
- this.replServer.defineCommand("clear", {
2426
- help: "Clear the screen",
2427
- action: () => {
2428
- console.clear();
2429
- this.displayVaultList();
2430
- this.replServer.displayPrompt();
2431
- }
2432
- });
2433
- const originalExit = this.replServer.commands.exit;
2434
- this.replServer.defineCommand("exit", {
2435
- help: originalExit.help,
2436
- action: () => {
2437
- console.log(chalk9.yellow("\nGoodbye!"));
2438
- this.ctx.dispose();
2439
- originalExit.action.call(this.replServer);
2440
- }
2441
- });
2442
- }
2443
2467
  async loadAllVaults() {
2444
- const spinner = createReplSafeSpinner("Loading vaults...").start();
2468
+ const spinner = createSpinner2("Loading vaults...").start();
2445
2469
  try {
2446
2470
  const activeVault = await this.ctx.sdk.getActiveVault();
2447
2471
  if (activeVault) {
@@ -3002,7 +3026,7 @@ async function init(vaultOverride) {
3002
3026
  }
3003
3027
  return ctx;
3004
3028
  }
3005
- program.command("create").description("Create a new vault").option("--type <type>", "Vault type: fast or secure", "fast").option("--name <name>", "Vault name").option("--password <password>", "Vault password").option("--email <email>", "Email for verification (fast vault)").option("--code <code>", "Verification code (if already received)").option("--threshold <m>", "Signing threshold (secure vault)").option("--shares <n>", "Total shares (secure vault)").action(
3029
+ program.command("create").description("Create a new vault").option("--type <type>", "Vault type: fast or secure", "fast").option("--name <name>", "Vault name").option("--password <password>", "Vault password").option("--email <email>", "Email for verification (fast vault)").option("--threshold <m>", "Signing threshold (secure vault)").option("--shares <n>", "Total shares (secure vault)").action(
3006
3030
  withExit(
3007
3031
  async (options) => {
3008
3032
  const context = await init(program.opts().vault);
@@ -3011,7 +3035,6 @@ program.command("create").description("Create a new vault").option("--type <type
3011
3035
  name: options.name,
3012
3036
  password: options.password,
3013
3037
  email: options.email,
3014
- code: options.code,
3015
3038
  threshold: options.threshold ? parseInt(options.threshold, 10) : void 0,
3016
3039
  shares: options.shares ? parseInt(options.shares, 10) : void 0
3017
3040
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vultisig/cli",
3
- "version": "0.1.1-alpha.2",
3
+ "version": "0.2.0-alpha.5",
4
4
  "description": "Command-line wallet for Vultisig - multi-chain MPC wallet management",
5
5
  "type": "module",
6
6
  "bin": {
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "homepage": "https://vultisig.com",
50
50
  "dependencies": {
51
- "@vultisig/sdk": "^0.1.1-alpha.0",
51
+ "@vultisig/sdk": "^0.2.0-alpha.5",
52
52
  "chalk": "^5.3.0",
53
53
  "cli-table3": "^0.6.5",
54
54
  "commander": "^12.0.0",