mihomo-cli 2.7.1 → 2.7.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.7.3] - 2026-05-04
4
+
5
+ ### 改进
6
+
7
+ - **代码清理** - 提取 `DEFAULT_CLEAN_ROUNDS` 常量,消除重复魔数;简化进度条内部状态
8
+
9
+ ---
10
+
11
+ ## [2.7.2] - 2026-05-04
12
+
13
+ ### 修复
14
+
15
+ - **进度条轮次标题** - 多轮测试时第 1 轮标题正确显示在进度条之前,单轮不显示轮次标题
16
+
17
+ ### 改进
18
+
19
+ - **自定义轮数** - clean 命令支持 `-r N` / `--rounds N` 指定测试轮数(默认 3)
20
+
21
+ ---
22
+
3
23
  ## [2.7.1] - 2026-05-04
4
24
 
5
25
  ### 修复
package/README.md CHANGED
@@ -102,9 +102,9 @@ mihomo ui yacd # YACD
102
102
  | `mihomo sub remove <name>` | 删除订阅(支持模糊匹配) |
103
103
  | `mihomo sub web [name]` | 打开订阅页面(无参打开默认) |
104
104
  | `mihomo sub test [name]` | 测试节点连通性(`-t` 超时,`-j` 并发) |
105
- | `mihomo sub clean [name]` | 测速并清理失败节点 |
105
+ | `mihomo sub clean [name]` | 测速并清理失败节点(`-r` 轮数,默认3)|
106
106
  | `mihomo test` | 快速测试当前节点连通性(`-t` 超时,`-j` 并发) |
107
- | `mihomo clean` | 清理失败节点并自动重启(`-t` 超时,`-j` 并发) |
107
+ | `mihomo clean` | 清理失败节点并自动重启(`-t` 超时,`-j` 并发,`-r` 轮数) |
108
108
 
109
109
  ### 覆写配置
110
110
 
package/dist/index.js CHANGED
@@ -4031,7 +4031,7 @@ ${colors.cyan("\u8BA2\u9605:")}
4031
4031
  ${colors.bold("subscription")} test [name] \u6D4B\u8BD5\u8282\u70B9\u8FDE\u901A\u6027
4032
4032
  ${colors.bold("subscription")} clean [name] \u6D4B\u901F\u5E76\u6E05\u7406\u5931\u8D25\u8282\u70B9
4033
4033
  ${colors.bold("test")} [-t ms] [-j N] \u5FEB\u901F\u6D4B\u8BD5\u5F53\u524D\u8282\u70B9\u8FDE\u901A\u6027
4034
- ${colors.bold("clean")} [-t ms] [-j N] \u6E05\u7406\u5931\u8D25\u8282\u70B9\u5E76\u81EA\u52A8\u91CD\u542F
4034
+ ${colors.bold("clean")} [-t ms] [-j N] [-r N] \u6E05\u7406\u5931\u8D25\u8282\u70B9\u5E76\u81EA\u52A8\u91CD\u542F
4035
4035
 
4036
4036
  ${colors.cyan("\u914D\u7F6E:")}
4037
4037
  ${colors.bold("overwrite")} \u67E5\u770B\u8986\u5199\u72B6\u6001\uFF08\u522B\u540D ow\uFF09
@@ -4433,6 +4433,7 @@ import path6 from "path";
4433
4433
 
4434
4434
  // src/subscription.ts
4435
4435
  var DEFAULT_UPDATE_INTERVAL_HOURS = 4;
4436
+ var DEFAULT_CLEAN_ROUNDS = 3;
4436
4437
  var YAML_DUMP_OPTS = { indent: 2, lineWidth: -1, noCompatMode: true };
4437
4438
  var HTTP_CLIENT2 = createHttpClient({ timeout: 6e4 });
