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,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 状态和节点测速错误/超时路径。