mihomo-cli 2.0.1 → 2.1.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 +24 -0
- package/README.md +3 -2
- package/dist/index.js +64 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.1.0] - 2026-05-01
|
|
4
|
+
|
|
5
|
+
### 新增
|
|
6
|
+
|
|
7
|
+
- **删除订阅**:`sub remove <name>` 删除订阅(别名 `rm`/`delete`),同时清理缓存和配置文件
|
|
8
|
+
- 删除当前使用中的订阅时自动切换到第一个剩余订阅
|
|
9
|
+
- **添加即切换**:`sub add` 添加订阅后自动切换为当前使用的订阅
|
|
10
|
+
|
|
11
|
+
### 安全
|
|
12
|
+
|
|
13
|
+
- **强制 `allow-lan: false`**:无论订阅配置如何,始终禁止局域网访问
|
|
14
|
+
- **强制 `external-controller: 127.0.0.1:9090`**:控制面板仅监听本地,防止不可信订阅暴露控制接口
|
|
15
|
+
- **剥离 `external-ui` 相关字段**:构建配置时强制删除 `external-ui`/`external-ui-name`/`external-ui-url`,防止订阅触发额外下载
|
|
16
|
+
|
|
17
|
+
### 优化
|
|
18
|
+
|
|
19
|
+
- **TUN DNS 劫持**:`dns-hijack` 从 `['0.0.0.0:53']` 改为 `['any:53', 'tcp://any:53']`,同时劫持 UDP 和 TCP DNS,覆盖 IPv4/IPv6
|
|
20
|
+
- **帮助顺序统一**:订阅子命令统一为 use → add → update → remove → web 顺序
|
|
21
|
+
- **`removeSubscription` 返回切换信息**:返回自动切换到的订阅名,避免调用方重复读取状态
|
|
22
|
+
- **`setDefaultSubscription` 跳过冗余写入**:已是同值时直接返回
|
|
23
|
+
- **删除后跳过自动更新**:`sub remove` 后列出订阅时不触发网络更新
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
3
27
|
## [2.0.1] - 2026-04-22
|
|
4
28
|
|
|
5
29
|
### 修复
|
package/README.md
CHANGED
|
@@ -94,10 +94,11 @@ mihomo ui yacd # YACD
|
|
|
94
94
|
| 命令 | 说明 |
|
|
95
95
|
| ----------------------------- | -------------------------------------- |
|
|
96
96
|
| `mihomo sub` | 列出所有订阅(含流量、到期时间) |
|
|
97
|
-
| `mihomo sub
|
|
97
|
+
| `mihomo sub use <name>` | 切换当前订阅(支持模糊匹配,自动重启) |
|
|
98
|
+
| `mihomo sub add <url> [name]` | 添加订阅并自动切换 |
|
|
98
99
|
| `mihomo sub update` | 更新所有订阅 |
|
|
99
100
|
| `mihomo sub update <name>` | 更新指定订阅(支持模糊匹配) |
|
|
100
|
-
| `mihomo sub
|
|
101
|
+
| `mihomo sub remove <name>` | 删除订阅(支持模糊匹配) |
|
|
101
102
|
| `mihomo sub web [name]` | 打开订阅页面(无参打开默认) |
|
|
102
103
|
|
|
103
104
|
### 覆写配置
|
package/dist/index.js
CHANGED
|
@@ -2695,13 +2695,15 @@ var TUN_CONFIG = {
|
|
|
2695
2695
|
tun: {
|
|
2696
2696
|
enable: true,
|
|
2697
2697
|
stack: "mixed",
|
|
2698
|
-
"dns-hijack": ["
|
|
2698
|
+
"dns-hijack": ["any:53", "tcp://any:53"],
|
|
2699
2699
|
"auto-route": true,
|
|
2700
2700
|
"auto-detect-interface": true,
|
|
2701
2701
|
"strict-route": true
|
|
2702
2702
|
}
|
|
2703
2703
|
};
|
|
2704
2704
|
var BASE_CONFIG = {
|
|
2705
|
+
"allow-lan": false,
|
|
2706
|
+
"external-controller": "127.0.0.1:9090",
|
|
2705
2707
|
"log-level": "warning",
|
|
2706
2708
|
"geodata-mode": true,
|
|
2707
2709
|
"geo-update-interval": 24,
|
|
@@ -2819,11 +2821,33 @@ function addSubscription(url, name = "default") {
|
|
|
2819
2821
|
}
|
|
2820
2822
|
writeSettings(updates);
|
|
2821
2823
|
}
|
|
2824
|
+
function removeSubscription(name) {
|
|
2825
|
+
const settings = readSettings();
|
|
2826
|
+
const subs = settings.subscriptions || [];
|
|
2827
|
+
const idx = subs.findIndex((s) => s.name === name);
|
|
2828
|
+
if (idx < 0) return null;
|
|
2829
|
+
subs.splice(idx, 1);
|
|
2830
|
+
const updates = { subscriptions: subs };
|
|
2831
|
+
let switchedTo = null;
|
|
2832
|
+
if (settings.active_subscription === name) {
|
|
2833
|
+
switchedTo = subs.length > 0 ? subs[0].name : null;
|
|
2834
|
+
updates.active_subscription = switchedTo ?? void 0;
|
|
2835
|
+
}
|
|
2836
|
+
writeSettings(updates);
|
|
2837
|
+
const cache = readSubscriptionCache();
|
|
2838
|
+
if (cache[name]) {
|
|
2839
|
+
delete cache[name];
|
|
2840
|
+
writeSubscriptionCache(cache);
|
|
2841
|
+
}
|
|
2842
|
+
fs2.rmSync(getSubscriptionRawConfigPath(name), { force: true });
|
|
2843
|
+
return switchedTo;
|
|
2844
|
+
}
|
|
2822
2845
|
function setDefaultSubscription(name) {
|
|
2823
2846
|
const settings = readSettings();
|
|
2824
2847
|
const subs = settings.subscriptions || [];
|
|
2825
2848
|
const idx = subs.findIndex((s) => s.name === name);
|
|
2826
2849
|
if (idx < 0) return false;
|
|
2850
|
+
if (settings.active_subscription === name) return true;
|
|
2827
2851
|
writeSettings({ active_subscription: name });
|
|
2828
2852
|
return true;
|
|
2829
2853
|
}
|
|
@@ -3003,6 +3027,11 @@ function buildConfig(subRawContent, mode) {
|
|
|
3003
3027
|
systemConfig[key] = value;
|
|
3004
3028
|
}
|
|
3005
3029
|
}
|
|
3030
|
+
systemConfig["allow-lan"] = false;
|
|
3031
|
+
systemConfig["external-controller"] = BASE_CONFIG["external-controller"];
|
|
3032
|
+
delete withOverwrites["external-ui"];
|
|
3033
|
+
delete withOverwrites["external-ui-name"];
|
|
3034
|
+
delete withOverwrites["external-ui-url"];
|
|
3006
3035
|
if (mode === "tun") {
|
|
3007
3036
|
systemConfig.tun = TUN_CONFIG.tun;
|
|
3008
3037
|
const subDns = withOverwrites.dns || {};
|
|
@@ -3833,9 +3862,10 @@ ${colors.cyan("\u754C\u9762:")}
|
|
|
3833
3862
|
|
|
3834
3863
|
${colors.cyan("\u8BA2\u9605:")}
|
|
3835
3864
|
${colors.bold("subscription")} \u5217\u51FA\u6240\u6709\u8BA2\u9605\uFF08\u522B\u540D sub\uFF09
|
|
3865
|
+
${colors.bold("subscription")} use <name> \u5207\u6362\u5F53\u524D\u8BA2\u9605
|
|
3836
3866
|
${colors.bold("subscription")} add <url> [name] \u6DFB\u52A0\u8BA2\u9605
|
|
3837
3867
|
${colors.bold("subscription")} update [name] \u66F4\u65B0\u8BA2\u9605\uFF08\u65E0\u53C2\u66F4\u65B0\u6240\u6709\uFF09
|
|
3838
|
-
${colors.bold("subscription")}
|
|
3868
|
+
${colors.bold("subscription")} remove <name> \u5220\u9664\u8BA2\u9605
|
|
3839
3869
|
${colors.bold("subscription")} web [name] \u6253\u5F00\u8BA2\u9605\u9875\u9762
|
|
3840
3870
|
|
|
3841
3871
|
${colors.cyan("\u914D\u7F6E:")}
|
|
@@ -4763,9 +4793,11 @@ async function cmdStop() {
|
|
|
4763
4793
|
}
|
|
4764
4794
|
|
|
4765
4795
|
// src/commands/subscription.ts
|
|
4766
|
-
async function printSubscriptionList() {
|
|
4767
|
-
|
|
4768
|
-
|
|
4796
|
+
async function printSubscriptionList(options) {
|
|
4797
|
+
if (options?.autoUpdate !== false) {
|
|
4798
|
+
const updateResult = await autoUpdateStaleSubscription();
|
|
4799
|
+
if (updateResult.total > 0) console.log("");
|
|
4800
|
+
}
|
|
4769
4801
|
const subs = getSubscriptionsWithCache();
|
|
4770
4802
|
if (subs.length === 0) {
|
|
4771
4803
|
console.log("\u6CA1\u6709\u8BA2\u9605");
|
|
@@ -4805,9 +4837,10 @@ async function printSubscriptionList() {
|
|
|
4805
4837
|
});
|
|
4806
4838
|
console.log("");
|
|
4807
4839
|
console.log("\u5207\u6362\u8BA2\u9605: mihomo sub use <name>");
|
|
4840
|
+
console.log("\u65B0\u589E\u8BA2\u9605: mihomo sub add <url> [name]");
|
|
4808
4841
|
console.log("\u66F4\u65B0\u8BA2\u9605: mihomo sub update [name]");
|
|
4842
|
+
console.log("\u5220\u9664\u8BA2\u9605: mihomo sub remove <name>");
|
|
4809
4843
|
console.log("\u6253\u5F00\u9875\u9762: mihomo sub web [name]");
|
|
4810
|
-
console.log("\u65B0\u589E\u8BA2\u9605: mihomo sub add <url> [name]");
|
|
4811
4844
|
console.log("");
|
|
4812
4845
|
}
|
|
4813
4846
|
async function cmdSubscription(args) {
|
|
@@ -4826,8 +4859,9 @@ async function cmdSubscription(args) {
|
|
|
4826
4859
|
console.log(`\u6DFB\u52A0\u8BA2\u9605: ${name}`);
|
|
4827
4860
|
try {
|
|
4828
4861
|
addSubscription(url, name);
|
|
4862
|
+
setDefaultSubscription(name);
|
|
4829
4863
|
const info = await downloadSubscription(url, name);
|
|
4830
|
-
console.log(`\u5DF2\u6DFB\u52A0 (${formatProxySummary(info)})`);
|
|
4864
|
+
console.log(`\u5DF2\u6DFB\u52A0\u5E76\u5207\u6362\u5230 "${name}" (${formatProxySummary(info)})`);
|
|
4831
4865
|
} catch (e) {
|
|
4832
4866
|
console.error(`\u6DFB\u52A0\u5931\u8D25: ${e.message}`);
|
|
4833
4867
|
process.exit(1);
|
|
@@ -4953,8 +4987,30 @@ async function cmdSubscription(args) {
|
|
|
4953
4987
|
}
|
|
4954
4988
|
return;
|
|
4955
4989
|
}
|
|
4990
|
+
if (action === "remove" || action === "rm" || action === "delete") {
|
|
4991
|
+
const name = args[2];
|
|
4992
|
+
const subs = getSubscriptions();
|
|
4993
|
+
if (!name) {
|
|
4994
|
+
console.error("\u9519\u8BEF: \u8BF7\u6307\u5B9A\u8981\u5220\u9664\u7684\u8BA2\u9605\u540D\u79F0");
|
|
4995
|
+
if (subs.length > 0) {
|
|
4996
|
+
console.log("\n\u53EF\u7528\u8BA2\u9605:");
|
|
4997
|
+
for (const s of subs) console.log(` ${s.name}`);
|
|
4998
|
+
}
|
|
4999
|
+
process.exit(1);
|
|
5000
|
+
}
|
|
5001
|
+
const matches = findSubscriptionFuzzy(subs, name);
|
|
5002
|
+
const target = pickSingleSubscription(matches, name);
|
|
5003
|
+
const switchedTo = removeSubscription(target.name);
|
|
5004
|
+
console.log(`\u5DF2\u5220\u9664\u8BA2\u9605 "${target.name}"`);
|
|
5005
|
+
if (switchedTo) {
|
|
5006
|
+
console.log(`\u5DF2\u81EA\u52A8\u5207\u6362\u5230 "${switchedTo}"`);
|
|
5007
|
+
}
|
|
5008
|
+
console.log("");
|
|
5009
|
+
await printSubscriptionList({ autoUpdate: false });
|
|
5010
|
+
return;
|
|
5011
|
+
}
|
|
4956
5012
|
console.error("\u9519\u8BEF: \u672A\u77E5\u7684\u8BA2\u9605\u547D\u4EE4");
|
|
4957
|
-
console.log("\u7528\u6CD5: mihomo sub [list|add|update|
|
|
5013
|
+
console.log("\u7528\u6CD5: mihomo sub [list|use|add|update|remove|web]");
|
|
4958
5014
|
process.exit(1);
|
|
4959
5015
|
}
|
|
4960
5016
|
|