TZ/docs/第一次开发日志.md
2026-08-21 18:34:18 +08:00

976 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 环境搭建
省略
# 初始文件树
`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 状态和节点测速错误/超时路径。