From 7de8ad0fbd63dddf18c334560b9ab83407fdf2f9 Mon Sep 17 00:00:00 2001 From: jackwener Date: Sat, 14 Mar 2026 13:41:59 +0800 Subject: [PATCH] refactor: remove doctor command --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- README.md | 4 +- tests/test_auth.py | 2 +- twitter_cli/auth.py | 2 +- twitter_cli/cli.py | 129 -------------------------- 5 files changed, 5 insertions(+), 134 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index d385cb0..940bf5d 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -70,7 +70,7 @@ body: id: diagnostics attributes: label: Diagnostics - description: "Paste the output of `twitter doctor` here. This helps us diagnose cookie and auth issues quickly." + description: "Paste the output of `twitter -v ` here. This helps us diagnose cookie and auth issues quickly." render: text - type: textarea id: logs diff --git a/README.md b/README.md index f472abc..faca886 100644 --- a/README.md +++ b/README.md @@ -292,7 +292,7 @@ Mode behavior: - `Invalid tweet JSON file` - Regenerate input using `twitter feed --json > tweets.json`. -**Diagnostics command**: Run `twitter doctor` to output a full diagnostic report (version, OS, browser detection, Keychain status, cookie extraction results). Paste this output into bug reports. + Structured error codes commonly include `not_authenticated`, `not_found`, `invalid_input`, `rate_limited`, and `api_error`. @@ -540,7 +540,7 @@ score = likes_w * likes - 或在弹出 Keychain 授权时点击 **"始终允许"**。 - 报错 `Twitter API error 404`:通常是 queryId 轮换,重试即可。 -**诊断命令**:运行 `twitter doctor` 可输出完整诊断报告(版本、OS、浏览器检测、Keychain 状态、cookie 提取结果),方便提交 bug report。 + - 结构化错误码通常会区分 `not_authenticated`、`not_found`、`invalid_input`、`rate_limited`、`api_error`。 diff --git a/tests/test_auth.py b/tests/test_auth.py index e30f1a8..c111676 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -373,7 +373,7 @@ def test_get_cookies_includes_keychain_hint_in_error(monkeypatch) -> None: msg = str(exc_info.value) assert "security unlock-keychain" in msg - assert "twitter doctor" in msg + assert "twitter -v" in msg def test_extract_in_process_returns_diagnostics_on_failure(monkeypatch) -> None: diff --git a/twitter_cli/auth.py b/twitter_cli/auth.py index 2e93a91..f5f0f5c 100644 --- a/twitter_cli/auth.py +++ b/twitter_cli/auth.py @@ -584,7 +584,7 @@ def get_cookies() -> Dict[str, str]: lines.append("Option 1: Set TWITTER_AUTH_TOKEN and TWITTER_CT0 environment variables") lines.append("Option 2: Make sure you are logged into x.com in your browser (Arc/Chrome/Edge/Firefox/Brave)") lines.append("") - lines.append("Run 'twitter doctor' for full diagnostics.") + lines.append("Run 'twitter -v ' for debug diagnostics.") raise RuntimeError("\n".join(lines)) # Verify only for explicit auth failures; transient endpoint issues are tolerated. diff --git a/twitter_cli/cli.py b/twitter_cli/cli.py index f181440..aac92f0 100644 --- a/twitter_cli/cli.py +++ b/twitter_cli/cli.py @@ -1230,135 +1230,6 @@ def unbookmark(tweet_id, as_json, as_yaml): _write_action("🔖", "Removing bookmark", "unbookmark_tweet", tweet_id, as_json=as_json, as_yaml=as_yaml) -@cli.command(name="doctor") -@structured_output_options -def doctor(as_json, as_yaml): - # type: (bool, bool) -> None - """Run diagnostics for cookie extraction and authentication. - - Useful for troubleshooting auth issues and for pasting into bug reports. - """ - import platform - - from .auth import ( - _diagnose_keychain_issues, - _extract_in_process, - _extract_via_subprocess, - load_from_env, - verify_cookies, - ) - - info: Dict[str, Any] = {} - mode = _structured_mode(as_json=as_json, as_yaml=as_yaml) - - # -- System info -- - info["version"] = __version__ - info["python"] = sys.version.split()[0] - info["platform"] = platform.platform() - info["os"] = sys.platform - - # -- Environment -- - is_ssh = bool( - os.environ.get("SSH_CLIENT") - or os.environ.get("SSH_TTY") - or os.environ.get("SSH_CONNECTION") - ) - info["ssh_session"] = is_ssh - info["env_auth_token_set"] = bool(os.environ.get("TWITTER_AUTH_TOKEN")) - info["env_ct0_set"] = bool(os.environ.get("TWITTER_CT0")) - info["chrome_profile_override"] = os.environ.get("TWITTER_CHROME_PROFILE", "") - - # -- Cookie extraction -- - env_cookies = load_from_env() - info["env_cookies"] = "found" if env_cookies else "not set" - - # In-process extraction - in_proc_cookies, in_proc_diag = _extract_in_process() - info["in_process"] = { - "status": "ok" if in_proc_cookies else "failed", - "diagnostics": in_proc_diag, - } - - # Subprocess extraction - sub_cookies, sub_diag = _extract_via_subprocess() - info["subprocess"] = { - "status": "ok" if sub_cookies else "failed", - "diagnostics": sub_diag, - } - - # Combined diagnostics - all_diag = in_proc_diag + sub_diag - cookies = in_proc_cookies or sub_cookies or env_cookies - - # Keychain hint - hint = _diagnose_keychain_issues(all_diag) - if hint: - info["keychain_hint"] = hint - - # Verification - if cookies: - try: - result = verify_cookies( - cookies["auth_token"], - cookies["ct0"], - cookies.get("cookie_string"), - ) - info["verification"] = "ok" - info["screen_name"] = result.get("screen_name", "") - except RuntimeError as exc: - info["verification"] = "failed: %s" % exc - else: - info["verification"] = "skipped (no cookies)" - - # -- Output -- - if _emit_mode_payload(info, mode): - return - - console.print("\n🩺 [bold]twitter-cli doctor[/bold]\n") - console.print(" Version: %s" % info["version"]) - console.print(" Python: %s" % info["python"]) - console.print(" Platform: %s" % info["platform"]) - console.print(" SSH session: %s" % ("yes ⚠️" if is_ssh else "no")) - console.print() - - console.print("[bold]Environment:[/bold]") - console.print(" TWITTER_AUTH_TOKEN: %s" % ("set ✅" if info["env_auth_token_set"] else "not set")) - console.print(" TWITTER_CT0: %s" % ("set ✅" if info["env_ct0_set"] else "not set")) - if info["chrome_profile_override"]: - console.print(" TWITTER_CHROME_PROFILE: %s" % info["chrome_profile_override"]) - console.print() - - console.print("[bold]Cookie Extraction:[/bold]") - in_status = info["in_process"]["status"] - console.print( - " In-process: %s" % ("[green]ok ✅[/green]" if in_status == "ok" else "[red]failed ❌[/red]") - ) - for d in info["in_process"]["diagnostics"]: - console.print(" [dim]• %s[/dim]" % d) - - sub_status = info["subprocess"]["status"] - console.print( - " Subprocess: %s" % ("[green]ok ✅[/green]" if sub_status == "ok" else "[red]failed ❌[/red]") - ) - for d in info["subprocess"]["diagnostics"]: - console.print(" [dim]• %s[/dim]" % d) - console.print() - - if hint: - console.print("[yellow]💡 Hint:[/yellow]") - for line in hint.splitlines(): - console.print(" [yellow]%s[/yellow]" % line) - console.print() - - v = info["verification"] - if v == "ok": - screen = info.get("screen_name", "") - console.print("[green]✅ Authentication: OK[/green]%s" % (" (@%s)" % screen if screen else "")) - elif v.startswith("failed"): - console.print("[red]❌ Authentication: %s[/red]" % v) - else: - console.print("[yellow]⚠️ Authentication: %s[/yellow]" % v) - console.print() if __name__ == "__main__":