diff --git a/agent-test-flows/README.md b/agent-test-flows/README.md index b9c55e74..a66a73e7 100644 --- a/agent-test-flows/README.md +++ b/agent-test-flows/README.md @@ -7,7 +7,7 @@ and reports the results. Keep these short — the agent works out the details. ## How to use Point an agent at this folder and ask for a **smoke** pass (quick, ~10–15 min) or a **full** pass (thorough, can take hours). The agent plans the tasks, picks models, runs them via `mobilerun run …` -(and `mobilerun device` / `mobilerun macro` / `mobilerun login` as needed), and writes a +(and `mobilerun device` / `mobilerun macro` / `mobilerun configure ` as needed), and writes a comparison table with screenshots. Smoke = one cheap model + a few core checks; full = sweep the areas below. diff --git a/mobilerun/agent/utils/llm_picker.py b/mobilerun/agent/utils/llm_picker.py index 7c4e7849..c9b927ee 100644 --- a/mobilerun/agent/utils/llm_picker.py +++ b/mobilerun/agent/utils/llm_picker.py @@ -96,7 +96,7 @@ def _validate_gemini_oauth_model(model: object) -> None: raise ValueError( f"Model '{model_id}' is from the deprecated gemini-cli Code Assist " f"path, which stops serving Google One / individual tiers on " - f"2026-06-18. Re-run `mobilerun gemini login` and pick one of: " + f"2026-06-18. Re-run `mobilerun configure gemini` and pick one of: " f"{supported}." ) diff --git a/mobilerun/cli/main.py b/mobilerun/cli/main.py index 131bf3dc..2c44179d 100644 --- a/mobilerun/cli/main.py +++ b/mobilerun/cli/main.py @@ -414,12 +414,6 @@ def _run_anthropic_oauth_login(credential_path: str, **kwargs) -> None: _print_oauth_login_success("Anthropic", credential_path) -def _prompt_anthropic_setup_token(token: str | None) -> str: - if token: - return token - return click.prompt("Paste your Anthropic setup token", hide_input=True) - - try: _available_agents = list_agents() except Exception: @@ -826,65 +820,7 @@ def tui(): run_tui() -@cli.command(name="setup-token") -@click.option( - "--timeout", - type=float, - default=300.0, - show_default=True, - help="Max seconds to wait for the browser callback.", -) -@click.option( - "--callback-host", - default="127.0.0.1", - show_default=True, - help="Host to bind the local OAuth callback server.", -) -@click.option( - "--callback-port", - type=int, - default=0, - show_default=True, - help="Port to bind the local OAuth callback server. Use 0 for auto.", -) -@click.option( - "--callback-path", - default="/callback", - show_default=True, - help="Callback path for the local OAuth server.", -) -@click.option( - "--open-browser/--no-browser", - default=True, - show_default=True, - help="Open the authorization URL automatically.", -) -def setup_token( - timeout: float, - callback_host: str, - callback_port: int, - callback_path: str, - open_browser: bool, -): - """Create a long-lived Anthropic setup token using Mobilerun's native OAuth flow.""" - console.print( - "This will guide you through long-lived (1-year) auth token setup for your Claude account." - ) - token = run_anthropic_setup_token_oauth( - timeout=timeout, - callback_host=callback_host, - callback_port=callback_port, - callback_path=callback_path, - open_browser=open_browser, - ) - console.print("\n[green]Setup token created.[/]") - console.print( - "Paste this token into `mobilerun configure` or `mobilerun anthropic login`." - ) - click.echo(token) - - -@cli.command(name="configure") +@cli.group(name="configure", invoke_without_command=True) @click.option( "--provider", type=str, @@ -907,14 +843,22 @@ def setup_token( default=None, help="Base URL override for compatible providers.", ) +@click.pass_context def configure( + ctx: click.Context, provider: str | None, auth_mode: str | None, model: str | None, api_key: str | None, base_url: str | None, ): - """Configure LLM provider, auth mode, and model.""" + """Configure LLM provider, auth mode, and model. + + Run without a subcommand for the interactive wizard, or use a provider + subcommand (e.g. `mobilerun configure anthropic`) to log in via OAuth. + """ + if ctx.invoked_subcommand is not None: + return run_configure_wizard( console, ConfigureWizardCallbacks( @@ -930,13 +874,7 @@ def configure( ) -@cli.group() -def openai(): - """OpenAI OAuth commands.""" - pass - - -@openai.command("login") +@configure.command("openai") @click.option( "--credential-path", default=str(DEFAULT_OPENAI_OAUTH_CREDENTIAL_PATH), @@ -978,7 +916,7 @@ def openai(): show_default=True, help="Open the authorization URL automatically.", ) -def openai_login( +def configure_openai( credential_path: str, model: str | None, timeout: float, @@ -987,7 +925,7 @@ def openai_login( callback_path: str, open_browser: bool, ): - """Login with ChatGPT/OpenAI OAuth and save credentials locally.""" + """Log in to ChatGPT/OpenAI via OAuth and save credentials locally.""" _run_openai_oauth_login( credential_path=credential_path, model=model, @@ -999,26 +937,20 @@ def openai_login( ) -@cli.group() -def anthropic(): - """Anthropic authentication commands.""" - pass - - -@anthropic.command("login") +@configure.command("anthropic") @click.option( "--credential-path", default=str(ANTHROPIC_OAUTH_CREDENTIAL_PATH), show_default=True, - help="Where to store the Anthropic setup-token.", + help="Where to store the Anthropic credentials.", ) @click.option( "--token", default=None, help="Anthropic setup-token value. If provided, skips the OAuth flow.", ) -def anthropic_login(credential_path: str, token: str | None): - """Login with Anthropic OAuth. Pass --token to save a setup-token without OAuth.""" +def configure_anthropic(credential_path: str, token: str | None): + """Log in to Anthropic via OAuth (or pass --token to save a setup-token).""" if token: save_anthropic_setup_token(credential_path, token) _print_oauth_login_success("Anthropic", credential_path) @@ -1026,31 +958,7 @@ def anthropic_login(credential_path: str, token: str | None): _run_anthropic_oauth_login(credential_path=credential_path) -@anthropic.command("setup-token") -@click.option( - "--credential-path", - default=str(ANTHROPIC_OAUTH_CREDENTIAL_PATH), - show_default=True, - help="Where to store the Anthropic setup-token.", -) -@click.option( - "--token", - default=None, - help="Setup-token value. If omitted, you will be prompted.", -) -def anthropic_setup_token(credential_path: str, token: str | None): - """Paste and save an Anthropic setup-token.""" - save_anthropic_setup_token(credential_path, _prompt_anthropic_setup_token(token)) - _print_oauth_login_success("Anthropic setup-token", credential_path) - - -@cli.group(name="gemini") -def gemini_group(): - """Gemini OAuth commands.""" - pass - - -@gemini_group.command("login") +@configure.command("gemini") @click.option( "--credential-path", default=str(GEMINI_OAUTH_CREDENTIAL_PATH), @@ -1092,7 +1000,7 @@ def gemini_group(): show_default=True, help="Open the authorization URL automatically.", ) -def gemini_login( +def configure_gemini( credential_path: str, model: str | None, timeout: float, @@ -1101,7 +1009,7 @@ def gemini_login( callback_path: str, open_browser: bool, ): - """Login with Gemini Code Assist OAuth and save credentials locally.""" + """Log in to Gemini Code Assist via OAuth and save credentials locally.""" _run_gemini_oauth_login( credential_path=credential_path, model=model,