+
    jHàj_p  ã            
      óš  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIH	t	 ^ RI
HtHtHtHt ^ RIHt ^ RIHtHt ^ RIHtHtHtHtHtHtHtHtHtHtHtH t  ^ RI!H"t" ]'       d   ^ R	I#H$t$ ]PJ                  ! R
4      t&Rt'R R lt(R R lt)R R lt*R R lt+RR/R R llt,R R lt-RRRRRRRRR R/R! R" llt.R# R$ lt/RQR% R& llt0R' R( lt1R) R* lt2R+ R, lt3R- R. lt4R/ R0 lt5RRR1 R2 llt6R3 R4 lt7R5RR6R7/R8 R9 llt8RR/R: R; llt9R< R= lt:R> R? lt;R@RARBRRCR/RD RE llt<RFRA/RG RH llt=RI]/RJ RK llt>RL RM lt?R6R7RNR/RO RP llt@R# )SzæxAI Grok OAuth: token store, discovery, refresh, device-code login.

Split out of ``hermes_cli/auth.py``; origin helpers are imported lazily per function so
``hermes_cli.auth.<helper>`` patches still intercept and no cycle forms.
)ÚannotationsN)ÚPath)ÚAnyÚDictÚOptionalÚTYPE_CHECKING)Úurlparse)Ú_load_auth_store_maybe_lockedÚ_refresh_payload_access_token)ÚAUTH_LOCK_TIMEOUT_SECONDSÚ	AuthErrorÚDEFAULT_XAI_OAUTH_BASE_URLÚDEVICE_CODE_GRANT_TYPEÚ%XAI_ACCESS_TOKEN_REFRESH_SKEW_SECONDSÚXAI_OAUTH_CLIENT_IDÚXAI_OAUTH_DEVICE_CODE_URLÚXAI_OAUTH_DISCOVERY_URLÚXAI_OAUTH_SCOPEÚ_FORM_JSON_HEADERSÚ_xai_errÚhttpx)Ú	env_float)ÚProviderConfigzhermes_cli.authz$Re-authenticate with `hermes model`.c               ó    € V ^8„  d   QhRRRR/# )é   Úvaluer   ÚreturnÚstr© )Úformats   "Ú8/home/ubuntu/.hermes/hermes-agent/hermes_cli/auth_xai.pyÚ__annotate__r!       s   € ÷ $ñ $�#ð $˜#ñ $ó    c                óH   € \        T ;'       g    R 4      P                  4       # )Ú )r   Ústrip)r   s   &r    Ú_cleanr&       s   € Üˆu�{ˆ{˜Ó×!Ñ!Ó#Ð#r"   c               ó    € V ^8„  d   QhRRRR/# )r   Útokensr   r   ztuple[str, str]r   )r   s   "r    r!   r!   $   s   € ÷ Sñ S˜ð S ñ Sr"   c                óš   € \        V \        4      '       g   R# \        V P                  R4      4      \        V P                  R4      4      3# )zV``(access_token, refresh_token)`` stripped; empty strings when *tokens* is not a dict.Úaccess_tokenÚrefresh_token)r$   r$   )Ú
isinstanceÚdictr&   Úget©r(   s   &r    Ú_token_pairr0   $   s;   € ä�fœd×#Ò#ØˆÜ�&—*‘*˜^Ó,Ó-¬v°f·j±jÀÓ6QÓ/RÐRÐRr"   c               ó    € V ^8„  d   QhRRRR/# )r   Ú
auth_storeúdict[str, Any]r   úOptional[dict[str, Any]]r   )r   s   "r    r!   r!   +   s   € ÷ 6ñ 6¨Nð 6Ð?Wñ 6r"   c                óÌ  € ^ RI Hp V! V R4      p\        V\        4      '       d,   \	        \        VP                  R4      4      4      '       d   V# V P                  R4      p\        V\        4      '       d   VP                  R4      MRp\        V\        4      '       d   TMR F£  p\        V4      w  rgV'       d	   V'       g   K"  \        T;'       g    / 4      pRTRTR\        VP                  R4      ;'       g    R	4      /VR&   VP                  R
4      '       d   VP                  R
4      VR
&   VP                  RR4       Vu # 	  \        V\        4      '       d   V# R# )zEReturn usable xAI OAuth state from provider state or credential pool.)Ú_load_provider_stateú	xai-oauthr(   Úcredential_poolNr*   r+   Ú
token_typeÚBearerÚlast_refreshÚ	auth_modeÚ
oauth_pkcer   )
Úhermes_cli.authr6   r,   r-   Úallr0   r.   Úlistr   Ú
setdefault)	r2   r6   Ústater8   ÚentriesÚentryr*   r+   Úmergeds	   &        r    Ú_xai_oauth_state_from_storerF   +   s+  € å4Ù  ¨[Ó9€EÜ�%œ×Ò¤3¤{°5·9±9¸XÓ3FÓ'G×#HÒ#HØˆà —n‘nÐ%6Ó7€OÜ2<¸_Ìd×2SÒ2Sˆo×!Ñ! +Ô.ÐY]€GÜ& w´×5Ò5‘¸2Ò=ˆÜ&1°%Ó&8Ñ#ˆß§=ÙÜ�e—k�k˜rÓ"ˆà˜L¨/¸=Øœ#˜eŸi™i¨Ó5×AÐA¸ÓBð
ˆˆxÑð �9‰9�^×$Ò$Ø%*§Y¡Y¨~Ó%>ˆF�>Ñ"Ø×Ñ˜+ |Ô4ØŠñ >ô ˜u¤d×+Ò+ˆ5Ð5°Ð5r"   c               ó    € V ^8„  d   QhRRRR/# )r   rB   r4   r   Úboolr   )r   s   "r    r!   r!   E   s   € ÷ Mñ MÐ.Fð MÈ4ñ Mr"   c                óx   € \        V \        4      ;'       d$    \        \        V P	                  R 4      4      4      # r/   )r,   r-   r?   r0   r.   )rB   s   &r    Ú"_xai_oauth_state_has_usable_tokensrJ   E   s*   € Ü�eœTÓ"×LÐL¤s¬;°u·y±yÀÓ7JÓ+KÓ'LÐLr"   Ú_lockTc               ó    € V ^8„  d   QhRRRR/# )r   rK   rH   r   r3   r   )r   s   "r    r!   r!   I   s   € ÷ ñ  Tð °^ñ r"   c           
     óF  € ^ RI Hp \        \        V 4      4      p\	        V4      '       g$   \        V! 4       4      p\	        V4      '       d   TpV'       g   \        RRRR7      hVP                  R4      p\        V\        4      '       g   \        R\         2RRR7      h\        V4      w  rVVR	3VR
33 F(  w  rxV'       d   K  \        RV R\         2RV 2RR7      h	  RTRVP                  R4      RVP                  R4      ;'       g    / RVP                  R4      /# )é    )Ú_load_global_auth_storez`No xAI OAuth credentials stored. Select xAI Grok OAuth (SuperGrok / Premium+) in `hermes model`.Úxai_auth_missingT©Úreloginr(   z#xAI OAuth state is missing tokens. Úxai_auth_invalid_shaper*   r+   zxAI OAuth state is missing z. Úxai_auth_missing_r;   Ú	discoveryÚredirect_uri)r>   rO   rF   r	   rJ   r   r.   r,   r-   Ú_RELOGINr0   )	rK   rO   rB   Úglobal_stater(   r*   r+   r   Úfields	   $        r    Ú_read_xai_oauth_tokensrZ   I   s'  € Ý7Ü'Ô(EÀeÓ(LÓM€EÜ-¨e×4Ò4Ü2Ñ3JÓ3LÓMˆÜ-¨l×;Ò;Ø ˆEßÜØnØ¨ô
ð 	
ð �Y‰Y�xÓ €FÜ�fœd×#Ò#ÜÐ<¼X¸JÐGÐIaÐkoÔpÐpÜ"-¨fÓ"5Ñ€LØ&¨Ð7¸-ÈÐ9YÓZ‰ˆß‰uÜØ-¨e¨W°B´x°jÐAÐEVÐW\ÐV]ÐC^Ðhlôð ñ [ð 	�&˜.¨%¯)©)°NÓ*CØ�U—Y‘Y˜{Ó+×1Ð1¨r°>À5Ç9Á9È^ÓC\ðð r"   c               ó    € V ^8„  d   QhRRRR/# )r   rB   r3   r   ÚNoner   )r   s   "r    r!   r!   d   s   € ÷ Pñ P°>ð PÀdñ Pr"   c                óð  € ^ RI HpHp V! 4       pVf   R# \        P                  P                  R4      '       d!   \        P                  P                  RR4      MRpV'       dE   \        V4      R,          R,          p VP                  RR	7      VP                  RR	7      8X  d   R#   V! R
WRR7       R#   \         d     R# i ; i  \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)aI  Best-effort persist of a rotated xAI grant into the global-root auth.json.

xAI rotates refresh_token on every refresh, so a profile that refreshed a root-resolved grant
must write the chain back to root. Touches only root ``providers.xai-oauth``; swallows all
errors (root-stale is better than breaking the profile's own save).
)Ú_global_auth_file_pathÚ _persist_provider_state_to_storeNÚPYTEST_CURRENT_TESTÚHOMEr$   z.hermesz	auth.jsonF)Ústrictr7   ©Ú
set_activez2xAI OAuth: write-through to global root failed: %s)r>   r^   r_   ÚosÚenvironr.   r   ÚresolveÚ	ExceptionÚloggerÚdebug)rB   r^   r_   Úglobal_pathÚreal_home_envÚ	real_rootÚexcs   &      r    Ú'_write_through_xai_oauth_to_global_rootro   d   sÚ   € ÷ YÙ(Ó*€KØÒÙô 35·*±*·.±.ÐAV×2WÒ2W”B—J‘J—N‘N 6¨2Ô.Ð]_€MßÜ˜Ó'¨)Õ3°kÕAˆ	ð	Ø×"Ñ"¨%Ð"Ó0°I×4EÑ4EÈUÐ4EÓ4SÔSÙð TðPÙ(¨°eÐUZ×[øô ô 	Úð	ûô ô PÜ�‰ÐIÈ3×OÒOûðPús*   Á?'B7 Â*C	 Â7CÃCÃ	C5ÃC0Ã0C5rU   rV   r$   r;   r<   Úoauth_device_coderd   c               ó4   € V ^8„  d   QhRRRRRRRRR	RR
RRR/# )r   r(   r3   rU   r4   rV   r   r;   zOptional[str]r<   rd   rH   r   r\   r   )r   s   "r    r!   r!      sH   € ÷ )ñ )Øð)Ø*Bð)ØY\ð)àð)à36ð)ð ð)ð 
ñ	)r"   c          	     ó¦  € ^ RI HpHpHpHp	Hp
HpHpHpH	p Vf   V! 4       pV! 4       ;_uu_ 4        V! 4       pV	! VR4      w  ppVe   TM/ pVP                  WVR7       V'       d   VVR&   V'       d   VVR&   V! 4       pVe   Ve   V
! VV4      '       d
   V! V4       MV! VRVVR7       V! V4       RRR4       R#   + '       g   i     R# ; i)zßPersist xAI OAuth tokens; *set_active* also promotes ``xai-oauth`` to ``active_provider``.