4438
4439
  function isMultiUrl(url) {
@@ -4812,7 +4813,7 @@ function cleanDeadProxies(parsed, deadNames) {
4812
4813
  }
4813
4814
  async function autoCleanSubscription(subName, options = {}) {
4814
4815
  const parsed = loadSubscriptionConfig(subName);
4815
- const { onResult, onRetryRound, ...testOptions } = options;
4816
+ const { onResult, onRetryRound, rounds = DEFAULT_CLEAN_ROUNDS, ...testOptions } = options;
4816
4817
  const wrapOnResult = (round) => onResult ? (r, i, t) => onResult(r, i, t, round) : void 0;
4817
4818
  const summary = await testSubscriptionProxies(subName, {
4818
4819
  ...testOptions,
@@ -4829,7 +4830,7 @@ async function autoCleanSubscription(subName, options = {}) {
4829
4830
  } else {
4830
4831
  const deadNames = new Set(summary.results.filter((r) => r.delay === null).map((r) => r.name));
4831
4832
  const deadProxies = parsed.proxies.filter((p) => deadNames.has(p.name));
4832
- for (let retry = 0; retry < 2; retry++) {
4833
+ for (let retry = 0; retry < rounds - 1; retry++) {
4833
4834
  const round = retry + 2;
4834
4835
  const retryTargets = deadProxies.filter((p) => deadNames.has(p.name));
4835
4836
  if (retryTargets.length === 0) break;
@@ -5042,7 +5043,7 @@ async function withTestInstance(subName, fn) {
5042
5043
  // src/commands/subscription.ts
5043
5044
  var IS_TTY = process.stdout.isTTY === true;
5044
5045
  var BAR_WIDTH = 20;
5045
- function createProgressPrinter() {
5046
+ function createProgressPrinter(totalRounds = 1) {
5046
5047
  let alive = 0;
5047
5048
  let dead = 0;
5048
5049
  const resultMap = /* @__PURE__ */ new Map();
@@ -5055,6 +5056,9 @@ function createProgressPrinter() {
5055
5056
  }
5056
5057
  return {
5057
5058
  onResult(result, index, total, round = 1) {
5059
+ if (resultMap.size === 0 && totalRounds > 1) {
5060
+ console.log(`--- \u7B2C 1 \u8F6E\u6D4B\u8BD5 (${total} \u4E2A\u8282\u70B9) ---`);
5061
+ }
5058
5062
  if (result.delay !== null) alive++;
5059
5063
  else dead++;
5060
5064
  resultMap.set(result.name, { result, round });
@@ -5382,14 +5386,16 @@ async function cmdSubscription(args) {
5382
5386
  }
5383
5387
  if (action === "clean") {
5384
5388
  const { target, timeout, concurrency } = resolveTestTarget(args);
5389
+ const rounds = parseIntArg(args, "-r", "--rounds", DEFAULT_CLEAN_ROUNDS);
5385
5390
  console.log(`\u6E05\u7406\u8BA2\u9605 "${target.name}"...`);
5386
5391
  console.log(`\u8D85\u65F6: ${timeout}ms \u5E76\u53D1: ${concurrency}`);
5387
5392
  console.log("");
5388
- const progress = createProgressPrinter();
5393
+ const progress = createProgressPrinter(rounds);
5389
5394
  const result = await withTestInstance(target.name, async (apiBase) => {
5390
5395
  return autoCleanSubscription(target.name, {
5391
5396
  timeout,
5392
5397
  concurrency,
5398
+ rounds,
5393
5399
  apiBase,
5394
5400
  onResult: progress.onResult,
5395
5401
  onRetryRound: progress.onRetryRound
@@ -5491,7 +5497,7 @@ async function cmdStart(args) {
5491
5497
  console.log(`\u8282\u70B9\u6570 ${configInfo.proxies} \u8D85\u8FC7 ${AUTO_CLEAN_THRESHOLD}\uFF0C\u81EA\u52A8\u6E05\u7406...`);
5492
5498
  console.log("");
5493
5499
  await sleep(1e3);
5494
- const progress = createProgressPrinter();
5500
+ const progress = createProgressPrinter(DEFAULT_CLEAN_ROUNDS);
5495
5501
  const cleanResult = await autoCleanSubscription(sub.name, {
5496
5502
  onResult: progress.onResult,
5497
5503
  onRetryRound: progress.onRetryRound
@@ -5803,13 +5809,15 @@ async function cmdClean(args) {
5803
5809
  const activeSub = requireActiveSub();
5804
5810
  const timeout = parseIntArg(args, "-t", "--timeout", 1500);
5805
5811
  const concurrency = parseIntArg(args, "-j", "--concurrency", 100);
5812
+ const rounds = parseIntArg(args, "-r", "--rounds", DEFAULT_CLEAN_ROUNDS);
5806
5813
  console.log(`\u6E05\u7406 "${activeSub.name}" \u5931\u8D25\u8282\u70B9...`);
5807
5814
  console.log(`\u8D85\u65F6: ${timeout}ms \u5E76\u53D1: ${concurrency}`);
5808
5815
  console.log("");
5809
- const progress = createProgressPrinter();
5816
+ const progress = createProgressPrinter(rounds);
5810
5817
  const result = await autoCleanSubscription(activeSub.name, {
5811
5818
  timeout,
5812
5819
  concurrency,
5820
+ rounds,
5813
5821
  onResult: progress.onResult,
5814
5822
  onRetryRound: progress.onRetryRound
5815
5823
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mihomo-cli",
3
- "version": "2.7.1",
3
+ "version": "2.7.3",
4
4
  "type": "module",
5
5
  "description": "A terminal-based mihomo (Clash.Meta) client for macOS",
6
6
  "bin": {