mihomo-cli 2.7.0 → 2.7.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.
- package/CHANGELOG.md +21 -0
- package/README.md +2 -2
- package/dist/index.js +20 -23
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.7.2] - 2026-05-04
|
|
4
|
+
|
|
5
|
+
### 修复
|
|
6
|
+
|
|
7
|
+
- **进度条轮次标题** - 多轮测试时第 1 轮标题正确显示在进度条之前,单轮不显示轮次标题
|
|
8
|
+
|
|
9
|
+
### 改进
|
|
10
|
+
|
|
11
|
+
- **自定义轮数** - clean 命令支持 `-r N` / `--rounds N` 指定测试轮数(默认 3)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## [2.7.1] - 2026-05-04
|
|
16
|
+
|
|
17
|
+
### 修复
|
|
18
|
+
|
|
19
|
+
- **进度条计数器修复** - 清理/测试多轮重试时,✓/✗ 计数不再跨轮累加,每轮独立计数
|
|
20
|
+
- **轮次标题位置修复** - 移除错位的"第 1 轮测试"标题,重试轮标题正确显示在对应进度条之前
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
3
24
|
## [2.7.0] - 2026-05-03
|
|
4
25
|
|
|
5
26
|
### 移除
|
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]
|
|
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
|
|
@@ -4812,7 +4812,7 @@ function cleanDeadProxies(parsed, deadNames) {
|
|
|
4812
4812
|
}
|
|
4813
4813
|
async function autoCleanSubscription(subName, options = {}) {
|
|
4814
4814
|
const parsed = loadSubscriptionConfig(subName);
|
|
4815
|
-
const { onResult, onRetryRound, ...testOptions } = options;
|
|
4815
|
+
const { onResult, onRetryRound, rounds = 3, ...testOptions } = options;
|
|
4816
4816
|
const wrapOnResult = (round) => onResult ? (r, i, t) => onResult(r, i, t, round) : void 0;
|
|
4817
4817
|
const summary = await testSubscriptionProxies(subName, {
|
|
4818
4818
|
...testOptions,
|
|
@@ -4829,7 +4829,7 @@ async function autoCleanSubscription(subName, options = {}) {
|
|
|
4829
4829
|
} else {
|
|
4830
4830
|
const deadNames = new Set(summary.results.filter((r) => r.delay === null).map((r) => r.name));
|
|
4831
4831
|
const deadProxies = parsed.proxies.filter((p) => deadNames.has(p.name));
|
|
4832
|
-
for (let retry = 0; retry <
|
|
4832
|
+
for (let retry = 0; retry < rounds - 1; retry++) {
|
|
4833
4833
|
const round = retry + 2;
|
|
4834
4834
|
const retryTargets = deadProxies.filter((p) => deadNames.has(p.name));
|
|
4835
4835
|
if (retryTargets.length === 0) break;
|
|
@@ -5042,10 +5042,10 @@ async function withTestInstance(subName, fn) {
|
|
|
5042
5042
|
// src/commands/subscription.ts
|
|
5043
5043
|
var IS_TTY = process.stdout.isTTY === true;
|
|
5044
5044
|
var BAR_WIDTH = 20;
|
|
5045
|
-
function createProgressPrinter() {
|
|
5045
|
+
function createProgressPrinter(totalRounds = 1) {
|
|
5046
5046
|
let alive = 0;
|
|
5047
5047
|
let dead = 0;
|
|
5048
|
-
let
|
|
5048
|
+
let started = false;
|
|
5049
5049
|
const resultMap = /* @__PURE__ */ new Map();
|
|
5050
5050
|
function render(done, total) {
|
|
5051
5051
|
if (!IS_TTY) return;
|
|
@@ -5056,31 +5056,24 @@ function createProgressPrinter() {
|
|
|
5056
5056
|
}
|
|
5057
5057
|
return {
|
|
5058
5058
|
onResult(result, index, total, round = 1) {
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
if (
|
|
5062
|
-
|
|
5063
|
-
dead--;
|
|
5059
|
+
if (!started) {
|
|
5060
|
+
started = true;
|
|
5061
|
+
if (totalRounds > 1) {
|
|
5062
|
+
console.log(`--- \u7B2C 1 \u8F6E\u6D4B\u8BD5 (${total} \u4E2A\u8282\u70B9) ---`);
|
|
5064
5063
|
}
|
|
5065
|
-
} else {
|
|
5066
|
-
if (result.delay !== null) alive++;
|
|
5067
|
-
else dead++;
|
|
5068
5064
|
}
|
|
5065
|
+
if (result.delay !== null) alive++;
|
|
5066
|
+
else dead++;
|
|
5069
5067
|
resultMap.set(result.name, { result, round });
|
|
5070
5068
|
render(index + 1, total);
|
|
5071
5069
|
},
|
|
5072
5070
|
onRetryRound(round, count) {
|
|
5073
|
-
if (!hasRetry) {
|
|
5074
|
-
hasRetry = true;
|
|
5075
|
-
if (IS_TTY) {
|
|
5076
|
-
process.stdout.write("\n");
|
|
5077
|
-
}
|
|
5078
|
-
console.log(`--- \u7B2C 1 \u8F6E\u6D4B\u8BD5 (${resultMap.size} \u4E2A\u8282\u70B9) ---`);
|
|
5079
|
-
}
|
|
5080
5071
|
if (IS_TTY) {
|
|
5081
5072
|
process.stdout.write("\n");
|
|
5082
5073
|
}
|
|
5083
5074
|
console.log(`--- \u7B2C ${round} \u8F6E\u91CD\u8BD5 (${count} \u4E2A\u8282\u70B9) ---`);
|
|
5075
|
+
alive = 0;
|
|
5076
|
+
dead = 0;
|
|
5084
5077
|
},
|
|
5085
5078
|
finish() {
|
|
5086
5079
|
if (IS_TTY) {
|
|
@@ -5396,14 +5389,16 @@ async function cmdSubscription(args) {
|
|
|
5396
5389
|
}
|
|
5397
5390
|
if (action === "clean") {
|
|
5398
5391
|
const { target, timeout, concurrency } = resolveTestTarget(args);
|
|
5392
|
+
const rounds = parseIntArg(args, "-r", "--rounds", 3);
|
|
5399
5393
|
console.log(`\u6E05\u7406\u8BA2\u9605 "${target.name}"...`);
|
|
5400
5394
|
console.log(`\u8D85\u65F6: ${timeout}ms \u5E76\u53D1: ${concurrency}`);
|
|
5401
5395
|
console.log("");
|
|
5402
|
-
const progress = createProgressPrinter();
|
|
5396
|
+
const progress = createProgressPrinter(rounds);
|
|
5403
5397
|
const result = await withTestInstance(target.name, async (apiBase) => {
|
|
5404
5398
|
return autoCleanSubscription(target.name, {
|
|
5405
5399
|
timeout,
|
|
5406
5400
|
concurrency,
|
|
5401
|
+
rounds,
|
|
5407
5402
|
apiBase,
|
|
5408
5403
|
onResult: progress.onResult,
|
|
5409
5404
|
onRetryRound: progress.onRetryRound
|
|
@@ -5505,7 +5500,7 @@ async function cmdStart(args) {
|
|
|
5505
5500
|
console.log(`\u8282\u70B9\u6570 ${configInfo.proxies} \u8D85\u8FC7 ${AUTO_CLEAN_THRESHOLD}\uFF0C\u81EA\u52A8\u6E05\u7406...`);
|
|
5506
5501
|
console.log("");
|
|
5507
5502
|
await sleep(1e3);
|
|
5508
|
-
const progress = createProgressPrinter();
|
|
5503
|
+
const progress = createProgressPrinter(3);
|
|
5509
5504
|
const cleanResult = await autoCleanSubscription(sub.name, {
|
|
5510
5505
|
onResult: progress.onResult,
|
|
5511
5506
|
onRetryRound: progress.onRetryRound
|
|
@@ -5817,13 +5812,15 @@ async function cmdClean(args) {
|
|
|
5817
5812
|
const activeSub = requireActiveSub();
|
|
5818
5813
|
const timeout = parseIntArg(args, "-t", "--timeout", 1500);
|
|
5819
5814
|
const concurrency = parseIntArg(args, "-j", "--concurrency", 100);
|
|
5815
|
+
const rounds = parseIntArg(args, "-r", "--rounds", 3);
|
|
5820
5816
|
console.log(`\u6E05\u7406 "${activeSub.name}" \u5931\u8D25\u8282\u70B9...`);
|
|
5821
5817
|
console.log(`\u8D85\u65F6: ${timeout}ms \u5E76\u53D1: ${concurrency}`);
|
|
5822
5818
|
console.log("");
|
|
5823
|
-
const progress = createProgressPrinter();
|
|
5819
|
+
const progress = createProgressPrinter(rounds);
|
|
5824
5820
|
const result = await autoCleanSubscription(activeSub.name, {
|
|
5825
5821
|
timeout,
|
|
5826
5822
|
concurrency,
|
|
5823
|
+
rounds,
|
|
5827
5824
|
onResult: progress.onResult,
|
|
5828
5825
|
onRetryRound: progress.onRetryRound
|
|
5829
5826
|
});
|