Initial release v0.1.0

This commit is contained in:
Lihatoo 2026-08-21 18:34:18 +08:00
commit b997bd6078
62 changed files with 56224 additions and 0 deletions

View file

@ -0,0 +1,189 @@
# TZ 统一控制指令架构(讨论稿)
状态Draft 0.1
范围Clash/Mihomo、sing-box以及待确认的 NinjaDesktop Lite 适配器
参考:`/mnt/data_4t2/lht_self/sing-box-13/sb`
第一版:下面的架构以假设使用.sh调用原二进制内核开发
## 1. 目标
对用户只暴露一套稳定的 `tz` 指令。切换内核后用户的日常命令、配置档名称、当前节点、路由模式、TUN、终端代理和系统代理等状态不变由内核适配器负责生成配置并执行不同的底层指令。
```text
用户 / shell
|
v
tz CLI解析、状态、锁、事务、统一输出
|
+-- clash adapter ------> mihomo/clash + Clash API
+-- sing-box adapter ---> sing-box + Clash API
`-- ninja adapter ------> 待探测
```
基本原则:
1. 正式命令统一为 `tz <对象> <动作> [参数]`
2. 常用操作保留短命令,但短命令只是正式命令的别名。
3. 用户状态由 `tz` 保存,不能以某个内核的运行配置作为唯一状态源。
4. 原始订阅/配置档只读保存端口、DNS、TUN、绕过规则等系统配置在启动前覆盖合并。
5. 所有内核差异只进入 adapter主控制逻辑中不散落 `if clash` / `if sing-box`
6. 不支持的能力必须明确报错并返回非零退出码,不能假装执行成功。
7. 修改内核、配置档、模式、TUN 等操作均先生成并校验配置,再应用;失败时保留旧的可运行状态。
## 2. 完整指令树
我想做的就是普通clash界面的终端操控指令
```text
tz
快速启动
|-- status [--watch] # 显示整体状态使用的内核profile情况节点延迟等
|-- start # 启动直接启动上次使用的profile之后立刻执行status做参考
|-- stop/end # 停止服务
|-- restart # 强制完整重启,等效于 stop 后 start
|-- reload # 重新生成配置并热加载,必要时自动重启
|
|-- list|-l [keyword] # 列出默认策略组节点并按延迟排序,快速切换节点
| [--group|-g <name>]
| [--fresh] # 这是什么?
|-- use <node> [--group <name>] # 快速选择节点
整体服务
|-- service 服务,选择节点(对应当前profile开关等
| |-- status [--watch]
| |-- stop/end # 停止进程
| |-- restart [profile] # 重启多用来刷新 bypass.list
|
|-- core
| |-- list 查看有哪些内核比如clash sing-boxmihomo。用*指出当前内核,选择可换
| |-- info [name] 当前内核的版本二进制位置、导入时的url是否正常启动等信息或者是指定的
| |-- add <name> <url>不需要这个我后面会给出内核加入的标准格式,只做上传到网上,下载即可。如果名字重复,可以选择覆盖或者输入新的名称
| |-- remove <name> 删除对应内核
| |-- use <name> [--no-start] 切换内核,
| `-- update [name] 去查看url的内核版本可选是否更新否则提示无更新
|-- setting 这个是所有的core共用(配置一次就可以用了)?还是每个core有自己的单独配置(麻烦)
| |-- list # 列表展示 项目(key+ 出来。可以选择设置哪一个
| |-- get <key> # 这个是只展示某个key的配置
| |-- set <key> <value> # 这个是单独配置
| `-- reset [key] # 恢复默认值
|
|-- key 这里展示setting可以打开哪些项目及其配置。下面指出的是默认配置
| |-- core mihomo # 等效于 core list
| |-- sysproxy on/off # 系统proxy开启注意需要识别bypass.list 配置ignore host
| |-- proxy on/off 终端~/.bashrc中的变量配置
| |-- http-proxy : 127.0.0.1:7892
| |-- socks-proxy : 127.0.0.1:7891
| |-- mixed-proxy : 127.0.0.1:7890
| |-- WebUI 127.0.0.1:9189
| |-- autostart : true/false
|-- env 环境配置
| |-- list # 展示出来,有哪些可以配置
| |-- sysproxy on/off # 系统proxy开启注意需要识别bypass.list 配置ignore host
| |-- proxy on/off 终端~/.bashrc中的变量配置
| |-- http-proxy : 127.0.0.1:7892
| |-- socks-proxy : 127.0.0.1:7891
| |-- mixed-proxy : 127.0.0.1:7890
| |-- WebUI 127.0.0.1:9189
|-- profile # 由于内核不同profile也不同所以注意区分。profile是对应core的
| |-- list # 列出订阅,*指出当前的订阅注意profile与core对应
| |-- show [name]
| |-- add <name> <url-or-file> [--format auto|clash|sing-box] # 新增订阅,重名选择覆盖(remove后add还是重命名
| |-- remove <name> # 删除
| |-- use <name> [--restart]
| |-- current
| |-- update [name]
| |-- update-all
| |-- check [name] [--core <name>]
| `-- source [name]
|
|-- group # profile对应的group可选择切换与node 节点应该在一起
| |-- list
| |-- current [group]
| `-- select <group> <node>
|-- node 节点
| |-- list [--group <name>] [--match <keyword>]
| |-- current [--group <name>]
| |-- select <node> [--group <name>]
| `-- test [--group <name>] [--match <keyword>]
| [--url <url>] [--timeout <ms>] [--select]
|
|-- mode # 这个放在这儿?为什么不放在setting
| |-- get
| `-- set rule|global|direct
|
|-- tun
| |-- status
| |-- on
| `-- off
|
|-- proxy
| |-- status
| |-- on
| |-- off
| |-- env
| |-- noenv
| |-- shell-init [bash|zsh|fish]
| |-- terminal on|off
| `-- system on|off
|
|-- rule
| `-- bypass
| |-- list
| |-- add <domain-or-cidr>
| |-- remove <domain-or-cidr>
| |-- import <file>
| |-- reset
| `-- apply
|
|-- connection
| |-- list
| |-- close <id>
| `-- close-all
|
|-- config
| |-- path
| |-- show [--effective|--source]
| |-- build [--core <name>] [--profile <name>]
| |-- check [--core <name>] [--profile <name>]
| `-- apply
|
|-- log # 日志没必要吧?
| `-- show [--lines <n>] [--follow] [--level <level>]
|
|-- diagnose # 这是什么?
| |-- run [--full]
| |-- ports
| |-- process [pid]
| |-- network direct|proxy|compare
| |-- dependencies
| |-- interfaces
| |-- dns
| |-- routes
| |-- api
| `-- config
|
|-- api status
|-- api get <path>
`-- completion generate bash|zsh|fish
```
# 文件树
##
# 具体配置

102
docs/control-interface.md Normal file
View file

@ -0,0 +1,102 @@
# TZ Control Interface v0.1
TZ 的公开命令围绕用户动作设计。配置文件是可查阅的内部存储格式,修改由固定命令完成并经过校验、锁保护和原子保存。
## 当前指令
```text
tz init
tz status
tz start
tz stop
tz 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 status|on|off
tz proxy system status|on|off
tz proxy env|noenv [bash|zsh|fish]
tz proxy shell-init bash|zsh|fish
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 <name>
tz core add <directory>
tz core list
tz core info [name]
tz core use [name]
tz core remove <name>
tz config build|check|show
tz completion generate bash|zsh|fish
```
`profile list` 默认只显示当前 core family`--all` 显示全部。`profile update` 不接名称,更新所有远程 profile本地 profile 自动跳过。
`profile list``core list` 和节点 `list` 在 TTY 中显示编号、用 `*` 标出当前项并允许直接选择;非交互环境只输出简洁列表。`profile/core use` 保留,作为脚本和明确指定名称的稳定入口。详细来源和路径使用 `info` 查看。
`list/-l``node test` 都通过当前 core controller API 最多并发测试 8 个节点并按延迟排序。`list/-l` 在 TTY 中允许从测速后的列表选择节点;`node test --select` 自动选择最快的成功节点。默认 URL 为 Google 204默认超时 1800ms最新结果保存在 `cache/speedtest/latest.json`
Mihomo 的 family 固定为 `clash`sing-box 的 family 固定为 `sing-box`,不能互换。
## 简洁指令
```text
tz # status并测速当前节点
tz on # 使用上次的可用 profile 启动并显示 status
tz off | tz end # stop
tz -l [keyword] # 测速、按延迟排序、搜索和选择
tz select # profile list
```
节点 keyword 使用不区分大小写的子串匹配。`list/-l` 在 TTY 中可输入测速后列表的编号切换当前节点;选择写入当前 profile并在下次启动后恢复。
## 快捷键
快捷键是当前指令的命令缩写,完整写法始终可用:
```text
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 补全通过 `tz completion generate <shell>` 生成。例如 Bash 当前会话可执行 `eval "$(tz completion generate bash)"`
## Proxy 与 TUN
`proxy terminal on|off` 保存终端代理状态。子进程不能直接修改父 shell因此当前 shell 使用 `eval "$(tz proxy env)"``eval "$(tz proxy noenv)"`;长期使用把 `eval "$(tz proxy shell-init bash)"` 加入对应 shell 启动文件。Fish 和 Zsh 使用各自的 shell 参数。
`proxy system on|off` 使用 GNOME `gsettings` 设置 HTTP、HTTPS、SOCKS 和 ignore-hosts端口与 bypass 均来自 TZ 配置。开启前要求 core 正在运行避免桌面流量指向空端口。TZ 会先私有备份原桌面代理,关闭或应用失败时逐项恢复;未由 TZ 开启时,`system off` 不修改桌面设置。`proxy on|off` 同时控制 terminal 和 system。
`tun on|off` 检查当前 core 的 TUN capability 和 `/dev/net/tun`。开启还要求受管 core 二进制具有 `CAP_NET_ADMIN`;缺少时打印对应的 `sudo setcap cap_net_admin,cap_net_raw+ep ...` 命令。运行中的切换会安全重启,失败时恢复原状态。
## Profile 下载
URL 只允许 HTTP/HTTPS并校验 DNS 与重定向目标。下载按 family 使用对应 provider User-AgentClash 对齐 `mh`sing-box 对齐 `sb`,以支持服务端按客户端返回不同格式。下载优先尝试环境代理,失败后回退直连,只要一种路径成功即完成添加或更新。实际成功路径保存为 profile 的 `download_via=proxy|direct`,可用 `tz profile info <name>` 查看;错误信息不会打印订阅 token。
## 运行闭环
`config build/check` 根据当前 core family 生成 Clash YAML 或 sing-box JSON并调用 core manifest 的 check 命令。Mihomo profile 引用 GEOIP/GEOSITE 时builder 从 core 包按需复制 `Country.mmdb``GeoSite.dat` 到独立工作目录;标准 core 包已携带这两份规则数据库,用户无需手工处理。自定义 core 包缺失时会明确提示,可先启用其他代理取得资源后补入 core 包。
`start/on` 读取当前 family 上次选择且 source 可用的 profile在校验通过后启动受管进程、等待 API 并显示 status没有可用 profile 时提示运行 `tz profile list``stop` 在发送信号前核对进程用户和 `/proc/<pid>/exe``status/tz` 简洁显示 core、profile、服务 PID并实时测试当前节点延迟失败时才回退显示缓存结果。
当前尚未开放的是 core 在线下载与自动更新。System proxy 的 v0.1 平台适配范围是 GNOME其他 Linux 桌面环境后续增加 adapter。

96
docs/core-package.md Normal file
View file

@ -0,0 +1,96 @@
# TZ Core Package v1
本规范定义 TZ 如何发现、校验和调用本地代理内核。core 包包含运行契约、二进制和该 core 固定的只读运行资源,不包含 profile、用户配置、secret、日志、PID 或缓存。
## 目录结构
稳定槽位名推荐使用 `mihomo``sing-box`
```text
<data_dir>/cores/
└── mihomo/
├── core.toml
├── mihomo
├── Country.mmdb # Mihomo GEOIP 规则数据库
├── GeoSite.dat # Mihomo GEOSITE 规则数据库
├── LICENSE # 可选
├── NOTICE # 可选
└── README.md # 可选TZ 不解析
```
目录名必须与 `core.name` 完全一致。完整版本保存在 `core.version`;需要多版本并存时使用完整槽位名,例如 `mihomo-1.19.14`
Mihomo 标准包固定携带 `Country.mmdb``GeoSite.dat`。生成配置实际引用 GEOIP/GEOSITE 时TZ 才把缺失资源复制到 `state/runtime/<core>/`;用户无需逐个 profile 手工下载。自制 Mihomo core 包也应携带这两个文件,否则 TZ 会在 build/check 阶段给出明确提示。
## Manifest
```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
[commands.start]
args = ["-d", "{workdir}", "-f", "{config}"]
[commands.check]
args = ["-t", "-d", "{workdir}", "-f", "{config}"]
[commands.version]
args = ["-v"]
```
字段约束:
- schema 当前仅支持 `1`,未知字段会被拒绝。
- name 只允许 ASCII 字母、数字、点、下划线和连字符。
- family/format 当前只允许 `clash/yaml``sing-box/json`
- os/arch 必须等于当前运行平台的 Rust target 常量。
- binary 与 entrypoint 必须是单个相对文件名,禁止绝对路径和 `..`
- binary 必须是普通可执行文件。
- start 必填check、version、reload 可选。命令存在即表示支持对应动作。
- 参数只支持 `{config}``{workdir}`TZ 直接执行 binary不经过 shell。
## 安装方式
手工复制是标准方式,无注册数据库:
```bash
cp -a ./mihomo <data_dir>/cores/mihomo
chmod +x <data_dir>/cores/mihomo/mihomo
tz core list
```
本地便捷导入:
```bash
tz core add ./mihomo
tz core info mihomo
tz core use mihomo
tz core remove mihomo
```
`core add` 只接收本地目录,不接收 URL。它会拒绝符号链接和特殊文件复制到 staging重新校验后原子移动重名直接拒绝。成功后不自动选择或启动。
`core remove` 在受管进程运行时拒绝。服务停止时可以删除当前 core并原子清空 current同时清理同名 generated/runtime 派生目录。
## 网络分发
网络下载不属于 `core add`。未来 `core install` 必须使用可信 registry 提供的外部 SHA256且 URL 只能是 HTTP/HTTPS请求和每次重定向前必须拒绝 localhost、环回、私有和保留地址。

10
docs/scope.md Normal file
View file

@ -0,0 +1,10 @@
# tz v0.1 范围
- 只支持 Linux同一时间只运行一个当前用户的受管 core不使用 systemd。
- 支持本地导入 Mihomo 1.19.18`family=clash`)和 sing-box 1.13.14`family=sing-box`)。
- 支持本地或 HTTP(S) profile远程下载在环境代理与直连之间回退并记录实际成功路径。
- 支持 Clash YAML 与 sing-box JSON 的生成、真实 core 校验、启动、状态、节点选择与测速、重启和安全停止。
- `profile list` 默认跟随当前 core family`--all` 才跨 family 显示。
- 支持 Bash/Zsh/Fish 终端代理环境输出与 shell hook支持 GNOME `gsettings` system proxy 和 bypass。
- 支持独立 TUN 开关、能力与权限检查、运行中重启及失败回滚;二进制 capability 由用户显式设置。
- 暂不支持非 GNOME 桌面 system proxy adapter、core 在线安装或自动更新。

View file

@ -0,0 +1,976 @@
# 环境搭建
省略
# 初始文件树
`cargo init --bin --name tz .`
#文件树1
```
TZ/
├── Cargo.toml
├── Cargo.lock
└── src/
├── main.rs # tz 可执行程序入口
└── lib.rs # 项目的主要代码入口
```
## 常用代码
```bash
# 检查代码,不生成最终程序
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 解析层的第一个小闭环
1. 添加clap依赖
```bash
cargo add clap --features derive
```
`cargo add` 会修改当前 Package 的 `Cargo.toml``derive` feature 让我们可以使用 `#[derive(Parser)]``#[derive(Subcommand)]`
2. 写文件功能 #文件树2
```bash
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 # 定义用户可以输入什么
```
3. `lib.rs`中添加声明
```rust
pub mod cli;
```
声明项目中存在 `cli` 模块Rust 会自动寻找`src/cli.rs`或者`src/cli/mod.rs`
4. `src/cli/mod.rs`中管理子模块
```rust
mod args; // cli 模块内部还有一个 args 子模块。
pub use args::{Cli, CliCommand, CoreCommand}; // 表示把三个类型重新导出到 cli 模块表面
```
没有写 `pub`,所以外部不能直接访问`args`/`tz::cli::args::Cli`;
然后补充[args.rs](../src/cli/args.rs)即可,注释也写在里面
即使`main.rs``lib.rs`在同一个 Cargo package 中, 仍然是两个独立 crate。Rust 官方文档明确说明:同时存在 `src/lib.rs``src/main.rs`package 中包含一个库 crate 和一个二进制 crate。
```tcl
package tz
├── library crate tz
│ └── cli
└── binary crate tz
└── main
```
5. 补充main.rs
```rust
use clap::Parser;
use tz::cli::Cli; // cli 当前是由 lib.rs 管理的,它属于库 crate tz不是 main.rs 所属二进制 crate 的直接模块。
fn main() {
let cli = Cli::parse();
println!("{cli:#?}");
}
```
6. 测试,`--`表示隔开,后面的参数是输入给二进制文件的
```bash
cargo run -- --help # 查看帮助
cargo run -- status #
cargo run -- core --help # 查看 core 的帮助
cargo run -- unknown # 测试错误输入
```
## 常用代码
```bash
cargo tree # 检查依赖
cargo tree -i clap
cargo fmt # 统一代码格式
cargo check # 类型检查和编译检查
cargo clippy # 检查潜在问题和不规范写法
```
# CLI 解析run态
1. 新增命令分发层 #文件树3
```bash
src/
├── main.rs
├── lib.rs
├── cli/
│ ├── mod.rs
│ ├── args.rs # 用户可以使用什么命令
│ └── commands/ # 定义“收到命令之后调用什么”
│ ├── mod.rs
│ ├── status.rs
│ ├── service.rs
│ └── core.rs
```
创建
```bash
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
```
2. 补充command代码
补充 [src/cli/mod.rs](../src/cli/mod.rs)
补充 [src/cli/commands/mod.rs](../src/cli/commands/mod.rs)
补充 [src/cli/commands/status.rs](../src/cli/commands/status.rs)
补充 [src/cli/commands/service.rs](../src/cli/commands/service.rs)
补充 [src/cli/commands/core.rs](../src/cli/commands/core.rs)
补充 [src/main.rs](../src/main.rs)
3. 测试
```bash
cargo fmt
cargo check
cargo clippy
```
然后
```bash
cargo run -- status
cargo run -- start
cargo run -- stop
cargo run -- restart
cargo run -- core list
```
```
之前:
用户输入 → Debug 打印
现在:
用户输入
Cli
CliCommand
match
具体 command handler
```
# application
```bash
mkdir -p src/application
touch src/application/mod.rs
touch src/application/service.rs
```
文件树4
````bash
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 : 真实实现
目前只是搭建了基础框架没有实际执行,
1. 搭建cli
2. 搭建application,改cli的调用路线为application
主要完成了指令的分发
# 路径系统
设定软件的路径系统,
```bash
mkdir -p src/platform
touch src/platform/mod.rs
touch src/platform/paths.rs
```
文件树5
```bash
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` 是文件系统路径的唯一配置源,文件只保存一次选定的四个目录,不保存布局类型或多个方案:
```toml
[layout]
config_dir = "~/.config/tz"
data_dir = "~/.local/share/tz"
state_dir = "~/.local/state/tz"
cache_dir = "~/.cache/tz"
```
路径文件定位规则:
1. 设置 `TZ_PATHS_TOML` 时,读取该绝对路径文件;文件不存在或格式错误直接报错,不回退。
2. 未设置时,读取 `$HOME/.config/tz/paths.toml`
3. 默认路径文件不存在时,提示运行 `tz init`
程序固定读取 `[layout]` 下的四个字段。路径可以写成绝对路径或 `~/...`;读取时展开 `~`,展开后必须是绝对路径。普通命令不再读取 `TZ_ROOT_DIR` 或四个 `XDG_*` 环境变量。
`tz init` 的首次选择提供三个模板:
1. 默认 XDG`~/.config/tz``~/.local/share/tz``~/.local/state/tz``~/.cache/tz`
2. 默认 Unified`~/.tz/config``~/.tz/data``~/.tz/state``~/.tz/cache`
3. 开发测试:项目目录下的 `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`,示例:
```bash
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_TOML` export自定义路径可确认后追加到 `~/.bashrc`
验证命令:
```bash
cargo fmt --check
cargo check
cargo test --all-targets
cargo clippy --all-targets -- -D warnings
```
# 文件作用
接下来固定文件作用
`paths.toml` TZ_PATHS_TOML
```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的运行不太相关。默认不会修改只是展示一下
```toml
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`
```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/` 保存。
```toml
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`
```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读取使用即可
```bash
cores/
└── mihomo/
├── core.toml # Core 描述文件
└── mihomo # 二进制
```
这一部分还作为后续cores制作的参考标准
`core.toml`
```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的
```toml
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 复杂参数;默认端口为 mixed `7890`、HTTP `7892`、SOCKS `7891`
- `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_TOML` export。
- `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 不一致时直接拒绝。
## 验证
```bash
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 编辑器。配置文件是内部存储格式,所有写操作都经过类型校验、运行状态检查、锁保护和原子保存。
## 当前命令
```bash
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` 当前明确返回未实现错误,不打印成功状态。
## 简明指令
```bash
tz start|on # 直接读取上一次的配置
tz off|stop|end # 关闭服务,清理环境
tz -l # 列出节点
tz -l <name> # 不区分大小写的关键词搜索
tz completion generate bash|zsh|fish # 生成 shell 补全脚本
# eval "$(tz completion generate bash)"
```
## 快捷键
```bash
tz # tz status 需要展示当前使用的coreprofile节点及其测速
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 已开放。
## 修改规则
1. 命令先重新读取并校验当前状态,再持有 `tz.lock` 执行修改。
2. 文件使用同目录临时文件和原子替换;失败时保留旧状态。
3. profile/core 在受管进程运行时拒绝 `use``update``remove` 等可能改变运行输入的操作。
4. profile URL 只允许 HTTP(S)校验公网地址、DNS 全部结果和每次重定向;本地文件复制为受管副本。
5. core 只接受本地目录,不接受 URL导入成功后不自动选择、不自动启动。
# core 制作
## 目标与范围
TZ 当前支持统一的本地 core 包格式,用于识别和调用已经存在的 Mihomo 或 sing-box 二进制。core 包只描述运行契约,不包含 profile、用户配置、secret、PID、日志或缓存。
当前稳定槽位为 `mihomo``sing-box`,目录名必须与 `core.name` 相同:
```text
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`](core-package.md) 为准。
```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"
[commands.start]
args = ["-d", "{workdir}", "-f", "{config}"]
```
## 当前制作和导入流程
1. 用户自行下载或制作二进制,在本地准备包含 `core.toml` 和可执行文件的目录。
2. 使用 `tz core add <directory>` 导入TZ 校验目录、manifest、平台、family、格式、二进制权限和命令占位符。
3. 如 manifest 声明 `commands.version`,导入前执行该命令;参数按数组传递,不经过 shell。
4. 目标名称已存在时拒绝覆盖;通过 staging 目录复制并原子重命名到 `data/cores/<name>`
5. 导入成功后不自动 `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、原子 renameprofile 索引和 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/removeURL 与本地文件都变成受管副本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` 为准。
## 当前指令
```bash
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` 或对应文件提供。
```text
nano_clash family=clash
* mihomo version=1.19.18 family=clash
```
Mihomo 读取 Clash 配置,所以其 family 必须为 `clash`sing-box 才使用 `family=sing-box`
## 简洁指令
```bash
tz # status并测速当前节点
tz on # 使用上次的可用 profile 启动并显示 status
tz off | tz end # stop
tz -l [keyword] # 节点测速、延迟排序、搜索和选择
tz select # 当前 family 的 profile 列表和选择
```
## 快捷键
```bash
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-Agentsing-box 对齐 `sb`。同一订阅 URL 若按客户端返回 Clash YAML 或 sing-box JSON`add` 与批量 `update` 都能取得对应 family 的原生格式;`--family` 仍只负责选择契约,不做跨格式转换。
## Proxy、TUN 与权限
- `proxy env/noenv` 输出可由当前 shell `eval/source` 的环境命令;`shell-init` 为 Bash、Zsh、Fish 生成持久 hook。
- `proxy system` 按 mh/sb 的当前参考路线使用 GNOME `gsettings`,读取 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 状态和节点测速错误/超时路径。

386
docs/第一版本.md Normal file
View file

@ -0,0 +1,386 @@
# 项目组织
> 使用语言 Go
> 第一版本需要实现的指令
```BASH
tz status
tz start
tz stop
tz restart
tz core list
tz core add
tz core remove
tz core use
tz core info
tz profile list
tz profile add
tz profile remove
tz profile use
tz profile update
tz config build
tz config check
tz node list
tz node select
tz node test
tz log
```
> 文件树
```
tz/
├── Cargo.toml
├── Cargo.lock
├── rust-toolchain.toml
├── README.md
├── LICENSE
├── src/
│ ├── main.rs
│ ├── lib.rs
│ │
│ ├── cli/
│ │ ├── mod.rs
│ │ ├── args.rs
│ │ ├── output.rs
│ │ └── commands/
│ │ ├── mod.rs
│ │ ├── status.rs
│ │ ├── service.rs
│ │ ├── core.rs
│ │ ├── profile.rs
│ │ ├── group.rs
│ │ ├── node.rs
│ │ ├── mode.rs
│ │ ├── tun.rs
│ │ ├── proxy.rs
│ │ ├── setting.rs
│ │ ├── rule.rs
│ │ ├── connection.rs
│ │ ├── config.rs
│ │ ├── log.rs
│ │ └── diagnose.rs
│ │
│ ├── application/
│ │ ├── mod.rs
│ │ ├── context.rs
│ │ └── usecase/
│ │ ├── mod.rs
│ │ ├── start.rs
│ │ ├── stop.rs
│ │ ├── restart.rs
│ │ ├── reload.rs
│ │ ├── switch_core.rs
│ │ ├── switch_profile.rs
│ │ ├── update_profile.rs
│ │ └── select_node.rs
│ │
│ ├── domain/
│ │ ├── mod.rs
│ │ ├── core.rs
│ │ ├── profile.rs
│ │ ├── settings.rs
│ │ ├── runtime.rs
│ │ ├── capability.rs
│ │ ├── group.rs
│ │ ├── node.rs
│ │ ├── connection.rs
│ │ └── error.rs
│ │
│ ├── adapter/
│ │ ├── mod.rs
│ │ ├── traits.rs
│ │ ├── registry.rs
│ │ │
│ │ ├── mihomo/
│ │ │ ├── mod.rs
│ │ │ ├── adapter.rs
│ │ │ ├── command.rs
│ │ │ ├── config.rs
│ │ │ ├── controller.rs
│ │ │ └── response.rs
│ │ │
│ │ └── sing_box/
│ │ ├── mod.rs
│ │ ├── adapter.rs
│ │ ├── command.rs
│ │ ├── config.rs
│ │ ├── controller.rs
│ │ └── response.rs
│ │
│ ├── core_manager/
│ │ ├── mod.rs
│ │ ├── manager.rs
│ │ ├── registry.rs
│ │ ├── package.rs
│ │ ├── installer.rs
│ │ └── remover.rs
│ │
│ ├── profile/
│ │ ├── mod.rs
│ │ ├── manager.rs
│ │ ├── store.rs
│ │ ├── fetcher.rs
│ │ ├── detector.rs
│ │ └── format/
│ │ ├── mod.rs
│ │ ├── clash.rs
│ │ ├── sing_box.rs
│ │ └── uri_list.rs
│ │
│ ├── config/
│ │ ├── mod.rs
│ │ ├── builder.rs
│ │ ├── overlay.rs
│ │ ├── effective.rs
│ │ ├── bypass.rs
│ │ └── validator.rs
│ │
│ ├── runtime/
│ │ ├── mod.rs
│ │ ├── manager.rs
│ │ ├── process.rs
│ │ ├── pid.rs
│ │ ├── lock.rs
│ │ ├── health.rs
│ │ ├── state.rs
│ │ └── log.rs
│ │
│ ├── platform/
│ │ ├── mod.rs
│ │ ├── paths.rs
│ │ ├── shell.rs
│ │ ├── system_proxy.rs
│ │ ├── service.rs
│ │ └── linux/
│ │ ├── mod.rs
│ │ ├── systemd.rs
│ │ ├── signal.rs
│ │ ├── tun.rs
│ │ └── routes.rs
│ │
│ ├── storage/
│ │ ├── mod.rs
│ │ ├── atomic_file.rs
│ │ ├── core_store.rs
│ │ ├── profile_store.rs
│ │ ├── settings_store.rs
│ │ └── runtime_store.rs
│ │
│ ├── infrastructure/
│ │ ├── mod.rs
│ │ ├── command.rs
│ │ ├── http.rs
│ │ ├── download.rs
│ │ ├── checksum.rs
│ │ └── filesystem.rs
│ │
│ └── diagnose/
│ ├── mod.rs
│ ├── process.rs
│ ├── ports.rs
│ ├── api.rs
│ ├── config.rs
│ └── network.rs
├── assets/
│ ├── defaults/
│ │ └── settings.toml
│ ├── templates/
│ │ ├── mihomo.yaml
│ │ └── sing-box.json
│ └── systemd/
│ └── tz.service
├── tests/
│ ├── cli.rs
│ ├── start_stop.rs
│ ├── profile.rs
│ └── adapter.rs
├── testdata/
│ ├── profiles/
│ │ ├── clash.yaml
│ │ └── sing-box.json
│ ├── api/
│ │ ├── mihomo-proxies.json
│ │ ├── mihomo-connections.json
│ │ └── mihomo-version.json
│ └── bin/
│ └── fake-core
├── docs/
│ ├── scope.md
│ ├── domain-model.md
│ ├── workflows.md
│ ├── adapter-contract.md
│ └── filesystem-layout.md
├── packaging/
│ ├── systemd/
│ └── completions/
└── scripts/
├── install.sh
├── uninstall.sh
└── release.sh
```
> 运行树
```
语言 Rust
异步运行时 Tokio
CLI clap derive
序列化 Serde
HTTP reqwest
错误类型 thiserror + anyhow
日志 tracing
项目配置 TOML
Clash Profile YAML
sing-box JSON
```
```
~/.config/tz/
├── settings.toml
├── current.toml
├── bypass.list
├── profiles/
│ ├── home/
│ │ ├── manifest.toml
│ │ └── source.yaml
│ └── company/
│ ├── manifest.toml
│ └── source.json
└── overlays/
├── common.toml
├── mihomo.yaml
└── sing-box.json
~/.local/share/tz/
└── cores/
├── mihomo/
│ ├── current
│ └── versions/
│ └── 1.20.0/
│ ├── manifest.toml
│ └── bin/
│ └── mihomo
└── sing-box/
├── current
└── versions/
└── 1.x/
├── manifest.toml
└── bin/
└── sing-box
~/.local/state/tz/
├── logs/
│ ├── tz.log
│ └── core.log
├── builds/
│ ├── effective-mihomo.yaml
│ └── effective-sing-box.json
├── history/
└── runtime-history/
~/.cache/tz/
├── downloads/
├── subscriptions/
└── latency/
${XDG_RUNTIME_DIR}/tz/
├── tz.lock
├── core.pid
├── runtime.json
├── effective-config
└── control.sock
```
# rust开发环境
```
Rust + Tokio + clap
Mihomo
Clash YAML profile
start / stop / status / log
node list / select
```
**现在使用一个 Package包含一个 Library target 和一个 Binary target。**
不使用 Workspace也不使用多 Bin。
# 开发顺序
```
第一阶段
├── 路径系统
├── SettingsStore
├── CoreRegistry
├── ProfileStore
├── MihomoAdapter
├── RuntimeManager
├── tz start
├── tz stop
├── tz status
└── tz log
```
```
第二阶段
├── Mihomo Controller API
├── group list/select
├── node list/select/test
├── mode
├── reload
└── profile update
```
```
第三阶段
├── sing-box Adapter
├── Capability 检测
├── sing-box 配置生成
├── TUN
├── system proxy
└── bypass
```
```
第四阶段
├── core install/update
├── diagnose
├── connection
├── completion
└── 发布与安装脚本
```