fix(reddit): install rdt-cli from GitHub source pinned to 0.4.2 (#326)

PyPI still only has rdt-cli 0.4.1 while the doctor hint required >=0.4.2, so the suggested install command always failed. Installs from the upstream GitHub repo pinned to the 0.4.2 commit instead, and syncs all four docs that still taught the PyPI path. Verified locally: clean-venv install from the pinned source yields rdt 0.4.2 and rdt status works. 86 tests pass. Fixes #294.
This commit is contained in:
Andrew Barnes
2026-06-10 02:59:16 -04:00
committed by GitHub
parent 5b07d95e7e
commit 9045fee67e
8 changed files with 53 additions and 14 deletions
+1 -1
View File
@@ -323,7 +323,7 @@ Agent Reach uses twitter-cli with cookie auth — zero API fees. Install with `p
<details> <details>
<summary><strong>Reddit 返回 403 怎么办?</strong></summary> <summary><strong>Reddit 返回 403 怎么办?</strong></summary>
Agent Reach 使用 [rdt-cli](https://github.com/public-clis/rdt-cli) 访问 Reddit。Reddit 自 2024 年起要求认证,安装后需运行 `rdt login` 登录。安装:`pipx install rdt-cli`,然后 `rdt login`(自动从浏览器提取 Cookie)。之后 Agent 可以用 `rdt search "关键词"` 搜索、`rdt read POST_ID` 读帖子全文和评论。 Agent Reach 使用 [rdt-cli](https://github.com/public-clis/rdt-cli) 访问 Reddit。Reddit 自 2024 年起要求认证,安装后需运行 `rdt login` 登录。安装:`pipx install 'git+https://github.com/public-clis/rdt-cli.git'`(PyPI 版本暂时落后,从 GitHub 装),然后 `rdt login`(自动从浏览器提取 Cookie)。之后 Agent 可以用 `rdt search "关键词"` 搜索、`rdt read POST_ID` 读帖子全文和评论。
</details> </details>
<details> <details>
+6 -3
View File
@@ -13,6 +13,8 @@ import subprocess
from .base import Channel from .base import Channel
_CREDENTIAL_FILE = "~/.config/rdt-cli/credential.json" _CREDENTIAL_FILE = "~/.config/rdt-cli/credential.json"
# Pinned to the 0.4.2 state — PyPI still only has 0.4.1 (upstream issue #10).
_RDT_GIT_SOURCE = "git+https://github.com/public-clis/rdt-cli.git@5e4fb3720d5c174e976cd425ccc3b879d52cac66"
class RedditChannel(Channel): class RedditChannel(Channel):
@@ -31,9 +33,10 @@ class RedditChannel(Channel):
rdt = shutil.which("rdt") rdt = shutil.which("rdt")
if not rdt: if not rdt:
return "off", ( return "off", (
"需要安装 rdt-cli(推荐使用最新版 v0.4.2+\n" "需要安装 rdt-cli。PyPI 版本可能暂时落后,推荐直接从 GitHub 安装\n"
" pip install 'rdt-cli>=0.4.2'\n" f" pipx install '{_RDT_GIT_SOURCE}'\n"
"\n" "如已确认 PyPI 版本已更新,也可使用\n"
" pipx install rdt-cli\n"
" uv tool install rdt-cli\n" " uv tool install rdt-cli\n"
"最新源码:https://github.com/public-clis/rdt-cli\n" "最新源码:https://github.com/public-clis/rdt-cli\n"
"安装后运行 `rdt login` 登录(需先在浏览器登录 reddit.com)" "安装后运行 `rdt login` 登录(需先在浏览器登录 reddit.com)"
+10 -4
View File
@@ -17,6 +17,9 @@ import time
from agent_reach import __version__ from agent_reach import __version__
# Pinned to the 0.4.2 state — PyPI still only has 0.4.1 (upstream issue #10).
_RDT_GIT_SOURCE = "git+https://github.com/public-clis/rdt-cli.git@5e4fb3720d5c174e976cd425ccc3b879d52cac66"
def _ensure_utf8_console(): def _ensure_utf8_console():
"""Best-effort Windows console UTF-8 setup for CLI runtime only.""" """Best-effort Windows console UTF-8 setup for CLI runtime only."""
@@ -706,8 +709,10 @@ def _install_reddit_deps():
if shutil.which("rdt"): if shutil.which("rdt"):
print(" ✅ rdt-cli already installed") print(" ✅ rdt-cli already installed")
return return
for tool, cmd in [("pipx", ["pipx", "install", "rdt-cli"]), for tool, cmd in [
("uv", ["uv", "tool", "install", "rdt-cli"])]: ("pipx", ["pipx", "install", _RDT_GIT_SOURCE]),
("uv", ["uv", "tool", "install", "--from", _RDT_GIT_SOURCE, "rdt-cli"]),
]:
if shutil.which(tool): if shutil.which(tool):
try: try:
subprocess.run(cmd, capture_output=True, encoding="utf-8", subprocess.run(cmd, capture_output=True, encoding="utf-8",
@@ -717,7 +722,7 @@ def _install_reddit_deps():
return return
except Exception: except Exception:
pass pass
print(" [!] rdt-cli install failed. Run: pipx install rdt-cli") print(f" [!] rdt-cli install failed. Run: pipx install '{_RDT_GIT_SOURCE}'")
def _install_bili_deps(): def _install_bili_deps():
@@ -1495,7 +1500,8 @@ def _cmd_setup():
# Step 3: Reddit — rdt-cli # Step 3: Reddit — rdt-cli
print("【信息】Reddit — 通过 rdt-cli 搜索和阅读,无需配置") print("【信息】Reddit — 通过 rdt-cli 搜索和阅读,无需配置")
print(" 安装:pipx install rdt-cli") print(f" 安装:pipx install '{_RDT_GIT_SOURCE}'")
print(" 然后运行:rdt login")
print() print()
# Step 4: Groq (Whisper) # Step 4: Groq (Whisper)
+2 -2
View File
@@ -17,9 +17,9 @@ Agent Reach 通过 **rdt-cli** 实现 Reddit 的搜索和阅读功能:
which rdt && echo "installed" || echo "not installed" which rdt && echo "installed" || echo "not installed"
``` ```
2. 如果未安装,自动安装: 2. 如果未安装,自动安装(PyPI 版本暂时落后,从 GitHub 安装最新版)
```bash ```bash
pipx install rdt-cli pipx install 'git+https://github.com/public-clis/rdt-cli.git'
``` ```
或一键安装: 或一键安装:
+1 -1
View File
@@ -223,6 +223,6 @@ rdt popular --limit 10
rdt all --limit 10 rdt all --limit 10
``` ```
> **安装**: `pipx install rdt-cli`(确保 v0.4.2+)。需要先登录(`rdt login`)才能搜索和阅读。 > **安装**: `pipx install 'git+https://github.com/public-clis/rdt-cli.git'`PyPI 版本暂时落后,需从 GitHub 装 v0.4.2+)。需要先登录(`rdt login`)才能搜索和阅读。
> 需要登录的功能:`rdt feed --subs-only`(订阅列表)、`rdt saved`(收藏)。 > 需要登录的功能:`rdt feed --subs-only`(订阅列表)、`rdt saved`(收藏)。
> 建议使用 `--yaml` 输出,对 AI agent 更友好。 > 建议使用 `--yaml` 输出,对 AI agent 更友好。
+2 -2
View File
@@ -50,8 +50,8 @@ Run these commands to ensure all upstream CLI tools are installed. Skip any that
# Twitter/X — twitter-cli (replaces deprecated bird CLI) # Twitter/X — twitter-cli (replaces deprecated bird CLI)
which twitter >/dev/null 2>&1 || pipx install twitter-cli 2>/dev/null || uv tool install twitter-cli 2>/dev/null which twitter >/dev/null 2>&1 || pipx install twitter-cli 2>/dev/null || uv tool install twitter-cli 2>/dev/null
# Reddit — rdt-cli (replaces Exa-based approach) # Reddit — rdt-cli (replaces Exa-based approach; PyPI lags, install from GitHub)
which rdt >/dev/null 2>&1 || pipx install rdt-cli 2>/dev/null || uv tool install rdt-cli 2>/dev/null which rdt >/dev/null 2>&1 || pipx install 'git+https://github.com/public-clis/rdt-cli.git' 2>/dev/null || uv tool install --from 'git+https://github.com/public-clis/rdt-cli.git' rdt-cli 2>/dev/null
# XiaoHongShu — xhs-cli (replaces Docker MCP) # XiaoHongShu — xhs-cli (replaces Docker MCP)
which xhs >/dev/null 2>&1 || pipx install xiaohongshu-cli 2>/dev/null || uv tool install xiaohongshu-cli 2>/dev/null which xhs >/dev/null 2>&1 || pipx install xiaohongshu-cli 2>/dev/null || uv tool install xiaohongshu-cli 2>/dev/null
+2
View File
@@ -654,6 +654,8 @@ class TestRedditChannel:
assert status == "off" assert status == "off"
assert "rdt-cli" in msg assert "rdt-cli" in msg
assert "public-clis/rdt-cli" in msg assert "public-clis/rdt-cli" in msg
assert "git+https://github.com/public-clis/rdt-cli.git" in msg
assert "rdt-cli>=0.4.2" not in msg
def test_reports_ok_when_authenticated(self, monkeypatch): def test_reports_ok_when_authenticated(self, monkeypatch):
monkeypatch.setattr(shutil, "which", lambda _: "/usr/local/bin/rdt") monkeypatch.setattr(shutil, "which", lambda _: "/usr/local/bin/rdt")
+29 -1
View File
@@ -1,9 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Tests for Agent Reach CLI.""" """Tests for Agent Reach CLI."""
import shutil
import subprocess
from unittest.mock import patch
import pytest import pytest
import requests import requests
from unittest.mock import patch
import agent_reach.cli as cli import agent_reach.cli as cli
from agent_reach.cli import main from agent_reach.cli import main
@@ -42,6 +45,31 @@ class TestCLI:
assert auth_token == "token123" assert auth_token == "token123"
assert ct0 == "ct0abc" assert ct0 == "ct0abc"
def test_install_reddit_deps_prefers_github_source(self, monkeypatch, capsys):
state = {"rdt_installed": False}
commands = []
def fake_which(name):
if name == "rdt":
return "/usr/local/bin/rdt" if state["rdt_installed"] else None
if name == "pipx":
return "/usr/local/bin/pipx"
return None
def fake_run(cmd, **kwargs):
commands.append(cmd)
state["rdt_installed"] = True
return subprocess.CompletedProcess(cmd, 0, "", "")
monkeypatch.setattr(shutil, "which", fake_which)
monkeypatch.setattr(subprocess, "run", fake_run)
cli._install_reddit_deps()
out = capsys.readouterr().out
assert commands == [["pipx", "install", cli._RDT_GIT_SOURCE]]
assert "✅ rdt-cli installed" in out
class TestCheckUpdateRetry: class TestCheckUpdateRetry:
def test_retry_timeout_classification(self): def test_retry_timeout_classification(self):