proxyctl 0.4.4__tar.gz → 0.4.5__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 (25) hide show
  1. {proxyctl-0.4.4 → proxyctl-0.4.5}/PKG-INFO +1 -1
  2. {proxyctl-0.4.4 → proxyctl-0.4.5}/man/proxyctl.1 +1 -1
  3. {proxyctl-0.4.4 → proxyctl-0.4.5}/pyproject.toml +1 -1
  4. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/explain.py +95 -23
  5. {proxyctl-0.4.4 → proxyctl-0.4.5}/.gitignore +0 -0
  6. {proxyctl-0.4.4 → proxyctl-0.4.5}/LICENSE +0 -0
  7. {proxyctl-0.4.4 → proxyctl-0.4.5}/README.md +0 -0
  8. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/__init__.py +0 -0
  9. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/_io.py +0 -0
  10. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/audit.py +0 -0
  11. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/builtin_plugins/__init__.py +0 -0
  12. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/builtin_plugins/connectivity_basic.py +0 -0
  13. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/builtin_plugins/corp_network.py +0 -0
  14. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/check.py +0 -0
  15. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/cli.py +0 -0
  16. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/completion.py +0 -0
  17. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/core/__init__.py +0 -0
  18. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/core/plugin.py +0 -0
  19. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/engine/__init__.py +0 -0
  20. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/engine/base.py +0 -0
  21. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/engine/mihomo.py +0 -0
  22. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/engine/singbox.py +0 -0
  23. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/status.py +0 -0
  24. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/subscription.py +0 -0
  25. {proxyctl-0.4.4 → proxyctl-0.4.5}/src/proxyctl/trace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: proxyctl
3
- Version: 0.4.4
3
+ Version: 0.4.5
4
4
  Summary: Proxy configuration lifecycle management for macOS and Linux
5
5
  Project-URL: Homepage, https://github.com/crhan/proxyctl
6
6
  Project-URL: Issues, https://github.com/crhan/proxyctl/issues
@@ -1,4 +1,4 @@
1
- .TH PROXYCTL 1 "2026-05" "proxyctl 0.4.4" "User Commands"
1
+ .TH PROXYCTL 1 "2026-05" "proxyctl 0.4.5" "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.4"
3
+ version = "0.4.5"
4
4
  description = "Proxy configuration lifecycle management for macOS and Linux"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -74,15 +74,16 @@ def _t_rules(backend, config) -> TopicCard:
74
74
  def _t_nodes(backend, config) -> TopicCard:
75
75
  return {
76
76
  "topic": "nodes",
77
- "summary": "代理节点(线路)— 出口节点和分组定义;订阅由 mihomo/sing-box 自身管理。",
77
+ "summary": "代理节点(线路)— 出口节点和分组定义;订阅由 mihomo/sing-box 或用户脚本管理(详见 explain subscription)。",
78
78
  "file": f"{backend.config_file} [proxies: / proxy-providers: / proxy-groups: 段]",
79
79
  "edit": (
80
80
  " # 添加单个节点:在 proxies: 段加 entry,再加到 proxy-groups: 的某个组\n"
81
- " # 订阅源:用 mihomo 自身的 proxy-providers: + url + path + interval\n"
82
- " # proxyctl 不管订阅更新;用 mihomo 的 'proxy-providers' 热更新机制"
81
+ " # 订阅源:用 mihomo 自身的 proxy-providers: + url + path + interval;\n"
82
+ " # 或用户脚本拉订阅写 config + ~/.config/proxyctl/subscription.json(v0.4.4+)\n"
83
+ " # proxyctl 不发起订阅拉取;但显示订阅状态(见 explain subscription)"
83
84
  ),
84
85
  "verify": "proxyctl bench <group> # 测节点延迟",
85
- "next_commands": ["bench", "explain engine"],
86
+ "next_commands": ["bench", "explain subscription", "explain engine"],
86
87
  }
87
88
 
88
89
 
