hufi-cli 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +16 -8
  2. package/dist/cli.js +171 -40
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,16 +5,16 @@ CLI tool for the [hu.fi](https://hu.finance) DeFi platform.
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- bun install -g hufi-cli
8
+ bun install -g hufi
9
9
  ```
10
10
 
11
11
  Or run without installing:
12
12
 
13
13
  ```bash
14
- bunx hufi-cli <command>
14
+ bunx hufi <command>
15
15
  ```
16
16
 
17
- All examples below assume global install. Otherwise replace `hufi` with `bunx hufi-cli`.
17
+ All examples below assume global install. Otherwise replace `hufi` with `bunx hufi`.
18
18
 
19
19
  ## Quick Start
20
20
 
@@ -76,6 +76,8 @@ hufi campaign leaderboard --address 0x... # leaderboard
76
76
 
77
77
  Requires staked HMT, gas, and fund tokens (USDT/USDC). Creates an escrow contract on-chain.
78
78
 
79
+ Before broadcasting, the CLI validates the campaign type-specific target, checks the 6-hour to 100-day duration window, verifies your minimum HMT stake when possible, inspects fund token balance, and estimates gas for approval plus creation.
80
+
79
81
  ```bash
80
82
  # Market Making
81
83
  hufi campaign create \
@@ -112,11 +114,16 @@ Running `campaign status/join/progress/leaderboard` without `-a` shows help.
112
114
 
113
115
  ```bash
114
116
  hufi exchange register --name mexc --api-key <key> --secret-key <secret>
117
+ hufi exchange register --name bitmart --api-key <key> --secret-key <secret> --bitmart-memo <memo>
115
118
  hufi exchange list
116
- hufi exchange revalidate --name mexc
117
- hufi exchange delete --name mexc
119
+ hufi exchange revalidate mexc
120
+ hufi exchange delete mexc
118
121
  ```
119
122
 
123
+ `exchange register` expects the CCXT exchange name in `--name` and accepts `--bitmart-memo` for Bitmart accounts that require an extra memo value.
124
+
125
+ You must run `hufi auth login` before `exchange register`, `exchange list`, `exchange delete`, or `exchange revalidate`.
126
+
120
127
  ### staking
121
128
 
122
129
  | Command | Description |
@@ -131,8 +138,8 @@ hufi exchange delete --name mexc
131
138
  hufi staking deposit # show address QR code
132
139
  hufi staking status # check your staking
133
140
  hufi staking status --address 0x... # check another address
134
- hufi staking stake -a 1000 # stake 1000 HMT
135
- hufi staking unstake -a 500 # unstake 500 HMT
141
+ hufi staking stake 1000 # stake 1000 HMT
142
+ hufi staking unstake 500 # unstake 500 HMT
136
143
  hufi staking withdraw # withdraw unlocked tokens
137
144
  ```
138
145
 
@@ -158,7 +165,7 @@ hufi dashboard --export json
158
165
  | `-V, --version` | Show version |
159
166
  | `-h, --help` | Show help |
160
167
 
161
- All commands support `--json` for machine-readable output.
168
+ Most command actions support `--json` for machine-readable output. Help output remains text, and commands that intentionally show help when required arguments are missing do not emit a JSON error envelope.
162
169
 
163
170
  ## Configuration
164
171
 
@@ -181,6 +188,7 @@ bun install # install deps
181
188
  bun run dev -- --help # run from source
182
189
  bun run build # build to dist/cli.js
183
190
  bun test # unit tests
191
+ ./test-cli.sh # full CLI integration coverage
184
192
  bun run test:cli # integration tests
185
193
  bun run typecheck # type check
186
194
  ```
package/dist/cli.js CHANGED
@@ -23063,9 +23063,33 @@ function requireAuthAddress() {
23063
23063
  }
23064
23064
 
23065
23065
  // src/commands/exchange.ts
23066
+ var authHintByAction = {
23067
+ register: "Run: hufi auth login --private-key <key> before registering exchange API keys.",
23068
+ list: "Run: hufi auth login --private-key <key> before listing exchange API keys.",
23069
+ delete: "Run: hufi auth login --private-key <key> before deleting exchange API keys.",
23070
+ revalidate: "Run: hufi auth login --private-key <key> before revalidating exchange API keys."
23071
+ };
23072
+ function isUnauthorizedError(err) {
23073
+ return err instanceof ApiError && err.status === 401;
23074
+ }
23075
+ function formatExchangeCommandErrorMessage(action, err) {
23076
+ const message = err instanceof Error ? err.message : String(err);
23077
+ const commandTarget = action === "list" ? "exchange API keys" : "exchange API key";
23078
+ if (isUnauthorizedError(err)) {
23079
+ return `Failed to ${action} ${commandTarget}: ${message}. ${authHintByAction[action]}`;
23080
+ }
23081
+ return `Failed to ${action} ${commandTarget}: ${message}`;
23082
+ }
23083
+ function formatRevalidateText(exchangeName, result) {
23084
+ const lines = [`${exchangeName}: ${result.is_valid ? "valid" : "invalid"}`];
23085
+ if ((result.missing_permissions?.length ?? 0) > 0) {
23086
+ lines.push(`Missing permissions: ${result.missing_permissions?.join(", ")}`);
23087
+ }
23088
+ return lines;
23089
+ }
23066
23090
  function createExchangeCommand() {
23067
23091
  const exchange = new Command("exchange").description("Exchange API key management");
23068
- exchange.command("register").description("Register a read-only exchange API key").requiredOption("-n, --name <name>", "Exchange name (e.g. binance, mexc)").requiredOption("--api-key <key>", "Read-only API key").requiredOption("--secret-key <key>", "Read-only API secret").option("--bitmart-memo <memo>", "Bitmart memo (only for bitmart)").option("--json", "Output as JSON").action(async (opts) => {
23092
+ exchange.command("register").description("Register a read-only exchange API key").requiredOption("-n, --name <name>", "CCXT exchange name (e.g. binance, mexc)").requiredOption("--api-key <key>", "Read-only API key").requiredOption("--secret-key <key>", "Read-only API secret").option("--bitmart-memo <memo>", "Bitmart memo (only for bitmart)").option("--json", "Output as JSON").action(async (opts) => {
23069
23093
  const { baseUrl, accessToken } = requireAuthToken();
23070
23094
  try {
23071
23095
  const result = await registerExchangeApiKey(baseUrl, accessToken, opts.name, opts.apiKey, opts.secretKey, opts.bitmartMemo);
@@ -23078,8 +23102,7 @@ function createExchangeCommand() {
23078
23102
  }
23079
23103
  }
23080
23104
  } catch (err) {
23081
- const message = err instanceof Error ? err.message : String(err);
23082
- printText(`Failed to register exchange API key: ${message}`);
23105
+ printText(formatExchangeCommandErrorMessage("register", err));
23083
23106
  process.exitCode = 1;
23084
23107
  }
23085
23108
  });
@@ -23100,42 +23123,49 @@ function createExchangeCommand() {
23100
23123
  }
23101
23124
  }
23102
23125
  } catch (err) {
23103
- const message = err instanceof Error ? err.message : String(err);
23104
- printText(`Failed to list exchange API keys: ${message}`);
23126
+ printText(formatExchangeCommandErrorMessage("list", err));
23105
23127
  process.exitCode = 1;
23106
23128
  }
23107
23129
  });