Pass ``set_active=False`` for side-tool bootstrap (TTS/setup, tools config, dashboard, refresh)
so inference routing is unchanged.
)	Ú_auth_store_lockr^   Ú_load_auth_storeÚ _load_provider_state_with_sourceÚ
_same_pathÚ_save_auth_storeÚ_store_provider_stateÚ
_utc_now_zro   Nr7   )r(   r;   r<   rU   rV   rc   )r>   rs   r^   rt   ru   rv   rw   rx   ry   ro   Úupdate)r(   rU   rV   r;   r<   rd   rs   r^   rt   ru   rv   rw   rx   ry   ro   r2   rB   Úsource_pathÚglobal_roots   &$$$$$             r    Ú_save_xai_oauth_tokensr}      sÈ   € ÷ g÷  gõ  gØÒÙ!“|ˆÙ	×	Õ	Ù%Ó'ˆ
ñ >¸jÈ+ÓVÑˆˆ{ØÒ*‘°ˆØ�‰˜FÈˆÔSßØ!*ˆE�+ÑßØ$0ˆE�.Ñ!Ù,Ó.ˆØÒ" {Ò'>Á:ÈkÐ[f×CgÒCgá3°EÕ:á! *¨k¸5ÈZÕXÙ˜ZÔ(÷% 
×	×	Ò	ús   ±AB?Á5"B?ÂB?Â?C	c               ó    € V ^8„  d   QhRRRR/# )r   r*   r   r   zOptional[float]r   )r   s   "r    r!   r!   ¡   s   € ÷ ñ ˜sð  ñ r"   c                ó
  € \        V \        4      '       d   RV 9  d   R#  V P                  R4      p\        V4      ^8  d   R# V^,          R\        V^,          4      ) ^,          ,          ,           p\        P
                  ! \        P                  ! VP                  R4      4      P                  R4      4      P                  R4      p\        V\        \        34      '       d   \        V4      # R#   \         d     R# i ; i)zL``exp`` claim of a JWT-shaped access token, or None when absent/undecodable.Ú.NÚ=Úasciizutf-8Úexp)r,   r   ÚsplitÚlenÚjsonÚloadsÚbase64Úurlsafe_b64decodeÚencodeÚdecoder.   ÚintÚfloatrh   )r*   ÚpartsÚpayload_b64rƒ   s   &   r    Ú_xai_jwt_expr�   ¡   sË   € ä�l¤C×(Ò(¨C°|Ô,CÙðØ×"Ñ" 3Ó'ˆÜˆu‹:˜Œ>ÙØ˜A•h ¬¨U°1­X«¨¸Õ(:Õ!;Õ;ˆÜ�jŠjœ×1Ò1°+×2DÑ2DÀWÓ2MÓN×UÑUÐV]Ó^Ó_×cÑcÐdiÓjˆÜ'¨¬c´5¨\×:Ò:Œu�S‹zÐDÀÐDøÜô Úðús   ¡!C3 ÁB,C3 Ã1C3 Ã3DÄDc               ó$   € V ^8„  d   QhRRRRRR/# )r   r*   r   Úskew_secondsrŒ   r   rH   r   )r   s   "r    r!   r!   °   s&   € ÷ Nñ N°ð NÀ3ð NÈtñ Nr"   c                ó”   € \        V 4      pVR J;'       d3    V\        P                  ! 4       \        ^ \        V4      4      ,           8*  # )N)r�   ÚtimeÚmaxrŒ   )r*   r’   rƒ   s   && r    Ú_xai_access_token_is_expiringr–   °   s:   € Ü
�|Ó
$€CØ�dˆ?×MÐM˜s¤d§i¢i£k´C¸¼3¸|Ó;LÓ4MÕ&MÑMÐMr"   c               ó    € V ^8„  d   QhRRRR/# )r   r*   r   r   rŒ   r   )r   s   "r    r!   r!   µ   s   € ÷ Hñ H°cð H¸cñ Hr"   c                ó¨   € \         p\        V 4      pVf   V# V\        P                  ! 4       ,
          p^ Tu;8  d   R8:  d   M M\        ^xV4      # T# )zêProactive-refresh lead time before JWT ``exp``.

Device-code logins often return ~15-minute JWTs; the full hour-long skew would refresh on every
resolution, burning single-use refresh tokens and racing callers into ``invalid_grant``.
iŒ
  )r   r�   r”   Úmin)r*   Úmax_skewrƒ   Ú	remainings   &   r    Ú#_xai_proactive_refresh_skew_secondsrœ   µ   sK   € ô 5€HÜ