@@ -281,26 +282,51 @@ def _t_subscription(backend, config) -> TopicCard:
281
282
  return {
282
283
  "topic": "subscription",
283
284
  "summary": (
284
- "节点订阅更新边界:proxyctl 不更新订阅。"
285
- "订阅由 mihomo / sing-box 自身的 proxy-providers 管,"
286
- "或用户用 Clash API 主动 PUT 触发。"
285
+ "订阅边界(双重立场):"
286
+ "(1) proxyctl 不更新订阅 拉新节点由用户脚本或引擎自身的 proxy-providers 负责。"
287
+ "(2) v0.4.4 proxyctl 显示订阅状态(到期日 / 已用流量 / 拉取健康度)— "
288
+ "通过读取 ~/.config/proxyctl/subscription.json 契约文件,"
289
+ "由用户脚本每次拉订阅后写入。proxyctl 自身不发起任何网络请求。"
290
+ ),
291
+ "file": (
292
+ f"{backend.config_file} [节点 / 订阅源仍由用户管]\n"
293
+ f"~/.config/proxyctl/subscription.json [订阅状态契约文件,proxyctl 读、用户脚本写]"
287
294
  ),
288
- "file": f"{backend.config_file} [proxy-providers: 段]",
289
295
  "edit": (
290
- " # mihomo / sing-box 内置:\n"
296
+ " # === 拉订阅 / 加节点(proxyctl 不做)===\n"
297
+ " # 选项 A: 写用户脚本 cron 拉订阅,参考仓库 update-subscription.sh\n"
298
+ " # 选项 B: 用 mihomo / sing-box 内置 proxy-providers:\n"
291
299
  " # proxy-providers:\n"
292
300
  " # myprovider:\n"
293
301
  " # type: http\n"
294
302
  " # url: https://...\n"
295
- " # interval: 86400 # 自动每 24h 更新\n"
303
+ " # interval: 86400\n"
304
+ " # 选项 C: 手动 Clash API PUT 触发刷新:\n"
305
+ " # curl -X PUT -H 'Authorization: Bearer <api_secret>' \\\n"
306
+ " # http://127.0.0.1:9090/providers/proxies/myprovider\n"
296
307
  " #\n"
297
- " # 手动触发:\n"
298
- " # curl -X PUT \\\n"
299
- " # -H 'Authorization: Bearer <api_secret>' \\\n"
300
- " # http://127.0.0.1:9090/providers/proxies/myprovider"
308
+ " # === 让 proxyctl 显示订阅状态(v0.4.4+)===\n"
309
+ " # 用户脚本拉完订阅后写入契约文件:\n"
310
+ " # ~/.config/proxyctl/subscription.json (schema v1)\n"
311
+ " # 关键字段 (全部可选,缺失 → None):\n"
312
+ " # fetch_ok / fetch_http_status / fetch_error\n"
313
+ " # expire_at / expire_days_left\n"
314
+ " # traffic_used_bytes / traffic_total_bytes / traffic_used_pct\n"
315
+ " # info_nodes / node_count\n"
316
+ " # 详细 schema 见 proxyctl.subscription 模块 docstring。\n"
317
+ " # 失败时也要写(fetch_ok=false + fetch_error),让 proxyctl 能区分\n"
318
+ " # 「过期」vs「网络挂」vs「订阅服务方挂」。"
319
+ ),
320
+ "verify": (
321
+ "proxyctl status # 末尾 SUBSCRIPTION 段显示\n"
322
+ "proxyctl status --json | jq .data.subscription # agent 消费"
301
323
  ),
302
- "verify": "proxyctl bench # 看新节点是否参与测速",
303
- "next_commands": ["bench", "explain nodes", "log --tail 50 --no-follow"],
324
+ "next_commands": [
325
+ "status",
326
+ "status --json | jq .data.subscription",
327
+ "bench",
328
+ "explain nodes",
329
+ ],
304
330
  }
305
331
 
306
332
 
@@ -644,9 +670,11 @@ def _build_agent_guide(backend, config) -> str:
644
670
  lock_dir = os.path.join(os.path.expanduser("~"), ".config", "proxyctl")
