feat(routing): ordered backend candidates + real-probing doctor
- backends is now an ordered candidate list (first = preferred); channels report the backend actually serving via active_backend, surfaced in the doctor text report and --json - new agent_reach/probe.py really executes upstream commands and tells apart missing / broken (stale venv shebang after a system Python upgrade) / timeout, with a reinstall prescription for broken installs - all 13 channels migrated off which()-only checks: fixes bilibili false-positive "bili-cli 可用" on broken shims, misleading xiaohongshu "连接失败", rdt OSError crashing doctor, mcporter breakage masquerading as "未配置" - twitter: 15s probe + 1 retry (flaky 10s timeout), broken twitter-cli now falls back to bird instead of aborting the check - doctor survives per-channel exceptions; config supports per-channel backend override (<channel>_backend / <CHANNEL>_BACKEND env) - fix skill install/uninstall crash on symlinked skill dirs (the "[Errno None] None" warning from shutil.rmtree on a symlink) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""XiaoHongShu — check if xhs-cli (xiaohongshu-cli) is available."""
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
from agent_reach.probe import probe_command
|
||||
|
||||
from .base import Channel
|
||||
|
||||
|
||||
@@ -127,8 +127,12 @@ class XiaoHongShuChannel(Channel):
|
||||
return "xiaohongshu.com" in d or "xhslink.com" in d
|
||||
|
||||
def check(self, config=None):
|
||||
xhs = shutil.which("xhs")
|
||||
if not xhs:
|
||||
self.active_backend = None
|
||||
probe = probe_command(
|
||||
"xhs", ["status"], timeout=10, package="xiaohongshu-cli"
|
||||
)
|
||||
|
||||
if probe.status == "missing":
|
||||
return "off", (
|
||||
"需要安装 xhs-cli:\n"
|
||||
" pipx install xiaohongshu-cli\n"
|
||||
@@ -136,27 +140,27 @@ class XiaoHongShuChannel(Channel):
|
||||
" uv tool install xiaohongshu-cli\n"
|
||||
"安装后运行 `xhs login` 登录"
|
||||
)
|
||||
if probe.status == "broken":
|
||||
return "error", "xhs 命令存在但无法执行\n" + probe.hint
|
||||
if probe.status == "timeout":
|
||||
return "warn", "xhs-cli 已安装但状态检测超时\n" + probe.hint
|
||||
|
||||
try:
|
||||
r = subprocess.run(
|
||||
[xhs, "status"], capture_output=True,
|
||||
encoding="utf-8", errors="replace", timeout=10,
|
||||
# 进程是活的(执行成功或运行后非零退出)——按输出内容分类
|
||||
if probe.ok and "ok: true" in probe.output:
|
||||
self.active_backend = self.backends[0]
|
||||
return "ok", (
|
||||
"完整可用(搜索、阅读、评论、发帖、热门、"
|
||||
"收藏、关注、用户查询)"
|
||||
)
|
||||
output = (r.stdout or "") + (r.stderr or "")
|
||||
if r.returncode == 0 and "ok: true" in output:
|
||||
return "ok", (
|
||||
"完整可用(搜索、阅读、评论、发帖、热门、"
|
||||
"收藏、关注、用户查询)"
|
||||
)
|
||||
if "not_authenticated" in output or "expired" in output:
|
||||
return "warn", (
|
||||
"xhs-cli 已安装但未登录。运行:\n"
|
||||
" xhs login\n"
|
||||
"(自动从浏览器提取 Cookie,或扫码登录)"
|
||||
)
|
||||
if "not_authenticated" in probe.output or "expired" in probe.output:
|
||||
self.active_backend = self.backends[0]
|
||||
return "warn", (
|
||||
"xhs-cli 已安装但状态异常。运行:\n"
|
||||
" xhs -v status 查看详细信息"
|
||||
"xhs-cli 已安装但未登录。运行:\n"
|
||||
" xhs login\n"
|
||||
"(自动从浏览器提取 Cookie,或扫码登录)"
|
||||
)
|
||||
except Exception:
|
||||
return "warn", "xhs-cli 已安装但连接失败"
|
||||
self.active_backend = self.backends[0]
|
||||
return "warn", (
|
||||
"xhs-cli 已安装但状态异常。运行:\n"
|
||||
" xhs -v status 查看详细信息"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user