�|Ó
$€CØ
‚{ØˆØ”d—i’i“kÕ!€IØ!" YÖ!9°'×!9Œ3ˆs�HÓÐG¸xÐGr"   c               ó    € V ^8„  d   QhRRRR/# )r   Úhostr   r   rH   r   )r   s   "r    r!   r!   Ã   s   € ÷ 4ñ 4˜cð 4 dñ 4r"   c                ó>   € V R8H  ;'       g    V P                  R4      # )zQ``x.ai`` is the bare apex, so an exact match or any ``.x.ai`` suffix is accepted.zx.aiz.x.ai)Úendswith)rž   s   &r    Ú_is_xai_origin_hostr¡   Ã   s   € à�6‰>×3Ð3˜TŸ]™]¨7Ó3Ð3r"   c               ó    € V ^8„  d   QhRRRR/# )r   Úurlr   r   ztuple[Optional[str], str]r   )r   s   "r    r!   r!   È   s   € ÷ 
ñ 
˜#ð 
Ð";ñ 
r"   c                óÔ   € \        V 4      pVP                  ;'       g    RP                  4       pVP                  R8w  d   RV3# V'       g   RV3# \	        V4      '       g   RV3# RV3# )un   ``(problem, host)`` â€” problem is ``"scheme"``, ``"host"``, ``"origin"`` or None when *url* is HTTPS on x.ai.r$   ÚhttpsÚschemerž   ÚoriginN)r   ÚhostnameÚlowerr¦   r¡   )r£   Úparsedrž   s   &  r    Ú_xai_url_problemr«   È   sg   € ä�c‹]€FØ�O‰O×!Ð!˜r×(Ñ(Ó*€DØ‡}�}˜ÔØ˜ˆ~ÐßØ�tˆ|ÐÜ˜t×$Ò$Ø˜ˆ~ÐØ�ˆ:Ðr"   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r£   r   rY   r   r   )r   s   "r    r!   r!   Õ   s!   € ÷ 5ñ 5 cð 5°Sð 5¸Sñ 5r"   c          
     óŽ   € \        V 4      w  r#Vf   V # RRV RV : R2RRV RV : R2RRV R	V: R
2/V,          p\        VR4      h)uõ   Refuse a discovery endpoint that isn't HTTPS on the xAI origin.

