diff --git a/agent_reach/cli.py b/agent_reach/cli.py index e3826d3..2532110 100644 --- a/agent_reach/cli.py +++ b/agent_reach/cli.py @@ -226,10 +226,11 @@ def _cmd_install(args): # Apply explicit flags if args.proxy: if dry_run: - print(f"[dry-run] Would configure proxy for Bilibili") + print(f"[dry-run] Would save network proxy") else: - config.set("bilibili_proxy", args.proxy) - print(f"✅ Proxy configured for Bilibili") + config.set("proxy", args.proxy) + config.set("bilibili_proxy", args.proxy) # legacy key + print(f"✅ 代理已保存(Agent 访问受限网络时使用)") # ── Install core system dependencies (lightweight, always) ── print() @@ -298,9 +299,9 @@ def _cmd_install(args): # Environment-specific advice if env == "server": print() - print("Tip: Bilibili may block server IPs.") - print(" Reddit: rdt-cli works without proxy (pipx install rdt-cli).") - print(" For Bilibili full access: agent-reach configure proxy http://user:pass@ip:port") + print("Tip: 部分平台对服务器 IP 有风控。") + print(" Reddit 必须登录态(rdt-cli + Cookie,见 doctor 提示),中国大陆网络还需代理。") + print(" 保存代理供 Agent 使用:agent-reach configure proxy http://user:pass@ip:port") print(" Cheap option: https://www.webshare.io ($1/month)") # Test channels @@ -1036,9 +1037,14 @@ def _cmd_configure(args): return if args.key == "proxy": + # Generic network proxy for restricted environments. Nothing reads + # this key at runtime — agents read it back and export HTTP(S)_PROXY + # before invoking upstream tools (see docs/install.md). The legacy + # bilibili_proxy key is kept in sync for older configs. + config.set("proxy", value) config.set("bilibili_proxy", value) - print(f"✅ Proxy configured for Bilibili!") - print(" Note: Reddit 已改为通过 rdt-cli 访问,无需代理。") + print("✅ 代理已保存(供 Agent 在访问 Reddit/Twitter 等需要代理的网络时设置 HTTP_PROXY/HTTPS_PROXY)") + print(" Note: B站走 bili-cli,国内网络无需代理。") elif args.key == "twitter-cookies": # Accept two formats: diff --git a/agent_reach/probe.py b/agent_reach/probe.py index 9f20c47..9a66a9a 100644 --- a/agent_reach/probe.py +++ b/agent_reach/probe.py @@ -53,6 +53,10 @@ def probe_command( ) -> ProbeResult: """Actually execute `cmd *args` and classify the result. + Intended for SIDE-EFFECT-FREE health probes only (version/status + commands): retries re-run the command verbatim with no backoff, so a + non-idempotent command would repeat its effect. + package: pip/pipx package name used in the broken-install hint (defaults to cmd). """ diff --git a/agent_reach/transcribe.py b/agent_reach/transcribe.py index ce5b637..2ffd612 100644 --- a/agent_reach/transcribe.py +++ b/agent_reach/transcribe.py @@ -58,9 +58,16 @@ def _require(binary: str) -> None: raise MissingDependency(f"{binary} not found in PATH") -def _run(cmd: List[str]) -> None: - """Run a subprocess, raising TranscribeError on nonzero exit.""" - proc = subprocess.run(cmd, capture_output=True, text=True) +def _run(cmd: List[str], timeout: int = 600) -> None: + """Run a subprocess, raising TranscribeError on nonzero exit or timeout. + + cmd carries user-supplied URLs/paths into yt-dlp/ffmpeg — a stalled + network read or a hung probe must not block the CLI forever. + """ + try: + proc = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout) + except subprocess.TimeoutExpired: + raise TranscribeError(f"{cmd[0]} timed out after {timeout}s") if proc.returncode != 0: raise TranscribeError( f"{cmd[0]} failed (exit {proc.returncode}): {proc.stderr.strip()[:300]}" @@ -82,7 +89,8 @@ def download_audio(url: str, out_dir: Path) -> Path: "-o", str(template), url, - ] + ], + timeout=1800, # long podcasts over slow networks — generous but bounded ) files = sorted(out_dir.glob("source.*")) if not files: diff --git a/docs/install.md b/docs/install.md index a62afb1..2511069 100644 --- a/docs/install.md +++ b/docs/install.md @@ -312,7 +312,7 @@ If the user wants a different agent to handle it, let them choose. | `agent-reach watch` | Quick health + update check (for scheduled tasks) | | `agent-reach check-update` | Check for new versions | | `agent-reach configure twitter-cookies "..."` | Unlock Twitter search + posting | -| `agent-reach configure proxy URL` | Unlock Reddit + Bilibili on servers | +| `agent-reach configure proxy URL` | 保存代理地址(Agent 访问 Reddit/Twitter 等受限网络时读取它设置 HTTP_PROXY/HTTPS_PROXY,不是自动解锁开关) | | `agent-reach configure groq-key gsk_xxx` | Unlock Xiaoyuzhou podcast transcription | After installation, use upstream tools directly. See SKILL.md for the full command reference: diff --git a/docs/update.md b/docs/update.md index a25499f..79a9bfa 100644 --- a/docs/update.md +++ b/docs/update.md @@ -58,8 +58,8 @@ which bili >/dev/null 2>&1 && { pipx upgrade bilibili-cli 2>/dev/null || uv t which xhs >/dev/null 2>&1 && { pipx upgrade xiaohongshu-cli 2>/dev/null || uv tool upgrade xiaohongshu-cli 2>/dev/null; } which yt-dlp >/dev/null 2>&1 && { pipx upgrade yt-dlp 2>/dev/null || uv tool upgrade yt-dlp 2>/dev/null || pip install -U yt-dlp 2>/dev/null; } -# rdt-cli is pinned to a git source (PyPI lags upstream) -which rdt >/dev/null 2>&1 && pipx install --force 'git+https://github.com/public-clis/rdt-cli.git' 2>/dev/null +# rdt-cli is pinned to a git source (PyPI lags upstream) — same pin as the code's _RDT_GIT_SOURCE +which rdt >/dev/null 2>&1 && pipx install --force 'git+https://github.com/public-clis/rdt-cli.git@5e4fb3720d5c174e976cd425ccc3b879d52cac66' 2>/dev/null # npm-based which mcporter >/dev/null 2>&1 && npm update -g mcporter 2>/dev/null