@morndream/mihomo-tui 0.5.0-rc.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 +93 -0
- package/LICENSE +21 -0
- package/README.md +462 -0
- package/bin/mihomo-tui +34 -0
- package/dist/App.js +161 -0
- package/dist/App.js.map +1 -0
- package/dist/api/client.js +239 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/status.js +43 -0
- package/dist/api/status.js.map +1 -0
- package/dist/api/stream.js +139 -0
- package/dist/api/stream.js.map +1 -0
- package/dist/api/types.js +6 -0
- package/dist/api/types.js.map +1 -0
- package/dist/cli.js +221 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/conn.js +122 -0
- package/dist/commands/conn.js.map +1 -0
- package/dist/commands/logs.js +99 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/output.js +177 -0
- package/dist/commands/output.js.map +1 -0
- package/dist/commands/provider.js +140 -0
- package/dist/commands/provider.js.map +1 -0
- package/dist/commands/proxy.js +161 -0
- package/dist/commands/proxy.js.map +1 -0
- package/dist/commands/proxyEnv.js +193 -0
- package/dist/commands/proxyEnv.js.map +1 -0
- package/dist/commands/rules.js +87 -0
- package/dist/commands/rules.js.map +1 -0
- package/dist/commands/status.js +75 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/components/ConfirmDialog.js +31 -0
- package/dist/components/ConfirmDialog.js.map +1 -0
- package/dist/components/DelayBadge.js +27 -0
- package/dist/components/DelayBadge.js.map +1 -0
- package/dist/components/InputDialog.js +325 -0
- package/dist/components/InputDialog.js.map +1 -0
- package/dist/components/ListDialog.js +86 -0
- package/dist/components/ListDialog.js.map +1 -0
- package/dist/components/ProgressDialog.js +34 -0
- package/dist/components/ProgressDialog.js.map +1 -0
- package/dist/components/ScrollList.js +26 -0
- package/dist/components/ScrollList.js.map +1 -0
- package/dist/components/StatusBar.js +58 -0
- package/dist/components/StatusBar.js.map +1 -0
- package/dist/components/TextEditor.js +112 -0
- package/dist/components/TextEditor.js.map +1 -0
- package/dist/components/textEditorModel.js +154 -0
- package/dist/components/textEditorModel.js.map +1 -0
- package/dist/config/manager.js +296 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/preserveGroups.js +9 -0
- package/dist/config/preserveGroups.js.map +1 -0
- package/dist/config/ruleDocument.js +88 -0
- package/dist/config/ruleDocument.js.map +1 -0
- package/dist/config/ruleService.js +256 -0
- package/dist/config/ruleService.js.map +1 -0
- package/dist/config/ruleValidation.js +98 -0
- package/dist/config/ruleValidation.js.map +1 -0
- package/dist/config/service.js +63 -0
- package/dist/config/service.js.map +1 -0
- package/dist/config/settingsService.js +162 -0
- package/dist/config/settingsService.js.map +1 -0
- package/dist/config/skeleton.js +324 -0
- package/dist/config/skeleton.js.map +1 -0
- package/dist/config/subscriptionService.js +284 -0
- package/dist/config/subscriptionService.js.map +1 -0
- package/dist/config/subscriptions.js +200 -0
- package/dist/config/subscriptions.js.map +1 -0
- package/dist/config/types.js +5 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config.js +101 -0
- package/dist/config.js.map +1 -0
- package/dist/hooks/useProviders.js +138 -0
- package/dist/hooks/useProviders.js.map +1 -0
- package/dist/hooks/useProxies.js +298 -0
- package/dist/hooks/useProxies.js.map +1 -0
- package/dist/hooks/useStream.js +127 -0
- package/dist/hooks/useStream.js.map +1 -0
- package/dist/kernel/installer.js +317 -0
- package/dist/kernel/installer.js.map +1 -0
- package/dist/kernel/releases.js +111 -0
- package/dist/kernel/releases.js.map +1 -0
- package/dist/kernel/sources.js +98 -0
- package/dist/kernel/sources.js.map +1 -0
- package/dist/rules/editor.js +181 -0
- package/dist/rules/editor.js.map +1 -0
- package/dist/rules/matcher.js +83 -0
- package/dist/rules/matcher.js.map +1 -0
- package/dist/rules/model.js +25 -0
- package/dist/rules/model.js.map +1 -0
- package/dist/rules/runtime.js +46 -0
- package/dist/rules/runtime.js.map +1 -0
- package/dist/rules/types.js +10 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/ui/FooterLine.js +62 -0
- package/dist/ui/FooterLine.js.map +1 -0
- package/dist/ui/Panel.js +47 -0
- package/dist/ui/Panel.js.map +1 -0
- package/dist/ui/RowIndicator.js +25 -0
- package/dist/ui/RowIndicator.js.map +1 -0
- package/dist/ui/SectionHeader.js +14 -0
- package/dist/ui/SectionHeader.js.map +1 -0
- package/dist/ui/StatusDot.js +15 -0
- package/dist/ui/StatusDot.js.map +1 -0
- package/dist/ui/TopBar.js +81 -0
- package/dist/ui/TopBar.js.map +1 -0
- package/dist/ui/exitGuard.js +20 -0
- package/dist/ui/exitGuard.js.map +1 -0
- package/dist/ui/keyCapture.js +28 -0
- package/dist/ui/keyCapture.js.map +1 -0
- package/dist/ui/layout.js +32 -0
- package/dist/ui/layout.js.map +1 -0
- package/dist/ui/rowIndicator.js +42 -0
- package/dist/ui/rowIndicator.js.map +1 -0
- package/dist/ui/tableHeader.js +33 -0
- package/dist/ui/tableHeader.js.map +1 -0
- package/dist/ui/theme.js +47 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/tone.js +131 -0
- package/dist/ui/tone.js.map +1 -0
- package/dist/version.js +27 -0
- package/dist/version.js.map +1 -0
- package/dist/views/Conns.js +107 -0
- package/dist/views/Conns.js.map +1 -0
- package/dist/views/Logs.js +89 -0
- package/dist/views/Logs.js.map +1 -0
- package/dist/views/Providers.js +392 -0
- package/dist/views/Providers.js.map +1 -0
- package/dist/views/Proxies.js +233 -0
- package/dist/views/Proxies.js.map +1 -0
- package/dist/views/RuleEditor.js +356 -0
- package/dist/views/RuleEditor.js.map +1 -0
- package/dist/views/Rules.js +286 -0
- package/dist/views/Rules.js.map +1 -0
- package/dist/views/Settings.js +734 -0
- package/dist/views/Settings.js.map +1 -0
- package/dist/views/groupDisplay.js +53 -0
- package/dist/views/groupDisplay.js.map +1 -0
- package/dist/views/subscriptionFields.js +59 -0
- package/dist/views/subscriptionFields.js.map +1 -0
- package/dist/views/yamlFile.js +32 -0
- package/dist/views/yamlFile.js.map +1 -0
- package/package.json +66 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 格式,
|
|
4
|
+
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.5.0-rc.0] - 2026-09-27
|
|
9
|
+
|
|
10
|
+
- 新增规则页 `e` 配置编辑弹窗,支持常用表单、单条原文、连续增改删和 `J/K` 调序,`Ctrl+S` 统一保存;保护订阅直连前缀并检查末尾 `MATCH`。
|
|
11
|
+
- 新增保留 YAML 节点和注释的规则保存事务:可取消的隔离异步校验、唯一备份、原权限原子写入、写后复验、明确路径重载与最多三次回读。
|
|
12
|
+
- 保存结果区分已确认、已保存待确认、未应用、已恢复和需要人工恢复;检测外部修改后停止自动覆盖,恢复使用原始字节,待确认仅重新读取。
|
|
13
|
+
- 增加规则编辑会话退出保护:写前校验取消并回收子进程,正式写入与恢复期间阻止退出;成功后刷新规则与规则集并清理旧标记和测试结果。
|
|
14
|
+
- 增加草稿、故障恢复、终端按键回归及 mihomo v1.19.24 隔离验收脚本;现有 CLI 和配置管理调用契约保持兼容。
|
|
15
|
+
- 规则页更新/禁用忙碌期间捕获按键:ESC 不再穿透到全局退出确认框(对齐订阅页「忙碌不弹退出」语义)。
|
|
16
|
+
- 窄终端下规则保存的「待确认」结果支持 `r` 重新读取并经确认退出编辑器,不再只剩 Ctrl+C 一条出路。
|
|
17
|
+
- 规则校验放行内核默认的 `geoip.metadb` 与未写 `path` 的 http 型 provider;GEOIP 缺库错误列出可接受的数据库文件名。
|
|
18
|
+
- 移除暂缓的代理链编辑死代码(`src/relay/`、`RelayEditor`):内核 v1.19.24 已移除 `type: relay`,待按 `dialer-proxy` 重新设计后再实现。
|
|
19
|
+
- 新增 shell 代理开关 `proxy on / off / status / init`:emit-eval 模式输出 shell 代码由父 shell eval 执行,端口按「`--port` → 内核 `/configs` → config.yaml」链发现;`proxy init` 一行集成提供 `proxy` / `proxy-on` / `proxy-off` / `proxy-tui` 快捷命令。
|
|
20
|
+
- 新增单二进制打包 `scripts/build-binary.mjs`:bun 1.4.2 交叉编译 Linux/macOS/Windows 五平台产物 + SHA256 checksums + 本机产物自动冒烟;版本号经 `src/version.ts` 来源链构建期注入(编译产物不再读 package.json)。
|
|
21
|
+
- 新增 npm 发布通道 `@morndream/mihomo-tui`(裸名 mihomo-tui 已被第三方占用)与 `release.yml` 双通道发布:tag↔version 一致性守卫、三平台冒烟矩阵、预发布版本走 dist-tag `next`、`NPM_TOKEN` 未配置时发布步骤自动跳过。
|
|
22
|
+
|
|
23
|
+
## [0.4.0] - 2026-09-25
|
|
24
|
+
|
|
25
|
+
- 新增规则页、规则集更新、保守域名/IP 测试和运行时规则禁用/启用。
|
|
26
|
+
- 新增 `rules ls`、`rules test`、`rule-provider ls/update` CLI 命令及 JSON 输出。
|
|
27
|
+
- 对齐 mihomo v1.19.24 的 `DomainSuffix`、`RuleSet`、`extra.disabled` 和 `/rules/disable` 接口。
|
|
28
|
+
- 代理链暂缓:v1.19.24 已移除 `type: relay`,后续按 `dialer-proxy` 另行设计。
|
|
29
|
+
|
|
30
|
+
## [0.2.0] - 2026-09-13
|
|
31
|
+
|
|
32
|
+
### 新增
|
|
33
|
+
|
|
34
|
+
- **TUI 内订阅生命周期管理**(`docs/specs/2026-08-17-subscription-management-design.md`):
|
|
35
|
+
- `a` 新增订阅:名称 / URL / 节点名前缀,逐字段实时校验
|
|
36
|
+
- `d` 删除订阅:红色确认框列出全部变更,执行后清理 provider 缓存文件
|
|
37
|
+
- `e` 编辑节点名前缀(名称与 URL 不可改)
|
|
38
|
+
- 全程进度对话框展示每一步;失败自动回滚并把 `systemctl status`
|
|
39
|
+
完整输出放进错误框
|
|
40
|
+
- **订阅事务层 `src/config/`**:订阅清单原子写、骨架生成(自迁移脚本迁移)、
|
|
41
|
+
`ConfigManager`(备份 → 临时目录 `mihomo -t` 校验 → 原子写 → 写后复验 →
|
|
42
|
+
回滚)、`ServiceManager`(systemd 用户服务操作)、订阅增删改编排
|
|
43
|
+
(清单 + 配置 + 服务三者同进同退);配置备份保留 7 天
|
|
44
|
+
- **自动化测试体系**:vitest,176 个用例覆盖 REST 客户端(本地假内核)、
|
|
45
|
+
WebSocket 状态机、订阅清单/骨架/管理器、订阅事务逐阶段回滚、TUI 对话框
|
|
46
|
+
(无头渲染 + 按键注入);`src/config/` 语句覆盖率 94%+;CI 增加 test 步骤
|
|
47
|
+
- **只读验收入口** `scripts/generate-config.mjs`:对真实配置执行
|
|
48
|
+
「读订阅 → 生成骨架 → `mihomo -t` 校验」,不写任何文件
|
|
49
|
+
- **真实内核冒烟脚本** `scripts/smoke-subscription.mjs`:前置快照后用测试
|
|
50
|
+
订阅走完整增删链路,失败自动恢复(手动执行)
|
|
51
|
+
|
|
52
|
+
### 变更
|
|
53
|
+
|
|
54
|
+
- `redactUrl` 从 `commands/output.ts` 迁至 `config/subscriptions.ts`
|
|
55
|
+
(原导出保留);订阅 URL 的 token 在所有错误信息中不再出现
|
|
56
|
+
- 安全边界表述更新:写 `config.yaml` 的代码路径收敛为唯一的 `ConfigManager`,
|
|
57
|
+
强制备份/校验/原子写/回滚流程
|
|
58
|
+
|
|
59
|
+
### 安全
|
|
60
|
+
|
|
61
|
+
- 测试套件全局禁止写入真实的 `~/.config/mihomo{,-tui}` 目录
|
|
62
|
+
(`vitest.setup.ts` 防护网)
|
|
63
|
+
|
|
64
|
+
## [0.1.0] - 2026-08-17
|
|
65
|
+
|
|
66
|
+
### 新增
|
|
67
|
+
|
|
68
|
+
- **CLI 子命令**:`status`、`proxy ls/use/unfix/test`、`provider ls/update/check`、
|
|
69
|
+
`logs`、`conn ls/close`、`reload`,全部支持 `--json` 输出
|
|
70
|
+
- **TUI 四标签页**:节点(双栏选择、延迟五状态、整组/单节点测速、可用过滤)、
|
|
71
|
+
订阅(更新 / 健康检查 / 展开节点)、日志(级别切换、关键字过滤、暂停)、
|
|
72
|
+
连接(排序、关闭单条 / 全部)
|
|
73
|
+
- **节点延迟测试**:单节点与整组并发测速,结果流式回填
|
|
74
|
+
- **模式切换**:规则 / 全局 / 直连循环切换
|
|
75
|
+
- **配置热重载**:`reload` 触发内核重读配置,进程不重启
|
|
76
|
+
- **配置迁移脚本**:`scripts/migrate-config.mjs`,将整份订阅配置改造为
|
|
77
|
+
「骨架 + proxy-providers」架构,默认 dry-run,`--apply` 时备份 + `mihomo -t`
|
|
78
|
+
校验 + 失败自动回滚
|
|
79
|
+
|
|
80
|
+
### 安全
|
|
81
|
+
|
|
82
|
+
- 运行时只通过 REST API 操作内核,代码中不存在写 `config.yaml` 的路径
|
|
83
|
+
- 迁移脚本为唯一配置写入入口,且必须显式 `--apply`
|
|
84
|
+
|
|
85
|
+
### 性能
|
|
86
|
+
|
|
87
|
+
- 日志流 1000 行环形缓冲,长时运行内存稳定
|
|
88
|
+
- 日志 / 连接流仅在对应标签页可见时渲染
|
|
89
|
+
- Spinner 心跳仅在有活动任务时启动
|
|
90
|
+
|
|
91
|
+
[Unreleased]: https://github.com/MrChen-hero/mihomo-tui/compare/v0.4.0...HEAD
|
|
92
|
+
[0.4.0]: https://github.com/MrChen-hero/mihomo-tui/compare/v0.2.0...v0.4.0
|
|
93
|
+
[0.1.0]: https://github.com/MrChen-hero/mihomo-tui/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MrChen-hero
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
# mihomo-tui
|
|
2
|
+
|
|
3
|
+
[](CHANGELOG.md)
|
|
4
|
+
[](package.json)
|
|
5
|
+
[](package.json)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://github.com/MrChen-hero/mihomo-tui/actions/workflows/ci.yml)
|
|
8
|
+
|
|
9
|
+
[mihomo](https://wiki.metacubex.one/)(Clash.Meta)内核的 **CLI + TUI** 管理工具。
|
|
10
|
+
切节点、更新订阅、看实时日志、管连接,全部通过本机 External Controller 的
|
|
11
|
+
REST API 完成 —— **运行时代码绝不写 `config.yaml`**。
|
|
12
|
+
|
|
13
|
+
```txt
|
|
14
|
+
┌─ mihomo-tui ────────────────────────────────────┐
|
|
15
|
+
│ [1]节点 [2]订阅 [3]规则 [4]日志 [5]连接 [6]设置 │
|
|
16
|
+
├─────────────────────────────────────────────────┤
|
|
17
|
+
│ PROXY → AUTO │
|
|
18
|
+
│ AUTO → [A]日本1 166ms │
|
|
19
|
+
│ 日本 → [B]高速02 213ms │
|
|
20
|
+
│ 机场-alpha → 新加坡2 ---(未测试) │
|
|
21
|
+
└─────────────────────────────────────────────────┘
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 目录
|
|
25
|
+
|
|
26
|
+
- [特性](#特性)
|
|
27
|
+
- [环境要求](#环境要求)
|
|
28
|
+
- [安装](#安装)
|
|
29
|
+
- [快速开始](#快速开始)
|
|
30
|
+
- [TUI 使用](#tui-使用)
|
|
31
|
+
- [CLI 使用](#cli-使用)
|
|
32
|
+
- [配置](#配置)
|
|
33
|
+
- [配置架构:骨架 + Provider](#配置架构骨架--provider)
|
|
34
|
+
- [迁移脚本](#迁移脚本)
|
|
35
|
+
- [常见问题与已知限制](#常见问题与已知限制)
|
|
36
|
+
- [开发](#开发)
|
|
37
|
+
- [路线图](#路线图)
|
|
38
|
+
- [贡献](#贡献)
|
|
39
|
+
- [许可证](#许可证)
|
|
40
|
+
|
|
41
|
+
## 特性
|
|
42
|
+
|
|
43
|
+
- **双入口**:TUI 适合日常操作,CLI 适合脚本化与管道场景(全命令支持 `--json`)
|
|
44
|
+
- **节点管理**:双栏选择代理组与节点,延迟五状态显示(正常 / 一般 / 缓慢 / 未测试 / 超时),
|
|
45
|
+
严格区分「未测试」与「不可用」;单节点与整组并发测速;url-test 组钉选与解除
|
|
46
|
+
- **订阅管理**:在 TUI 内直接增删改订阅(自动备份、校验、原子写入、失败回滚、
|
|
47
|
+
自动重启内核),查看节点数 / 流量 / 到期时间,一键更新单个或全部订阅,
|
|
48
|
+
健康检查,更新失败完整展示错误(订阅域名失效、被 403 都是常态)
|
|
49
|
+
- **规则管理**:查看生效规则与 rule-providers,按类型/关键字筛选,保守测试域名/IP,支持运行时禁用;不支持禁用的内核降级为本地标记。
|
|
50
|
+
- **实时监控**:WebSocket 日志流(级别切换、关键字过滤、环形缓冲 1000 行)、
|
|
51
|
+
连接流(排序、关闭)、底部状态栏常驻显示内核版本 / 模式 / 速率 / 流量 / 内存
|
|
52
|
+
- **模式切换**:规则 / 全局 / 直连循环切换,热重载配置无需重启内核
|
|
53
|
+
- **安全边界**:写 `config.yaml` 的代码路径只有一条,且被封装在
|
|
54
|
+
`ConfigManager` 里强制走「备份 → `mihomo -t` 校验 → 原子写 → 写后复验 →
|
|
55
|
+
失败自动回滚」流程;配置备份保留 7 天;订阅 URL 的 token 在所有展示与
|
|
56
|
+
日志中一律脱敏
|
|
57
|
+
|
|
58
|
+
### 它解决什么问题
|
|
59
|
+
|
|
60
|
+
传统「整份订阅覆盖 config.yaml」的用法有几个痛点,本项目通过
|
|
61
|
+
「骨架 + proxy-providers 配置架构 + API 操作层」一并解决:
|
|
62
|
+
|
|
63
|
+
| 痛点 | 解决方式 |
|
|
64
|
+
|---|---|
|
|
65
|
+
| 订阅一更新,手工修改的端口 / DNS / 规则全部丢失 | 订阅只作为 provider 数据源,骨架配置永不触碰 |
|
|
66
|
+
| 多份订阅互斥,无法混用不同机场的节点 | 多 provider 同时挂载,节点可混在同一个组里 |
|
|
67
|
+
| 切换订阅要重启内核,掐断所有连接 | 更新订阅走 API(`PUT /providers/proxies/{name}`),内核不重启 |
|
|
68
|
+
| 看不到节点存活与延迟 | 健康检查数据直接展示,支持手动测速 |
|
|
69
|
+
| 看不到订阅流量与到期时间 | 自动解析 `Subscription-Userinfo` 响应头 |
|
|
70
|
+
|
|
71
|
+
## 环境要求
|
|
72
|
+
|
|
73
|
+
- **Node.js ≥ 22**(依赖内置的 `fetch` 与全局 `WebSocket`,不依赖 ws / undici / axios)
|
|
74
|
+
- 一个正在运行的 mihomo 内核,且配置了 `external-controller`(本工具默认连接
|
|
75
|
+
`http://127.0.0.1:19090`,可在配置文件中修改)
|
|
76
|
+
- 可选:Linux + systemd(`--user` 服务),仅影响迁移脚本的部分检查项
|
|
77
|
+
|
|
78
|
+
## 安装
|
|
79
|
+
|
|
80
|
+
**方式一:npm 全局安装(需 Node.js ≥ 22)**
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install -g @morndream/mihomo-tui@latest
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**方式二:单二进制下载(免 Node.js)**
|
|
87
|
+
|
|
88
|
+
从 [GitHub Releases](https://github.com/MrChen-hero/mihomo-tui/releases) 下载对应平台产物
|
|
89
|
+
(Linux / macOS / Windows,x64 与 arm64,约 60–100 MB),并用同目录的 `checksums.txt` 校验:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
sha256sum -c checksums.txt
|
|
93
|
+
chmod +x mihomo-tui-*-linux-x64
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
macOS 首次运行如被 Gatekeeper 拦截:`xattr -d com.apple.quarantine mihomo-tui-*`。
|
|
97
|
+
|
|
98
|
+
**方式三:源码安装**
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
git clone https://github.com/MrChen-hero/mihomo-tui.git
|
|
102
|
+
cd mihomo-tui
|
|
103
|
+
npm install && npm run build
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Shell 集成(推荐)**:一行装进 `~/.bashrc`,获得 `proxy` / `proxy-on` / `proxy-off` /
|
|
107
|
+
`proxy-tui` 快捷命令:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
echo 'eval "$(mihomo-tui proxy init)"' >> ~/.bashrc && source ~/.bashrc
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
之后日常操作只需:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
proxy on # 本 shell 开启系统代理(自动发现内核混合端口)
|
|
117
|
+
proxy off # 关闭系统代理
|
|
118
|
+
proxy status # 查看内核端口与本 shell 代理状态
|
|
119
|
+
proxy # 进入 TUI
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
说明:`proxy on` 的本质是 CLI 算好端口后输出 shell 代码、由 shell `eval` 执行
|
|
123
|
+
(子进程改不了父 shell 的环境变量)。不装集成也可直接 `eval "$(mihomo-tui proxy on)"`;
|
|
124
|
+
终端直跑 `mihomo-tui proxy on` 时 stderr 会提示这一用法。
|
|
125
|
+
|
|
126
|
+
## 快速开始
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
mihomo-tui status # 先确认能连上内核:打印版本、模式、端口、provider 概览
|
|
130
|
+
mihomo-tui # 无参数进入 TUI
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## TUI 使用
|
|
134
|
+
|
|
135
|
+
六个标签页,数字键 `1`–`6` 直接切换,`Tab` 循环。`ESC` 逐层返回,在主界面弹退出确认;`Ctrl+C` 直接退出。
|
|
136
|
+
|
|
137
|
+
### [1] 节点
|
|
138
|
+
|
|
139
|
+
左栏代理组,右栏该组节点。默认只列**含真实节点的组**,按延迟升序排列,
|
|
140
|
+
可用节点浮在顶部。
|
|
141
|
+
|
|
142
|
+
| 键 | 作用 |
|
|
143
|
+
|---|---|
|
|
144
|
+
| `↑↓` / `jk` | 移动光标 |
|
|
145
|
+
| `←→` / `hl` | 左右切栏 |
|
|
146
|
+
| `Enter` | 选用节点(自动组会联动切换 PROXY 到对应区域组) |
|
|
147
|
+
| `u` | 恢复自动选路(PROXY → AUTO) |
|
|
148
|
+
| `t` | 测速:焦点在左栏测整组,在右栏测单个节点 |
|
|
149
|
+
| `T` | 整组测速 |
|
|
150
|
+
| `s` | 切换排序(延迟升序 / 配置顺序) |
|
|
151
|
+
| `v` | 只看可用(滤掉超时与未测试) |
|
|
152
|
+
| `m` | 切换模式(规则 → 全局 → 直连 → 规则) |
|
|
153
|
+
| `r` | 刷新 |
|
|
154
|
+
|
|
155
|
+
解除 url-test / fallback 组的钉选请使用 CLI:`mihomo-tui proxy unfix <组名>`。
|
|
156
|
+
|
|
157
|
+
节点状态五分显示——`lazy: true` 的组在被使用前所有节点的 `history` 都是空的,
|
|
158
|
+
所以「未测试」与「不可用」严格区分:
|
|
159
|
+
|
|
160
|
+
| 状态 | 显示 |
|
|
161
|
+
|---|---|
|
|
162
|
+
| 正常(< 300ms) | 绿色延迟值 |
|
|
163
|
+
| 一般(300–800ms) | 黄色延迟值 |
|
|
164
|
+
| 缓慢(> 800ms) | 红色延迟值 |
|
|
165
|
+
| 未测试 | 灰色 `---` |
|
|
166
|
+
| 超时/错误 | 红色 `超时` |
|
|
167
|
+
|
|
168
|
+
### [2] 订阅
|
|
169
|
+
|
|
170
|
+
| 键 | 作用 |
|
|
171
|
+
|---|---|
|
|
172
|
+
| `a` | 新增订阅(名称 / URL / 节点名前缀,逐字段实时校验) |
|
|
173
|
+
| `d` | 删除当前订阅(红色确认框,列出将发生的全部变更) |
|
|
174
|
+
| `e` | 编辑当前订阅的节点名前缀(名称与 URL 不可改) |
|
|
175
|
+
| `u` | 更新当前订阅 |
|
|
176
|
+
| `U` | 更新全部订阅 |
|
|
177
|
+
| `c` | 健康检查 |
|
|
178
|
+
| `Enter` | 展开该订阅的节点列表 |
|
|
179
|
+
| `r` | 刷新 |
|
|
180
|
+
|
|
181
|
+
增删改是完整的事务流程:自动备份 `config.yaml` → 临时目录 `mihomo -t` 校验 →
|
|
182
|
+
原子写入 → 自动重启 `mihomo` 服务并确认状态;任何一步失败都会自动回滚
|
|
183
|
+
配置与订阅清单,并把 `systemctl status` 完整输出展示在错误框里。
|
|
184
|
+
配置备份保留 7 天(`config.yaml.bak.<时间戳>`)。
|
|
185
|
+
|
|
186
|
+
更新订阅失败会把完整错误显示在红框里(订阅域名失效、经代理被 403 都是常态)。
|
|
187
|
+
|
|
188
|
+
### [3] 规则
|
|
189
|
+
|
|
190
|
+
规则页支持 `l` 切换类型、`/` 关键字过滤、`Enter` 查看详情、`t` 测试域名/IP、`u` 更新规则集、`d` 临时禁用/启用、`r` 刷新。规则测试无法确定时会提示需内核判定。
|
|
191
|
+
|
|
192
|
+
禁用仅修改内核运行时状态,配置重载或内核重启后可能恢复。旧内核或缺少禁用字段时,使用 `m` 作会话内本地标记,**不影响实际分流和规则测试**;规则页的 `m` 不切换全局模式。
|
|
193
|
+
|
|
194
|
+
本地测试支持域名和 IP 网段。遇到 `GEOIP`、`RULE-SET`、进程规则或需要 DNS 查询的规则即停止并提示“需内核判定”;命中结果只表示规则目标,不代表最终节点或真实流量路径。禁用操作与外部配置重载可能竞争,显示“结果未确认”时请刷新检查,不会自动重试。
|
|
195
|
+
|
|
196
|
+
按 **`e` 打开配置规则编辑器**,编辑本机 `mihomoDir/config.yaml` 中的规则。配置草稿独立于当前生效规则,允许连续操作后统一保存;原规则页的 `d` 仍表示临时禁用。
|
|
197
|
+
|
|
198
|
+
| 编辑器按键 | 操作 |
|
|
199
|
+
|---|---|
|
|
200
|
+
| `↑↓` / `j/k` | 选择规则 |
|
|
201
|
+
| `a` / `e` / `d` | 新增 / 编辑 / 确认删除草稿规则 |
|
|
202
|
+
| `J/K` | 向后 / 向前移动一条,保持选中规则身份 |
|
|
203
|
+
| `/` | 按原文过滤;提交空字符串清除;过滤期间禁止新增和调序 |
|
|
204
|
+
| `Enter` | 查看完整原文、路径与保护原因;`↑↓` 滚动 |
|
|
205
|
+
| `Ctrl+S` | 确认后统一校验、保存并重载完整配置 |
|
|
206
|
+
| `ESC` | 取消当前弹窗;有草稿时确认放弃 |
|
|
207
|
+
|
|
208
|
+
常用表单覆盖域名、网段、端口、进程、`RULE-SET` 和 `MATCH`;候选字段按 `e` 选择。复杂表达式和额外参数使用单条原文,保留内部内容。`MATCH` 最多一条且须位于末尾,也允许删除它并明确提示“无显式 MATCH”。订阅直连规则按内容识别并保护;订阅清单缺失、为空、损坏或保护前缀不一致时禁止写入。
|
|
209
|
+
|
|
210
|
+
保存先在独立目录校验,创建唯一的 `config.yaml.bak.*` 备份,再原子替换、写后复验、按绝对路径重载和回读确认。保留原 YAML 节点及注释,但成功序列化可能调整排版。失败恢复使用保存前的原始字节和文件权限。**重载会重新建立规则状态,临时禁用、本地标记和旧测试结果会清除。** 校验期间可以取消;正式写入至重载/恢复结束期间,`ESC`、`Ctrl+C` 和切页不会终止事务。
|
|
211
|
+
|
|
212
|
+
重载已接受但回读失败时显示“已保存 · 待确认”,按 `r` 仅重新读取,不重复重载,也不允许叠加保存。恢复未完成时分别显示磁盘和内核状态及备份路径,保留草稿;处理状态后需重新打开编辑器。检测到其他程序修改配置或订阅清单时停止覆盖和自动恢复。
|
|
213
|
+
|
|
214
|
+
**支持边界:** 仅支持普通本地配置文件和回环控制器,保存确认要求该控制器确实读取显示的本机路径;SSH 隧道、容器路径映射不在支持范围。校验复制数据目录内相对路径的 provider 缓存及标准 geodata(地域数据库);缺少依赖、绝对/逃逸路径、外部 UI、证书/私钥文件等未支持资源会阻止保存。`rules` 的锚点、别名、自定义标签和顶层合并来源不支持写入。复杂规则的附加参数由内核校验,回读不承诺逐项验证,也不保证远程规则集已下载或实际流量一定命中。避免其他程序同时编辑同一文件;进程强杀、断电及多进程严格事务不在保证范围。后续订阅/代理组配置流程仍可能调整规则引用。规则集本身仍只查看与更新,没有新增 CLI 写命令。
|
|
215
|
+
|
|
216
|
+
### [4] 日志
|
|
217
|
+
|
|
218
|
+
| 键 | 作用 |
|
|
219
|
+
|---|---|
|
|
220
|
+
| `l` | 循环切换级别(silent / error / warning / info / debug) |
|
|
221
|
+
| `/` | 输入关键字过滤 |
|
|
222
|
+
| `Space` | 暂停 / 恢复滚动 |
|
|
223
|
+
| `c` | 清屏 |
|
|
224
|
+
|
|
225
|
+
环形缓冲上限 1000 行,长时运行内存稳定。
|
|
226
|
+
|
|
227
|
+
### [5] 连接
|
|
228
|
+
|
|
229
|
+
| 键 | 作用 |
|
|
230
|
+
|---|---|
|
|
231
|
+
| `d` | 关闭选中连接 |
|
|
232
|
+
| `D` | 关闭全部(需按 `y` 二次确认) |
|
|
233
|
+
| `s` | 切换排序(流量 / 时间 / 主机) |
|
|
234
|
+
|
|
235
|
+
### [6] 设置
|
|
236
|
+
|
|
237
|
+
查看和编辑内核常用设置、下载源偏好与内核版本。
|
|
238
|
+
|
|
239
|
+
### 底部状态栏
|
|
240
|
+
|
|
241
|
+
所有标签页常驻,显示:内核版本、当前模式、实时速率、累计流量、内存、
|
|
242
|
+
控制口连接状态。内核连不上时转红显示断开状态。
|
|
243
|
+
|
|
244
|
+
## CLI 使用
|
|
245
|
+
|
|
246
|
+
每条命令输出一行或一张表,均支持 `--json` 供 `jq` 消费。
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
mihomo-tui status # 内核版本、模式、端口、provider 概览
|
|
250
|
+
mihomo-tui proxy on # 本 shell 开启系统代理(输出 shell 代码,eval 执行)
|
|
251
|
+
mihomo-tui proxy off # 关闭系统代理;不访问内核,离线可用
|
|
252
|
+
mihomo-tui proxy status # 内核端口与本 shell 代理状态(--json 可查)
|
|
253
|
+
mihomo-tui proxy ls # 列出所有代理组及当前选中
|
|
254
|
+
mihomo-tui proxy ls 香港 # 列出该组节点、延迟、状态
|
|
255
|
+
mihomo-tui proxy use <组> <节点> # 切换节点(url-test 组会钉选并提示)
|
|
256
|
+
mihomo-tui proxy unfix <组> # 解除 url-test/fallback 组的钉选
|
|
257
|
+
mihomo-tui proxy test 香港 -u <url> -t 5000 # 整组延迟测试,可自定义测速地址与超时
|
|
258
|
+
mihomo-tui provider ls # 订阅列表(节点数/流量/到期/更新时间)
|
|
259
|
+
mihomo-tui provider update [名称] # 更新订阅,省略名称则全部
|
|
260
|
+
mihomo-tui provider check <名称> # 触发健康检查
|
|
261
|
+
mihomo-tui rules ls --type DOMAIN-SUFFIX --json # 规则类型同时接受 DomainSuffix
|
|
262
|
+
mihomo-tui rules test example.com --json # hit / miss / unsupported
|
|
263
|
+
mihomo-tui rule-provider ls --json # 规则集列表
|
|
264
|
+
mihomo-tui rule-provider update <名称> --json # 更新规则集
|
|
265
|
+
mihomo-tui logs -f # 实时日志跟随,Ctrl+C 退出
|
|
266
|
+
mihomo-tui logs -n 20 -g 'error' # 抓 20 条含 error 的日志后退出
|
|
267
|
+
mihomo-tui conn ls -s traffic -n 50 # 连接列表,按流量排序
|
|
268
|
+
mihomo-tui conn close <id|--all> # 关闭连接(id 支持 8 位前缀)
|
|
269
|
+
mihomo-tui reload # 热重载配置(内核不重启)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
组名含中文与 emoji 时正常传入即可,程序全程 `encodeURIComponent`:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
mihomo-tui proxy ls '🇭🇰 香港聚合'
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**退出码约定**:`0` 成功,`1` 通用错误,`2` 参数错误,`3` 内核不可达。
|
|
279
|
+
|
|
280
|
+
## 配置
|
|
281
|
+
|
|
282
|
+
程序自身配置位于 `~/.config/mihomo-tui/config.json`,首次运行自动生成:
|
|
283
|
+
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"api": "http://127.0.0.1:19090",
|
|
287
|
+
"secret": "",
|
|
288
|
+
"mihomoDir": "~/.config/mihomo",
|
|
289
|
+
"testUrl": "https://www.gstatic.com/generate_204",
|
|
290
|
+
"testTimeout": 5000,
|
|
291
|
+
"delayThresholds": { "good": 300, "fair": 800 }
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
| 字段 | 说明 |
|
|
296
|
+
|---|---|
|
|
297
|
+
| `api` | mihomo External Controller 地址 |
|
|
298
|
+
| `secret` | 控制口密钥,与 `external-controller` 的 `secret` 一致 |
|
|
299
|
+
| `testUrl` | 延迟测试地址(默认 `gstatic.com`,实测比 `cp.cloudflare.com` 兼容性好) |
|
|
300
|
+
| `testTimeout` | 单节点测速超时(毫秒) |
|
|
301
|
+
| `delayThresholds` | 好 / 一般 / 缓慢三档延迟阈值 |
|
|
302
|
+
|
|
303
|
+
命令行可用 `--api <url>` 与 `--secret <token>` 临时覆盖。
|
|
304
|
+
|
|
305
|
+
## 配置架构:骨架 + Provider
|
|
306
|
+
|
|
307
|
+
推荐的 mihomo 配置为「骨架 + provider」两层结构,订阅更新不再覆盖任何自定义配置:
|
|
308
|
+
|
|
309
|
+
```txt
|
|
310
|
+
config.yaml(骨架,只维护一次)
|
|
311
|
+
├── 通用设置 / sniffer / dns / rules / rule-providers
|
|
312
|
+
├── proxy-providers: ← 订阅作为节点来源
|
|
313
|
+
│ ├── alpha → ./providers/alpha.yaml
|
|
314
|
+
│ ├── beta → ./providers/beta.yaml
|
|
315
|
+
└── proxy-groups:
|
|
316
|
+
├── PROXY / AUTO / FALLBACK
|
|
317
|
+
├── 区域组:香港 台湾 日本 韩国 新加坡 美国 …
|
|
318
|
+
├── 机场组:机场-alpha / 机场-beta
|
|
319
|
+
└── 用途组:AI Google YouTube Telegram 流媒体 …
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
> **关键约束**:provider 的 `path` **必须是相对路径** —— mihomo 对此有路径安全
|
|
323
|
+
> 校验,配置文件之外的绝对路径会被拒绝启动。
|
|
324
|
+
|
|
325
|
+
## 迁移脚本
|
|
326
|
+
|
|
327
|
+
`scripts/migrate-config.mjs` 负责把现有整份订阅配置一次性改造为上述架构。
|
|
328
|
+
它是一次性迁移入口;日常订阅与设置变更通过内置配置事务完成。迁移脚本的安全机制如下:
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
node scripts/migrate-config.mjs --dry-run --diff # 预览骨架与差异,不落盘
|
|
332
|
+
node scripts/migrate-config.mjs --apply # 备份 + 校验 + 写入
|
|
333
|
+
node scripts/migrate-config.mjs --apply --no-dns # 写入但不改 dns 段
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
- 订阅链接放在 `~/.config/mihomo-tui/subscriptions.json`(权限 600,含 token):
|
|
337
|
+
|
|
338
|
+
```json
|
|
339
|
+
{
|
|
340
|
+
"subscriptions": [
|
|
341
|
+
{ "name": "alpha", "prefix": "[A] ", "url": "https://example.com/sub?token=..." }
|
|
342
|
+
]
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
- `name` 只能用字母数字与 `-_`(要作文件名);`prefix` 会通过
|
|
347
|
+
`additional-prefix` 注入到节点名前,用于标记来源。
|
|
348
|
+
- 安全保证:`--dry-run` 也会跑 `mihomo -t` 校验;`--apply` 先备份再写,
|
|
349
|
+
写入后再校验一次,失败自动从备份回滚;重复运行结果一致(幂等)。
|
|
350
|
+
- 脚本会自动处理若干实测踩到的坑:DNS 上游可达性、`respect-rules` 与
|
|
351
|
+
`proxy-server-nameserver` 的成对约束、订阅域名 DIRECT 规则防拉取死锁、
|
|
352
|
+
过滤机场下发的「剩余流量 / 套餐到期」等伪装节点。
|
|
353
|
+
|
|
354
|
+
## 常见问题与已知限制
|
|
355
|
+
|
|
356
|
+
**Q:延迟测试全部超时?**
|
|
357
|
+
先确认测速地址本身可达:`curl -I https://www.gstatic.com/generate_204`。
|
|
358
|
+
部分内网环境对特定测速域名不通,可在 `config.json` 中更换 `testUrl`。
|
|
359
|
+
|
|
360
|
+
**Q:TUI 显示「内核不可达」?**
|
|
361
|
+
确认 mihomo 正在运行且 `external-controller` 地址正确:
|
|
362
|
+
|
|
363
|
+
```bash
|
|
364
|
+
curl http://127.0.0.1:19090/version
|
|
365
|
+
systemctl --user status mihomo # 按你的实际部署方式
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Q:AI 服务商(Claude / ChatGPT)不可用?**
|
|
369
|
+
多数机场出口 IP 被 AI 服务商封锁(403 或地区不可用页),这是节点 IP 问题,
|
|
370
|
+
改配置无法解决,需要带 AI 解锁的节点。
|
|
371
|
+
|
|
372
|
+
**Q:为什么日志命令有时不会立即退出?**
|
|
373
|
+
mihomo 内核不回应 WebSocket close 帧,客户端关闭握手永不完成,因此所有用到
|
|
374
|
+
流的命令都显式退出;非 `--follow` 的 `logs` 有 `--idle` 空闲超时(默认 5 秒)兜底。
|
|
375
|
+
|
|
376
|
+
**Q:TUI 里的修改重启内核后会丢吗?**
|
|
377
|
+
会。运行时操作(切节点、切模式)都是内存中变更。需要持久化的变更请编辑
|
|
378
|
+
`config.yaml` 后执行 `mihomo-tui reload`;订阅的增删改则直接持久化
|
|
379
|
+
(通过内置的备份 → 校验 → 原子写 → 回滚事务)。
|
|
380
|
+
|
|
381
|
+
**Q:添加订阅时提示「订阅名称已存在」?**
|
|
382
|
+
订阅名称会用作 provider 名与缓存文件名,全局唯一且只允许字母数字与 `-_`
|
|
383
|
+
(1–32 位)。换一个名字,或先删除旧订阅。
|
|
384
|
+
|
|
385
|
+
**Q:新增 / 删除订阅会导致代理断流吗?**
|
|
386
|
+
会重启 mihomo 服务一次(秒级断流)。随后的订阅更新(`u` / `U`)走 API,
|
|
387
|
+
不重启、不断流。
|
|
388
|
+
|
|
389
|
+
**Q:订阅 URL 里的 token 会泄露吗?**
|
|
390
|
+
token 只保存在本机两个文件里(`subscriptions.json` 与内核 `config.yaml`),
|
|
391
|
+
所有 TUI/CLI 展示、日志、错误信息都经过 `redactUrl` 脱敏;
|
|
392
|
+
测试套件里禁止出现真实 token,并有全局防护禁止测试写入生产配置目录。
|
|
393
|
+
|
|
394
|
+
## 开发
|
|
395
|
+
|
|
396
|
+
```bash
|
|
397
|
+
npm install
|
|
398
|
+
npm run typecheck # tsc --noEmit
|
|
399
|
+
npm test # vitest 单元 + 集成测试
|
|
400
|
+
npm run coverage # 覆盖率报告
|
|
401
|
+
npm run build # 编译到 dist/
|
|
402
|
+
npm run dev -- status # tsx 直跑源码
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
测试覆盖 `src/config/` 全模块(语句 94%+)、REST 客户端(本地假内核)、
|
|
406
|
+
WebSocket 状态机(FakeWebSocket + fake timers)、TUI 对话框(无头渲染 +
|
|
407
|
+
按键注入)与订阅事务的逐阶段回滚;测试物理禁止写入真实的
|
|
408
|
+
`~/.config/mihomo{,-tui}` 目录(`vitest.setup.ts` 全局防护)。
|
|
409
|
+
|
|
410
|
+
`bin/mihomo-tui` 优先用 `dist/cli.js`,未编译时回退 tsx 直跑源码。
|
|
411
|
+
|
|
412
|
+
```txt
|
|
413
|
+
src/
|
|
414
|
+
├── api/ # REST 客户端 + WebSocket 流封装
|
|
415
|
+
├── commands/ # CLI 子命令
|
|
416
|
+
├── config/ # 订阅清单、骨架生成、ConfigManager(唯一写配置的模块)、
|
|
417
|
+
│ # ServiceManager、订阅事务编排(subscriptionService)
|
|
418
|
+
├── rules/ # 规则类型转换、保守匹配与运行时禁用确认
|
|
419
|
+
├── views/ # TUI 六个标签页 + 订阅表单校验
|
|
420
|
+
├── components/ # DelayBadge / ScrollList / StatusBar / 三个对话框
|
|
421
|
+
├── hooks/ # useProxies / useProviders / useStream
|
|
422
|
+
├── App.tsx # TUI 根组件
|
|
423
|
+
├── cli.tsx # CLI/TUI 路由
|
|
424
|
+
└── config.ts # mihomo-tui 自身配置读取
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
更多设计与一手实测数据:
|
|
428
|
+
|
|
429
|
+
规则管理的隔离内核验收:先 `npm run build`,再运行 `node scripts/smoke-rules.mjs /absolute/path/to/mihomo`。该脚本使用临时配置和随机回环端口验证禁用/恢复及规则集更新,不读取或重载现有服务配置。
|
|
430
|
+
|
|
431
|
+
规则编辑的隔离验收使用 `node scripts/smoke-rule-editing.mjs /absolute/path/to/mihomo`,要求 v1.19.24;覆盖增改移删、所有常用类型及复杂原文保留、无效配置阻断、重载响应丢失后的原字节恢复。检查过程仅操作脚本自己的临时配置目录和内核进程。
|
|
432
|
+
|
|
433
|
+
| 文档 | 内容 |
|
|
434
|
+
|---|---|
|
|
435
|
+
| [`docs/SPEC.md`](docs/SPEC.md) | 完整设计规格:痛点分析、API 实测、架构决策、踩坑记录 |
|
|
436
|
+
| [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) | 开发文档:架构分层、核心实现、扩展指南、FAQ |
|
|
437
|
+
| [`docs/ROADMAP.md`](docs/ROADMAP.md) | 路线图与技术债:待实现功能、竞品对比、非目标清单 |
|
|
438
|
+
| [`docs/specs/2026-08-17-subscription-management-design.md`](docs/specs/2026-08-17-subscription-management-design.md) | 订阅生命周期管理(v0.2.0)设计稿 |
|
|
439
|
+
| [`docs/specs/2026-09-22-tui-standardize-polish-spec.md`](docs/specs/2026-09-22-tui-standardize-polish-spec.md) | TUI 标准化美化(v0.2.1)设计稿 |
|
|
440
|
+
| [`docs/specs/2026-09-24-config-management-spec.md`](docs/specs/2026-09-24-config-management-spec.md) | v0.4.0 规则管理规范与代理链范围修订 |
|
|
441
|
+
|
|
442
|
+
## 路线图
|
|
443
|
+
|
|
444
|
+
- [x] v0.1.0 —— CLI + TUI + 配置迁移脚本
|
|
445
|
+
- [x] v0.2.0 —— TUI 内订阅生命周期管理(新增 / 删除 / 编辑)+ 自动化测试体系
|
|
446
|
+
- [x] v0.2.1 —— TUI 标准化美化:响应式布局、设计系统统一、内核版本管理
|
|
447
|
+
- [x] v0.3.0 —— 订阅增强:分组、重命名、远程/本地类型、更新间隔、内联 YAML 编辑(前缀按订阅名自动派生)
|
|
448
|
+
- [x] v0.4.0 —— 规则管理:规则页、规则集更新、保守规则测试、运行时禁用/降级标记
|
|
449
|
+
- [ ] 后续 —— dialer-proxy 代理链设计;本机 mihomo v1.19.24 已移除 `type: relay`
|
|
450
|
+
- [x] v0.5.0(实现就绪)—— 单二进制打包(Bun 1.4.2)、shell 代理开关(`proxy on/off`)、npm 双通道;发布待 `v0.5.0-rc.0` tag
|
|
451
|
+
|
|
452
|
+
详细规划与技术债请参阅 [docs/ROADMAP.md](docs/ROADMAP.md)
|
|
453
|
+
|
|
454
|
+
## 贡献
|
|
455
|
+
|
|
456
|
+
欢迎提交 Issue 与 Pull Request!请先阅读
|
|
457
|
+
[CONTRIBUTING.md](CONTRIBUTING.md),特别注意两条设计红线:
|
|
458
|
+
运行时代码不写 `config.yaml`,不新增监听端口。
|
|
459
|
+
|
|
460
|
+
## 许可证
|
|
461
|
+
|
|
462
|
+
[MIT](LICENSE)
|
package/bin/mihomo-tui
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// mihomo-tui 可执行入口。
|
|
3
|
+
// 优先跑已编译的 dist/cli.js;未编译时回退到 tsx 直跑 TypeScript 源码(开发期)。
|
|
4
|
+
import { spawnSync } from 'node:child_process'
|
|
5
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
6
|
+
import { dirname, join } from 'node:path'
|
|
7
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
8
|
+
|
|
9
|
+
const root = dirname(dirname(fileURLToPath(import.meta.url)))
|
|
10
|
+
const compiled = join(root, 'dist', 'cli.js')
|
|
11
|
+
// 版本号读取失败或畸形不能拦住启动:src/version.ts 自有兜底链
|
|
12
|
+
let pkgVersion
|
|
13
|
+
try {
|
|
14
|
+
const parsed = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
|
|
15
|
+
pkgVersion = typeof parsed.version === 'string' && parsed.version ? parsed.version : undefined
|
|
16
|
+
} catch {}
|
|
17
|
+
|
|
18
|
+
if (existsSync(compiled)) {
|
|
19
|
+
// 进程内加载前注入,cli 侧免读盘;bun 编译产物不走本文件(版本经 --define 注入)
|
|
20
|
+
globalThis.__MIHOMO_TUI_VERSION__ = pkgVersion
|
|
21
|
+
await import(pathToFileURL(compiled).href)
|
|
22
|
+
} else {
|
|
23
|
+
const tsx = join(root, 'node_modules', 'tsx', 'dist', 'cli.mjs')
|
|
24
|
+
if (!existsSync(tsx)) {
|
|
25
|
+
process.stderr.write('未找到 dist/cli.js,也未安装 tsx。请先执行:npm install && npm run build\n')
|
|
26
|
+
process.exit(1)
|
|
27
|
+
}
|
|
28
|
+
const result = spawnSync(process.execPath, [tsx, join(root, 'src', 'cli.tsx'), ...process.argv.slice(2)], {
|
|
29
|
+
stdio: 'inherit',
|
|
30
|
+
// 子进程拿不到 globalThis,版本号走环境变量通道
|
|
31
|
+
env: { ...process.env, MIHOMO_TUI_VERSION: pkgVersion },
|
|
32
|
+
})
|
|
33
|
+
process.exit(result.status ?? 1)
|
|
34
|
+
}
|