Discovery is cached in auth.json, so one MITM at login could plant a ``token_endpoint`` that
receives the refresh_token forever; pinning scheme + host (RFC 8414 Â§2) removes that.
r¦   z(xAI OIDC discovery returned a non-HTTPS z: r€   rž   zxAI OIDC discovery z is missing a hostname: r§   z host zÖ is not on the xAI origin (expected x.ai or a *.x.ai subdomain). Refusing to use a cached endpoint that may have been substituted by a MITM during initial discovery; re-authenticate with `hermes model` to re-fetch.Úxai_discovery_invalid)r«   r   )r£   rY   Úproblemrž   Úmessages   &$   r    Ú_xai_validate_oauth_endpointr±   Õ   s‚   € ô % SÓ)�M€GØ‚Øˆ
àÐ<¸U¸GÀ2ÀcÁWÈAÐNØÐ% e WÐ,DÀSÁGÈ1ÐMØØ! % ¨¨t©hð 7Jð Kð		ð õ	€Gô �7Ð3Ó
4Ð4r"   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r   Úfallbackr   r   )r   s   "r    r!   r!   ë   s!   € ÷ ñ ¨Cð ¸cð Àcñ r"   c               ó�  € T ;'       g    RP                  4       P                  R4      pV'       g   V#  \        V4      w  r4Tf   T# TR8X  d   \        P                  RY!4       T# TR8X  d   \        P                  RY!4       T# \        P                  RY$T4       T#   \         d    \        P                  RY!4       Tu # i ; i)	z·Pin the OAuth inference base_url to ``*.x.ai``; warn and use *fallback* on rejection.

Warn-not-raise: a bad env var must not deadlock auth, but the bearer must never leak elsewhere.
r$   Ú/z>Ignoring malformed xAI base_url override %r; using %s instead.r¦   znRefusing non-HTTPS xAI base_url override %r (xai-oauth bearer would be sent in cleartext); falling back to %s.rž   zEIgnoring xAI base_url override %r with no hostname; using %s instead.uñ   Refusing xAI base_url override %r â€” host %r is not on the xAI origin (expected x.ai or a *.x.ai subdomain). The xai-oauth bearer is only valid against xAI's inference API; sending it elsewhere would leak the credential. Falling back to %s.)r%   Úrstripr«   rh   ri   Úwarning)r   r³   Ú	candidater¯   rž   s   &$   r    Ú _xai_validate_inference_base_urlr¹   ë   sÔ   € ð
 —�˜"×#Ñ#Ó%×,Ñ,¨SÓ1€IßØˆðÜ(¨Ó3‰ˆð ‚ØÐØ�(ÔÜ�‰ð9àô	
ð €Oð 
�FÔ	Ü�‰Ð^Ð`iÔtð €Oô 	�‰ð2ð ˜Xô	
ð €Oøô+ ô Ü�‰ÐWÐYbÔmØŠðús   µB Â#CÃCc               ó    € V ^8„  d   QhRRRR/# )r   Útimeout_secondsr�   r   zdict[str, str]r   )r   s   "r    r!   r!     s   € ÷ ñ ¨%ð ¸>ñ r"   c           	     óŠ  €  \         P                  ! \        R R/V R7      pTP
                  ^È8w  d   \	        RTP
                   R2R4      h TP                  4       p\        T\        4      '       g   \	        R
R4      hR Uu/ uF  qD\        TP                  T4      4      bK  	  pp\        TP                  4       4      '       g   \	        RR4      hTP                  4        F  w  rg\        YvR7       K  	  T#   \         d   p\	        RT 2R4      ThRp?ii ; i  \         d   p\	        RT 2R	4      ThRp?ii ; iu upi )ÚAcceptúapplication/json)ÚheadersÚtimeoutzxAI OIDC discovery failed: Úxai_discovery_failedNz#xAI OIDC discovery returned status r€   z*xAI OIDC discovery returned invalid JSON: Úxai_discovery_invalid_jsonz2xAI OIDC discovery response was not a JSON object.Úxai_discovery_incompletez;xAI OIDC discovery response was missing required endpoints.©rY   )Úauthorization_endpointÚtoken_endpoint)r   r.   r   rh   r   Ústatus_coder†   r,   r-   r&   r?   ÚvaluesÚitemsr±   )r»   Úresponsern   ÚpayloadÚkÚ	endpointsrY   r£   s   &       r    Ú_xai_oauth_discoveryrÎ     sI  € ð]Ü—9’9Ô4¸xÐI[Ð>\ÐfuÔvˆð ×Ñ˜sÔ"ÜÐ<¸X×=QÑ=QÐ<RÐRSÐTÐVlÓmÐmðrØ—-‘-“/ˆô �gœt×$Ò$ÜÐKÐMgÓhÐhÙ4`ÓaÑ4`¨q”F˜7Ÿ;™; q›>Ó*Ò*Ñ4`€IÐaÜˆy×ÑÓ!×"Ò"ÜÐTÐVpÓqÐqØ—o‘oÖ'‰
ˆÜ$ S×6ñ (àÐøô ô ]ÜÐ4°S°EÐ:Ð<RÓSÐY\Ð\ûð]ûô ô rÜÐCÀCÀ5ÐIÐKgÓhÐnqÐqûðrüò bs5   ‚C: ÁD Â#E Ã:DÄDÄDÄD=Ä(D8Ä8D=c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   rË   r3   r*   r   Úfallback_refreshr   r   )r   s   "r    r!   r!   "  s*   € ÷ ñ  nð ÀCð Ð[^ð Ðcqñ r"   c                ó   € RTR\        V P                  R4      ;'       g    T4      P                  4       R\        V P                  R4      4      RV P                  R4      R\        V P                  R4      ;'       g    R4      ;'       g    R/# )z^Token block persisted for xAI OAuth; falls back to *fallback_refresh* when none is rotated in.r*   r+   Úid_tokenÚ
expires_inr9   r:   )r   r.   r%   r&   )rË   r*   rÐ   s   &&&r    Ú_xai_tokens_from_payloadrÔ   "  s{   € ð 	˜Øœ˜WŸ[™[¨Ó9×MÐMÐ=MÓN×TÑTÓVØ”F˜7Ÿ;™; zÓ2Ó3°\À7Ç;Á;È|ÓC\Ø”f˜WŸ[™[¨Ó6×BÐB¸(ÓC×OÐOÀxð	ð r"   rÆ   r»   ç      4@c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   r*   r   r+   rÆ   r»   r�   r   r3   r   )r   s   "r    r!   r!   ,  s=   € ÷ 3pñ 3pØð3pØ&)ð3pØ>Að3pàð3pð ñ3pr"   c               ó<  € ^ RI HpHpHp ? V! V4      '       g   \	        R\
         2RRR7      hVP                  4       ;'       g    V! V4      R,          p\        VRR7       \        P                  ! \        R\        V4      4      4      p\        P                  ! VR	R