645
671
  return f"""# proxyctl — Agent 接入指南(runtime / v0.3)
646
672
 
647
- > 一句话:proxyctl 是 macOS(含 Linux 部分支持)的代理 *生命周期管理* CLI。
673
+ > 一句话:proxyctl 是 macOS + Linux 的代理 *生命周期管理* CLI。
648
674
  > 它管「启停 / 状态 / 健康检查 / DNS 防护 / 配置切换」,**不装 mihomo、
649
- > 不改规则、不改订阅** —— 这些去引擎自己的配置文件里改。
675
+ > 不改规则、不更新订阅** —— 这些去引擎自己的配置文件里改。
676
+ > v0.4.4 起,proxyctl **显示**订阅状态(到期日 / 已用流量 / 拉取健康度),
677
+ > 通过用户脚本写入的契约文件读取 —— 详见下方 `Subscription Status` 段。
650
678
  >
651
679
  > 本文档由 `proxyctl agent-guide` 在运行时输出,含当前 backend/路径/端口。
652
680
  > 仓库视角(开发/贡献协议)见仓库根 `AGENTS.md`。
@@ -680,12 +708,53 @@ Step 6 proxyctl explain <topic> # 深入概念(topic 见下)
680
708
  ## Exclusions — 不能做什么(去别处改)
681
709
 
682
710
  - 添加 / 修改 / 删除分流规则 → 编辑 `{mcfg}` 的 `rules:` 段
683
- - 添加节点 / 改订阅 → 编辑 `{mcfg}` 的 `proxies:` / `proxy-providers:` 段
684
- - 触发订阅刷新 → mihomo `proxy-providers.interval` 自动 / Clash API 手动;
685
- proxyctl **不管订阅更新**(见 `proxyctl explain subscription`)
711
+ - 添加节点 / 改订阅源 → 编辑 `{mcfg}` 的 `proxies:` / `proxy-providers:` 段
712
+ - **更新订阅 / 拉新节点** → mihomo `proxy-providers.interval` 自动 / Clash API 手动 /
713
+ 用户自己写脚本(参考仓库 `update-subscription.sh`);proxyctl 自己不发起网络拉取。
714
+ **但 proxyctl 会显示订阅状态**(v0.4.4+),见 `Subscription Status` 段。
686
715
  - 安装 mihomo / sing-box → `brew install mihomo` 等
687
716
  - 重启第三方应用 → 浏览器 / Slack / VSCode 需用户自己重启读 system proxy
688
717
 
718
+ ## Subscription Status — 订阅状态展示(v0.4.4+)
719
+
720
+ proxyctl **不更新订阅**,但 **会显示订阅状态**——通过读取契约文件
721
+ `~/.config/proxyctl/subscription.json`(schema v1)。
722
+
723
+ ### Agent 怎么用
724
+
725
+ ```bash
726
+ proxyctl status --json | jq .data.subscription
727
+ # 关键字段(全部可选):
728
+ # fetch_ok / fetch_http_status / fetch_error (拉取健康度)
729
+ # expire_at / expire_days_left (套餐到期)
730
+ # traffic_used_bytes / traffic_total_bytes / traffic_used_pct (流量)
731
+ # info_nodes / node_count / url_host
732
+
733
+ proxyctl status --json | jq .hints
734
+ # 风险摘要也会进 envelope.hints[]:
735
+ # 过期 ≤ 7 天 → "subscription expires in Nd ..."
736
+ # 过期已发生 → "subscription EXPIRED Nd ago ..." (critical)
737
+ # 流量 ≥ 80% → "subscription traffic at X% ..."
738
+ # 流量 ≥ 100% → "subscription traffic exhausted ..." (critical)
739
+ # fetch_ok=false → "subscription fetch failed: <error>" (critical)
740
+ ```
741
+
742
+ ### 谁来写契约文件
743
+
744
+ **用户脚本**(不是 proxyctl)。proxyctl 自己不发起任何网络请求 / 不解析订阅 URL。
745
+ 本仓库 `update-subscription.sh` 是参考实现:拉两个订阅 → 解析 Subscription-Userinfo
746
+ HTTP header → 写出 subscription.json。**任何符合 schema v1 的脚本都行**。
747
+
748
+ 成功或失败都要写:fetch_ok=false 时也填出 fetch_error / fetch_http_status,
749
+ proxyctl 才能区分「过期 / 网络挂 / 订阅服务方挂」。
750
+
751
+ ### 探测 capability
752
+
753
+ `proxyctl --version --json` → `data.supported_features.status_subscription = true`
754
+ (0.4.4+)。`false` 或缺失字段表示老版本,agent 应忽略 `data.subscription`。
755
+
756
+ 详见 `proxyctl explain subscription`。
757
+
689
758
  ## Concept Map — "想改 X 去哪"
690
759
 
691
760
  | 想改 | 文件 | 段 / 字段 |
@@ -883,10 +952,13 @@ COMMANDS_META: list[dict] = [
883
952
  "examples": ["proxyctl restart-clean",
884
953
  "proxyctl restart-clean --dry-run"]},
885
954
  # diagnostic
886
- {"name": "status", "group": "diagnostic", "summary": "系统状态面板",
955
+ {"name": "status", "group": "diagnostic",
956
+ "summary": "系统状态面板(含订阅状态:到期/流量/拉取健康度,v0.4.4+)",
887
957
  "args": [], "supports_json": True, "side_effects": [],
888
958
  "needs_sudo": False, "interactive": False, "exit_codes": [0, 5],
889
- "examples": ["proxyctl status", "proxyctl status --json"]},
959
+ "examples": ["proxyctl status",
960
+ "proxyctl status --json",
961
+ "proxyctl status --json | jq .data.subscription"]},
890
962
  {"name": "doctor", "group": "diagnostic", "summary": "极简 5 项健康打分(最快)",
891
963
  "args": [], "supports_json": True, "side_effects": [],
892
964
  "needs_sudo": False, "interactive": False, "exit_codes": [0, 5],
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes