docs: add design spec and implementation plan
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1087
docs/superpowers/plans/2026-05-28-cli-tool-packaging.md
Normal file
1087
docs/superpowers/plans/2026-05-28-cli-tool-packaging.md
Normal file
File diff suppressed because it is too large
Load Diff
148
docs/superpowers/specs/2026-05-28-cli-tool-packaging-design.md
Normal file
148
docs/superpowers/specs/2026-05-28-cli-tool-packaging-design.md
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
# jianda-proxy CLI 工具打包设计
|
||||||
|
|
||||||
|
**日期**:2026-05-28
|
||||||
|
**状态**:已批准
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
jianda-proxy 是一个 HTTP 代理工具,用于解决腾讯云 ICP 拦截导致 Git LFS 下载失败的问题。目前是一个单文件 Python 脚本(`lfs-proxy.py`),配置硬编码,直接 `python3` 运行。
|
||||||
|
|
||||||
|
目标:将其打包为标准的 Python CLI 工具,支持 `uvx` 运行、`uv tool install` 安装、后台运行、CLI 管理生命周期,且跨平台(Windows + Mac)。
|
||||||
|
|
||||||
|
## 决策
|
||||||
|
|
||||||
|
- **工具名称**:`jianda-proxy`
|
||||||
|
- **配置格式**:INI(标准库 `configparser`,零外部依赖)
|
||||||
|
- **后台运行**:纯标准库,Unix 用 `os.fork()`,Windows 用 `subprocess` detached
|
||||||
|
- **配置管理**:CLI `config` 子命令
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
jianda-proxy/
|
||||||
|
├── pyproject.toml
|
||||||
|
├── src/
|
||||||
|
│ └── jianda_proxy/
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── cli.py # CLI 入口,argparse 子命令
|
||||||
|
│ ├── proxy.py # 代理逻辑
|
||||||
|
│ ├── config.py # INI 配置管理
|
||||||
|
│ └── daemon.py # 跨平台后台运行管理
|
||||||
|
├── docs/
|
||||||
|
│ └── superpowers/specs/
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### pyproject.toml
|
||||||
|
|
||||||
|
- 零外部依赖
|
||||||
|
- Python >= 3.8
|
||||||
|
- 入口点:`jianda-proxy = "jianda_proxy.cli:main"`
|
||||||
|
- 构建后端:`hatchling`
|
||||||
|
|
||||||
|
## 打包与分发
|
||||||
|
|
||||||
|
- `uv tool install .`:本地安装
|
||||||
|
- `uvx jianda-proxy`:临时运行(需发布到 PyPI 后)
|
||||||
|
- `python -m jianda_proxy`:作为模块运行
|
||||||
|
|
||||||
|
## 配置管理
|
||||||
|
|
||||||
|
### 配置文件位置
|
||||||
|
|
||||||
|
- Mac/Linux:`~/.config/jianda-proxy/config.ini`
|
||||||
|
- Windows:`%APPDATA%\jianda-proxy\config.ini`
|
||||||
|
|
||||||
|
通过 `os.path.expanduser` 和 `os.environ` 手动拼路径,不引入 `platformdirs`。
|
||||||
|
|
||||||
|
### 配置格式
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[proxy]
|
||||||
|
remote_domain = git.zz.com
|
||||||
|
upstream_host = 62.234.191.215
|
||||||
|
upstream_port = 3000
|
||||||
|
listen_port = 13000
|
||||||
|
listen_host = 127.0.0.1
|
||||||
|
```
|
||||||
|
|
||||||
|
### config 子命令
|
||||||
|
|
||||||
|
| 命令 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `config set <key> <value>` | 设置配置项 |
|
||||||
|
| `config get <key>` | 查看单个配置项 |
|
||||||
|
| `config list` | 列出所有配置 |
|
||||||
|
| `config path` | 显示配置文件路径 |
|
||||||
|
|
||||||
|
首次使用 `start` 时,如果配置文件不存在,用默认值自动创建。
|
||||||
|
|
||||||
|
## CLI 命令
|
||||||
|
|
||||||
|
```
|
||||||
|
jianda-proxy start [--port PORT] [--foreground]
|
||||||
|
jianda-proxy stop
|
||||||
|
jianda-proxy status
|
||||||
|
jianda-proxy config set <key> <value>
|
||||||
|
jianda-proxy config get <key>
|
||||||
|
jianda-proxy config list
|
||||||
|
jianda-proxy config path
|
||||||
|
```
|
||||||
|
|
||||||
|
`start --foreground`:前台运行,日志直接输出到终端,方便调试。
|
||||||
|
|
||||||
|
## 后台运行与生命周期
|
||||||
|
|
||||||
|
### start
|
||||||
|
|
||||||
|
1. 检查端口是否可用
|
||||||
|
2. 检查是否已有进程运行(PID 文件存在且进程存活)
|
||||||
|
3. 如果已有进程:提示错误并退出
|
||||||
|
4. 如果 PID 文件存在但进程已死:清理后继续
|
||||||
|
5. Unix:`os.fork()` 后父进程退出
|
||||||
|
6. Windows:`subprocess.Popen` with `CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS`
|
||||||
|
7. 写 PID 文件
|
||||||
|
8. 日志写到 `~/.config/jianda-proxy/proxy.log`(RotatingFileHandler,5MB,3 个备份)
|
||||||
|
|
||||||
|
### stop
|
||||||
|
|
||||||
|
1. 读取 PID 文件
|
||||||
|
2. 检查进程是否存在
|
||||||
|
3. 发送 SIGTERM(Unix)/ taskkill(Windows)
|
||||||
|
4. 等待最多 3 秒
|
||||||
|
5. 如果还活着:SIGKILL / 强制终止
|
||||||
|
6. 删除 PID 文件
|
||||||
|
|
||||||
|
### status
|
||||||
|
|
||||||
|
1. 读取 PID 文件
|
||||||
|
2. 检查进程是否存在
|
||||||
|
3. 显示:运行状态、PID、端口、运行时间
|
||||||
|
|
||||||
|
### PID 文件
|
||||||
|
|
||||||
|
位置:和配置文件同目录 `~/.config/jianda-proxy/daemon.pid`。
|
||||||
|
|
||||||
|
## 跨平台细节
|
||||||
|
|
||||||
|
| 操作 | Unix | Windows |
|
||||||
|
|------|------|---------|
|
||||||
|
| 后台启动 | `os.fork()` | `subprocess.Popen` + detached flags |
|
||||||
|
| 进程检查 | `os.kill(pid, 0)` | `ctypes` 调用 `kernel32.OpenProcess` + `GetExitCodeProcess` |
|
||||||
|
| 优雅停止 | `SIGTERM` | `taskkill /PID` |
|
||||||
|
| 强制停止 | `SIGKILL` | `taskkill /F /PID` |
|
||||||
|
| 配置目录 | `~/.config/` | `%APPDATA%` |
|
||||||
|
|
||||||
|
## 错误处理
|
||||||
|
|
||||||
|
- 端口被占用:提示具体端口和可能原因
|
||||||
|
- 配置无效(IP 格式错误等):启动前验证
|
||||||
|
- 权限不足:提示需要的权限
|
||||||
|
- 后台进程异常退出:`status` 检测到后提示查看日志
|
||||||
|
|
||||||
|
## 模块职责
|
||||||
|
|
||||||
|
- **cli.py**:argparse 定义、子命令分发、入口函数
|
||||||
|
- **config.py**:读写配置文件、默认值管理、配置路径计算
|
||||||
|
- **proxy.py**:HTTP 代理服务器逻辑(从现有 `lfs-proxy.py` 提取)
|
||||||
|
- **daemon.py**:PID 文件管理、跨平台进程检查、进程终止
|
||||||
Reference in New Issue
Block a user