/R7      ;_uu_ 4       p	V	P                  VRR/RRR\        RV/R7      p
RRR4       X
P                  ^È8w  dy   V
P                   P                  4       pV'       d   RV 2MRpV
P                  R8X  d   \	        RV,           R,           RRR7      h\	        RV,           RV
P                  R9   R7      h\#        V
RR RRR!R"R7      w  rÞ/ \%        WÞV4      CRV! 4       /C#   + '       g   i     LÄ; i)#rN   )Ú_nonempty_strry   rÎ   z$xAI OAuth is missing refresh_token. Úxai_auth_missing_refresh_tokenTrQ   rÆ   rÄ   ç      @r½   r¾   ©rÀ   r¿   zContent-Typez!application/x-www-form-urlencodedÚ
grant_typer+   Ú	client_id©r¿   ÚdataNú Response: r$   i“  z'xAI token refresh failed with HTTP 403.uP   This OAuth account is not authorized for xAI API access â€” xAI may be restricting API/OAuth use to specific SuperGrok tiers despite the in-app subscription being active. Re-logging in won't change that; set ``XAI_API_KEY`` and switch to ``provider: xai`` (API-key path) if available, or upgrade your subscription at https://x.ai/grok.Úxai_oauth_tier_deniedFzxAI token refresh failed.Úxai_refresh_failedr7   )ÚproviderÚinvalid_jsonÚinvalid_json_reloginÚ
strict_strÚinvalid_responseÚmissing_accessr;   >   é�  é‘  )z.xAI token refresh returned invalid JSON: {exc}Úxai_refresh_invalid_json)z1xAI token refresh response was not a JSON object.Úxai_refresh_invalid_response)z4xAI token refresh response was missing access_token.Ú xai_refresh_missing_access_token)r>   rØ   ry   rÎ   r   rW   r%   r±   r   ÚTimeoutr•   r�   ÚClientÚpostr   rÇ   Útextr
   rÔ   )r*   r+   rÆ   r»   rØ   ry   rÎ   ÚendpointrÀ   ÚclientrÊ   ÚdetailÚsuffixrË   Úrefreshed_accesss   &&$$           r    Úrefresh_xai_oauth_purer÷   ,  s´  € ÷ PÑOØÙ˜×'Ò'ÜØ2´8°*Ð=Ð?_Ðimô
ð 	
ð ×#Ñ#Ó%×`Ð`Ñ)=¸oÓ)NÐO_Õ)`€Hô ! Ð1AÕBÜ�mŠmœC ¤U¨?Ó%;Ó<Ó=€GÜ	�Š˜g°Ð:LÐ/M×	NÕ	NÐRXØ—;‘;Ø˜~Ð/RÐSØ °Ô>QÐSbÐdqÐrð ó 
ˆ÷ 
Oð
 ×Ñ˜sÔ"Ø—‘×$Ñ$Ó&ˆß+1�;˜v˜hÑ'°rˆð ×Ñ 3Ô&ÜØ9¸FÕBðEõEð (°ô
ð 
ô Ø'¨&Õ0Ð2FÐPX×PdÑPdÐhrÑPrô
ð 	
ô !>Ø˜;ØcØ"¨uØnØsô!Ñ€Gð pÔ& wÀ-ÓPÐoÐR`ÑblÓbnÑoÐo÷I 
O×	Nús   Â.!FÆF	c          
     ó,   € V ^8„  d   QhRRRRRRRRRR/# )	r   r(   r3   rÆ   r   rV   r»   r�   r   r   )r   s   "r    r!   r!   b  s4   € ÷ ñ ØðØ/2ðØBEðØ]bðàñr"   c          	     ót  € ^ RI HpHpHp  V! V! 4       R4      ;'       g    / p\	        VP                  R4      ;'       g    R4      pV! \        V P                  R4      4      \        V P                  R4      4      WR7      p	\        V 4      p
