feat(cli): support github-copilot in provider logout
Logout previously claimed to support github-copilot in --help text but had no registered handler, so `provider logout github-copilot` failed with "Logout not implemented". Add the handler, sharing token deletion with the codex flow via `_delete_oauth_files`. Tighten handler-table types, fix the codex test fixture filename, and cover github-copilot plus the unknown provider path.
This commit is contained in:
+43
-11
@@ -5,6 +5,7 @@ import os
|
||||
import select
|
||||
import signal
|
||||
import sys
|
||||
from collections.abc import Callable
|
||||
from contextlib import nullcontext, suppress
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
@@ -1487,8 +1488,13 @@ provider_app = typer.Typer(help="Manage providers")
|
||||
app.add_typer(provider_app, name="provider")
|
||||
|
||||
|
||||
_LOGIN_HANDLERS: dict[str, Any] = {}
|
||||
_LOGOUT_HANDLERS: dict[str, Any] = {}
|
||||
_LOGIN_HANDLERS: dict[str, Callable[[], None]] = {}
|
||||
_LOGOUT_HANDLERS: dict[str, Callable[[], None]] = {}
|
||||
|
||||
_PROVIDER_DISPLAY: dict[str, str] = {
|
||||
"openai_codex": "OpenAI Codex",
|
||||
"github_copilot": "GitHub Copilot",
|
||||
}
|
||||
|
||||
|
||||
def _register_login(name: str):
|
||||
@@ -1587,20 +1593,46 @@ def _logout_openai_codex() -> None:
|
||||
raise typer.Exit(1)
|
||||
|
||||
storage = FileTokenStorage(token_filename=OPENAI_CODEX_PROVIDER.token_filename)
|
||||
_delete_oauth_files(storage.get_token_path(), _PROVIDER_DISPLAY["openai_codex"])
|
||||
|
||||
|
||||
@_register_logout("github_copilot")
|
||||
def _logout_github_copilot() -> None:
|
||||
"""Clear local OAuth credentials for GitHub Copilot."""
|
||||
try:
|
||||
from nanobot.providers.github_copilot_provider import get_storage
|
||||
except ImportError:
|
||||
console.print("[red]GitHub Copilot provider unavailable. Ensure oauth-cli-kit is installed.[/red]")
|
||||
raise typer.Exit(1)
|
||||
|
||||
storage = get_storage()
|
||||
_delete_oauth_files(storage.get_token_path(), _PROVIDER_DISPLAY["github_copilot"])
|
||||
|
||||
|
||||
def _delete_oauth_files(token_path: Path, provider_label: str) -> None:
|
||||
"""Delete OAuth token and lock files, reporting the result."""
|
||||
removed_paths: list[Path] = []
|
||||
|
||||
for path in (storage.get_token_path(), storage.get_token_path().with_suffix(".lock")):
|
||||
if path.exists():
|
||||
skipped: list[tuple[Path, OSError]] = []
|
||||
for path in (token_path, token_path.with_suffix(".lock")):
|
||||
try:
|
||||
path.unlink()
|
||||
removed_paths.append(path)
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
except OSError as exc:
|
||||
skipped.append((path, exc))
|
||||
continue
|
||||
removed_paths.append(path)
|
||||
|
||||
if not removed_paths:
|
||||
console.print("[yellow]! No local OAuth credentials found for OpenAI Codex[/yellow]")
|
||||
if not removed_paths and not skipped:
|
||||
console.print(f"[yellow]! No local OAuth credentials found for {provider_label}[/yellow]")
|
||||
return
|
||||
|
||||
console.print("[green]✓ Logged out from OpenAI Codex[/green]")
|
||||
for path in removed_paths:
|
||||
console.print(f"[dim]Removed: {path}[/dim]")
|
||||
if removed_paths:
|
||||
console.print(f"[green]✓ Logged out from {provider_label}[/green]")
|
||||
for path in removed_paths:
|
||||
console.print(f"[dim]Removed: {path}[/dim]")
|
||||
for path, exc in skipped:
|
||||
console.print(f"[yellow]! Could not remove {path}: {exc}[/yellow]")
|
||||
|
||||
|
||||
@_register_login("github_copilot")
|
||||
|
||||
Reference in New Issue
Block a user