29 KiB
环境搭建
省略
初始文件树
cargo init --bin --name tz .
#文件树1
TZ/
├── Cargo.toml
├── Cargo.lock
└── src/
├── main.rs # tz 可执行程序入口
└── lib.rs # 项目的主要代码入口
常用代码
# 检查代码,不生成最终程序
cargo check
# 编译
cargo build
# 编译并运行
cargo run
# 向 tz 传入参数
cargo run -- status
cargo run -- core list
# 运行测试
cargo test
# 格式代码
cargo fmt
# 静态检查
cargo clippy
# 添加依赖
cargo add clap --features derive
# 删除依赖
cargo remove clap
# 查看依赖树
cargo tree
# 查看项目元数据
cargo metadata
--format-version 1
CLI 解析层的第一个小闭环
- 添加clap依赖
cargo add clap --features derive
cargo add 会修改当前 Package 的 Cargo.toml;derive feature 让我们可以使用 #[derive(Parser)] 和 #[derive(Subcommand)]。
- 写文件功能 #文件树2
mkdir -p src/cli
touch src/cli/mod.rs # 管理并导出 cli 模块
touch src/cli/args.rs # 定义用户可以输入什么
src/
├── main.rs # 程序入口
├── lib.rs # 整个项目的库模块入口
└── cli/
├── mod.rs # 管理并导出 cli 模块
└── args.rs # 定义用户可以输入什么
lib.rs中添加声明
pub mod cli;
声明项目中存在 cli 模块,Rust 会自动寻找src/cli.rs或者src/cli/mod.rs
src/cli/mod.rs中管理子模块
mod args; // cli 模块内部还有一个 args 子模块。
pub use args::{Cli, CliCommand, CoreCommand}; // 表示把三个类型重新导出到 cli 模块表面
没有写 pub,所以外部不能直接访问args/tz::cli::args::Cli;
然后补充args.rs即可,注释也写在里面
即使main.rs和lib.rs在同一个 Cargo package 中, 仍然是两个独立 crate。Rust 官方文档明确说明:同时存在 src/lib.rs 和 src/main.rs 时,package 中包含一个库 crate 和一个二进制 crate。
package tz
├── library crate tz
│ └── cli
└── binary crate tz
└── main
- 补充main.rs
use clap::Parser;
use tz::cli::Cli; // cli 当前是由 lib.rs 管理的,它属于库 crate tz,不是 main.rs 所属二进制 crate 的直接模块。
fn main() {
let cli = Cli::parse();
println!("{cli:#?}");
}
- 测试,
--表示隔开,后面的参数是输入给二进制文件的
cargo run -- --help # 查看帮助
cargo run -- status #
cargo run -- core --help # 查看 core 的帮助
cargo run -- unknown # 测试错误输入
常用代码
cargo tree # 检查依赖
cargo tree -i clap
cargo fmt # 统一代码格式
cargo check # 类型检查和编译检查
cargo clippy # 检查潜在问题和不规范写法
CLI 解析run态
- 新增命令分发层 #文件树3
src/
├── main.rs
├── lib.rs
├── cli/
│ ├── mod.rs
│ ├── args.rs # 用户可以使用什么命令
│ └── commands/ # 定义“收到命令之后调用什么”
│ ├── mod.rs
│ ├── status.rs
│ ├── service.rs
│ └── core.rs
创建
mkdir -p src/cli/commands
touch src/cli/commands/mod.rs
touch src/cli/commands/status.rs
touch src/cli/commands/service.rs
touch src/cli/commands/core.rs
- 补充command代码
补充 src/cli/commands/service.rs
补充 src/main.rs
- 测试
cargo fmt
cargo check
cargo clippy
然后
cargo run -- status
cargo run -- start
cargo run -- stop
cargo run -- restart
cargo run -- core list
之前:
用户输入 → Debug 打印
现在:
用户输入
↓
Cli
↓
CliCommand
↓
match
↓
具体 command handler
application
mkdir -p src/application
touch src/application/mod.rs
touch src/application/service.rs
文件树4
src/
├── main.rs # 程序入口
├── lib.rs # 整个项目的库模块入口
└── cli/
│ ├── mod.rs # 管理并导出 cli 模块
│ ├── args.rs # 定义用户可以输入什么
│ └── commands/ # 定义“收到命令之后调用什么”
│ ├── mod.rs # commands 本体
│ ├── status.rs # commands 的 子模块
│ ├── service.rs
│ └── core.rs
│
└── application/
├── mod.rs
└── service.rs # 这个替换commands/service.rs的服务
随后需要补充的 lib.rs中定义新的模块
之后将commands中的相关模块替换成
前部小结
这里主要是创建两个模块
cli : 指令列表,以及管理\调用
application : 真实实现 目前只是搭建了基础框架没有实际执行,
- 搭建cli
- 搭建application,改cli的调用路线为application
主要完成了指令的分发
路径系统
设定软件的路径系统,
mkdir -p src/platform
touch src/platform/mod.rs
touch src/platform/paths.rs
文件树5
src/
├── main.rs # 程序入口
├── lib.rs # 整个项目的库模块入口
└── cli/
│ ├── mod.rs # 管理并导出 cli 模块
│ ├── args.rs # 定义用户可以输入什么
│ └── commands/ # 定义“收到命令之后调用什么”
│ ├── mod.rs # commands 本体
│ ├── status.rs # commands 的 子模块
│ ├── service.rs
│ └── core.rs
│
└── application/
│ ├── mod.rs
│ └── service.rs # 这个替换commands/service.rs的服务
│
└── platform/
├── mod.rs
└── paths.rs
要求:
- 默认配置不依赖环境变量即可使用。
- 路径配置统一保存在
paths.toml,由TZ_PATHS_TOML指向;未设置时使用$HOME/.config/tz/paths.toml。 tz init可以在用户确认后把TZ_PATHS_TOML的 export 追加到~/.bashrc。
文件系统初始化规则
paths.toml 是文件系统路径的唯一配置源,文件只保存一次选定的四个目录,不保存布局类型或多个方案:
[layout]
config_dir = "~/.config/tz"
data_dir = "~/.local/share/tz"
state_dir = "~/.local/state/tz"
cache_dir = "~/.cache/tz"
路径文件定位规则:
- 设置
TZ_PATHS_TOML时,读取该绝对路径文件;文件不存在或格式错误直接报错,不回退。 - 未设置时,读取
$HOME/.config/tz/paths.toml。 - 默认路径文件不存在时,提示运行
tz init。
程序固定读取 [layout] 下的四个字段。路径可以写成绝对路径或 ~/...;读取时展开 ~,展开后必须是绝对路径。普通命令不再读取 TZ_ROOT_DIR 或四个 XDG_* 环境变量。
tz init 的首次选择提供三个模板:
- 默认 XDG:
~/.config/tz、~/.local/share/tz、~/.local/state/tz、~/.cache/tz。 - 默认 Unified:
~/.tz/config、~/.tz/data、~/.tz/state、~/.tz/cache。 - 开发测试:项目目录下的
target/tz-dev/{config,data,state,cache}。
选择模板后,交互询问四个目录,回车保留模板值,也可以修改。最终只写入一个 [layout] 表。
重复运行 tz init 时,如果 paths 文件已存在,先询问是否继续;拒绝则退出且不修改文件,确认后才重新选择和写入。写入路径文件后,初始化根据四个目录补齐结构和初始文件,已有文件一律跳过,不覆盖内容。
tz init 交互
- 第一次运行时选择三个内置模板:默认 XDG、默认 Unified、开发测试
target/tz-dev。 - 选择后分别询问
config_dir、data_dir、state_dir、cache_dir,回车使用模板值。 - 如果 paths 文件已经存在,先询问是否继续;默认退出,不修改现有路径。
- 初始化结束后始终打印
export TZ_PATHS_TOML='...'提示。默认$HOME/.config/tz/paths.toml不需要设置变量;自定义 paths 文件可以确认后追加到~/.bashrc。
开发测试
开发测试模板使用项目目录下的 target/tz-dev,示例:
cargo run -- init
# 选择 3) 开发测试 target/tz-dev
TZ_PATHS_TOML="$PWD/target/tz-paths.toml" cargo run -- status
如果 paths 文件放在默认 $HOME/.config/tz/paths.toml,后续命令不需要设置环境变量;如果使用自定义路径文件,需要设置 TZ_PATHS_TOML 或按初始化结束时的提示加入 bashrc。
本次修改的代码文件
src/platform/paths.rs- 使用
paths.toml作为唯一路径配置源。 - 支持
TZ_PATHS_TOML和默认$HOME/.config/tz/paths.toml。 - 解析
[layout]的四个固定目录,支持~/展开和绝对路径校验。 - 保留初始化目录、五个初始文件和幂等补全。
- 使用
src/application/init.rs- 提供默认 XDG、默认 Unified、开发
target/tz-dev三个模板。 - 已有 paths 文件先确认,再允许重新选择。
- 初始化结束打印
TZ_PATHS_TOMLexport;自定义路径可确认后追加到~/.bashrc。
- 提供默认 XDG、默认 Unified、开发
验证命令:
cargo fmt --check
cargo check
cargo test --all-targets
cargo clippy --all-targets -- -D warnings
文件作用
接下来固定文件作用
paths.toml TZ_PATHS_TOML
[layout]
config_dir = "/mnt/data_4t2/lht_self/TZ/target/tz-dev/config"
data_dir = "/mnt/data_4t2/lht_self/TZ/target/tz-dev/data"
state_dir = "/mnt/data_4t2/lht_self/TZ/target/tz-dev/state"
cache_dir = "/mnt/data_4t2/lht_self/TZ/target/tz-dev/cache"
三级配置
一级配置
全局、长期、比较稳定的信息。
settings.toml:tz软件的统一配置信息,与core的运行不太相关。默认不会修改,只是展示一下
schema_version = 1
[bypass]
enabled = true
# bypass.list 之外的内联补充项,生成规则时合并并去重。
inline = [
"localhost",
"127.0.0.0/8",
]
[log]
level = "warn"
# tz.log 超限后直接清除重建,不保留归档。
max_size_mb = 10
[update.profiles]
auto_update = false
interval_minutes = 4320
[update.cores]
auto_update = false
interval_minutes = 14400
runtime.toml:TZ 可以跨 core 表达的运行参数,包括端口、API、DNS 和 TUN 的复杂参数。是否开启 TUN 不在这里,开关保存在 active.toml。
schema_version = 1
[proxy]
mode = "rule"
listen = "127.0.0.1"
mixed_port = 7890
http_port = 7892
socks_port = 7891
allow_lan = false
ipv6 = false
[api]
enabled = true
listen = "127.0.0.1"
port = 9189
[dns]
enabled = true
listen = "127.0.0.1"
port = 1053
ipv6 = false
[tun]
stack = "system"
auto_route = true
auto_detect_interface = true
dns_hijack = true
二级配置
active.toml:保存主页需要展示和切换的状态,只放当前 core 与三个开关。当前 profile 和节点选择由 profiles.toml 保存,PID 与锁由 state/runtime/ 保存。
schema_version = 1
[current]
core = "mihomo"
[tun]
enabled = false
[shell_proxy]
enabled = false
bypass = true
[system_proxy]
enabled = false
bypass = true
三级配置
state/generated/<core>/ 只保存根据配置生成的内核入口文件,可随时删除重建。state/runtime/<core>/ 才是 {workdir} 指向的内核工作目录,用来隔离 cache.db 等副产物。
介绍文档
除了上面的一些控制文档,还需要有一些总结性的文档,避免每次都重新扫描文件。
profiles.toml
schema_version = 1
# 每个 family 各自保存当前 profile,切换 core 后可以恢复对应选择。
[current]
clash = "home"
sing-box = "sid"
[[profiles]]
name = "home"
family = "clash"
format = "yaml"
source_file = "home/source.yaml"
[profiles.origin]
kind = "remote"
url = "https://example.com/subscription"
[profiles.update]
updated_at = "2026-08-14T10:00:00Z"
# 一个 profile 可以保存多个策略组的节点选择。
[profiles.state.selected]
Proxy = "Hong Kong 01"
Final = "Proxy"
[[profiles]]
name = "company"
family = "clash"
format = "yaml"
source_file = "company/source.yaml"
[profiles.origin]
kind = "local"
original_path = "/home/lht/config/company.yaml"
cores标准设计
下面的不需要tz程序初始化,也不需要其修改,基本上手动制作,tz读取使用即可
cores/
└── mihomo/
├── core.toml # Core 描述文件
└── mihomo # 二进制
这一部分还作为后续cores制作的参考标准
core.toml
schema_version = 1
[core]
name = "mihomo"
family = "clash"
version = "1.19.18"
binary = "mihomo"
os = "linux"
arch = "x86_64"
[runtime]
entrypoint = "config.yaml"
format = "yaml"
[capabilities.config]
mixed_proxy = true
http_proxy = true
socks_proxy = true
api = true
dns = true
tun = true
# start 必填;check/version/reload 为可选表。
# 某个命令表存在就表示支持对应 CLI 动作,不再维护重复的 actions 布尔值。
[commands.start]
args = ["-d", "{workdir}", "-f", "{config}"]
[commands.check]
args = ["-t", "-d", "{workdir}", "-f", "{config}"]
[commands.version]
args = ["-v"]
core.toml 只允许 {config} 和 {workdir} 两个占位符。binary 与 entrypoint 必须是单个相对文件名;加载 core 时还会检查 schema、目录名、family/format 组合、二进制是否存在且可执行。
最终文件树
这里是结合文件作用+cores的
TZ_PATHS_TOML
└── paths.toml # 保存四个基础路径
config/
├── settings.toml # TZ 自身的长期策略:bypass、日志、更新配置
├── runtime.toml # 跨 core 的端口、API、DNS、TUN 参数
├── shell/ # 后续生成 shell 代理脚本;当前阶段尚未实装
└── bypass.list
data/
├── profiles/
│ ├── profiles.toml # profile 索引、当前选择和策略组节点选择
│ ├── tnt/
│ │ └── source.yaml
│ └── sid/
│ └── source.json
│
└── cores/ # 手工制作、TZ 只读;目录名必须等于 core.name
├── mihomo/
│ ├── core.toml
│ └── mihomo
└── sing-box/
├── core.toml
└── sing-box
state/
├── active.toml # 当前 core 与主页开关
│
├── generated/ # 只放可删除重建的生成配置
│ ├── mihomo/
│ │ └── config.yaml
│ └── sing-box/
│ └── config.json
│
├── runtime/
│ ├── mihomo/ # Mihomo cache.db 等运行副产物,{workdir} 指向这里
│ ├── sing-box/
│ ├── tz.lock # 防止多个 TZ 同时修改运行状态
│ └── core.pid # 停止时还必须通过 /proc/<pid>/exe 校验身份
│
└── logs/
├── tz.log
└── core.log
cache/
├── downloads/
└── speedtest/
配置层 domain 与命令实装
本次目标
把“文件作用 + cores 标准”定稿落到 Rust:用 domain 结构体描述 settings.toml、runtime.toml、active.toml、profiles.toml 和 core.toml,由 tz init 生成默认文件,由 tz status 与 tz core list 严格读取。配置 builder 和真实进程启停留到下一阶段。
代码结构
src/domain/ 只负责配置结构、序列化和业务校验;application 负责行为;platform 负责路径:
src/
├── domain/
│ ├── mod.rs # domain 类型重导出
│ ├── settings.rs # settings.toml:[bypass]/[log]/[update]
│ ├── runtime.rs # runtime.toml:[proxy]/[api]/[dns]/[tun]
│ ├── active.rs # active.toml:当前 core + 三个主页开关
│ ├── profiles.rs # profiles.toml:当前 profile、索引、节点选择
│ └── core_manifest.rs # core.toml 加载、校验和 list_cores
├── platform/paths.rs # 四个根目录和固定子路径
├── application/
│ ├── init.rs # 生成默认配置
│ └── service.rs # status 与未实现启停错误
└── cli/commands/ # CLI 薄分发
配置职责与校验
settings.toml保存 TZ 自身的长期策略。日志超限直接清除重建,因此没有keep字段。runtime.toml保存端口、API、DNS 与 TUN 复杂参数;默认端口为 mixed7890、HTTP7892、SOCKS7891。active.toml只保存[current].core、tun.enabled、shell proxy 和 system proxy 开关。profiles.toml在顶层[current]按 family 保存当前 profile;[profiles.state.selected]可以保存多个策略组各自选择的节点。state/generated/<core>/只保存可删除重建的入口配置;state/runtime/<core>/是{workdir},用于隔离内核数据库和缓存。- 四份配置都只支持
schema_version = 1并拒绝未知字段。Default只供tz init生成模板;普通命令严格读取,文件缺失、损坏或版本不支持都会报错。 - profile 会校验名称、family/format、来源字段、重复项、当前选择引用和
source_file安全相对路径。
cores 标准
core.name必须等于目录名,名称只能使用 ASCII 字母、数字、点、下划线和连字符。family/format当前支持clash/yaml与sing-box/json。binary和runtime.entrypoint必须是单个相对文件名;binary 还必须实际存在且可执行。commands.start必填;commands.check、commands.version、commands.reload可选。命令表存在即表示支持对应动作,不再使用重复的[capabilities.actions]布尔值。- 命令参数只支持
{config}和{workdir},由CoreDescriptor::render_args展开。 [capabilities.config].api只表示内核提供控制 API,不等同于支持 CLI reload。
paths.rs 与初始化
paths.toml仍是四个根目录的唯一来源;设置TZ_PATHS_TOML时必须是绝对路径。AppPaths::from_env_or_none()让非 init 命令自己输出未初始化提示,不再提前重复解析路径。initialize_files只建目录并幂等写bypass.list;domain 默认值负责生成四份 TOML,已有文件不覆盖。- 初始化先准备目录与默认配置,最后写
paths.toml,避免配置生成失败后留下已提交的路径文件。 generated_dir与core_workdir分离;没有独立的active.example.toml。
当前命令行为
tz init:选择模板,确认四个路径,准备目录和默认配置,最后写paths.toml,再提示TZ_PATHS_TOMLexport。tz status:显示当前 core、profile、受管进程和当前节点;PID 检查会排除僵尸进程。tz core list:扫描data/cores/*/core.toml,通过完整校验后按名称排序,并在 TTY 中允许直接选择。tz start、tz stop、tz restart:生成并校验配置后真实控制受管进程;停止前核对进程用户和可执行文件。
stop 不会仅凭 PID 发送信号;/proc/<pid>/exe 与当前受管 core 不一致时直接拒绝。
验证
cargo fmt --check
cargo check
cargo test --all-targets
cargo clippy --all-targets -- -D warnings
TZ_PATHS_TOML="$PWD/target/tz-paths.toml" cargo run -- status
TZ_PATHS_TOML="$PWD/target/tz-paths.toml" cargo run -- core list
控制逻辑界面
TZ 的公开控制入口围绕对象和业务动作组织,不提供任意 TOML 编辑器。配置文件是内部存储格式,所有写操作都经过类型校验、运行状态检查、锁保护和原子保存。
当前命令
tz init
tz status
tz setting
tz setting list
tz setting get <key>
tz setting set <key> [value]
tz setting reset [key]
tz profile add <name> <url-or-file> --family clash|sing-box
tz profile list [--family clash|sing-box] [--all]
tz profile info <name>
tz profile use [name]
tz profile update
tz profile remove <na
tz core add <directory>
tz core list
tz core info [name]
tz core use [name]
tz core remove <name>
tz completion generate bash|zsh|fish # 生成tab服务
tz setting 无子命令时在 TTY 中进入选择界面;非交互调用使用 list。set 缺少 value 时只允许 TTY 交互。start、stop、restart 当前明确返回未实现错误,不打印成功状态。
简明指令
tz start|on # 直接读取上一次的配置
tz off|stop|end # 关闭服务,清理环境
tz -l # 列出节点
tz -l <name> # 不区分大小写的关键词搜索
tz completion generate bash|zsh|fish # 生成 shell 补全脚本
# eval "$(tz completion generate bash)"
快捷键
tz # tz status ,需要展示当前使用的core,profile,节点及其测速
tz select # tz profile list
状态归属
settings.toml与runtime.toml由tz setting的固定 key registry 管理,禁止任意路径写入。active.toml只由 core 选择等业务命令维护,tz status负责展示,不提供通用字段编辑。profiles.toml与受管 profile source 由tz profile管理;远程来源保存 URL 和实际下载路径,下载优先使用环境代理,失败后回退直连。profile list默认按当前 core 的 family 过滤;只有--all才显示全部 family。core.toml与二进制由tz core只读校验和管理;PID、锁、日志属于运行状态。- generated 配置由当前 family builder 生成并调用真实 core 校验;节点选择、测速、真实启停、TUN 独立开关及 shell/GNOME system proxy 已开放。
修改规则
- 命令先重新读取并校验当前状态,再持有
tz.lock执行修改。 - 文件使用同目录临时文件和原子替换;失败时保留旧状态。
- profile/core 在受管进程运行时拒绝
use、update、remove等可能改变运行输入的操作。 - profile URL 只允许 HTTP(S),校验公网地址、DNS 全部结果和每次重定向;本地文件复制为受管副本。
- core 只接受本地目录,不接受 URL;导入成功后不自动选择、不自动启动。
core 制作
目标与范围
TZ 当前支持统一的本地 core 包格式,用于识别和调用已经存在的 Mihomo 或 sing-box 二进制。core 包只描述运行契约,不包含 profile、用户配置、secret、PID、日志或缓存。
当前稳定槽位为 mihomo 和 sing-box,目录名必须与 core.name 相同:
data/cores/
├── mihomo/
│ ├── core.toml
│ └── mihomo
└── sing-box/
├── core.toml
└── sing-box
当前 schema v1
core.toml 必须声明 schema、名称、family、版本、二进制、目标平台、配置格式、能力和命令参数。Mihomo 使用 family = "clash"、format = "yaml",sing-box 使用 family = "sing-box"、format = "json"。命令参数只支持 {config} 和 {workdir} 占位符,由 TZ 展开。完整字段以 docs/core-package.md 为准。
schema_version = 1
[core]
name = "mihomo"
family = "clash"
version = "1.19.18"
binary = "mihomo"
os = "linux"
arch = "x86_64"
[runtime]
entrypoint = "config.yaml"
format = "yaml"
[commands.start]
args = ["-d", "{workdir}", "-f", "{config}"]
当前制作和导入流程
- 用户自行下载或制作二进制,在本地准备包含
core.toml和可执行文件的目录。 - 使用
tz core add <directory>导入;TZ 校验目录、manifest、平台、family、格式、二进制权限和命令占位符。 - 如 manifest 声明
commands.version,导入前执行该命令;参数按数组传递,不经过 shell。 - 目标名称已存在时拒绝覆盖;通过 staging 目录复制并原子重命名到
data/cores/<name>。 - 导入成功后不自动
core use,也不自动启动;后续用tz core list/info/use/remove管理。
core remove 在运行中拒绝,删除前检查当前选择和受管 PID,并清理该 core 的派生配置。手工复制到 data/cores/ 也会被扫描,但不会绕过运行状态和安全校验。
当前不做
core 不通过 URL 安装、不负责下载更新、不覆盖正在运行的 core。远端 registry、归档校验和 core update 不在当前路线内。任意其他代理二进制也不能只凭一份 core.toml 接入,必须先提供对应 family 的配置 builder 和控制 adapter。
本轮实现结果
- 新增
platform/storage.rs:tz.lock非阻塞独占锁、同目录临时文件、flush/fsync、原子 rename;profile 索引和 source 使用当前用户私有权限。 - 新增
platform/process.rs:统一正整数 PID、存活和僵尸状态判断,供 status、profile/core use/remove 共用。 - 新增
platform/network.rs:profile URL 只允许 HTTP/HTTPS,拒绝凭据、本机、环回、私有和保留地址;DNS 全结果与重定向逐次复核,优先使用环境代理并在失败后回退直连,限制超时、重定向和响应大小,错误不泄露订阅 URL。 - 新增 typed setting registry,完成
setting/list/get/set/reset;不允许任意 TOML 路径编辑,保存后明确提示需要重新 build/start。 - 完成 profile add/list/info/use/update/remove:URL 与本地文件都变成受管副本,family 固定映射格式,运行中禁止 use/update/remove,删除不触碰用户原文件。
- core schema v1 新增必填 os/arch,稳定槽位统一为
mihomo、sing-box。 - 完成 core add/list/info/use/remove:手工复制仍可直接扫描,add 只做本地安全导入,version 命令不经过 shell,运行中禁止 use/remove。
- 新增正式规范
docs/control-interface.md、docs/core-package.md和examples/cores/mihomo/制作模板。
当前边界与下一阶段
当前路线已完成 config builder、节点选择与测速、受管进程启停、TUN 独立控制及 shell/GNOME system proxy。core 在线更新与其他桌面环境 adapter 留在后续阶段。
v0.1 可运行闭环
本章覆盖当前可运行行为;前文中的阶段性设计以这里和 docs/control-interface.md 为准。
当前指令
tz status|start|stop|restart
tz list [keyword]
tz node test [keyword] [--url <url>] [--timeout <ms>] [--select]
tz tun status|on|off
tz proxy status|on|off
tz proxy terminal|system status|on|off
tz proxy env|noenv [bash|zsh|fish]
tz proxy shell-init bash|zsh|fish
tz setting [list|get|set|reset]
tz profile add|list|info|use|update|remove
tz core add|list|info|use|remove
tz config build|check|show
tz completion generate bash|zsh|fish
profile update 不接名称,一次更新全部远程 profile。profile list 默认只看当前 core family,只有 --all 跨 family。profile/core/node 的 list 在终端中均可编号选择并以 * 标记当前项;use 保留给脚本和显式操作。列表保持简洁,路径和来源等详情由 info 或对应文件提供。
nano_clash family=clash
* mihomo version=1.19.18 family=clash
Mihomo 读取 Clash 配置,所以其 family 必须为 clash;sing-box 才使用 family=sing-box。
简洁指令
tz # status,并测速当前节点
tz on # 使用上次的可用 profile 启动并显示 status
tz off | tz end # stop
tz -l [keyword] # 节点测速、延迟排序、搜索和选择
tz select # 当前 family 的 profile 列表和选择
快捷键
tz st # status
tz r # restart
tz set # setting
tz p # profile
tz c # core
tz cfg # config
tz comp # completion
tz p a|l|i|u|up|rm
tz c a|l|i|u|rm
Tab 提示由 completion generator 提供。节点选择会写入 profile state 并在下次启动后恢复。tz -l 和 node test 都走 controller delay API,最多 8 路并发、按延迟排序并缓存最新结果;--select 选择最快节点。tz 对当前节点实时测速,失败时才显示缓存结果。
Mihomo 标准 core 包携带 Country.mmdb 与 GeoSite.dat。Clash profile 实际引用 GEOIP/GEOSITE 时,builder 按需复制到该 core 的独立 runtime 工作目录,避免首次校验因 GitHub 下载受阻而误报超时;自制 core 包缺失资源时直接提示用户启用其他代理或补齐 core 包。tz on/start 始终使用当前 family 上次选择且 source 可用的 profile,启动后立即显示含节点测速的 status。
profile 下载的 User-Agent 按 family 选择:Clash 对齐 mh 的 Mihomo provider User-Agent,sing-box 对齐 sb。同一订阅 URL 若按客户端返回 Clash YAML 或 sing-box JSON,add 与批量 update 都能取得对应 family 的原生格式;--family 仍只负责选择契约,不做跨格式转换。
Proxy、TUN 与权限
proxy env/noenv输出可由当前 shelleval/source的环境命令;shell-init为 Bash、Zsh、Fish 生成持久 hook。proxy system按 mh/sb 的当前参考路线使用 GNOMEgsettings,读取 runtime/capability 端口并把 bypass 转成 ignore-hosts;开启前备份原桌面设置,关闭或失败时恢复。tun on/off检查 core capability、/dev/net/tun和CAP_NET_ADMIN;运行中切换会重启,失败回滚,不自动执行 sudo/setcap。
配置生成已通过 Mihomo 1.19.18 和 sing-box 1.13.14 的真实 check。隔离测试覆盖 sing-box 的 start/status/list/select/stop,并继续覆盖 proxy 环境输出、TUN 状态和节点测速错误/超时路径。