proxyctl 0.4.3__tar.gz → 0.4.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. proxyctl-0.4.4/PKG-INFO +337 -0
  2. proxyctl-0.4.4/README.md +308 -0
  3. {proxyctl-0.4.3 → proxyctl-0.4.4}/man/proxyctl.1 +1 -1
  4. {proxyctl-0.4.3 → proxyctl-0.4.4}/pyproject.toml +1 -1
  5. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/cli.py +1 -0
  6. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/status.py +30 -1
  7. proxyctl-0.4.4/src/proxyctl/subscription.py +190 -0
  8. proxyctl-0.4.3/PKG-INFO +0 -279
  9. proxyctl-0.4.3/README.md +0 -250
  10. {proxyctl-0.4.3 → proxyctl-0.4.4}/.gitignore +0 -0
  11. {proxyctl-0.4.3 → proxyctl-0.4.4}/LICENSE +0 -0
  12. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/__init__.py +0 -0
  13. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/_io.py +0 -0
  14. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/audit.py +0 -0
  15. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/builtin_plugins/__init__.py +0 -0
  16. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/builtin_plugins/connectivity_basic.py +0 -0
  17. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/builtin_plugins/corp_network.py +0 -0
  18. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/check.py +0 -0
  19. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/completion.py +0 -0
  20. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/core/__init__.py +0 -0
  21. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/core/plugin.py +0 -0
  22. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/engine/__init__.py +0 -0
  23. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/engine/base.py +0 -0
  24. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/engine/mihomo.py +0 -0
  25. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/engine/singbox.py +0 -0
  26. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/explain.py +0 -0
  27. {proxyctl-0.4.3 → proxyctl-0.4.4}/src/proxyctl/trace.py +0 -0