V	R,          V
R&   V	R,          V
R&   V	P                  R4      '       d   V	R,          V
R&   V	P                  R	4      e   V	R	,          V
R	&   V	P                  R
4      '       d   V	R
,          V
R
&   \        V
RV/VV	R,          VRR7       V
#   \         d    Rp Lîi ; i)rN   )rt   r6   r÷   r7   r<   rp   r*   r+   )rÆ   r»   rÒ   rÓ   r9   rÆ   r;   F)rU   rV   r;   r<   rd   )
r>   rt   r6   r÷   r   r.   rh   r&   r-   r}   )r(   rÆ   rV   r»   rt   r6   r÷   rB   r<   Ú	refreshedÚupdated_tokenss   &$$$       r    Ú_refresh_xai_oauth_tokensrü   b  s8  € ÷ _Ñ^ð(Ù$Ñ%5Ó%7¸ÓE×KÐKÈˆÜ˜Ÿ	™	 +Ó.×EÐEÐ2EÓFˆ	ñ 'Üˆv�z‰z˜.Ó)Ó*¬F°6·:±:¸oÓ3NÓ,OØ%ô€Iô ˜&“\€NØ%.¨~Õ%>€N�>Ñ"Ø&/°Õ&@€N�?Ñ#Ø‡}�}�Z× Ò Ø%.¨zÕ%:ˆ�zÑ"Ø‡}�}�\Ó"Ò.Ø'0°Õ'>ˆ�|Ñ$Ø‡}�}�\×"Ò"Ø'0°Õ'>ˆ�|Ñ$äØÐ#3°^Ð"DÐS_Ø˜~Õ.¸)ÐPUõð Ðøô) ô (Ø'Š	ð(ús   ŒD' ¡D' ÁD' Ä'D7Ä6D7c               ó    € V ^8„  d   QhRRRR/# )r   rn   r   r   r\   r   )r   s   "r    r!   r!   �  s   € ÷ Uñ U ið U°Dñ Ur"   c                ó”  € ^ RI HpHpHpHpHp  V! 4       pV! VR4      ;'       g    / p\        VP                  R4      ;'       g    / 4      pVP                  RR4       VP                  RR4       W‡R&   V! RV RRR	7      VR
&   V! VRVRR7       V! V4       R#   \         d"   p	\        P                  RT	4        Rp	?	R# Rp	?	ii ; i)zÀClear dead xAI tokens after a terminal (400/401/403) refresh failure so later sessions fail fast.

Best-effort: persistence failures are logged and swallowed; the caller re-raises regardless.
)Ú_last_auth_error_markerrt   r6   rw   rx   r7   r(   r*   Nr+   Úruntime_refresh_failurerâ   )ÚreasonÚdefault_codeÚlast_auth_errorFrc   z2xAI OAuth: failed to persist quarantined state: %s)r>   rÿ   rt   r6   rw   rx   r-   r.   Úpoprh   ri   rj   )
rn   rÿ   rt   r6   rw   rx   ÚstorerB   r(   Úsave_excs
   &         r    Ú_quarantine_xai_oauth_tokensr  �  sÇ   € ÷
 Iõ  IðUÙ Ó"ˆÙ$ U¨KÓ8×>Ð>¸BˆÜ�e—i‘i Ó)×/Ð/¨RÓ0ˆØ�
‰
�> 4Ô(Ø�
‰
�? DÔ)ð !ˆh‰Ù#:Ø˜Ð%>ÐMaô$
ˆÐÑ ñ 	˜e [°%ÀEÕJÙ˜ÖøÜô UÜ�‰ÐIÈ8×TÒTûðUús#   �B §B ÁAB ÂCÂ&CÃCc               ó   € V ^8„  d   QhRR/# )r   r   r   r   )r   s   "r    r!   r!   š  s   € ÷ ñ  sñ r"   c                 ó   € \        \        P                  ! R R4      P                  4       P	                  R4      ;'       g5    \        P                  ! RR4      P                  4       P	                  R4      \
        R7      # )ÚHERMES_XAI_BASE_URLr$   rµ   ÚXAI_BASE_URL)r³   )r¹   re   Úgetenvr%   r¶   r   r   r"   r    Ú_xai_oauth_inference_base_urlr  š  s^   € Ü+Ü
�	Š	Ð'¨Ó,×2Ñ2Ó4×;Ñ;¸CÓ@×uÐuÄBÇIÂIÈnÐ^`ÓDa×DgÑDgÓDi×DpÑDpÐqtÓDuÜ+ôð r"   Úforce_refreshFÚrefresh_if_expiringÚrefresh_skew_secondsc               ó(   € V ^8„  d   QhRRRRRRRR/# )r   r  rH   r  r  zOptional[int]r   r3   r   )r   s   "r    r!   r!   ¡  s.   € ÷ /ñ /Øð/Ø9=ð/à'ð/ð ñ/r"   c                óR  a aa€ ^ RI HpHpHpHp R V VV3R llp\        4       p\        VR,          4      p	\        R^4      p
V! V4      '       dÜ   V! \        \        \        4      V
R,           4      R7      ;_uu_ 4        \        RR	7      p\        VR,          4      p	V! V4      '       dx   \        \        VP                  R
4      ;'       g    / 4      P                  R4      4      ;'       g    V! V
4      R,          p V! W›\        VP                  R4      4      V
R7      p	RRR4       RRR\        4       R\        V	P                  R4      4      RRRVP                  R4      RR/#   \         d    pT! T4      '       d   \        T4       h Rp?ii ; i  + '       g   i     Lz; i)rN   )rs   Ú$_is_terminal_xai_oauth_refresh_errorrü   rÎ   c               ó    € V ^8„  d   QhRRRR/# )r   rß   r3   r   rH   r   )r   s   "r    r!   Ú;resolve_xai_oauth_runtime_credentials.<locals>.__annotate__§  s   € ÷ 
ñ 
˜nð 
°ñ 
r"   c                óÜ   <€ \        V R ,          P                  R4      4      pSe   \        S4      M
\        V4      p\	        S4      ;'       g    \	        S;'       d    \        W4      4      # )r(   r*   )r&   r.   rŒ   rœ   rH   r–   )rß   r*   Úskewr  r  r  s   &  €€€r    Ú_should_refreshÚ>resolve_xai_oauth_runtime_credentials.<locals>._should_refresh§  sh   ø€ Ü˜d 8�n×0Ñ0°Ó@ÓAˆà)=Ò)IŒCÐ$Ô%Ü4°\ÓBð 	ô �MÓ"÷ 
ð 
¤dØ×UÐUÔ$AÀ,Ó$Uó'
ð 	
r"   r(   Ú"HERMES_XAI_REFRESH_TIMEOUT_SECONDSrÚ   )r»   F)rK   rU   rÆ   rV   )rÆ   rV   r»   Nrã   r7   Úbase_urlÚapi_keyr*   Úsourcezhermes-auth-storer;   r<   rp   )r>   rs   r  rü   rÎ   rZ   r-   r   r•   r�   r   r&   r.   r   r  r  )r  r  r  rs   r  rü   rÎ   r  rß   r(   Úrefresh_timeout_secondsrÆ   rn   s   ddd          r    Ú%resolve_xai_oauth_runtime_credentialsr  ¡  s~  ú€ ÷ Hó  H÷
ò 
ô "Ó#€DÜ�$�x•.Ó!€FÜ'Ð(LÈbÓQÐÙ�t×ÒÙ¬c´%Ô8QÓ2RÐTkÐnqÕTqÓ.r×sÖsä)°Ô6ˆDÜ˜$˜x�.Ó)ˆFÙ˜t×$Ò$äœ4 §¡¨Ó 5× ;Ð ;¸Ó<×@Ñ@ÐAQÓRÓS÷ Wð WÙ+Ð,CÓDÐEUÕVð ðÙ6ØÌFÐSW×S[ÑS[Ð\jÓSkÓLlØ(?ô�F÷ tð( 	�KØÔ1Ó3Ø”6˜&Ÿ*™* ^Ó4Ó5ØÐ%Ø˜Ÿ™ Ó0àÐ(ðð øô !ô Ù;¸C×@Ò@Ü4°SÔ9Øûðú÷ t×sús7   Â AFÃ FÃ0FÄ#E)Å)FÅ4FÆFÆFÆF&	Úforce_new_loginc               ó$   € V ^8„  d   QhRRRRRR/# )r   Úpconfigr   r   rH   r   r\   r   )r   s   "r    r!   r!   Ó  s'   € ÷ "Iñ "I Nð "IÈð "IÐY]ñ "Ir"   c               óJ  € ^ RI HpHpHpHpHpHpHp	 ?V'       g   V! RV\        R\        R7      '       d   R# \        4        \        R4       \        R4       \        4        \        \        V RR4      ;'       g    R	4      p
\        V R
R4      '       * pV! 4       '       d   RpV! W«R7      p\        VR,          VP                  R4      VP                  RR4      VP                  R4      RR7       V	! RR4       V! RVP                  R\        4      4      pV! RVRR7       R# )rN   )Ú_is_remote_sessionÚ!_offer_existing_oauth_credentialsÚ_print_login_successÚ_update_config_for_providerÚ_xai_oauth_device_code_loginr  Úunsuppress_credential_sourcer7   z	xAI OAuth)rg   Úis_expiringÚdisplay_nameÚdefault_base_urlNz6Signing in to xAI Grok OAuth (SuperGrok / Premium+)...z,(Hermes creates its own local OAuth session)rÀ   rÕ   Ú
no_browserF)r»   Úopen_browserr(   rU   rV   r$   r;   rp   )rU   rV   r;   r<   Údevice_coder  T)Úshow_auth_state)r>   r$  r%  r&  r'  r(  r  r)  r–   r   Úprintr�   Úgetattrr}   r.   )Úargsr"  r   r$  r%  r&  r'  r(  r  r)  r»   r.  ÚcredsÚconfig_paths   &&$           r    Ú_login_xai_oauthr6  Ó  s  € ÷ l÷  lñ  lØçÑ@ØØ5Ü1Ø Ü3÷ ó  ñ 	ä	„GÜ	Ð
BÔCÜ	Ð
8Ô9Ü	„GäœG D¨)°TÓ:×BÐB¸dÓC€OÜ˜t \°5Ó9Ô9€LÙ×ÒØˆá(¸Ôd€EÜØˆh� 5§9¡9¨[Ó#9Ø—Y‘Y˜~¨rÓ2ÀÇÁÈ>ÓAZØ%õñ ! ¨mÔ<Ù-¨k¸5¿9¹9ÀZÔQkÓ;lÓm€KÙ˜ kÀ4×Hr"   Úscopec               ó$   € V ^8„  d   QhRRRRRR/# )r   ró   úhttpx.Clientr7  r   r   r3   r   )r   s   "r    r!   r!   ø  s"   € ÷ ñ ¨<ð À3ð Ð]kñ r"   c               óÒ  € V P                  \        \        R \        RV/R7      pVP                  ^È8w  d\   \        RVP                   R2VP                  '       d)   RVP                  P                  4        2,           R4      hR,           R4      hVP                  4       pRpV Uu. uF  qUV9  g   K  VNK  	  ppV'       d   \        RR	P                  V4       2R
4      hV# u upi )rÝ   r7  rÞ   z%xAI device-code request failed (HTTP z).rà   r$   Údevice_code_request_failedz)xAI device-code response missing fields: z, Údevice_code_invalid)r/  Ú	user_codeÚverification_uriÚverification_uri_completerÓ   Úinterval)
rð   r   r   r   rÇ   r   rñ   r%   r†   Újoin)ró   r7  rÊ   rË   ÚrequiredÚkeyÚmissings   &$     r    Ú_xai_oauth_request_device_coderE  ø  sò   € Ø�{‰{Ü!Ô+=À[ÔReÐgnÐpuÐDvð ó €Hð ×Ñ˜sÔ"ÜØ3°H×4HÑ4HÐ3IÈÐLØ8@¿¿¸�˜XŸ]™]×0Ñ0Ó2Ð3Ð4õOà(ó
ð 	
àKMõOà(ó
ð 	
ð
 �m‰m‹o€GØv€HÙ&Ó=™h�s°WÑ*<�sˆs™h€GÐ=ßÜÐBÀ4Ç9Á9ÈWÓCUÐBVÐWÐYnÓoÐoØ€Nùò >s   Â'C$Â4C$c               ó0   € V ^8„  d   QhRRRRRRRRRRR	R
/# )r   ró   r9  rÆ   r   r/  rÓ   rŒ   Úpoll_intervalr   r3   r   )r   s   "r    r!   r!   
  s>   € ÷  ñ  Øð Ø-0ð Ø?Bð ØPSð àð ð ñ r"   c          
     ó’   a aa€ ^ RI Hp R R lpR R lpV! V VV3R l\        V4      \        ^\        V4      4      VR VR R	7      # )
rN   )Ú_poll_device_token_genericc               ó    € V ^8„  d   QhRRRR/# )r   rË   r3   r   r\   r   )r   s   "r    r!   Ú2_xai_oauth_poll_device_token.<locals>.__annotate__  s   € ÷ ñ ˜>ð ¨dñ r"   c                óp   € R F/  w  rV P                  V4      '       d   K  \        RV RV R2R4      h	  R# )r*   z/xAI device-code token response did not include Ú r€   Úxai_device_token_invalidN))r*   Úan)r+   Úa)r.   r   )rË   Ú
field_nameÚarticles   &  r    Ú	_validateÚ/_xai_oauth_poll_device_token.<locals>._validate  sC   € Û#SÑˆJØ—;‘;˜z×*Ô*ÜØEÀgÀYÈaÐPZÈ|Ð[\Ð]Ø.óð ó $Tr"   c               ó   € V ^8„  d   QhRR/# )r   r   rh   r   )r   s   "r    r!   rK    s   € ÷ ñ ¨9ñ r"   c                óò   € VP                  R 4      ;'       g&    VP                  R4      ;'       g    V P                  p\        RV 2R4      p\        VP                  R4      ;'       g    R4      Vn        V# )Úerror_descriptionÚerrorz&xAI device-code token polling failed: Úxai_device_token_failedr$   )r.   rñ   r   r   Úoauth_error_code)rÊ   Úerror_payloadÚdescriptionÚerrs   &&  r    Ú_errorÚ,_xai_oauth_poll_device_token.<locals>._error  sp   € Ø#×'Ñ'Ð(;Ó<×kÐkÀ×@QÑ@QÐRYÓ@Z×kÐkÐ^f×^kÑ^kˆÜÐ?À¸}ÐMÐOhÓiˆÜ" =×#4Ñ#4°WÓ#=×#CÐ#CÀÓDˆÔØˆ
r"   c            
     óP   <€ S P                  S\        R \        R\        RS/R7      # )rÜ   rÝ   r/  rÞ   )rð   r   r   r   )ró   r/  rÆ   s   €€€r    Ú<lambda>Ú._xai_oauth_poll_device_token.<locals>.<lambda>  s-   ø€ �—‘ØÔ$6ØÔ 6¸ÔEXÐZgÐitÐuð ô 
r"   c                ó   € \        R R4      # )zAxAI device-code token polling returned a non-JSON error response.rY  ©r   )Ú_rs   &r    ra  rb  %  s   € ¤XØOÐQjô&
r"   c                 ó   € \        R R4      # )z/Timed out waiting for xAI device authorization.Údevice_code_timeoutrd  r   r"   r    ra  rb  )  s   € œ8Ð$UÐWlÔmr"   )rÓ   rG  Úvalidate_successÚon_non_json_errorÚon_errorÚ
on_timeout)r>   rI  rŒ   r•   )ró   rÆ   r/  rÓ   rG  rI  rS  r^  s   fdd$$   r    Ú_xai_oauth_poll_device_tokenrl  
  sN   ú€ õ ;õõñ &ö	
ô �z“?Ü˜!œS Ó/Ó0Ø"ñ
ð Ùmôð r"   r.  c               ó$   € V ^8„  d   QhRRRRRR/# )r   r»   r�   r.  rH   r   r3   r   )r   s   "r    r!   r!   -  s#   € ÷ ñ °Uð ÐQUð Ðaoñ r"   c                ó,  € ^ RI HpHpHpHpHpHp V! V 4      p\        P                  ! \        RV 4      4      p	\        P                  ! V	RR/R7      ;_uu_ 4       p
\        V
4      p\        VR,          4      pT! \        VP                  R4      ;'       g
    VR,          4      \        VR	,          4      T;'       d    V! 4       '       * ;'       d    V! 4       R
R7       \        R\        ^V4       R24       V! W¨R,          \        VR,          4      \        VR,          4      VR7      pRRR4       \!        X4      w  rïV'       d	   V'       g   \#        RR4      hR\%        WÞV4      RVRRR\'        4       RV! 4       RR/#   + '       g   i     L^; i)rN   )Ú_can_open_graphical_browserr$  Ú_print_device_code_instructionsry   rÎ   rl  rÕ   r½   r¾   rÛ   r@  r?  r>  r=  T)r.  Úswallow_open_errorsz$Waiting for approval (polling every zs)...rÆ   r/  rÓ   )rÆ   r/  rÓ   rG  Nz;xAI device-code token response was missing required tokens.rN  r(   rU   rV   r$   r  r;   r  zoauth-device-code)r>   ro  r$  rp  ry   rÎ   rl  r   rî   r•   rï   rE  rŒ   r   r.   r1  r0   r   rÔ   r  )r»   r.  ro  r$  rp  ry   rÎ   rl  rU   rÀ   ró   Údevice_datar@  rË   r*   r+   s   $$              r    r(  r(  -  si  € ÷ q÷  qÙ$ _Ó5€IÜ�mŠmœC  oÓ6Ó7€GÜ	�Š˜g°Ð:LÐ/M×	NÕ	NÐRXÜ4°VÓ<ˆÜ�{ :Õ.Ó/ˆÙ'Ü�—‘Ð ;Ó<×_Ð_ÀÐL^Õ@_Ó`Ü�˜KÕ(Ó)Ø%×dÐdÑ.@Ó.BÔ*B×dÐdÑGbÓGdØ $õ		
ô 	Ð4´S¸¸HÓ5EÐ4FÀeÐLÔMÙ.ØÐ-=Õ#>Ü˜K¨Õ6Ó7ÄCÈÐT`ÕHaÓDbØ"ô
ˆ÷ 
Oô  #.¨gÓ"6Ñ€LßŸ}ÜÐTÐVpÓqÐqàÔ*¨7À-ÓPØ�Y °°JÔ@]Ó@_Ø™
› hÐ0Cðð ÷' 
O×	Nús   ÁA#FÂ?FÃAFÆF	)rN   )g      .@)AÚ__doc__Ú
__future__r   Úloggingrˆ   r†   re   r”   Úpathlibr   Útypingr   r   r   r   Úurllib.parser   Úhermes_cli.auth_codexr	   r
   Úhermes_cli.auth_constantsr   r   r   r   r   r   r   r   r   r   r   r   Úutilsr   r>   r   Ú	getLoggerri   rW   r&   r0   rF   rJ   rZ   ro   r}   r�   r–   rœ   r¡   r«   r±   r¹   rÎ   rÔ   r÷   rü   r  r  r  r6  rE  rl  r(  r   r"   r    Ú<module>r}     ss  ðñõ #ã Û Û Û 	Û Ý ß 5Ó 5Ý !ß ^÷÷ ÷ ó õ
 çÝ.Ø	×	Ò	Ð,Ó	-€à1€õ$õSõ6õ4Mð¨D÷ õ6Pð6)ØEIð)Ø_að)à"&ð)à9Lð)ð ÷)õD÷Nõ
Hõ4õ

õ5õ,÷Dõ*ð3pØDFð3pà!÷3pðlØHJ÷õ>Uõ2ð/Ø"ð/Ø@Dð/à*.÷/ðd"IÈu÷ "IðJÈ÷ õ$ ðF¸Tð ÐX\÷ ñ r"   