mihomo-cli 2.7.2 → 2.8.0
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 +22 -0
- package/README.md +4 -4
- package/dist/index.js +32 -20
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.8.0] - 2026-05-05
|
|
4
|
+
|
|
5
|
+
### 新功能
|
|
6
|
+
|
|
7
|
+
- **start/up 支持测速参数** - `-r N` 清理轮次、`-t ms` 超时、`-j N` 并发数
|
|
8
|
+
- **GitHub 订阅差异化策略** - 自动清理阈值 GitHub 50 / 其他 100;默认更新间隔 GitHub 6h / 其他 12h
|
|
9
|
+
|
|
10
|
+
### 改进
|
|
11
|
+
|
|
12
|
+
- **默认测速轮次** - 从 3 轮调整为 2 轮
|
|
13
|
+
- **统一超时默认值** - 所有测速命令默认超时统一为 2000ms
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## [2.7.3] - 2026-05-04
|
|
18
|
+
|
|
19
|
+
### 改进
|
|
20
|
+
|
|
21
|
+
- **代码清理** - 提取 `DEFAULT_CLEAN_ROUNDS` 常量,消除重复魔数;简化进度条内部状态
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
3
25
|
## [2.7.2] - 2026-05-04
|
|
4
26
|
|
|
5
27
|
### 修复
|
package/README.md
CHANGED
|
@@ -83,7 +83,7 @@ mihomo ui yacd # YACD
|
|
|
83
83
|
|
|
84
84
|
| 命令 | 说明 |
|
|
85
85
|
| --------------------------- | ---------------------------------------------------------------------------- |
|
|
86
|
-
| `mihomo start [tun\|mixed]` |
|
|
86
|
+
| `mihomo start [tun\|mixed]` | 启动/重启/切换代理模式(`-r` 清理轮次,`-t` 超时,`-j` 并发) |
|
|
87
87
|
| `mihomo stop` | 停止代理 |
|
|
88
88
|
| `mihomo status` | 查看运行状态 |
|
|
89
89
|
| `mihomo log` | 实时查看日志 (`-o` 用系统编辑器打开) |
|
|
@@ -102,7 +102,7 @@ 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]` | 测速并清理失败节点(`-r` 轮数,默认
|
|
105
|
+
| `mihomo sub clean [name]` | 测速并清理失败节点(`-r` 轮数,默认2)|
|
|
106
106
|
| `mihomo test` | 快速测试当前节点连通性(`-t` 超时,`-j` 并发) |
|
|
107
107
|
| `mihomo clean` | 清理失败节点并自动重启(`-t` 超时,`-j` 并发,`-r` 轮数) |
|
|
108
108
|
|
|
@@ -142,7 +142,7 @@ mihomo ui yacd # YACD
|
|
|
142
142
|
|
|
143
143
|
| 快捷命令 | 等效于 |
|
|
144
144
|
| ---------------------- | -------------------------- |
|
|
145
|
-
| `mihomo up` | `mihomo start
|
|
145
|
+
| `mihomo up` | `mihomo start`(同样支持 `-r`/`-t`/`-j`)|
|
|
146
146
|
| `mihomo down` | `mihomo stop` |
|
|
147
147
|
| `mihomo tun` | `mihomo start tun` |
|
|
148
148
|
| `mihomo use <name>` | `mihomo sub use <name>` |
|
|
@@ -194,7 +194,7 @@ mihomo kernel --mirror-all hk.gh-proxy.org
|
|
|
194
194
|
|
|
195
195
|
## 订阅自动更新
|
|
196
196
|
|
|
197
|
-
- 默认更新间隔:
|
|
197
|
+
- 默认更新间隔:GitHub 订阅 6 小时,其他订阅 12 小时(订阅服务端可通过 `profile-update-interval` 覆盖)
|
|
198
198
|
- 触发时机:`start` 命令、`sub list` 命令
|
|
199
199
|
- 更新失败时继续使用本地缓存,不影响使用
|
|
200
200
|
|
package/dist/index.js
CHANGED
|
@@ -4012,7 +4012,7 @@ ${colors.cyan(colors.bold(`mihomo-cli v${VERSION}`))}
|
|
|
4012
4012
|
mihomo <\u547D\u4EE4> [\u9009\u9879]
|
|
4013
4013
|
|
|
4014
4014
|
${colors.cyan("\u63A7\u5236:")}
|
|
4015
|
-
${colors.bold("start")} [tun|mixed]
|
|
4015
|
+
${colors.bold("start")} [tun|mixed] [-r N] [-t ms] [-j N] \u542F\u52A8/\u5207\u6362\u4EE3\u7406 (\u9ED8\u8BA4 mixed)
|
|
4016
4016
|
${colors.bold("stop")} \u505C\u6B62\u4EE3\u7406
|
|
4017
4017
|
${colors.bold("status")} \u67E5\u770B\u72B6\u6001
|
|
4018
4018
|
|
|
@@ -4432,7 +4432,17 @@ function cmdLogs(args) {
|
|
|
4432
4432
|
import path6 from "path";
|
|
4433
4433
|
|
|
4434
4434
|
// src/subscription.ts
|
|
4435
|
-
var DEFAULT_UPDATE_INTERVAL_HOURS =
|
|
4435
|
+
var DEFAULT_UPDATE_INTERVAL_HOURS = 12;
|
|
4436
|
+
var DEFAULT_UPDATE_INTERVAL_HOURS_GITHUB = 6;
|
|
4437
|
+
var DEFAULT_CLEAN_ROUNDS = 2;
|
|
4438
|
+
var AUTO_CLEAN_THRESHOLD = 100;
|
|
4439
|
+
var AUTO_CLEAN_THRESHOLD_GITHUB = 50;
|
|
4440
|
+
function isGithubUrl(url) {
|
|
4441
|
+
return /github\.com|raw\.githubusercontent\.com/i.test(url);
|
|
4442
|
+
}
|
|
4443
|
+
function getDefaultUpdateInterval(url) {
|
|
4444
|
+
return isGithubUrl(url) ? DEFAULT_UPDATE_INTERVAL_HOURS_GITHUB : DEFAULT_UPDATE_INTERVAL_HOURS;
|
|
4445
|
+
}
|
|
4436
4446
|
var YAML_DUMP_OPTS = { indent: 2, lineWidth: -1, noCompatMode: true };
|
|
4437
4447
|
var HTTP_CLIENT2 = createHttpClient({ timeout: 6e4 });
|
|
4438
4448
|
function isMultiUrl(url) {
|
|
@@ -4667,7 +4677,7 @@ function needsAutoUpdate(sub) {
|
|
|
4667
4677
|
if (!sub.updated_at) return true;
|
|
4668
4678
|
const lastUpdate = new Date(sub.updated_at).getTime();
|
|
4669
4679
|
if (Number.isNaN(lastUpdate)) return true;
|
|
4670
|
-
const intervalHours = sub.update_interval ||
|
|
4680
|
+
const intervalHours = sub.update_interval || getDefaultUpdateInterval(sub.url);
|
|
4671
4681
|
const intervalMs = intervalHours * 60 * 60 * 1e3;
|
|
4672
4682
|
return Date.now() - lastUpdate > intervalMs;
|
|
4673
4683
|
}
|
|
@@ -4692,7 +4702,7 @@ async function autoUpdateStaleSubscription() {
|
|
|
4692
4702
|
}
|
|
4693
4703
|
if (staleSubs.length === 1) {
|
|
4694
4704
|
const sub = staleSubs[0];
|
|
4695
|
-
const interval = sub.update_interval ||
|
|
4705
|
+
const interval = sub.update_interval || getDefaultUpdateInterval(sub.url);
|
|
4696
4706
|
console.log(`\u8BA2\u9605 "${sub.name}" \u8D85\u8FC7 ${interval} \u5C0F\u65F6\u672A\u66F4\u65B0\uFF0C\u6B63\u5728\u66F4\u65B0...`);
|
|
4697
4707
|
} else {
|
|
4698
4708
|
console.log(`\u68C0\u67E5\u5230 ${staleSubs.length} \u4E2A\u8BA2\u9605\u9700\u8981\u66F4\u65B0\uFF0C\u6B63\u5728\u5E76\u884C\u66F4\u65B0...`);
|
|
@@ -4812,7 +4822,7 @@ function cleanDeadProxies(parsed, deadNames) {
|
|
|
4812
4822
|
}
|
|
4813
4823
|
async function autoCleanSubscription(subName, options = {}) {
|
|
4814
4824
|
const parsed = loadSubscriptionConfig(subName);
|
|
4815
|
-
const { onResult, onRetryRound, rounds =
|
|
4825
|
+
const { onResult, onRetryRound, rounds = DEFAULT_CLEAN_ROUNDS, ...testOptions } = options;
|
|
4816
4826
|
const wrapOnResult = (round) => onResult ? (r, i, t) => onResult(r, i, t, round) : void 0;
|
|
4817
4827
|
const summary = await testSubscriptionProxies(subName, {
|
|
4818
4828
|
...testOptions,
|
|
@@ -5045,7 +5055,6 @@ var BAR_WIDTH = 20;
|
|
|
5045
5055
|
function createProgressPrinter(totalRounds = 1) {
|
|
5046
5056
|
let alive = 0;
|
|
5047
5057
|
let dead = 0;
|
|
5048
|
-
let started = false;
|
|
5049
5058
|
const resultMap = /* @__PURE__ */ new Map();
|
|
5050
5059
|
function render(done, total) {
|
|
5051
5060
|
if (!IS_TTY) return;
|
|
@@ -5056,11 +5065,8 @@ function createProgressPrinter(totalRounds = 1) {
|
|
|
5056
5065
|
}
|
|
5057
5066
|
return {
|
|
5058
5067
|
onResult(result, index, total, round = 1) {
|
|
5059
|
-
if (
|
|
5060
|
-
|
|
5061
|
-
if (totalRounds > 1) {
|
|
5062
|
-
console.log(`--- \u7B2C 1 \u8F6E\u6D4B\u8BD5 (${total} \u4E2A\u8282\u70B9) ---`);
|
|
5063
|
-
}
|
|
5068
|
+
if (resultMap.size === 0 && totalRounds > 1) {
|
|
5069
|
+
console.log(`--- \u7B2C 1 \u8F6E\u6D4B\u8BD5 (${total} \u4E2A\u8282\u70B9) ---`);
|
|
5064
5070
|
}
|
|
5065
5071
|
if (result.delay !== null) alive++;
|
|
5066
5072
|
else dead++;
|
|
@@ -5155,7 +5161,7 @@ async function printSubscriptionList(options) {
|
|
|
5155
5161
|
const time = formatDate(s.updated_at);
|
|
5156
5162
|
const defaultMark = activeSub && s.name === activeSub.name ? colors.green(" [\u4F7F\u7528\u4E2D]") : "";
|
|
5157
5163
|
const mergeBadge = isMultiUrl(s.url) ? colors.cyan(` [\u5408\u5E76 ${splitUrls(s.url).length} \u6E90]`) : "";
|
|
5158
|
-
const interval = s.update_interval ||
|
|
5164
|
+
const interval = s.update_interval || getDefaultUpdateInterval(s.url);
|
|
5159
5165
|
console.log(` ${i + 1}. ${s.name}${defaultMark}${mergeBadge}`);
|
|
5160
5166
|
console.log(` ${colors.gray("\u66F4\u65B0: ")}${time} (\u95F4\u9694: ${interval}h)`);
|
|
5161
5167
|
if (s.username) {
|
|
@@ -5389,7 +5395,7 @@ async function cmdSubscription(args) {
|
|
|
5389
5395
|
}
|
|
5390
5396
|
if (action === "clean") {
|
|
5391
5397
|
const { target, timeout, concurrency } = resolveTestTarget(args);
|
|
5392
|
-
const rounds = parseIntArg(args, "-r", "--rounds",
|
|
5398
|
+
const rounds = parseIntArg(args, "-r", "--rounds", DEFAULT_CLEAN_ROUNDS);
|
|
5393
5399
|
console.log(`\u6E05\u7406\u8BA2\u9605 "${target.name}"...`);
|
|
5394
5400
|
console.log(`\u8D85\u65F6: ${timeout}ms \u5E76\u53D1: ${concurrency}`);
|
|
5395
5401
|
console.log("");
|
|
@@ -5443,7 +5449,6 @@ async function cmdSubscription(args) {
|
|
|
5443
5449
|
}
|
|
5444
5450
|
|
|
5445
5451
|
// src/commands/start.ts
|
|
5446
|
-
var AUTO_CLEAN_THRESHOLD = 50;
|
|
5447
5452
|
function handleStopResult(result) {
|
|
5448
5453
|
if (result.remaining && result.remaining.length > 0) {
|
|
5449
5454
|
console.error(`${colors.red("\u90E8\u5206\u8FDB\u7A0B\u672A\u7EC8\u6B62:")} ${result.remaining.join(", ")}`);
|
|
@@ -5457,6 +5462,9 @@ async function cmdStart(args) {
|
|
|
5457
5462
|
process.exit(1);
|
|
5458
5463
|
}
|
|
5459
5464
|
const targetMode = args[1] === "tun" ? "tun" : "mixed";
|
|
5465
|
+
const rounds = parseIntArg(args, "-r", "--rounds", DEFAULT_CLEAN_ROUNDS);
|
|
5466
|
+
const timeout = parseIntArg(args, "-t", "--timeout", 2e3);
|
|
5467
|
+
const concurrency = parseIntArg(args, "-j", "--concurrency", 100);
|
|
5460
5468
|
const sub = getActiveSubscription();
|
|
5461
5469
|
if (!sub) {
|
|
5462
5470
|
console.error("\u9519\u8BEF: \u6CA1\u6709\u8BA2\u9605\uFF0C\u8BF7\u5148\u6DFB\u52A0\u8BA2\u9605");
|
|
@@ -5495,13 +5503,17 @@ async function cmdStart(args) {
|
|
|
5495
5503
|
}
|
|
5496
5504
|
process.exit(1);
|
|
5497
5505
|
}
|
|
5498
|
-
|
|
5506
|
+
const cleanThreshold = isGithubUrl(sub.url) ? AUTO_CLEAN_THRESHOLD_GITHUB : AUTO_CLEAN_THRESHOLD;
|
|
5507
|
+
if (configInfo.proxies > cleanThreshold) {
|
|
5499
5508
|
console.log("");
|
|
5500
|
-
console.log(`\u8282\u70B9\u6570 ${configInfo.proxies} \u8D85\u8FC7 ${
|
|
5509
|
+
console.log(`\u8282\u70B9\u6570 ${configInfo.proxies} \u8D85\u8FC7 ${cleanThreshold}\uFF0C\u81EA\u52A8\u6E05\u7406...`);
|
|
5501
5510
|
console.log("");
|
|
5502
5511
|
await sleep(1e3);
|
|
5503
|
-
const progress = createProgressPrinter(
|
|
5512
|
+
const progress = createProgressPrinter(rounds);
|
|
5504
5513
|
const cleanResult = await autoCleanSubscription(sub.name, {
|
|
5514
|
+
timeout,
|
|
5515
|
+
concurrency,
|
|
5516
|
+
rounds,
|
|
5505
5517
|
onResult: progress.onResult,
|
|
5506
5518
|
onRetryRound: progress.onRetryRound
|
|
5507
5519
|
});
|
|
@@ -5793,7 +5805,7 @@ function requireActiveSub() {
|
|
|
5793
5805
|
async function cmdTest(args) {
|
|
5794
5806
|
requireRunning();
|
|
5795
5807
|
const activeSub = requireActiveSub();
|
|
5796
|
-
const timeout = parseIntArg(args, "-t", "--timeout",
|
|
5808
|
+
const timeout = parseIntArg(args, "-t", "--timeout", 2e3);
|
|
5797
5809
|
const concurrency = parseIntArg(args, "-j", "--concurrency", 100);
|
|
5798
5810
|
console.log(`\u6D4B\u8BD5 "${activeSub.name}" \u8282\u70B9\u8FDE\u901A\u6027...`);
|
|
5799
5811
|
console.log(`\u8D85\u65F6: ${timeout}ms \u5E76\u53D1: ${concurrency}`);
|
|
@@ -5810,9 +5822,9 @@ async function cmdTest(args) {
|
|
|
5810
5822
|
async function cmdClean(args) {
|
|
5811
5823
|
requireRunning();
|
|
5812
5824
|
const activeSub = requireActiveSub();
|
|
5813
|
-
const timeout = parseIntArg(args, "-t", "--timeout",
|
|
5825
|
+
const timeout = parseIntArg(args, "-t", "--timeout", 2e3);
|
|
5814
5826
|
const concurrency = parseIntArg(args, "-j", "--concurrency", 100);
|
|
5815
|
-
const rounds = parseIntArg(args, "-r", "--rounds",
|
|
5827
|
+
const rounds = parseIntArg(args, "-r", "--rounds", DEFAULT_CLEAN_ROUNDS);
|
|
5816
5828
|
console.log(`\u6E05\u7406 "${activeSub.name}" \u5931\u8D25\u8282\u70B9...`);
|
|
5817
5829
|
console.log(`\u8D85\u65F6: ${timeout}ms \u5E76\u53D1: ${concurrency}`);
|
|
5818
5830
|
console.log("");
|