@@ -0,0 +1,337 @@
1
+ Metadata-Version: 2.4
2
+ Name: proxyctl
3
+ Version: 0.4.4
4
+ Summary: Proxy configuration lifecycle management for macOS and Linux
5
+ Project-URL: Homepage, https://github.com/crhan/proxyctl
6
+ Project-URL: Issues, https://github.com/crhan/proxyctl/issues
7
+ Project-URL: Changelog, https://github.com/crhan/proxyctl/blob/main/CHANGELOG.md
8
+ Project-URL: Repository, https://github.com/crhan/proxyctl
9
+ Author-email: crhan <crhan123@gmail.com>
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: clash,cli,lifecycle,mihomo,proxy,sing-box
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: System Administrators
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: System :: Networking
25
+ Classifier: Topic :: Utilities
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: pyyaml>=6.0
28
+ Description-Content-Type: text/markdown
29
+
30
+ # proxyctl
31
+
32
+ [![PyPI](https://img.shields.io/pypi/v/proxyctl.svg)](https://pypi.org/project/proxyctl/)
33
+ [![CI](https://github.com/crhan/proxyctl/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/crhan/proxyctl/actions/workflows/ci.yml)
34
+ [![Python](https://img.shields.io/pypi/pyversions/proxyctl.svg)](https://pypi.org/project/proxyctl/)
35
+ [![License](https://img.shields.io/pypi/l/proxyctl.svg)](https://github.com/crhan/proxyctl/blob/main/LICENSE)
36
+
37
+ **代理配置的生命周期管理 — 为 AI Agent 打造。**
38
+
39
+ macOS + Linux,单 CLI 托管 **mihomo** 代理内核的完整生命周期:
40
+ 启停 · 健康检查 · 链路诊断 · 日志驱动的配置审计 · 切网软恢复。
41
+ (sing-box 后端骨架已搭,未端到端验证 — 详见下方矩阵)
42
+ 所有命令支持 `--json` envelope、`--dry-run` 真 plan、语义化退出码、
43
+ 错误带可执行 hints —— **agent 可端到端编程**,不是给人看完再手工敲键盘。
44
+
45
+ ---
46
+
47
+ ## 30 秒:让 agent 用 proxyctl 接管你的代理
48
+
49
+ 复制这段 prompt,喂给 Claude / Cursor / 任何 LLM agent(要求它能跑 shell):
50
+
51
+ ```text
52
+ 帮我用 proxyctl 接管本机代理:
53
+ 1. 跑 `proxyctl agent-guide` 拿协议;扫现有系统代理 + 引擎配置
54
+ 2. 用 `--dry-run --json` 生成等价接管方案,先给我看 plan 再落地
55
+ 3. 跑 `proxyctl check --json` + `proxyctl audit 7 --json`,
56
+ 给我 3 条最值得动的优化(按收益/风险排序)
57
+ ```
58
+
59
+ agent 会:自描述协议 → 读取本机现状 → 用 dry-run 演示要做什么 →
60
+ 落地后审计日志找出"该走直连却在过代理"的域名、被错误代理的内网请求、
61
+ 被忽略的分流规则漏洞,最后给排好序的改进列表。
62
+
63
+ <details>
64
+ <summary><b>更详细的版本</b>(让 agent 把每一步讲透、出报告)</summary>
65
+
66
+ ```text
67
+ 帮我用 proxyctl 系统化接管本机代理。按这个流程:
68
+
69
+ 1. 自描述阶段
70
+ - 跑 `proxyctl agent-guide` 拿 envelope schema / 退出码 / 决策树
71
+ - 跑 `PROXYCTL_AGENT=1 proxyctl --version` 读 supported_features
72
+ - 一切后续命令带 `--json`,错误读 `hints[]` 路由下一步
73
+
74
+ 2. 现状普查
75
+ - `PROXYCTL_AGENT=1 proxyctl status`(拿引擎 + 系统代理 + DNS 一站式)
76
+ - `networksetup -getwebproxy` 等系统命令交叉印证
77
+ - 看 `~/.config/{mihomo,clash}/config.yaml`、`env | grep -i proxy`
78
+ - 用一段话告诉我:现在谁在代理我、怎么代理、为什么
79
+
80
+ 3. 接管方案
81
+ - 生成等价的 proxyctl 接管配置(含 backend / api / dns_lock 等)
82
+ - 跑 `proxyctl start --dry-run --json`(v0.4.2+ 真实化 plan,每步 argv 可读)
83
+ - 把 plan 列给我审,OK 后真落地
84
+
85
+ 4. 健康打底
86
+ - `proxyctl check --json` —— 任一 stage 失败时 envelope.hints
87
+ 已聚合真凶摘要(v0.4.3+),不必挖 stages.*.ok
88
+ - `proxyctl doctor --json` —— 5 项快速打分
89
+ - `proxyctl audit 7 --json` —— 扫近 7 天访问日志,找走代理但落地国内的域名
90
+
91
+ 5. 给我可执行的改进列表
92
+ - 最多 3 条,按 (收益 × 把握) / 风险 排序
93
+ - 每条给出:现状、建议改动、可复读的 proxyctl 命令、回滚方法
94
+ - 引用 `proxyctl explain <topic>` 让我能自查
95
+ ```
96
+
97
+ </details>
98
+
99
+ ---
100
+
101
+ ## For AI Agents — 凭什么 "for agent"
102
+
103
+ proxyctl 把 agent 友好度做成一等公民。完整接入协议见
104
+ [AGENTS.md](AGENTS.md)(仓库视角)与 `proxyctl agent-guide`(运行时视角)。
105
+
106
+ ```bash
107
+ proxyctl agent-guide # Agent 入门 markdown(注入当前路径/端口)
108
+ proxyctl agent-guide --list-sections # 15 个段,按需取小块(省 token)
109
+ proxyctl --version --json # schema_version + supported_features 探测
110
+ proxyctl commands --json # 全部命令元数据(机读)
111
+ proxyctl commands --schema # 上面 JSON 的 JSON Schema
112
+ proxyctl explain # "我想改 X 去哪?" 速查
113
+ proxyctl doctor --json # 5 项健康打分 + healthy 布尔字段
114
+ PROXYCTL_AGENT=1 proxyctl <cmd> # 一键 --json + 关色 + 非交互
115
+ ```
116
+
117
+ **硬核能力**:
118
+
119
+ - **envelope schema v2**:`schema_version / cmd / ok / data / error / code / hints[] / warnings[] / doc / meta{ts,elapsed_ms,proxyctl_version,request_id}` ——
120
+ 失败时 `hints[]` 聚合真凶摘要(v0.4.3+),不必挖 stages.*.ok
121
+ - **退出码分语义**:`0 OK / 2 USAGE / 3 NOT_FOUND / 4 PERMISSION / 5 ENGINE_DOWN / 6 CONFIG_ERR / 7 NETWORK_ERR / 8 LOCKED / 9 TIMEOUT / 10 DEPENDENCY_MISSING`
122
+ - **`--dry-run` 真 plan**:写命令输出 `data.plan = [PlanStep, ...]`,
123
+ 自 0.4.0 起 `plan.target` 全部真实化(`subprocess` action 的 target.split()
124
+ 可直接当 argv 复读),自 0.4.2 起 `start / stop / restart / restart-clean / recover`
125
+ 也加入 `--dry-run` 行列。PlanStep.action 枚举:
126
+ `subprocess / system_op / fs_write / fs_copy / fs_write_atomic / fs_remove / edit_yaml / scan_log / http_put`
127
+ - **CI 层 contract test**(`tests/integration/test_plan_exec_contract.py`)
128
+ 保证 plan ↔ exec **永不漂移**
129
+ - **错误带可执行 hints + explain topic**:agent 可路由下一步而不需要规则匹配
130
+ - **`audit/check` 支持 `--plain` TSV**:4 行 stage/ok/detail,agent 友好的备选
131
+ - **`proxyctl help <cmd>` 与 `<cmd> --help` 同源**
132
+ - **非 TTY 自动关色 / 不读 stdin / 不 prompt / 写操作 fcntl.flock 互斥**
133
+
134
+ 示例:dry-run 拿 argv:
135
+
136
+ ```bash
137
+ proxyctl stop --dry-run --json | jq -r '.data.plan[] | select(.action=="subprocess").target'
138
+ # macOS → launchctl bootout system/com.proxyctl.dns-lock
139
+ # → launchctl bootout system/com.mihomo.tun
140
+ # Linux → systemctl --user stop mihomo.service
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 核心能力(按使用频次)
146
+
147
+ ### `status` —— 一站式系统面板
148
+ ```bash
149
+ proxyctl status # 引擎 / 端口 / TUN / DNS / 系统代理 / 网络环境
150
+ proxyctl status --json # 同上,envelope 输出
151
+ ```
152
+ 插件扩展点(StatusSection)可加企业 VPN / Tailscale / TUIC relay 等业务面板。
153
+
154
+ ### `check` —— 4 阶段健康检查
155
+ ```bash
156
+ proxyctl check # 基础 → 代理组 → 连通性 → 出口 IP
157
+ proxyctl check --json # 失败时 hints[] 聚合真凶摘要
158
+ proxyctl check --plain # 4 行 TSV
159
+ ```
160
+
161
+ ### `trace` —— 域名链路诊断
162
+ ```bash
163
+ proxyctl trace github.com # DNS / 规则匹配 / 连通性 / 实际连接
164
+ proxyctl trace github.com --json
165
+ ```
166
+
167
+ ### `audit` —— 日志驱动的配置优化
168
+ ```bash
169
+ proxyctl audit 7 # 扫最近 7 天日志,找"走代理但落地国内"的域名
170
+ proxyctl audit apply --dry-run # 生成 rules 补丁 plan,审阅后再 apply
171
+ ```
172
+
173
+ ### `bench` —— 节点测速(NDJSON 流式 + summary envelope)
174
+ ```bash
175
+ proxyctl bench # 测全部 URLTest / Fallback / LoadBalance 组
176
+ proxyctl bench proxy claude # 测指定组
177
+ ```
178
+
179
+ ### `recover` —— 切网后软恢复
180
+ ```bash
181
+ proxyctl recover # 不重启引擎,热重载 + 清 fakeip + 刷代理组延迟
182
+ proxyctl recover --dry-run # 看 3 个 Clash API endpoint 再决定
183
+ ```
184
+
185
+ ---
186
+
187
+ ## 安装
188
+
189
+ ### 方式 1:PyPI(推荐)
190
+
191
+ ```bash
192
+ uv tool install proxyctl # uv(推荐)
193
+ pipx install proxyctl # 或 pipx
194
+ pip install --user proxyctl # 或 pip
195
+
196
+ proxyctl --version # → proxyctl v0.4.3
197
+ proxyctl --help
198
+ ```
199
+
200
+ ### 方式 2:后端引擎
201
+
202
+ ```bash
203
+ brew install mihomo # 首发后端,macOS / Linux 都通
204
+ # Linux 也可用各发行版包管理器(apt / dnf / pacman)
205
+ # sing-box 后端见末尾"平台支持矩阵",目前未端到端验证
206
+ ```
207
+
208
+ ### 方式 3:配置 API
209
+
210
+ ```bash
211
+ mkdir -p ~/.config/proxyctl
212
+ curl -fsSL https://raw.githubusercontent.com/crhan/proxyctl/main/config.yaml.example \
213
+ -o ~/.config/proxyctl/config.yaml
214
+ # 编辑 ~/.config/proxyctl/config.yaml,填 api_secret 等
215
+ ```
216
+
217
+ ### 方式 4:系统服务托管(可选)
218
+
219
+ 需要把 mihomo(或预留中的 sing-box)作为系统服务托管(开机自启 + 守护进程重启):
220
+
221
+ ```bash
222
+ git clone https://github.com/crhan/proxyctl.git
223
+ cd proxyctl
224
+ ./install.sh # 自动识别 macOS(LaunchDaemon)/ Linux(systemd user unit)
225
+ ```
226
+
227
+ > 只想跑 `proxyctl status / check / trace` 等只读命令的话,**不必跑 install.sh**。
228
+
229
+ ---
230
+
231
+ ## 配置示例
232
+
233
+ ```yaml
234
+ # ~/.config/proxyctl/config.yaml
235
+
236
+ backend: mihomo # mihomo (默认) | singbox(预留,未端到端验证)
237
+
238
+ api_base: http://127.0.0.1:9090 # Clash API
239
+ api_secret: your-clash-api-secret
240
+
241
+ config_dir: /Users/yourname/.config
242
+
243
+ dns_lock_label: com.proxyctl.dns-lock # DNS 看门狗 launchd label
244
+
245
+ proxy_port: 7890 # 自 0.1.4 起可配
246
+ no_proxy_extra: # 自 0.1.5 起追加 NO_PROXY
247
+ - "*.internal.example.com"
248
+ - 10.0.0.0/8
249
+ ```
250
+
251
+ 完整字段见 [config.yaml.example](config.yaml.example)。
252
+
253
+ ---
254
+
255
+ ## 命令速查
256
+
257
+ | 命令 | 功能 | dry-run | json |
258
+ |---|---|:---:|:---:|
259
+ | `start / stop / restart / restart-clean` | 启停引擎 + DNS/代理注入 | ✅ | ✅ |
260
+ | `status` | 一站式系统面板 | — | ✅ |
261
+ | `check` | 4 阶段健康检查 | — | ✅ |
262
+ | `doctor` | 5 项健康打分 | — | ✅ |
263
+ | `trace <domain>` | 域名链路诊断 | — | ✅ |
264
+ | `audit [days] [apply]` | 日志驱动配置优化 | ✅ | ✅ |
265
+ | `bench [groups]` | 节点测速 (NDJSON) | — | ✅ |
266
+ | `fix` | 修复 DNS / 代理 / 热重载 | ✅ | ✅ |
267
+ | `recover` | 切网后软恢复 | ✅ | ✅ |
268
+ | `mode tun\|proxy` | 切换 TUN / 代理模式 | ✅ | ✅ |
269
+ | `dns-lock / dns-unlock` | 启停 DNS 看门狗 | ✅ | ✅ |
270
+ | `daemon` | 管理 extra_daemons | ✅ | ✅ |
271
+ | `agent-guide / commands / explain` | agent 自描述三件套 | — | ✅ |
272
+
273
+ ---
274
+
275
+ ## 平台支持矩阵(Mihomo 后端)
276
+
277
+ | 命令 | macOS | Linux |
278
+ |---|:---:|:---:|
279
+ | start / stop / restart / restart-clean | ✅ launchd | ✅ systemd user unit |
280
+ | status / check / doctor / trace / bench | ✅ | ✅ |
281
+ | audit (含 apply) | ✅ | ✅ |
282
+ | recover (切网软恢复) | ✅ | ✅ |
283
+ | mode tun \| proxy 切换 | ✅ | ✅ |
284
+ | dns-lock 看门狗 | ✅ | N/A* |
285
+
286
+ \* Linux 下系统 DNS 由 systemd-resolved / NetworkManager / resolvconf
287
+ 管理,机制差异大,看门狗目前 macOS-only。Linux 用户用引擎自身的 fakeip
288
+ 或 `nameserver-policy` 即可达成类似效果。
289
+
290
+ ### Sing-box 后端 — 预留 / 未端到端验证
291
+
292
+ `SingboxBackend`、launchd plist、systemd unit、`audit` 的
293
+ sing-box JSON config 解析、`trace` 的 sing-box 日志 grep、`engine` /
294
+ `mode` 切换命令都已实现,单测覆盖路径/配置/API URL 解析。**但没人在
295
+ 生产里跑过完整的 start → check → audit → recover 闭环**——
296
+ `config.yaml.example` 自己写着"首发支持 mihomo,singbox 后端预留中"。
297
+
298
+ 想用 sing-box 的话:基础启停 / status / audit 大概率能跑,
299
+ `bench` 和 `recover` 依赖 Clash API 兼容子集,行为可能不齐;遇到 bug
300
+ 欢迎提 issue 或 PR。
301
+
302
+ ---
303
+
304
+ ## 深入阅读
305
+
306
+ | 文档 | 受众 / 内容 |
307
+ |---|---|
308
+ | [ARCHITECTURE.md](ARCHITECTURE.md) | 架构哲学、DNS 三层防线、配置生命周期闭环、后端抽象 |
309
+ | [AGENTS.md](AGENTS.md) | 仓库内 coding agent 工作协议(贡献者向) |
310
+ | `proxyctl agent-guide` | 运行时 agent 入门 markdown(动态注入当前路径/端口) |
311
+ | [MIGRATION-0.3.md](MIGRATION-0.3.md) | 0.2.x → 0.3.x envelope schema v2 迁移 |
312
+ | [CHANGELOG.md](CHANGELOG.md) | 版本历史 |
313
+
314
+ ---
315
+
316
+ ## 开发
317
+
318
+ ```bash
319
+ git clone https://github.com/crhan/proxyctl.git
320
+ cd proxyctl
321
+ uv sync --group dev # 装运行 + 测试依赖
322
+ uv run pytest # 跑 523 个测试
323
+ uv run proxyctl status # 用本地源码版本
324
+
325
+ export PROXYCTL_DEBUG=1 # 调试模式
326
+ ```
327
+
328
+ ---
329
+
330
+ ## License
331
+
332
+ MIT — 见 [LICENSE](LICENSE)。
333
+
334
+ ## 致谢
335
+
336
+ - [Mihomo](https://github.com/MetaCubeX/mihomo) —— Clash Meta 内核
337
+ - [Sing-box](https://github.com/SagerNet/sing-box) —— 下一代代理内核
@@ -0,0 +1,308 @@
1
+ # proxyctl
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/proxyctl.svg)](https://pypi.org/project/proxyctl/)
4
+ [![CI](https://github.com/crhan/proxyctl/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/crhan/proxyctl/actions/workflows/ci.yml)
5
+ [![Python](https://img.shields.io/pypi/pyversions/proxyctl.svg)](https://pypi.org/project/proxyctl/)
6
+ [![License](https://img.shields.io/pypi/l/proxyctl.svg)](https://github.com/crhan/proxyctl/blob/main/LICENSE)
7
+
8
+ **代理配置的生命周期管理 — 为 AI Agent 打造。**
9
+
10
+ macOS + Linux,单 CLI 托管 **mihomo** 代理内核的完整生命周期:
11
+ 启停 · 健康检查 · 链路诊断 · 日志驱动的配置审计 · 切网软恢复。
12
+ (sing-box 后端骨架已搭,未端到端验证 — 详见下方矩阵)
13
+ 所有命令支持 `--json` envelope、`--dry-run` 真 plan、语义化退出码、
14
+ 错误带可执行 hints —— **agent 可端到端编程**,不是给人看完再手工敲键盘。
15
+
16
+ ---
17
+
18
+ ## 30 秒:让 agent 用 proxyctl 接管你的代理
19
+
20
+ 复制这段 prompt,喂给 Claude / Cursor / 任何 LLM agent(要求它能跑 shell):
21
+
22
+ ```text
23
+ 帮我用 proxyctl 接管本机代理:
24
+ 1. 跑 `proxyctl agent-guide` 拿协议;扫现有系统代理 + 引擎配置
25
+ 2. 用 `--dry-run --json` 生成等价接管方案,先给我看 plan 再落地
26
+ 3. 跑 `proxyctl check --json` + `proxyctl audit 7 --json`,
27
+ 给我 3 条最值得动的优化(按收益/风险排序)
28
+ ```
29
+
30
+ agent 会:自描述协议 → 读取本机现状 → 用 dry-run 演示要做什么 →
31
+ 落地后审计日志找出"该走直连却在过代理"的域名、被错误代理的内网请求、
32
+ 被忽略的分流规则漏洞,最后给排好序的改进列表。
33
+
34
+ <details>
35
+ <summary><b>更详细的版本</b>(让 agent 把每一步讲透、出报告)</summary>
36
+
37
+ ```text
38
+ 帮我用 proxyctl 系统化接管本机代理。按这个流程:
39
+
40
+ 1. 自描述阶段
41
+ - 跑 `proxyctl agent-guide` 拿 envelope schema / 退出码 / 决策树
42
+ - 跑 `PROXYCTL_AGENT=1 proxyctl --version` 读 supported_features
43
+ - 一切后续命令带 `--json`,错误读 `hints[]` 路由下一步
44
+
45
+ 2. 现状普查
46
+ - `PROXYCTL_AGENT=1 proxyctl status`(拿引擎 + 系统代理 + DNS 一站式)
47
+ - `networksetup -getwebproxy` 等系统命令交叉印证
48
+ - 看 `~/.config/{mihomo,clash}/config.yaml`、`env | grep -i proxy`
49
+ - 用一段话告诉我:现在谁在代理我、怎么代理、为什么
50
+
51
+ 3. 接管方案
52
+ - 生成等价的 proxyctl 接管配置(含 backend / api / dns_lock 等)
53
+ - 跑 `proxyctl start --dry-run --json`(v0.4.2+ 真实化 plan,每步 argv 可读)
54
+ - 把 plan 列给我审,OK 后真落地
55
+
56
+ 4. 健康打底
57
+ - `proxyctl check --json` —— 任一 stage 失败时 envelope.hints
58
+ 已聚合真凶摘要(v0.4.3+),不必挖 stages.*.ok
59
+ - `proxyctl doctor --json` —— 5 项快速打分
60
+ - `proxyctl audit 7 --json` —— 扫近 7 天访问日志,找走代理但落地国内的域名
61
+
62
+ 5. 给我可执行的改进列表
63
+ - 最多 3 条,按 (收益 × 把握) / 风险 排序
64
+ - 每条给出:现状、建议改动、可复读的 proxyctl 命令、回滚方法
65
+ - 引用 `proxyctl explain <topic>` 让我能自查
66
+ ```
67
+
68
+ </details>
69
+
70
+ ---
71
+
72
+ ## For AI Agents — 凭什么 "for agent"
73
+
74
+ proxyctl 把 agent 友好度做成一等公民。完整接入协议见
75
+ [AGENTS.md](AGENTS.md)(仓库视角)与 `proxyctl agent-guide`(运行时视角)。
76
+
77
+ ```bash
78
+ proxyctl agent-guide # Agent 入门 markdown(注入当前路径/端口)
79
+ proxyctl agent-guide --list-sections # 15 个段,按需取小块(省 token)
80
+ proxyctl --version --json # schema_version + supported_features 探测
81
+ proxyctl commands --json # 全部命令元数据(机读)
82
+ proxyctl commands --schema # 上面 JSON 的 JSON Schema
83
+ proxyctl explain # "我想改 X 去哪?" 速查
84
+ proxyctl doctor --json # 5 项健康打分 + healthy 布尔字段
85
+ PROXYCTL_AGENT=1 proxyctl <cmd> # 一键 --json + 关色 + 非交互
86
+ ```
87
+
88
+ **硬核能力**:
89
+
90
+ - **envelope schema v2**:`schema_version / cmd / ok / data / error / code / hints[] / warnings[] / doc / meta{ts,elapsed_ms,proxyctl_version,request_id}` ——
91
+ 失败时 `hints[]` 聚合真凶摘要(v0.4.3+),不必挖 stages.*.ok
92
+ - **退出码分语义**:`0 OK / 2 USAGE / 3 NOT_FOUND / 4 PERMISSION / 5 ENGINE_DOWN / 6 CONFIG_ERR / 7 NETWORK_ERR / 8 LOCKED / 9 TIMEOUT / 10 DEPENDENCY_MISSING`
93
+ - **`--dry-run` 真 plan**:写命令输出 `data.plan = [PlanStep, ...]`,
94
+ 自 0.4.0 起 `plan.target` 全部真实化(`subprocess` action 的 target.split()
95
+ 可直接当 argv 复读),自 0.4.2 起 `start / stop / restart / restart-clean / recover`
96
+ 也加入 `--dry-run` 行列。PlanStep.action 枚举:
97
+ `subprocess / system_op / fs_write / fs_copy / fs_write_atomic / fs_remove / edit_yaml / scan_log / http_put`
98
+ - **CI 层 contract test**(`tests/integration/test_plan_exec_contract.py`)
99
+ 保证 plan ↔ exec **永不漂移**
100
+ - **错误带可执行 hints + explain topic**:agent 可路由下一步而不需要规则匹配
101
+ - **`audit/check` 支持 `--plain` TSV**:4 行 stage/ok/detail,agent 友好的备选
102
+ - **`proxyctl help <cmd>` 与 `<cmd> --help` 同源**
103
+ - **非 TTY 自动关色 / 不读 stdin / 不 prompt / 写操作 fcntl.flock 互斥**
104
+
105
+ 示例:dry-run 拿 argv:
106
+
107
+ ```bash
108
+ proxyctl stop --dry-run --json | jq -r '.data.plan[] | select(.action=="subprocess").target'
109
+ # macOS → launchctl bootout system/com.proxyctl.dns-lock
110
+ # → launchctl bootout system/com.mihomo.tun
111
+ # Linux → systemctl --user stop mihomo.service
112
+ ```
113
+
114
+ ---
115
+
116
+ ## 核心能力(按使用频次)
117
+
118
+ ### `status` —— 一站式系统面板
119
+ ```bash
120
+ proxyctl status # 引擎 / 端口 / TUN / DNS / 系统代理 / 网络环境
121
+ proxyctl status --json # 同上,envelope 输出
122
+ ```
123
+ 插件扩展点(StatusSection)可加企业 VPN / Tailscale / TUIC relay 等业务面板。
124
+
125
+ ### `check` —— 4 阶段健康检查
126
+ ```bash
127
+ proxyctl check # 基础 → 代理组 → 连通性 → 出口 IP
128
+ proxyctl check --json # 失败时 hints[] 聚合真凶摘要
129
+ proxyctl check --plain # 4 行 TSV
130
+ ```
131
+
132
+ ### `trace` —— 域名链路诊断
133
+ ```bash
134
+ proxyctl trace github.com # DNS / 规则匹配 / 连通性 / 实际连接
135
+ proxyctl trace github.com --json
136
+ ```
137
+
138
+ ### `audit` —— 日志驱动的配置优化
139
+ ```bash
140
+ proxyctl audit 7 # 扫最近 7 天日志,找"走代理但落地国内"的域名
141
+ proxyctl audit apply --dry-run # 生成 rules 补丁 plan,审阅后再 apply
142
+ ```
143
+
144
+ ### `bench` —— 节点测速(NDJSON 流式 + summary envelope)
145
+ ```bash
146
+ proxyctl bench # 测全部 URLTest / Fallback / LoadBalance 组
147
+ proxyctl bench proxy claude # 测指定组
148
+ ```
149
+
150
+ ### `recover` —— 切网后软恢复
151
+ ```bash
152
+ proxyctl recover # 不重启引擎,热重载 + 清 fakeip + 刷代理组延迟
153
+ proxyctl recover --dry-run # 看 3 个 Clash API endpoint 再决定
154
+ ```
155
+
156
+ ---
157
+
158
+ ## 安装
159
+
160
+ ### 方式 1:PyPI(推荐)
161
+
162
+ ```bash
163
+ uv tool install proxyctl # uv(推荐)
164
+ pipx install proxyctl # 或 pipx
165
+ pip install --user proxyctl # 或 pip
166
+
167
+ proxyctl --version # → proxyctl v0.4.3
168
+ proxyctl --help
169
+ ```
170
+
171
+ ### 方式 2:后端引擎
172
+
173
+ ```bash
174
+ brew install mihomo # 首发后端,macOS / Linux 都通
175
+ # Linux 也可用各发行版包管理器(apt / dnf / pacman)
176
+ # sing-box 后端见末尾"平台支持矩阵",目前未端到端验证
177
+ ```
178
+
179
+ ### 方式 3:配置 API
180
+
181
+ ```bash
182
+ mkdir -p ~/.config/proxyctl
183
+ curl -fsSL https://raw.githubusercontent.com/crhan/proxyctl/main/config.yaml.example \
184
+ -o ~/.config/proxyctl/config.yaml
185
+ # 编辑 ~/.config/proxyctl/config.yaml,填 api_secret 等
186
+ ```
187
+
188
+ ### 方式 4:系统服务托管(可选)
189
+
190
+ 需要把 mihomo(或预留中的 sing-box)作为系统服务托管(开机自启 + 守护进程重启):
191
+
192
+ ```bash
193
+ git clone https://github.com/crhan/proxyctl.git
194
+ cd proxyctl
195
+ ./install.sh # 自动识别 macOS(LaunchDaemon)/ Linux(systemd user unit)
196
+ ```
197
+
198
+ > 只想跑 `proxyctl status / check / trace` 等只读命令的话,**不必跑 install.sh**。
199
+
200
+ ---
201
+
202
+ ## 配置示例
203
+
204
+ ```yaml
205
+ # ~/.config/proxyctl/config.yaml
206
+
207
+ backend: mihomo # mihomo (默认) | singbox(预留,未端到端验证)
208
+
209
+ api_base: http://127.0.0.1:9090 # Clash API
210
+ api_secret: your-clash-api-secret
211
+
212
+ config_dir: /Users/yourname/.config
213
+
214
+ dns_lock_label: com.proxyctl.dns-lock # DNS 看门狗 launchd label
215
+
216
+ proxy_port: 7890 # 自 0.1.4 起可配
217
+ no_proxy_extra: # 自 0.1.5 起追加 NO_PROXY
218
+ - "*.internal.example.com"
219
+ - 10.0.0.0/8
220
+ ```
221
+
222
+ 完整字段见 [config.yaml.example](config.yaml.example)。
223
+
224
+ ---
225
+
226
+ ## 命令速查
227
+
228
+ | 命令 | 功能 | dry-run | json |
229
+ |---|---|:---:|:---:|
230
+ | `start / stop / restart / restart-clean` | 启停引擎 + DNS/代理注入 | ✅ | ✅ |
231
+ | `status` | 一站式系统面板 | — | ✅ |
232
+ | `check` | 4 阶段健康检查 | — | ✅ |
233
+ | `doctor` | 5 项健康打分 | — | ✅ |
234
+ | `trace <domain>` | 域名链路诊断 | — | ✅ |
235
+ | `audit [days] [apply]` | 日志驱动配置优化 | ✅ | ✅ |
236
+ | `bench [groups]` | 节点测速 (NDJSON) | — | ✅ |
237
+ | `fix` | 修复 DNS / 代理 / 热重载 | ✅ | ✅ |
238
+ | `recover` | 切网后软恢复 | ✅ | ✅ |
239
+ | `mode tun\|proxy` | 切换 TUN / 代理模式 | ✅ | ✅ |
240
+ | `dns-lock / dns-unlock` | 启停 DNS 看门狗 | ✅ | ✅ |
241
+ | `daemon` | 管理 extra_daemons | ✅ | ✅ |
242
+ | `agent-guide / commands / explain` | agent 自描述三件套 | — | ✅ |
243
+
244
+ ---
245
+
246
+ ## 平台支持矩阵(Mihomo 后端)
247
+
248
+ | 命令 | macOS | Linux |
249
+ |---|:---:|:---:|
250
+ | start / stop / restart / restart-clean | ✅ launchd | ✅ systemd user unit |
251
+ | status / check / doctor / trace / bench | ✅ | ✅ |
252
+ | audit (含 apply) | ✅ | ✅ |
253
+ | recover (切网软恢复) | ✅ | ✅ |
254
+ | mode tun \| proxy 切换 | ✅ | ✅ |
255
+ | dns-lock 看门狗 | ✅ | N/A* |
256
+
257
+ \* Linux 下系统 DNS 由 systemd-resolved / NetworkManager / resolvconf
258
+ 管理,机制差异大,看门狗目前 macOS-only。Linux 用户用引擎自身的 fakeip
259
+ 或 `nameserver-policy` 即可达成类似效果。
260
+
261
+ ### Sing-box 后端 — 预留 / 未端到端验证
262
+
263
+ `SingboxBackend`、launchd plist、systemd unit、`audit` 的
264
+ sing-box JSON config 解析、`trace` 的 sing-box 日志 grep、`engine` /
265
+ `mode` 切换命令都已实现,单测覆盖路径/配置/API URL 解析。**但没人在
266
+ 生产里跑过完整的 start → check → audit → recover 闭环**——
267
+ `config.yaml.example` 自己写着"首发支持 mihomo,singbox 后端预留中"。
268
+
269
+ 想用 sing-box 的话:基础启停 / status / audit 大概率能跑,
270
+ `bench` 和 `recover` 依赖 Clash API 兼容子集,行为可能不齐;遇到 bug
271
+ 欢迎提 issue 或 PR。
272
+
273
+ ---
274
+
275
+ ## 深入阅读
276
+
277
+ | 文档 | 受众 / 内容 |
278
+ |---|---|
279
+ | [ARCHITECTURE.md](ARCHITECTURE.md) | 架构哲学、DNS 三层防线、配置生命周期闭环、后端抽象 |
280
+ | [AGENTS.md](AGENTS.md) | 仓库内 coding agent 工作协议(贡献者向) |
281
+ | `proxyctl agent-guide` | 运行时 agent 入门 markdown(动态注入当前路径/端口) |
282
+ | [MIGRATION-0.3.md](MIGRATION-0.3.md) | 0.2.x → 0.3.x envelope schema v2 迁移 |
283
+ | [CHANGELOG.md](CHANGELOG.md) | 版本历史 |
284
+
285
+ ---
286
+
287
+ ## 开发
288
+
289
+ ```bash
290
+ git clone https://github.com/crhan/proxyctl.git
291
+ cd proxyctl
292
+ uv sync --group dev # 装运行 + 测试依赖
293
+ uv run pytest # 跑 523 个测试
294
+ uv run proxyctl status # 用本地源码版本
295
+
296
+ export PROXYCTL_DEBUG=1 # 调试模式
297
+ ```
298
+
299
+ ---
300
+
301
+ ## License
302
+
303
+ MIT — 见 [LICENSE](LICENSE)。
304
+
305
+ ## 致谢
306
+
307
+ - [Mihomo](https://github.com/MetaCubeX/mihomo) —— Clash Meta 内核
308
+ - [Sing-box](https://github.com/SagerNet/sing-box) —— 下一代代理内核
@@ -1,4 +1,4 @@
1
- .TH PROXYCTL 1 "2026-05" "proxyctl 0.4.3" "User Commands"
1
+ .TH PROXYCTL 1 "2026-05" "proxyctl 0.4.4" "User Commands"
2
2
  .SH NAME
3
3
  proxyctl \- Proxy configuration lifecycle management for macOS / Linux
4
4
  .SH SYNOPSIS
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "proxyctl"
3
- version = "0.4.3"
3
+ version = "0.4.4"
4
4
  description = "Proxy configuration lifecycle management for macOS and Linux"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -1583,6 +1583,7 @@ def cmd_version_print() -> None:
1583
1583
  "log_ndjson_v2": True,
1584
1584
  "lifecycle_dry_run": True, # 0.4.2: start/stop/restart/recover --dry-run
1585
1585
  "version_subcommand": True, # 0.4.2: `proxyctl version` 子命令
1586
+ "status_subscription": True, # 0.4.4: status envelope.data.subscription
1586
1587
  },
1587
1588
  }
1588
1589
  _io.emit_json(_io.envelope("version", data=data))