feat(cli): wire --manual-paste into `hermes auth add and hermes model`

Register the new ``--manual-paste`` flag on both entry points and
thread it through to the xAI loopback login:

* ``hermes auth add xai-oauth --manual-paste`` — pool-add path,
  forwarded inside ``auth_commands.handle_auth_add``.
* ``hermes model --manual-paste`` — model-picker path, forwarded
  by ``_model_flow_xai_oauth`` into the synthetic ``argparse.Namespace``
  it passes to ``_login_xai_oauth``.  The picker also now forwards
  ``--no-browser`` and ``--timeout`` for consistency (previously
  hardcoded to defaults regardless of CLI flags).

Help text on both flags points at #26923 and names the
browser-only remote consoles (Cloud Shell, Codespaces, EC2
Instance Connect) so users searching ``hermes --help`` can find
the workaround.
This commit is contained in:
xxxigm 2026-05-16 19:47:22 +07:00 committed by Teknium
parent 5a5c265bcf
commit cafbc9a734
2 changed files with 38 additions and 4 deletions

View file

@ -339,6 +339,7 @@ def auth_add_command(args) -> None:
creds = auth_mod._xai_oauth_loopback_login(
timeout_seconds=getattr(args, "timeout", None) or 20.0,
open_browser=not getattr(args, "no_browser", False),
manual_paste=bool(getattr(args, "manual_paste", False)),
)
label = (getattr(args, "label", None) or "").strip() or label_from_token(
creds["tokens"]["access_token"],

View file

@ -2022,7 +2022,7 @@ def select_provider_and_model(args=None):
elif selected_provider == "openai-codex":
_model_flow_openai_codex(config, current_model)
elif selected_provider == "xai-oauth":
_model_flow_xai_oauth(config, current_model)
_model_flow_xai_oauth(config, current_model, args=args)
elif selected_provider == "qwen-oauth":
_model_flow_qwen_oauth(config, current_model)
elif selected_provider == "minimax-oauth":
@ -2903,7 +2903,7 @@ def _model_flow_openai_codex(config, current_model=""):
print("No change.")
def _model_flow_xai_oauth(_config, current_model=""):
def _model_flow_xai_oauth(_config, current_model="", *, args=None):
"""xAI Grok OAuth (SuperGrok Subscription) provider: ensure logged in, then pick model."""
from hermes_cli.auth import (
get_xai_oauth_auth_status,
@ -2934,7 +2934,15 @@ def _model_flow_xai_oauth(_config, current_model=""):
print("Starting a fresh xAI OAuth login...")
print()
try:
mock_args = argparse.Namespace()
# Forward CLI flags from ``hermes model --manual-paste``
# / ``--no-browser`` / ``--timeout`` into the loopback
# login. Without this, browser-only remotes (#26923)
# can't reach the manual-paste path via ``hermes model``.
mock_args = argparse.Namespace(
manual_paste=bool(getattr(args, "manual_paste", False)),
no_browser=bool(getattr(args, "no_browser", False)),
timeout=getattr(args, "timeout", None),
)
_login_xai_oauth(
mock_args,
PROVIDER_REGISTRY["xai-oauth"],
@ -2952,7 +2960,11 @@ def _model_flow_xai_oauth(_config, current_model=""):
print("Not logged into xAI Grok OAuth (SuperGrok Subscription). Starting login...")
print()
try:
mock_args = argparse.Namespace()
mock_args = argparse.Namespace(
manual_paste=bool(getattr(args, "manual_paste", False)),
no_browser=bool(getattr(args, "no_browser", False)),
timeout=getattr(args, "timeout", None),
)
_login_xai_oauth(mock_args, PROVIDER_REGISTRY["xai-oauth"])
except SystemExit:
print("Login cancelled or failed.")
@ -10041,6 +10053,16 @@ def main():
action="store_true",
help="Do not attempt to open the browser automatically during Nous login",
)
model_parser.add_argument(
"--manual-paste",
action="store_true",
help=(
"For loopback OAuth providers (xai-oauth, ...): skip the local "
"callback listener and paste the failed callback URL from your "
"browser instead. Use on browser-only remotes (Cloud Shell, "
"Codespaces, EC2 Instance Connect, ...). See #26923."
),
)
model_parser.add_argument(
"--timeout",
type=float,
@ -10503,6 +10525,17 @@ def main():
action="store_true",
help="Do not auto-open a browser for OAuth login",
)
auth_add.add_argument(
"--manual-paste",
action="store_true",
help=(
"Skip the loopback callback listener and paste the failed "
"callback URL from your browser instead. Use this on "
"browser-only remotes (GCP Cloud Shell, GitHub Codespaces, "
"EC2 Instance Connect, ...) where 127.0.0.1 on the remote "
"isn't reachable from your laptop. See #26923."
),
)
auth_add.add_argument(
"--timeout", type=float, help="OAuth/network timeout in seconds"
)