23108
- exchange.command("delete").description("Delete API keys for an exchange").requiredOption("-n, --name <name>", "Exchange name (e.g. mexc, bybit)").option("--json", "Output as JSON").action(async (opts) => {
23130
+ exchange.command("delete [name]").description("Delete API keys for an exchange").usage("[name] [options]").option("-n, --name <name>", "Exchange name (e.g. mexc, bybit)").option("--json", "Output as JSON").action(async (nameArg, opts) => {
23131
+ const exchangeName = nameArg ?? opts.name;
23132
+ if (!exchangeName) {
23133
+ printText("Exchange name is required. Usage: hufi exchange delete <name>");
23134
+ process.exitCode = 1;
23135
+ return;
23136
+ }
23109
23137
  const { baseUrl, accessToken } = requireAuthToken();
23110
23138
  try {
23111
- await deleteExchangeApiKey(baseUrl, accessToken, opts.name);
23139
+ await deleteExchangeApiKey(baseUrl, accessToken, exchangeName);
23112
23140
  if (opts.json) {
23113
- printJson({ deleted: true, exchange_name: opts.name });
23141
+ printJson({ deleted: true, exchange_name: exchangeName });
23114
23142
  } else {
23115
- printText(`Deleted API keys for ${opts.name}.`);
23143
+ printText(`Deleted API keys for ${exchangeName}.`);
23116
23144
  }
23117
23145
  } catch (err) {
23118
- const message = err instanceof Error ? err.message : String(err);
23119
- printText(`Failed to delete exchange API keys: ${message}`);
23146
+ printText(formatExchangeCommandErrorMessage("delete", err));
23120
23147
  process.exitCode = 1;
23121
23148
  }
23122
23149
  });
23123
- exchange.command("revalidate").description("Revalidate exchange API key").requiredOption("-n, --name <name>", "Exchange name (e.g. mexc, bybit)").option("--json", "Output as JSON").action(async (opts) => {
23150
+ exchange.command("revalidate [name]").description("Revalidate exchange API key").usage("[name] [options]").option("-n, --name <name>", "Exchange name (e.g. mexc, bybit)").option("--json", "Output as JSON").action(async (nameArg, opts) => {
23151
+ const exchangeName = nameArg ?? opts.name;
23152
+ if (!exchangeName) {
23153
+ printText("Exchange name is required. Usage: hufi exchange revalidate <name>");
23154
+ process.exitCode = 1;
23155
+ return;
23156
+ }
23124
23157
  const { baseUrl, accessToken } = requireAuthToken();
23125
23158
  try {
23126
- const result = await revalidateExchangeApiKey(baseUrl, accessToken, opts.name);
23159
+ const result = await revalidateExchangeApiKey(baseUrl, accessToken, exchangeName);
23127
23160
  if (opts.json) {
23128
23161
  printJson(result);
23129
23162
  } else {
23130
- const status = result.is_valid ? "valid" : "invalid";
23131
- printText(`${opts.name}: ${status}`);
23132
- if (result.missing_permissions.length > 0) {
23133
- printText(`Missing permissions: ${result.missing_permissions.join(", ")}`);
23163
+ for (const line of formatRevalidateText(exchangeName, result)) {
23164
+ printText(line);
23134
23165
  }
23135
23166
  }
23136
23167
  } catch (err) {
23137
- const message = err instanceof Error ? err.message : String(err);
23138
- printText(`Failed to revalidate exchange API key: ${message}`);
23168
+ printText(formatExchangeCommandErrorMessage("revalidate", err));
23139
23169
  process.exitCode = 1;
23140
23170
  }
23141
23171
  });
@@ -24971,6 +25001,56 @@ function formatCampaignTimestamp(value) {
24971
25001
  return "-";
24972
25002
  return value.replace("T", " ").replace(/\.\d+Z$/, "").replace(/Z$/, "");
24973
25003
  }
25004
+ function formatUtcTimestamp(value) {
25005
+ if (typeof value !== "string")
25006
+ return "-";
25007
+ const date = new Date(value);
25008
+ if (Number.isNaN(date.getTime()))
25009
+ return String(value);
25010
+ return date.toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC");
25011
+ }
25012
+ function formatMetricValue(value) {
25013
+ if (value === null || value === undefined)
25014
+ return "-";
25015
+ if (typeof value === "number") {
25016
+ return Number.isInteger(value) ? String(value) : value.toFixed(4).replace(/\.0+$/, "").replace(/(\.\d*?)0+$/, "$1");
25017
+ }
25018
+ if (typeof value === "string") {
25019
+ const trimmed = value.trim();
25020
+ if (trimmed && /^-?\d+(\.\d+)?$/.test(trimmed)) {
25021
+ const num = Number(trimmed);
25022
+ if (!Number.isNaN(num)) {
25023
+ return formatMetricValue(num);
25024
+ }
25025
+ }
25026
+ return value;
25027
+ }
25028
+ return JSON.stringify(value);
25029
+ }
25030
+ function printAlignedMetric(label, value, labelWidth = 14) {
25031
+ printText(` ${label.padEnd(labelWidth)} ${formatMetricValue(value)}`);
25032
+ }
25033
+ function printCampaignProgressCard(result) {
25034
+ const myMeta = result.my_meta && typeof result.my_meta === "object" ? result.my_meta : {};
25035
+ const totalMeta = result.total_meta && typeof result.total_meta === "object" ? result.total_meta : {};
25036
+ const myScore = Number(result.my_score ?? 0);
25037
+ const totalScore = Number(totalMeta.total_score ?? 0);
25038
+ const scoreShare = totalScore > 0 && Number.isFinite(myScore) ? `${(myScore / totalScore * 100).toFixed(2)}%` : "-";
25039
+ printText("Campaign Progress");
25040
+ printText("-----------------");
25041
+ printText("[Window]");
25042
+ printAlignedMetric("From", formatUtcTimestamp(result.from));
25043
+ printAlignedMetric("To", formatUtcTimestamp(result.to));
25044
+ printText("");
25045
+ printText("[Mine]");
25046
+ printAlignedMetric("Score", result.my_score);
25047
+ printAlignedMetric("Token balance", myMeta.token_balance);
25048
+ printAlignedMetric("Score share", scoreShare);
25049
+ printText("");
25050
+ printText("[Totals]");
25051
+ printAlignedMetric("Total score", totalMeta.total_score);
25052
+ printAlignedMetric("Total balance", totalMeta.total_balance);
25053
+ }
24974
25054
  function formatTokenAmount(value, decimals, displayDecimals = 2) {
24975
25055
  const amount = new bignumber_default(value).dividedBy(new bignumber_default(10).pow(decimals));
24976
25056
  const rounded = amount.decimalPlaces(displayDecimals, bignumber_default.ROUND_HALF_UP);
@@ -24986,6 +25066,34 @@ function getLauncherUrl() {
24986
25066
  const config = loadConfig();
24987
25067
  return (config.launcherApiUrl ?? "https://cl.hu.finance").replace(/\/+$/, "");
24988
25068
  }
25069
+ function printCampaignSummary(campaign, options = {}) {
25070
+ const indent = options.indent ?? "";
25071
+ const joinedTag = options.joinedTag ?? "";
25072
+ const showLauncher = options.showLauncher ?? true;
25073
+ const exchange = String(campaign.exchange_name ?? "?");
25074
+ const symbol = String(campaign.symbol ?? "?");
25075
+ const type = String(campaign.type ?? "?");
25076
+ const chainId = String(campaign.chain_id ?? "-");
25077
+ const address = String(campaign.address ?? campaign.escrow_address ?? "-");
25078
+ const status = String(campaign.status ?? "-");
25079
+ const startDate = typeof campaign.start_date === "string" ? campaign.start_date : undefined;
25080
+ const endDate = typeof campaign.end_date === "string" ? campaign.end_date : undefined;
25081
+ const launcher = typeof campaign.launcher === "string" ? campaign.launcher : undefined;
25082
+ const decimals = Number(campaign.fund_token_decimals ?? 0);
25083
+ const fundAmount = new bignumber_default(String(campaign.fund_amount ?? 0));
25084
+ const balanceNum = new bignumber_default(String(campaign.balance ?? 0));
25085
+ const pct = fundAmount.gt(0) ? balanceNum.dividedBy(fundAmount).times(100).toFixed(1) : "0.0";
25086
+ const fundTokenSymbol = String(campaign.fund_token_symbol ?? campaign.fund_token ?? "-");
25087
+ printText(`${indent}${exchange} ${symbol} (${type})${joinedTag}`);
25088
+ printText(`${indent} chain: ${chainId}`);
25089
+ printText(`${indent} address: ${address}`);
25090
+ printText(`${indent} status: ${status}`);
25091
+ printText(`${indent} duration: ${formatCampaignTimestamp(startDate)} ~ ${formatCampaignTimestamp(endDate)}`);
25092
+ printText(`${indent} funded: ${formatTokenAmount(String(campaign.fund_amount ?? 0), decimals)} ${fundTokenSymbol} paid: ${formatTokenAmount(String(campaign.amount_paid ?? 0), decimals)} balance: ${formatTokenAmount(String(campaign.balance ?? 0), decimals)} (${pct}%)`);
25093
+ if (showLauncher && launcher) {
25094
+ printText(`${indent} launcher: ${launcher}`);
25095
+ }
25096
+ }
24989
25097
  function createCampaignCommand() {
24990
25098
  const campaign = new Command("campaign").description("Campaign management commands");
24991
25099
  campaign.command("list").description("List available campaigns").option("-c, --chain-id <id>", "Chain ID (default: from config)", Number, getDefaultChainId()).option("-s, --status <status>", "Filter by status (active, completed, cancelled, to_cancel)", "active").option("--page <n>", "Page number", Number, 1).option("--page-size <n>", "Items per page", Number, 20).option("-l, --limit <n>", "Max results", Number, 20).option("--json", "Output as JSON").action(async (opts) => {
@@ -25017,16 +25125,10 @@ function createCampaignCommand() {
25017
25125
  const key = `${c.chain_id}:${c.address}`;
25018
25126
  const joined = joinedKeys.has(key);
25019
25127
  const tag = joined ? " [JOINED]" : "";
25020
- const decimals = c.fund_token_decimals ?? 0;
25021
- const fundAmount = new bignumber_default(c.fund_amount);
25022
- const balanceNum = new bignumber_default(c.balance);
25023
- const pct = fundAmount.gt(0) ? balanceNum.dividedBy(fundAmount).times(100).toFixed(1) : "0.0";
25024
- printText(` ${c.exchange_name} ${c.symbol} (${c.type})${tag}`);
25025
- printText(` chain: ${c.chain_id}`);
25026
- printText(` address: ${c.address}`);
25027
- printText(` status: ${c.status}`);
25028
- printText(` duration: ${formatCampaignTimestamp(c.start_date)} ~ ${formatCampaignTimestamp(c.end_date)}`);
25029
- printText(` funded: ${formatTokenAmount(c.fund_amount, decimals)} ${c.fund_token_symbol} paid: ${formatTokenAmount(c.amount_paid, decimals)} balance: ${formatTokenAmount(c.balance, decimals)} (${pct}%)`);
25128
+ printCampaignSummary(c, {
25129
+ indent: " ",
25130
+ joinedTag: tag
25131
+ });
25030
25132
  printText("");
25031
25133
  }
25032
25134
  if (opts.status === "active") {
@@ -25078,10 +25180,24 @@ function createCampaignCommand() {
25078
25180
  if (campaigns.length === 0) {
25079
25181
  printText("No joined campaigns found.");
25080
25182
  } else {
25081
- printText(`Joined campaigns (${campaigns.length}):`);
25183
+ printText(`Joined campaigns (${campaigns.length}):
25184
+ `);
25082
25185
  for (const c of campaigns) {
25083
- const label = c.campaign_name ?? c.name ?? c.id;
25084
- printText(` - ${label}`);
25186
+ const record = c;
25187
+ const hasListMetadata = Boolean(record.exchange_name ?? record.symbol ?? record.type ?? record.address ?? record.escrow_address);
25188
+ if (hasListMetadata) {
25189
+ printCampaignSummary(record, {
25190
+ indent: " ",
25191
+ showLauncher: typeof record.launcher === "string"
25192
+ });
25193
+ } else {
25194
+ const exchange = String(record.exchange_name ?? "").trim();
25195
+ const symbol = String(record.symbol ?? "").trim();
25196
+ const exchangeSymbol = [exchange, symbol].filter(Boolean).join(" ");
25197
+ const label = record.campaign_name ?? record.name ?? (exchangeSymbol || undefined) ?? record.address ?? record.escrow_address ?? c.id ?? "(unnamed campaign)";
25198
+ printText(` - ${label}`);
25199
+ }
25200
+ printText("");
25085
25201
  }
25086
25202
  }
25087
25203
  }
@@ -25171,9 +25287,12 @@ function createCampaignCommand() {
25171
25287
  const r = result;
25172
25288
  if (r.message) {
25173
25289
  printText(String(r.message));
25290
+ } else if ("from" in r || "to" in r || "my_score" in r || "my_meta" in r || "total_meta" in r) {
25291
+ printCampaignProgressCard(r);
25174
25292
  } else {
25175
25293
  for (const [key, value] of Object.entries(r)) {
25176
- printText(` ${key}: ${value}`);
25294
+ const displayValue = value !== null && typeof value === "object" ? JSON.stringify(value) : String(value);
25295
+ printText(` ${key}: ${displayValue}`);
25177
25296
  }
25178
25297
  }
25179
25298
  }
@@ -25406,11 +25525,17 @@ function createStakingCommand() {
25406
25525
  process.exitCode = 1;
25407
25526
  }
25408
25527
  });
25409
- staking.command("stake").description("Stake HMT tokens").requiredOption("-a, --amount <amount>", "Amount of HMT to stake").option("-c, --chain-id <id>", "Chain ID (default: from config)", Number, getDefaultChainId()).option("--json", "Output as JSON").action(async (opts) => {
25528
+ staking.command("stake [amount]").description("Stake HMT tokens").usage("[amount] [options]").option("-a, --amount <amount>", "Amount of HMT to stake").option("-c, --chain-id <id>", "Chain ID (default: from config)", Number, getDefaultChainId()).option("--json", "Output as JSON").action(async (amountArg, opts) => {
25529
+ const amount = amountArg ?? opts.amount;
25530
+ if (!amount) {
25531
+ printText("Amount is required. Usage: hufi staking stake <amount>");
25532
+ process.exitCode = 1;
25533
+ return;
25534
+ }
25410
25535
  const privateKey = requireKey();
25411
25536
  try {
25412
- printText(`Staking ${opts.amount} HMT on chain ${opts.chainId}...`);
25413
- const hash2 = await stakeHMT(privateKey, opts.amount, opts.chainId);
25537
+ printText(`Staking ${amount} HMT on chain ${opts.chainId}...`);
25538
+ const hash2 = await stakeHMT(privateKey, amount, opts.chainId);
25414
25539
  if (opts.json) {
25415
25540
  printJson({ txHash: hash2 });
25416
25541
  } else {
@@ -25423,11 +25548,17 @@ function createStakingCommand() {
25423
25548
  process.exitCode = 1;
25424
25549
  }
25425
25550
  });
25426
- staking.command("unstake").description("Initiate unstaking (tokens will be locked for the lock period)").requiredOption("-a, --amount <amount>", "Amount of HMT to unstake").option("-c, --chain-id <id>", "Chain ID (default: from config)", Number, getDefaultChainId()).option("--json", "Output as JSON").action(async (opts) => {
25551
+ staking.command("unstake [amount]").description("Initiate unstaking (tokens will be locked for the lock period)").usage("[amount] [options]").option("-a, --amount <amount>", "Amount of HMT to unstake").option("-c, --chain-id <id>", "Chain ID (default: from config)", Number, getDefaultChainId()).option("--json", "Output as JSON").action(async (amountArg, opts) => {
25552
+ const amount = amountArg ?? opts.amount;
25553
+ if (!amount) {
25554
+ printText("Amount is required. Usage: hufi staking unstake <amount>");
25555
+ process.exitCode = 1;
25556
+ return;
25557
+ }
25427
25558
  const privateKey = requireKey();
25428
25559
  try {
25429
- printText(`Unstaking ${opts.amount} HMT on chain ${opts.chainId}...`);
25430
- const hash2 = await unstakeHMT(privateKey, opts.amount, opts.chainId);
25560
+ printText(`Unstaking ${amount} HMT on chain ${opts.chainId}...`);
25561
+ const hash2 = await unstakeHMT(privateKey, amount, opts.chainId);
25431
25562
  if (opts.json) {
25432
25563
  printJson({ txHash: hash2 });
25433
25564
  } else {
@@ -25600,7 +25731,7 @@ function createDashboardCommand() {
25600
25731
 
25601
25732
  // src/cli.ts
25602
25733
  var program2 = new Command;
25603
- program2.name("hufi").description("CLI tool for hu.fi DeFi platform").version("1.0.1").option("--config-file <path>", "Custom config file path (default: ~/.hufi-cli/config.json)").option("--key-file <path>", "Custom key file path (default: ~/.hufi-cli/key.json)").hook("preAction", (thisCommand) => {
25734
+ program2.name("hufi").description("CLI tool for hu.fi DeFi platform").version("1.0.2").option("--config-file <path>", "Custom config file path (default: ~/.hufi-cli/config.json)").option("--key-file <path>", "Custom key file path (default: ~/.hufi-cli/key.json)").hook("preAction", (thisCommand) => {
25604
25735
  const opts = thisCommand.opts();
25605
25736
  if (opts.configFile) {
25606
25737
  setConfigFile(opts.configFile);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hufi-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "hufi": "./dist/cli.js"