§
    øžyj²¸ ã                  ó  — U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlZddlZddlZddlmZ ddlmZmZ ddlmZmZ ddlmZmZ ddlmZ dd	lmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z& dd
l'm(Z(m)Z)m*Z* ddl+Z+ddl,m-Z-m.Z.m/Z/m0Z0 ddl1m2Z2m3Z3 ddl4m5Z5 ddl6m7Z7m8Z8m9Z9m:Z:  ej;        e<¦  «        Z=	 ddl>Z>n# e?$ r dZ>Y nw xY w	 ddl@Z@n# e?$ r dZ@Y nw xY wdZAdZBdZCdZDdZEdZFdZGeFZHdZIdZJdZKeKZLdZMdZNdZOdZPdZQdZRdZSdZTd ZUd!ZVd"ZWd#ZXd$ZYd%ZZd&Z[d'Z\d(Z]d)Z^d*Z_d+Z`d,Za	 dd-lbmcZd n# e?$ r d.ZdY nw xY wd/ed› �ZedZfd0Zgeg› d1�Zhd2Zid3Zjeg› d4�Zkd5Zld6Zmd7ZndZod8Zpd9Zqd:Zrd;Zsd<ZtdZud=Zvd> w                    d?¦  «        Zxd@dAiZydBezdC<   dDZ{dEZ|�d¿dJ„Z}�dÀdK„Z~e G dL„ dM¦  «        ¦   «         Zi dN edNdOdPeCeDeEeH¬Q¦  «        “dR edRdSdTeN¬U¦  «        “dV edVdWdXdYdZd[¬\¦  «        “d] ed]d^dTeO¬U¦  «        “d_ ed_d`dTeX¬U¦  «        “da edadbdXdcddde¬\¦  «        “df edfdgdXeYdhdi¬\¦  «        “dj edjdkdleZdm¬n¦  «        “do edodpdXdqdrds¬\¦  «        “dt edtdudXdvdwdx¬\¦  «        “dy edydzdXd{d|d}¬\¦  «        “d~ ed~ddXd€d�¬‚¦  «        “dƒ edƒd„dXe^d…d†¬\¦  «        “d‡ ed‡dˆdXd‰dŠd‹¬\¦  «        “dŒ edŒd�dXdŽd�d�¬\¦  «        “d‘ ed‘d’dXe\d“d”¬\¦  «        “d• ed•d–dXd d—d˜¬\¦  «        “i d™ ed™dšd›eSeUePeQdœeTeVd�œ¬ž¦  «        “dŸ edŸd dXd¡d¢d£¬\¦  «        “d¤ ed¤d¥dXd¦d§d¨¬\¦  «        “d© ed©dªdXd«d¬d­¬\¦  «        “d® ed®d¯dXd!d°d±¬\¦  «        “d² ed²d³dXd´dµd¶¬\¦  «        “d· ed·d¸dXdd¹dº¬\¦  «        “d» ed»d¼dXd½d¾d¿¬\¦  «        “dÀ edÀdÁdXdÂdÃdÄ¬\¦  «        “dÅ edÅdÆdXdÇdÈdÉ¬\¦  «        “dÊ edÊdËdXdÌdÍdÎ¬\¦  «        “dÏ edÏdÐdXdÑdÒdÓ¬\¦  «        “dÔ edÔdÕdXdÖd×dØ¬\¦  «        “dÙ edÙdÚdXdÛdÜdÝ¬\¦  «        “dÞ edÞdßdXdàdádâ¬\¦  «        “dã edãdädXe[dådæ¬\¦  «        “dç edçdèdédêdëdì¬\¦  «        “¥ edídîdídïdëdï¬\¦  «         edðdñdXdïdòdó¬\¦  «        dôœ¥Z€dõezdö<   	 dd÷l�m‚Zƒ  eƒ¦   «         D ]´Z„e„j…        e€v rŒe„j†        dXk    se„j‡        sŒe„j…        døv rŒ) eˆdù„ e„j‡        D ¦   «         ¦  «        Z‰ eŠdú„ e„j‡        D ¦   «         d¦  «        Z‹ ee„j…        e„jŒ        pe„j…        dXe„j�        e‰pe„j‡        e‹pdï¬\¦  «        e€e„j…        <   e„jŽ        D ]Z�e�e€vre€e„j…                 e€e�<   ŒŒµn# e?$ r Y nw xY w�dÁdû„Z�düZ‘�dÂdÿ„Z’h �d £Z“�d�dœ�dÃ�d„Z”�dÄ�d„Z•dœdv�dg�df�d�d�dg�df�d�dg �d¢�df�d�dg �d¢�dfgZ–�dÅ�d„Z—�dÆ�dÇ�d„Z˜�dÂ�d „Z™�dÀ�d!„Zš�d"Z› G �d#„ �d$eœ¦  «        Z��dÈ�d'„Zž�dÉ�d*„ZŸ�dÊ�d+„Z �dË�d,„Z¡�dÌ�d/„Z¢�dÍ�d0„Z£d�d1œ�dÎ�d6„Z¤�dÏ�d8„Z¥�dÐ�d:„Z¦�dÑ�d<„Z§�dÏ�d=„Z¨i Z©�d>ez�d?<    ejª        ¦   «         Z«�dÒ�dB„Z¬�dÓ�dE„Z­e�dÔ�dJ„¦   «         Z®eeBfd�dKœ�dÕ�dL„¦   «         Z¯�dÖ�d×�dN„Z°�dÖ�dØ�dP„Z±�dÙ�dR„Z²e�dÚ�dS„¦   «         Z³�dÛ�dU„Z´�dÜ�dW„Zµ�dÝ�dY„Z¶�dZ�d[œ�dÞ�d]„Z·�d^�d[œ�dß�d_„Z¸�dà�d`„Z¹�dá�da„Zº�dâ�db„Z»�dá�dc„Z¼�dÖ�dã�dd„Z½�deZ¾�dä�dh„Z¿d�diœ�då�dn„ZÀ�dæ�dp„ZÁ�dç�dq„ZÂ�dç�dr„ZÃ�dè�ds„ZÄ�dé�dt„ZÅ�dá�du„ZÆ�dÖ�dê�dv„ZÇ�dë�dw„ZÈ�dì�dy„ZÉ	 �dÖdd�dzœ�dí�d~„ZÊ�dî�d€„ZË�dï�dƒ„ZÌ�dð�d…„ZÍ�dñ�d†„ZÎ eÏ�d‡h¦  «        ZÐ�dˆez�d‰<    eÏh �dŠ£¦  «        ZÑ�dˆez�d‹<   �dò�d�„ZÒ eÏ�dŽh¦  «        ZÓ�dˆez�d�<   �dó�d‘„ZÔ�dé�d’„ZÕ�dé�d“„ZÖ�dô�d”„Z×�dõ�d—„ZØddeL�d˜œ�dö�dœ„ZÙddeL�d˜œ�d÷�d�„ZÚd�džœ�dø�d „ZÛd�d1œ�dù�d¡„ZÜ�dÖ�dú�d£„ZÝd�d¤œ�dû�d¦„ZÞdd�d§œ�dü�d¨„Zß eÏ�d„�d©h¦  «        Zà�dý�dª„Zá�dþ�d«„Zâ�dÏ�d¬„Zã�dÑ�d­„Zä�dÿ�d¯„Zåeof�d �d±„Zæ�d�d�d³„Zç�d�dµ„Zè�d^�dZeo�d¶œ�d�dº„Zé�dÑ�d»„Zê�dÖ�d�d½„Zë�dÖ�d�d¾„Zì	 	 �d�d�dÀ„Zí	 	 �d�d�dÁ„Zî�dÖ�d	�dÂ„Zï�dÖ�d	�dÃ„Zð�d
�d�dÆ„Zñ�d�dÈ„Zò�d
�d�dÉ„Zó�d�dÊ„Zô�d�dÏ„Zõ�d�dÑ„Zö�d�dÔ„Z÷�dÕ�dÖœ�d�dØ„Zød�dÙœ�d�dÞ„Zù�d²�dÖœ�d�dà„Zú�d²�dÖœ�d�dá„Zû�d^�dZeu�d¶œ�d�dâ„Zü�dÑ�dã„Zý�d�då„Zþ�dë�dæ„Zÿ�dÍ�dç„�Z  eÏh �dè£¦  «        �Z�dˆez�dé<   �dÍ�dê„�Z�dÁ�dë„�Zd�dìœ�d�dï„�Z�dZ�dðœ�d�dò„�Z	 �dÖ�d�dõ„�Z�d�d�d÷„�Z�d�dù„�Z�d²�dÖœ�d�dû„�Z	�d�dü„�Z
�d�dý„�Z�d^�dZef�d¶œ�d�dþ„�Z�d�d „�Z�d�Zi �Z�dez�d<    ejª        ¦   «         �Z�d�d„�Zd�e�dœ�d�d„�Z�dÖ�d �d	„�Z�d!�d
„�Z�dÁ�d„�Z�d"�d„�Z�d#�d„�Z�dZ�dðœ�d�d„�Z�d$�d„�Z�d%�d„�ZddïddP�dZ�dœ�d&�d„�Z�d'�d(�d„�Z�d)�d„�Z�d*�d„�Z�d+�d„�Z�d,�d-�d„�Z dï�d²�dœ�d.�d„�Z!dï�dœ�d/�d „�Z"�d^�dZd�d¶œ�d0�d!„�Z#�d1�d#„�Z$ddd�d$œ�d2�d(„�Z%�d3�d,„�Z&�d4�d-„�Z'�d5�d/„�Z(�d0�Z) e�j*        ¦   «         �Z+�dÏ�d1„�Z,�dÏ�d2„�Z-eeBf�d6�d3„¦   «         �Z.�d7�d4„�Z/�d%�d5„�Z0�d!�d6„�Z1�d8�d7„�Z2�d9�d9„�Z3�d9�d:„�Z4�d9�d;„�Z5�d:�d<„�Z6�d;�d=„�Z7d�dÖœ�d<�d>„�Z8�d=�d?„�Z9d�dZ�d@œ�d>�dD„�Z:�d?�dE„�Z; ejª        ¦   «         �Z<d�a=�dFez�dG<   �dH�Z>dddeK�dIœ�d@�dJ„�Z?�dKeHddddddd�d^d�dLœ�dA�dR„�Z@d�d^d�dSœ�dB�dT„�ZAd�dUœ�dC�dV„�ZB�dë�dW„�ZCddd�d^�dXœ�dD�dY„�ZD�dÑ�dZ„�ZE�dÑ�d[„�ZFd�ZGd�aH�d\ez�d]<   �dE�d_„�ZI�dë�d`„�ZJ�dÑ�da„�ZK�dÑ�db„�ZL�dÑ�dc„�ZM�dd�ZN�de�ZOd.�ZP�dÁ�df„�ZQ�dÑ�dg„�ZR�dÑ�dh„�ZS�dF�di„�ZT�dF�dj„�ZU�dÖ�dã�dk„�ZV�dÑ�dl„�ZW�dF�dm„�ZX�dF�dn„�ZY	 �dÖ�dG�dp„�ZZ�dé�dq„�Z[�dê�dr„�Z\�dê�ds„�Z]�dé�dt„�Z^�dÏ�du„�Z_dïdïdï�dvœ�dH�dy„�Z`	 	 	 	 	 	 	 	 �dI�dJ�d…„�Za�dK�d†„�Zb�dë�d‡„�Zc�d^�dˆœ�dL�dŠ„�Zd�d^�dˆœ�dL�d‹„�Zeej�dŒœ�dM�d�„�Zf�dN�dŽ„�Zg�d²�dZ�d�œ�dO�d‘„�Zh�dÑ�d’„�Zi�d“�Zj�ej�d”œ�dP�d˜„�Zk�dQ�dš„�Zl�dR�d›„�Zm�dS�dœ„�Zn�dT�dŸ„�Zo�dU�d¢„�Zp�dV�d¥„�Zq�dW�d¦„�Zrdœ�dZd�d§œ�dX�d©„�Zsd�d^�dªœ�dY�d¬„�Zt�dZ�d­„�Zu�d[�d¯„�ZveW�d^�d°œ�d\�d³„�Zw�dÑ�d´„�Zx�d]�dµ„�Zydddd�dZd�d^dd�d¶œ	�d^�d¹„�Zz�dÍ�dº„�Z{�dZdd�d»œ�d_�d¼„�Z|�d]�d½„�Z}�dë�d¾„�Z~dS (`  aÃ  
Multi-provider authentication system for Hermes Agent.

Supports OAuth device code flows (Nous Portal, future: OpenAI Codex) and
traditional API key providers (OpenRouter, custom endpoints). Auth state
is persisted in ~/.hermes/auth.json with cross-process file locking.

Architecture:
- ProviderConfig registry defines known OAuth providers
- Auth store (auth.json) holds per-provider credential state
- resolve_provider() picks the active provider via priority chain
- resolve_*_runtime_credentials() handles token refresh and runtime keys
- logout_command() is the CLI entry point for clearing auth

Nous authentication paths:
- Invoke JWT (preferred): use a scoped access_token directly for inference.
é    )ÚannotationsN)Úcontextmanager)Ú	dataclassÚfield)ÚdatetimeÚtimezone)ÚBaseHTTPRequestHandlerÚ
HTTPServer)ÚPath)ÚAnyÚCallableÚDictÚ	FrozenSetÚIterableÚListÚOptionalÚTuple)Úparse_qsÚ	urlencodeÚurlparse)Úget_hermes_homeÚget_config_pathÚread_raw_configÚ$require_readable_config_before_write)ÚOPENROUTER_BASE_URLÚsecure_parent_dir)Ú$sanitize_borrowed_credential_payload)Úatomic_replaceÚatomic_yaml_writeÚ	env_floatÚis_truthy_valueé   ç      .@zhttps://portal.nousresearch.comz)https://inference-api.nousresearch.com/v1ú
hermes-clizinference:invokezbilling:manageÚdevice_codeÚ
invoke_jwtéx   z%https://chatgpt.com/backend-api/codexzhttps://api.x.ai/v1z$78257093-7e40-4613-99e0-527b14b39113z!group_id profile model.completionz*urn:ietf:params:oauth:grant-type:user_codezhttps://api.minimax.iozhttps://api.minimaxi.comz https://api.minimax.io/anthropicz"https://api.minimaxi.com/anthropicé<   zhttps://portal.qwen.ai/v1zhttps://api.githubcopilot.comzacp://copilotzhttps://ollama.com/v1zhttps://api.actual.inc/v1zhttp://127.0.0.1:8080/v1z#https://api.stepfun.ai/step_plan/v1z$https://api.stepfun.com/step_plan/v1Úapp_EMoamEEZ73f0CkXaXp7hrannz#https://auth.openai.com/oauth/token)Ú__version__Úunknownzhermes-cli/zhttps://auth.x.aiz!/.well-known/openid-configurationz$b1a00492-073a-47ea-816f-4c329264a828z>openid profile email offline_access grok-cli:access api:accessz/oauth2/device/codei  Ú f0304373b74a44d2b584a3fb70ca9e56z(https://chat.qwen.ai/api/v1/oauth2/tokenzhttps://accounts.spotify.comzhttps://api.spotify.com/v1z'http://127.0.0.1:43827/spotify/callbackzFhttps://hermes-agent.nousresearch.com/docs/user-guide/features/spotifyz'https://developer.spotify.com/dashboardz@https://hermes-agent.nousresearch.com/docs/guides/oauth-over-sshÚ )
zuser-modify-playback-statezuser-read-playback-statezuser-read-currently-playingzuser-read-recently-playedzplaylist-read-privatezplaylist-read-collaborativezplaylist-modify-publiczplaylist-modify-privatezuser-library-readzuser-library-modifyÚspotifyÚSpotifyúDict[str, str]ÚSERVICE_PROVIDER_NAMESzdummy-lm-api-keyzdummy-actual-local-api-keyÚbase_urlÚstrÚreturnÚboolc                óª   — 	 t          | pd¦  «        j        pd                     ¦   «                              d¦  «        }n# t          $ r Y dS w xY w|dv S )z5Return True for Actual's loopback local API endpoint.Ú ú.F>   ú0.0.0.0Ú	localhostú::1ú	127.0.0.1)r   ÚhostnameÚlowerÚrstripÚ	Exception)r2   Úhosts     ú5/home/ragecks/.hermes/hermes-agent/hermes_cli/auth.pyÚis_actual_local_base_urlrC   ž   sj   € ðÝ˜˜ RÑ(Ô(Ô1Ð7°R×>Ò>Ñ@Ô@×GÒGÈÑLÔLˆˆøÝð ð ð ØˆuˆuðøøøàÐ?Ð?Ð?s   ‚=A  Á 
AÁAc                ó¨  — t          | pd¦  «                             ¦   «                              d¦  «        }|st          S 	 t	          |¦  «        }|j        pd                     ¦   «                              d¦  «        }|j                             d¦  «        }n# t          $ r |cY S w xY w|dk    r	|dv r|dz   S t          |¦  «        r	|dv r|dz   S |S )zõReturn Actual's OpenAI-compatible base URL.

    Actual hosted inference is exposed at api.actual.inc, while the Actual
    client's offline local server binds a loopback host. Both use a /v1 API
    surface for Hermes' Responses transport.
    r7   ú/r8   zapi.actual.inc>   r7   rE   ú/v1)
r3   Ústripr?   ÚDEFAULT_ACTUAL_BASE_URLr   r=   r>   Úpathr@   rC   )r2   ÚurlÚparsedrA   rI   s        rB   Únormalize_actual_base_urlrL   §   s÷   € õ ˆhˆn˜"Ñ
Ô
×
#Ò
#Ñ
%Ô
%×
,Ò
,¨SÑ
1Ô
1€CØð 'Ý&Ð&ðÝ˜#‘”ˆØ”Ð% 2×,Ò,Ñ.Ô.×5Ò5°cÑ:Ô:ˆØŒ{×!Ò! #Ñ&Ô&ˆˆøÝð ð ð Øˆ
ˆ
ˆ
ðøøøàÐÒÐ D¨IÐ$5Ð$5Ø�U‰{ÐÝ Ñ$Ô$ð ¨°Ð):Ð):Ø�U‰{ÐØ€Js   ÁAB ÂB(Â'B(c                  ó¨   — e Zd ZU dZded<   ded<   ded<   dZded<   dZded<   dZded	<   dZded
<    e	e
¬¦  «        Zded<   dZded<   dZded<   dS )ÚProviderConfigz%Describes a known inference provider.r3   ÚidÚnameÚ	auth_typer7   Úportal_base_urlÚinference_base_urlÚ	client_idÚscope)Údefault_factoryúDict[str, Any]Úextra© ÚtupleÚapi_key_env_varsÚbase_url_env_varN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__rR   rS   rT   rU   r   ÚdictrX   r[   r\   rY   ó    rB   rN   rN   Â   s¶   € € € € € € à/Ð/Ø€G€G�GØ€I€I�IØ€N€N�NØ€OÐÐÐÑØ ÐÐ Ð Ð Ñ Ø€IÐÐÐÑØ€E€O€O€O�OØ!˜E°$Ð7Ñ7Ô7€EÐ7Ð7Ð7Ñ7à ÐÐ Ð Ð Ñ àÐÐÐÐÑÐÐrc   rN   ÚnouszNous PortalÚoauth_device_code)rO   rP   rQ   rR   rS   rT   rU   úopenai-codexzOpenAI CodexÚoauth_external)rO   rP   rQ   rS   z
openai-apiz
OpenAI APIÚapi_keyzhttps://api.openai.com/v1)ÚOPENAI_API_KEYÚOPENAI_BASE_URL)rO   rP   rQ   rS   r[   r\   ú	xai-oauthz%xAI Grok OAuth (SuperGrok / Premium+)ú
qwen-oauthz
Qwen OAuthÚlmstudioz	LM Studiozhttp://127.0.0.1:1234/v1)Ú
LM_API_KEYÚLM_BASE_URLÚcopilotzGitHub Copilot)ÚCOPILOT_GITHUB_TOKENÚGH_TOKENÚGITHUB_TOKENÚCOPILOT_API_BASE_URLúcopilot-acpzGitHub Copilot ACPÚexternal_processÚCOPILOT_ACP_BASE_URL)rO   rP   rQ   rS   r\   ÚgeminizGoogle AI Studioz0https://generativelanguage.googleapis.com/v1beta)ÚGOOGLE_API_KEYÚGEMINI_API_KEYÚGEMINI_BASE_URLÚzaiz
Z.AI / GLMzhttps://api.z.ai/api/paas/v4)ÚGLM_API_KEYÚZAI_API_KEYÚZ_AI_API_KEYÚGLM_BASE_URLúkimi-codingzKimi / Moonshotzhttps://api.moonshot.ai/v1)ÚKIMI_API_KEYÚKIMI_CODING_API_KEYÚKIMI_BASE_URLúkimi-coding-cnzKimi / Moonshot (China)zhttps://api.moonshot.cn/v1)ÚKIMI_CN_API_KEY)rO   rP   rQ   rS   r[   ÚstepfunzStepFun Step Plan)ÚSTEPFUN_API_KEYÚSTEPFUN_BASE_URLÚarceezArcee AIzhttps://api.arcee.ai/api/v1)ÚARCEEAI_API_KEYÚARCEE_BASE_URLÚgmiz	GMI Cloudzhttps://api.gmi-serving.com/v1)ÚGMI_API_KEYÚGMI_BASE_URLÚactualzActual Computer)ÚACTUAL_API_KEYÚACTUAL_BASE_URLÚminimaxÚMiniMax)ÚMINIMAX_API_KEYÚMINIMAX_BASE_URLúminimax-oauthu   MiniMax (OAuth Â· minimax.io)Úoauth_minimaxÚglobal)ÚregionÚcn_portal_base_urlÚcn_inference_base_url)rO   rP   rQ   rR   rS   rT   rU   rX   Ú	anthropicÚ	Anthropiczhttps://api.anthropic.com)ÚANTHROPIC_API_KEYÚANTHROPIC_TOKENÚCLAUDE_CODE_OAUTH_TOKENÚANTHROPIC_BASE_URLÚalibabaz
Qwen Cloudz6https://dashscope-intl.aliyuncs.com/compatible-mode/v1)ÚDASHSCOPE_API_KEYÚDASHSCOPE_BASE_URLúalibaba-coding-planzAlibaba Cloud (Coding Plan)z-https://coding-intl.dashscope.aliyuncs.com/v1)ÚALIBABA_CODING_PLAN_API_KEYr¤   ÚALIBABA_CODING_PLAN_BASE_URLú
minimax-cnzMiniMax (China))ÚMINIMAX_CN_API_KEYÚMINIMAX_CN_BASE_URLÚdeepseekÚDeepSeekzhttps://api.deepseek.com/v1)ÚDEEPSEEK_API_KEYÚDEEPSEEK_BASE_URLÚxaiÚxAI)ÚXAI_API_KEYÚXAI_BASE_URLÚnvidiaz
NVIDIA NIMz#https://integrate.api.nvidia.com/v1)ÚNVIDIA_API_KEYÚNVIDIA_BASE_URLú
ai-gatewayzVercel AI Gatewayzhttps://ai-gateway.vercel.sh/v1)ÚAI_GATEWAY_API_KEYÚAI_GATEWAY_BASE_URLúopencode-zenzOpenCode Zenzhttps://opencode.ai/zen/v1)ÚOPENCODE_ZEN_API_KEYÚOPENCODE_ZEN_BASE_URLúopencode-gozOpenCode Gozhttps://opencode.ai/zen/go/v1)ÚOPENCODE_GO_API_KEYÚOPENCODE_GO_BASE_URLÚkilocodez	Kilo Codezhttps://api.kilo.ai/api/gateway)ÚKILOCODE_API_KEYÚKILOCODE_BASE_URLÚhuggingfacezHugging Facez https://router.huggingface.co/v1)ÚHF_TOKENÚHF_BASE_URLÚxiaomizXiaomi MiMozhttps://api.xiaomimimo.com/v1)ÚXIAOMI_API_KEYÚXIAOMI_BASE_URLútencent-tokenhubzTencent TokenHubz#https://tokenhub.tencentmaas.com/v1)ÚTOKENHUB_API_KEYÚTOKENHUB_BASE_URLúollama-cloudzOllama Cloud)ÚOLLAMA_API_KEYÚOLLAMA_BASE_URLÚbedrockzAWS BedrockÚaws_sdkz/https://bedrock-runtime.us-east-1.amazonaws.comrY   ÚBEDROCK_BASE_URLÚvertexzGoogle Vertex AIr7   úazure-foundryzAzure Foundry)ÚAZURE_FOUNDRY_API_KEYÚAZURE_FOUNDRY_BASE_URL)rÒ   rÓ   zDict[str, ProviderConfig]ÚPROVIDER_REGISTRY©Úlist_providers>   r|   Úcustomrp   Ú
openrouterr�   r…   c              #  ón   K  — | ]0}|                      d ¦  «        °|                      d¦  «        °,|V — Œ1dS ©Ú	_BASE_URLÚ_URLN©Úendswith©Ú.0Úvs     rB   ú	<genexpr>rä     sH   è è € ÐpÐp A¸Q¿ZºZÈÑ=TÔ=TÐpÐ]^×]gÒ]gÐhnÑ]oÔ]oÐp˜aÐpÐpÐpÐpÐpÐprc   c              #  ón   K  — | ]0}|                      d ¦  «        s|                      d¦  «        ¯,|V — Œ1dS rÜ   rß   rá   s     rB   rä   rä     sH   è è € ÐgÐg A¸¿ºÀKÑ9PÔ9PÐgÐTU×T^ÒT^Ð_eÑTfÔTfÐg˜aÐgÐgÐgÐgÐgÐgrc   c                 ób   — ddl m}  t          d         j        D ]} | |¦  «        pd}|r|c S ŒdS )uÀ  Return the first usable Anthropic credential, or ``""``.

    Checks both the ``.env`` file and the process environment, preferring
    ``~/.hermes/.env`` so a deliberate key rotation isn't shadowed by a stale
    shell export (matches the api-key resolution path â€” see #20591).  The
    order mirrors the ``PROVIDER_REGISTRY["anthropic"].api_key_env_vars``
    tuple:

        ANTHROPIC_API_KEY -> ANTHROPIC_TOKEN -> CLAUDE_CODE_OAUTH_TOKEN
    r   ©Úget_env_value_prefer_dotenvr�   r7   )Úhermes_cli.configrè   rÖ   r[   )rè   ÚvarÚvalues      rB   Úget_anthropic_keyrì   $  s]   € ð >Ð=Ð=Ð=Ð=Ð=å  Ô-Ô>ð ð ˆØ+Ð+¨CÑ0Ô0Ð6°BˆØð 	ØˆLˆLˆLð	àˆ2rc   zhttps://api.kimi.com/codingÚdefault_urlÚenv_overridec                óN   — |r|S | s|S |                       d¦  «        rt          S |S )zÎReturn the correct Kimi base URL based on the API key prefix.

    If the user has explicitly set KIMI_BASE_URL, that always wins.
    Otherwise, sk-kimi- prefixed keys route to api.kimi.com/coding/v1.
    zsk-kimi-)Ú
startswithÚKIMI_CODE_BASE_URL)rh   rí   rî   s      rB   Ú_resolve_kimi_base_urlrò   I  sB   € ð ð ØÐàð ØÐØ×Ò˜*Ñ%Ô%ð "Ý!Ð!ØÐrc   >   ú**ú***úyour-api-keyÚ*ÚnoneÚnullÚdummyÚexampleÚchangemeÚplaceholderÚyour_api_keyÚyour_api_key_hereé   )Ú
min_lengthrë   r   r   Úintc               óÀ   — t          | t          ¦  «        sdS |                      ¦   «         }t          |¦  «        |k     rdS |                     ¦   «         t
          v rdS dS )zIReturn True when a configured secret looks usable, not empty/placeholder.FT)Ú
isinstancer3   rG   Úlenr>   Ú_PLACEHOLDER_SECRET_VALUES)rë   r   Úcleaneds      rB   Úhas_usable_secretr  j  sZ   € å�e�SÑ!Ô!ð ØˆuØ�kŠk‰mŒm€GÝ
ˆ7�|„|�jÒ Ð ØˆuØ‡}‚}�„Õ4Ð4Ð4ØˆuØˆ4rc   Úprovider_idÚpconfigútuple[str, str]c                ó¾  — | dk    rj	 ddl m}m}  |¦   «         \  }}|r ||¦  «        \  }}||fS n=# t          $ r%}t                               d|¦  «         Y d}~nd}~wt          $ r Y nw xY wdS ddlm}	 |j	        D ]6}
 |	|
¦  «        pd 
                    ¦   «         }t          |¦  «        r||
fc S Œ7	 dd	lm}  || ¦  «        }|rƒ|                     ¦   «         ro|                     ¦   «         }|rYt!          |d
d¦  «        pt!          |dd¦  «        }t#          |¦  «         
                    ¦   «         }t          |¦  «        r|d| › �fS n# t          $ r Y nw xY wdS )zDResolve an API-key provider's token and indicate where it came from.rp   r   ©Úresolve_copilot_tokenÚget_copilot_api_tokenz#Copilot token validation failed: %sN)r7   r7   rç   r7   ©Ú	load_poolÚaccess_tokenÚruntime_api_keyzcredential_pool:)Úhermes_cli.copilot_authr  r  Ú
ValueErrorÚloggerÚwarningr@   ré   rè   r[   rG   r  Úagent.credential_poolr  Úhas_credentialsÚpeekÚgetattrr3   )r  r	  r  r  ÚtokenÚsourceÚ	api_tokenÚ	_base_urlÚexcrè   Úenv_varÚvalr  ÚpoolÚentryÚkeys                   rB   Ú _resolve_api_key_provider_secretr%  v  s  € ð �iÒÐð		Ø\Ð\Ð\Ð\Ð\Ð\Ð\Ð\Ø1Ð1Ñ3Ô3‰MˆE�6Øð )Ø'<Ð'<¸UÑ'CÔ'CÑ$�	˜9Ø  &Ð(Ð(ð)øõ ð 	Gð 	Gð 	GÝ�NŠNÐ@À#ÑFÔFÐFÐFÐFÐFÐFÐFøøøøÝð 	ð 	ð 	ØˆDð	øøøàˆvà=Ð=Ð=Ð=Ð=Ð=ØÔ+ð  ð  ˆð +Ð*¨7Ñ3Ô3Ð9°r×@Ò@ÑBÔBˆÝ˜SÑ!Ô!ð 	 Ø˜�<ÐÐÐð	 ðØ3Ð3Ð3Ð3Ð3Ð3Øˆy˜Ñ%Ô%ˆØð 	A�D×(Ò(Ñ*Ô*ð 	AØ—I’I‘K”KˆEØð AÝ˜e ^°RÑ8Ô8Ða½GÀEÐK\Ð^`Ñ<aÔ<a�Ý˜#‘h”h—n’nÑ&Ô&�Ý$ SÑ)Ô)ð AØÐ @°;Ð @Ð @Ð@Ð@øøÝð ð ð Øˆðøøøð ˆ6s-   ˆ(2 ²
A,¼AÁA,Á+A,Â6BE Å
EÅEzglm-5ÚGlobalÚcnz$https://open.bigmodel.cn/api/paas/v4ÚChinazcoding-globalz#https://api.z.ai/api/coding/paas/v4)zglm-5.2zglm-5.1zglm-5v-turbozglm-4.7zGlobal (Coding Plan)z	coding-cnz+https://open.bigmodel.cn/api/coding/paas/v4zChina (Coding Plan)ÚendpointrZ   ÚtimeoutÚfloatúOptional[Dict[str, str]]c                ó‚  — |\  }}}}|D ]´}	 t          j        |› d�d| › �ddœ|ddddd	œgd
œ|¬¦  «        }|j        dk    r&t                               d|||¦  «         ||||dœc S t                               d|||j        ¦  «         Œ�# t
          $ r'}	t                               d|||	¦  «         Y d}	~	Œ­d}	~	ww xY wdS )a  Probe a single Z.AI endpoint. Returns endpoint info dict or None.

    Preserves the per-endpoint candidate-model loop: endpoints carry a
    ``probe_models`` LIST and each model is tried in order until one
    succeeds (some plans only accept newer/older GLM slugs).
    z/chat/completionsúBearer úapplication/json)ÚAuthorizationúContent-TypeFr"   ÚuserÚping)ÚroleÚcontent)ÚmodelÚstreamÚ
max_tokensÚmessages)ÚheadersÚjsonr*  éÈ   z(Z.AI endpoint probe: %s (%s) model=%s OK)rO   r2   r6  Úlabelz,Z.AI endpoint probe: %s model=%s returned %sz+Z.AI endpoint probe: %s model=%s failed: %sN)ÚhttpxÚpostÚstatus_coder  Údebugr@   )
rh   r)  r*  Úep_idr2   Úprobe_modelsr=  r6  Úrespr  s
             rB   Ú_probe_single_zai_endpointrE  ¶  sO  € ð ,4Ñ(€Eˆ8�\ 5Øð [ð [ˆð	[Ý”:ØÐ.Ð.Ð.à%8¨wÐ%8Ð%8Ø$6ðð ð
 #Ø#Ø"#Ø*0¸VÐ!DÐ!DÐ Eð	ð ð  ðñ ô ˆDð Ô 3Ò&Ð&Ý—’ÐGÈÐPXÐZ_Ñ`Ô`Ð`àØ (Ø"Ø"ð	ð ð ð ð õ �LŠLÐGÈÐPUÐW[ÔWgÑhÔhÐhÐhøÝð 	[ð 	[ð 	[Ý�LŠLÐFÈÈuÐVYÑZÔZÐZÐZÐZÐZÐZÐZøøøøð	[øøøàˆ4s   �ABÁ("BÂ
B<ÂB7Â7B<ç       @c                óÞ  ‡ ‡‡— ddl m}m}  |t          t          ¦  «        ¬¦  «        Š	 ˆ ˆˆfd„t          D ¦   «         }d„ |                     ¦   «         D ¦   «         }i } ||¦  «        D ]•}||         }	 |                     ¦   «         }	|	�|	||<   n# t          $ r Y nw xY wt          D ]V}
||
d                                       ¦   «         s n3|
d         |v r(||
d                  c c ‰ 	                    d¬¦  «         S ŒWŒ–t          D ]2}
|
d         |v r&||
d                  c ‰ 	                    d¬¦  «         S Œ3	 ‰ 	                    d¬¦  «         dS # ‰ 	                    d¬¦  «         w xY w)	az  Probe z.ai endpoints in parallel to find one that accepts this API key.

    Returns {"id": ..., "base_url": ..., "model": ..., "label": ...} for the
    first working endpoint (in ZAI_ENDPOINTS priority order), or None if all
    fail.  For endpoints with multiple candidate models, each worker tries
    its endpoint's models in order and returns the first that succeeds.
    r   )ÚThreadPoolExecutorÚas_completed)Úmax_workersc                óX   •— i | ]&}‰                      t          ‰|‰¦  «        |d          “Œ'S ©r   )ÚsubmitrE  )râ   Úeprh   r"  r*  s     €€€rB   ú
<dictcomp>z'detect_zai_endpoint.<locals>.<dictcomp>î  sB   ø€ ð 
ð 
ð 
àð �KŠKÕ2°G¸RÀÑIÔIÈ2ÈaÌ5ð
ð 
ð 
rc   c                ó   — i | ]\  }}||“Œ	S rY   rY   )râ   ÚfrB  s      rB   rO  z'detect_zai_endpoint.<locals>.<dictcomp>ò  s   € Ð:Ð:Ð:™h˜a �˜Ð:Ð:Ð:rc   NF)Úwait)
Úconcurrent.futuresrH  rI  r  ÚZAI_ENDPOINTSÚitemsÚresultr@   ÚdoneÚshutdown)rh   r*  rH  rI  ÚfuturesÚby_idÚresultsÚfuturerB  rV  rN  r"  s   ``         @rB   Údetect_zai_endpointr]  Þ  s÷  øøø€ ð DÐCÐCÐCÐCÐCÐCÐCð Ð­#­mÑ*<Ô*<Ð=Ñ=Ô=€Dð "ð
ð 
ð 
ð 
ð 
ð 
å#ð
ñ 
ô 
ˆð ;Ð:¨'¯-ª-©/¬/Ð:Ñ:Ô:ˆØ-/ˆØ"�l 7Ñ+Ô+ð 	*ð 	*ˆFØ˜F”OˆEðØŸš™œ�ØÐ%Ø%+�G˜E‘NøøÝð ð ð Ø�ðøøøõ $ð *ð *�Ø˜R œU”|×(Ò(Ñ*Ô*ð Ø�EØ�a”5˜GÐ#Ð#Ø" 2 a¤5œ>Ð)Ð)Ð)Ð)ð 	�Š˜5ˆÑ!Ô!Ð!Ð!ð $øõ  ð 	&ð 	&ˆBØ�!Œu˜ÐÐØ˜r !œu”~Ð%Ð%ð 	�Š˜5ˆÑ!Ô!Ð!Ð!ð	  àà�Š˜5ˆÑ!Ô!Ð!Ð!Ð!øˆ�Š˜5ˆÑ!Ô!Ð!Ð!øøøs=   «A
E Á6BÂE Â
BÂE ÂBÂA	E Ã?$E Ä:E ÅE,c                ó  — |r|S | s|S t          ¦   «         }t          |d¦  «        pi }|                     d¦  «        }t          |t          ¦  «        r˜|                     d¦  «        rƒ|                     dd¦  «        }|t          j        |                      ¦   «         ¦  «                             ¦   «         dd…         k    r)t           
                    d|d         ¦  «         |d         S t          | ¦  «        }|�rq|                     d¦  «        �r[t          j        |                      ¦   «         ¦  «                             ¦   «         dd…         }|d         |                     d	d¦  «        |                     d
d¦  «        |                     dd¦  «        |dœ}	 t          ¦   «         5  t          ¦   «         }t          |d¦  «        pi }	||	d<   t          |d|	d¬¦  «         t          |¦  «         ddd¦  «         n# 1 swxY w Y   n2# t          $ r%}
t                               d|
¦  «         Y d}
~
nd}
~
ww xY wt                               d|d         |d         ¦  «         |d         S t           
                    d|¦  «         |S )aY  Return the correct Z.AI base URL by probing endpoints.

    If the user has explicitly set GLM_BASE_URL, that always wins.
    Otherwise, probe the candidate endpoints to find one that accepts the
    key.  The detected endpoint is cached in provider state (auth.json) keyed
    on a hash of the API key so subsequent starts skip the probe.
    r|   Údetected_endpointr2   Úkey_hashr7   Né   zZ.AI: using cached endpoint %srO   r6  r=  )r2   Úendpoint_idr6  r=  r`  F©Ú
set_activezHZ.AI: could not persist detected endpoint (%s); will re-probe next startz$Z.AI: auto-detected endpoint %s (%s)z.Z.AI: probe failed, falling back to default %s)Ú_load_auth_storeÚ_load_provider_stateÚgetr  rb   ÚhashlibÚsha256ÚencodeÚ	hexdigestr  rA  r]  Ú_auth_store_lockÚ_store_provider_stateÚ_save_auth_storer@   r  Úinfo)rh   rí   rî   Ú
auth_storeÚstateÚcachedr`  Údetectedr_  Ústate_under_lockr  s              rB   Ú_resolve_zai_base_urlru    sØ  € ð ð ØÐð ð ØÐõ "Ñ#Ô#€JÝ  ¨UÑ3Ô3Ð9°r€EØ�YŠYÐ*Ñ+Ô+€FÝ�&�$ÑÔð & F§J¢J¨zÑ$:Ô$:ð &Ø—:’:˜j¨"Ñ-Ô-ˆØ•w”~ g§n¢nÑ&6Ô&6Ñ7Ô7×AÒAÑCÔCÀCÀRÀCÔHÒHÐHÝ�LŠLÐ9¸6À*Ô;MÑNÔNÐNØ˜*Ô%Ð%õ # 7Ñ+Ô+€HØñ $�H—L’L Ñ,Ô,ñ $å”> '§.¢.Ñ"2Ô"2Ñ3Ô3×=Ò=Ñ?Ô?ÀÀÀÔDˆà  Ô,Ø#Ÿ<š<¨¨bÑ1Ô1Ø—\’\ '¨2Ñ.Ô.Ø—\’\ '¨2Ñ.Ô.Ø ð
ð 
Ðð	lÝ!Ñ#Ô#ð 	-ð 	-å-Ñ/Ô/�
Ý#7¸
ÀEÑ#JÔ#JÐ#PÈbÐ Ø8IÐ Ð!4Ñ5õ & j°%Ð9IÐV[Ð\Ñ\Ô\Ð\Ý  Ñ,Ô,Ð,ð	-ð 	-ð 	-ñ 	-ô 	-ð 	-ð 	-ð 	-ð 	-ð 	-ð 	-øøøð 	-ð 	-ð 	-ð 	-øøõ ð 	lð 	lð 	lÝ�NŠNÐeÐgjÑkÔkÐkÐkÐkÐkÐkÐkøøøøð	løøøå�ŠÐ:¸HÀWÔ<MÈxÐXbÔOcÑdÔdÐdØ˜
Ô#Ð#å
‡L‚LÐAÀ;ÑOÔOÐOØÐs=   ÆH Æ,AH Ç4H È HÈH ÈHÈH È
H;ÈH6È6H;c                ó
  — t          | pd¦  «                             ¦   «                              d¦  «        }dD ]D}|                     |¦  «        r-|dt	          |¦  «         …                              d¦  «        } nŒE|pddz   S )aP  Return the OpenAI-compatible LM Studio runtime base URL.

    LM Studio's native management API lives under ``/api/v1`` while its
    OpenAI-compatible chat endpoint lives under ``/v1``. Users often paste
    either form into ``LM_BASE_URL`` or ``model.base_url``; normalize before
    the OpenAI SDK appends ``/chat/completions``.
    r7   rE   )z/api/v1z/apirF   Nzhttp://127.0.0.1:1234rF   )r3   rG   r?   rà   r  )r2   ÚrootÚsuffixs      rB   Ú$_normalize_lmstudio_runtime_base_urlry  P  s“   € õ ˆxˆ~˜2ÑÔ×$Ò$Ñ&Ô&×-Ò-¨cÑ2Ô2€DØ,ð ð ˆØ�=Š=˜Ñ Ô ð 	Ø˜�3˜v™;œ;˜,˜Ô'×.Ò.¨sÑ3Ô3ˆDØˆEð	ð Ð+Ð+¨uÑ4Ð4rc   Úcodex_rate_limitedc                  ó.   ‡ — e Zd ZdZddddœdˆ fd„Zˆ xZS )Ú	AuthErrorz,Structured auth error with UX mapping hints.r7   NF©ÚproviderÚcodeÚrelogin_requiredÚmessager3   r~  r  úOptional[str]r€  r5   r4   ÚNonec               ót   •— t          ¦   «                              |¦  «         || _        || _        || _        d S ©N)ÚsuperÚ__init__r~  r  r€  )Úselfr�  r~  r  r€  Ú	__class__s        €rB   r‡  zAuthError.__init__m  s9   ø€ õ 	‰Œ×Ò˜Ñ!Ô!Ð!Ø ˆŒØˆŒ	Ø 0ˆÔÐÐrc   )
r�  r3   r~  r3   r  r‚  r€  r5   r4   rƒ  )r]   r^   r_   r`   r‡  Ú__classcell__)r‰  s   @rB   r|  r|  j  sX   ø€ € € € € Ø6Ð6ð Ø"Ø!&ð1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1rc   r|  Úerrorr@   c                ó\   — t          | t          ¦  «        o| j         o| j        t          k    S )uh  True when an :class:`AuthError` represents upstream rate-limiting / quota
    exhaustion rather than missing or invalid credentials.

    These failures are transient â€” re-authenticating cannot resolve them â€” so
    callers should surface a "retry later" notice and prefer a fallback chain
    instead of prompting the operator to run ``hermes auth``.
    )r  r|  r€  r  ÚCODEX_RATE_LIMITED_CODE©r‹  s    rB   Úis_rate_limited_auth_errorr�  {  s4   € õ 	�5�)Ñ$Ô$ð 	2ØÔ&Ð&ð	2àŒJÕ1Ò1ðrc   r:  úOptional[int]c                óJ   — ddl m}  || ¦  «        }|€dnt          |¦  «        S )a  Best-effort parse of a ``Retry-After`` header into whole seconds.

    Thin wrapper around :func:`agent.retry_utils.parse_retry_after_seconds`
    (delta-seconds and HTTP-date forms; negatives clamp to 0; missing or
    unparseable values return ``None``).
    r   )Úparse_retry_after_secondsN)Úagent.retry_utilsr’  r  )r:  r’  Úsecondss      rB   Ú_parse_retry_after_secondsr•  Š  s:   € ð <Ð;Ð;Ð;Ð;Ð;à'Ð'¨Ñ0Ô0€GØ�?ˆ4ˆ4­¨G©¬Ð4rc   c                ó¾  — t          | t          ¦  «        st          | ¦  «        S t          | ¦  «        rt          | ¦  «        S | j        r| › d�S | j        dk    r| j        dk    rt          | ¦  «        S dS | j        dk    r| j        dk    rt          | ¦  «        S dS | j        dv r| j        dk    rt          | ¦  «        S | j        dk    r| › d	�S t          | ¦  «        S )
z2Map auth failures to concise user-facing guidance.z' Run `hermes model` to re-authenticate.Úsubscription_requiredrd   zWNo active paid subscription found. Please purchase/activate a subscription, then retry.Úinsufficient_creditszESubscription credits are exhausted. Top up/renew credits, then retry.>   Úaccount_missingÚno_usable_creditsÚsubscription_expiredÚmember_spend_cap_exceededÚtemporarily_unavailablez Please retry in a few seconds.)r  r|  r3   r�  r€  r  r~  Ú#_format_nous_entitlement_auth_errorrŽ  s    rB   Úformat_auth_errorrŸ  —  s	  € å�e�YÑ'Ô'ð Ý�5‰zŒzÐõ " %Ñ(Ô(ð Ý�5‰zŒzÐàÔð AØÐ@Ð@Ð@Ð@à„zÐ,Ò,Ð,ØŒ>˜VÒ#Ð#Ý6°uÑ=Ô=Ð=ØhÐhà„zÐ+Ò+Ð+ØŒ>˜VÒ#Ð#Ý6°uÑ=Ô=Ð=ØVÐVà„zÐrÐrÐrØŒ>˜VÒ#Ð#Ý6°uÑ=Ô=Ð=à„zÐ.Ò.Ð.ØÐ8Ð8Ð8Ð8åˆu‰:Œ:Ðrc   c                óz   — 	 ddl m}m}  |d¬¦  «        } ||d¬¦  «        }|r|S n# t          $ r Y nw xY w| › d�S )Nr   ©Ú&format_nous_portal_entitlement_messageÚget_nous_portal_account_infoT©Úforce_freshzNous model access©Ú
capabilityz5 Check credits or billing in Nous Portal, then retry.)Úhermes_cli.nous_accountr¢  r£  r@   )r‹  r¢  r£  Úaccount_infor�  s        rB   rž  rž  ¸  s¤   € ðð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð
 4Ð3ÀÐEÑEÔEˆØ8Ð8ØØ*ð
ñ 
ô 
ˆð ð 	ØˆNð	øåð ð ð ØˆðøøøàÐJÐJÐJÐJs   ‚$( ¨
5´5r  r‚  c                óâ   — t          | t          ¦  «        sdS |                      ¦   «         }|sdS t          j        |                     d¦  «        ¦  «                             ¦   «         dd…         S )zJReturn a short hash fingerprint for telemetry without leaking token bytes.Núutf-8é   )r  r3   rG   rh  ri  rj  rk  )r  r  s     rB   Ú_token_fingerprintr­  Ë  sd   € å�e�SÑ!Ô!ð ØˆtØ�kŠk‰mŒm€GØð ØˆtÝŒ>˜'Ÿ.š.¨Ñ1Ô1Ñ2Ô2×<Ò<Ñ>Ô>¸sÀ¸sÔCÐCrc   c                 ó|   — t          j        dd¦  «                             ¦   «                              ¦   «         } | dv S )NÚHERMES_OAUTH_TRACEr7   >   Ú1ÚonÚyesÚtrue)ÚosÚgetenvrG   r>   )Úraws    rB   Ú_oauth_trace_enabledr·  Õ  s8   € Ý
Œ)Ð(¨"Ñ
-Ô
-×
3Ò
3Ñ
5Ô
5×
;Ò
;Ñ
=Ô
=€CØÐ,Ð,Ð,rc   )Úsequence_idÚeventr¸  Úfieldsrƒ  c               óÆ   — t          ¦   «         sd S d| i}|r||d<   |                     |¦  «         t                               dt	          j        |dd¬¦  «        ¦  «         d S )Nr¹  r¸  zoauth_trace %sTF©Ú	sort_keysÚensure_ascii)r·  Úupdater  ro  r;  Údumps)r¹  r¸  rº  Úpayloads       rB   Ú_oauth_tracerÂ  Ú  sp   € ÝÑ!Ô!ð ØˆØ&¨Ð.€GØð -Ø!,ˆ�ÑØ‡N‚N�6ÑÔÐÝ
‡K‚KÐ ¥$¤*¨WÀÐSXÐ"YÑ"YÔ"YÑZÔZÐZÐZÐZrc   r   c                 óF  — t          ¦   «         dz  } t          j                             d¦  «        rpt	          j        ¦   «         dz  dz                       d¬¦  «        }	 |                      d¬¦  «        }n# t          $ r | }Y nw xY w||k    rt          d| › d�¦  «        ‚| S )Nú	auth.jsonÚPYTEST_CURRENT_TESTú.hermesF©Ústrictz8Refusing to touch real user auth store during test run: zq. Set HERMES_HOME to a tmp_path in your test fixture, or run via scripts/run_tests.sh for hermetic CI-parity env.)	r   r´  Úenvironrg  r   ÚhomeÚresolver@   ÚRuntimeError)rI   Úreal_home_authÚresolveds      rB   Ú_auth_file_pathrÏ  è  sÎ   € ÝÑÔ˜{Ñ*€Dõ 
„z‡~‚~Ð+Ñ,Ô,ð Ýœ)™+œ+¨	Ñ1°KÑ?×HÒHÐPUÐHÑVÔVˆð	Ø—|’|¨5�|Ñ1Ô1ˆHˆHøÝð 	ð 	ð 	ØˆHˆHˆHð	øøøà�~Ò%Ð%ÝðGÈ4ð Gð Gð Gñô ð ð
 €Ks   ÁA6 Á6BÂBúOptional[Path]c                 ó  — 	 ddl m}   | ¦   «         }n# t          $ r Y dS w xY wt          ¦   «         }	 |                     d¬¦  «        |                     d¬¦  «        k    rdS n# t          $ r ||k    rY dS Y nw xY w|dz  S )a­  Return the global-root auth.json when the process is in profile mode.

    Returns ``None`` when the profile and global root resolve to the same
    directory (classic mode, or custom HERMES_HOME that is not a profile).
    Used by read-only fallback paths so providers authed at the root are
    visible to profile processes that haven't configured them locally.

    See issue #18594 follow-up (credential_pool shadowing).
    r   ©Úget_default_hermes_rootNFrÇ  rÄ  )Úhermes_constantsrÓ  r@   r   rË  )rÓ  Úglobal_rootÚprofile_homes      rB   Ú_global_auth_file_pathr×  þ  sÕ   € ðØ<Ð<Ð<Ð<Ð<Ð<Ø-Ð-Ñ/Ô/ˆˆøÝð ð ð Øˆtˆtðøøøå"Ñ$Ô$€LðØ×Ò uÐÑ-Ô-°×1DÒ1DÈEÐ1DÑ1RÔ1RÒRÐRØ�4ð Søåð ð ð Ø˜;Ò&Ð&Ø�4�4ð 'Ð&ðøøøð ˜Ñ$Ð$s   ‚ “
! !³.A$ Á$A:Á9A:rW   c                 óÂ  — t          ¦   «         } | �|                      ¦   «         si S t          j                             d¦  «        ryt          j                             dd¦  «        }|rWt          |¦  «        dz  dz  }	 |                      d¬¦  «        |                     d¬¦  «        k    ri S n# t          $ r Y nw xY w	 t          | ¦  «        S # t          $ r i cY S w xY w)	a8  Load the global-root auth store (read-only fallback).

    Returns an empty dict when no global fallback exists (classic mode,
    or the global auth.json is absent). Never raises on missing file.

    Seat belt: under pytest, refuses to read the real user's
    ``~/.hermes/auth.json`` even when HERMES_HOME is set to a profile
    path. The hermetic conftest does not redirect ``HOME``, so
    ``get_default_hermes_root()`` for a profile-shaped HERMES_HOME can
    still resolve to the real user's home on a dev machine. That would
    leak real credentials into tests. This guard uses the unmodified
    ``HOME`` env var (what ``os.path.expanduser('~')`` would resolve to),
    not ``Path.home()``, because ``Path.home`` is sometimes monkeypatched
    by fixtures that want to relocate the global root to a tmp path.
    NrÅ  ÚHOMEr7   rÆ  rÄ  FrÇ  )	r×  Úexistsr´  rÉ  rg  r   rË  r@   re  )Úglobal_pathÚreal_home_envÚ	real_roots      rB   Ú_load_global_auth_storerÞ    s  € õ  )Ñ*Ô*€KØÐ +×"4Ò"4Ñ"6Ô"6ÐØˆ	Ý	„z‡~‚~Ð+Ñ,Ô,ð Ýœ
Ÿš v¨rÑ2Ô2ˆØð 	Ý˜]Ñ+Ô+¨iÑ7¸+ÑEˆIðØ×&Ò&¨eÐ&Ñ4Ô4¸	×8IÒ8IÐQVÐ8IÑ8WÔ8WÒWÐWØ�Ið Xøåð ð ð Ø�ðøøøðÝ Ñ,Ô,Ð,øÝð ð ð ð ˆ	ˆ	ˆ	ðøøøs$   Á>/B/ Â/
B<Â;B<Ã C ÃCÃCc                 óD   — t          ¦   «                              d¦  «        S )Nú.lock)rÏ  Úwith_suffixrY   rc   rB   Ú_auth_lock_pathrâ  A  s   € ÝÑÔ×(Ò(¨Ñ1Ô1Ð1rc   zDict[str, threading.local]Ú_auth_target_lock_holdersÚleftÚrightc                óŒ   — 	 |                       d¬¦  «        |                      d¬¦  «        k    S # t          $ r	 | |k    cY S w xY w©NFrÇ  )rË  r@   )rä  rå  s     rB   Ú
_same_pathrè  I  sY   € ðØ�|Š| 5ˆ|Ñ)Ô)¨U¯]ª]À%¨]Ñ-HÔ-HÒHÐHøÝð ð ð Ø�uŠ}ÐÐÐðøøøs   ‚-0 °AÁAÚtarget_pathúthreading.localc                ó$  — 	 t          |                      d¬¦  «        ¦  «        }n# t          $ r t          | ¦  «        }Y nw xY wt          5  t                               |t          j        ¦   «         ¦  «        cddd¦  «         S # 1 swxY w Y   dS )zCReturn a reentrancy tracker keyed to one canonical auth-store path.FrÇ  N)r3   rË  r@   Ú_auth_target_lock_holders_guardrã  Ú
setdefaultÚ	threadingÚlocal)ré  r$  s     rB   Ú_auth_lock_holder_forrð  P  sì   € ðÝ�+×%Ò%¨UÐ%Ñ3Ô3Ñ4Ô4ˆˆøÝð ð ð Ý�+ÑÔˆˆˆðøøøå	(ð Lð LÝ(×3Ò3°C½¼Ñ9JÔ9JÑKÔKðLð Lð Lð Lñ Lô Lð Lð Lð Lð Lð Lð Løøøð Lð Lð Lð Lð Lð Ls!   ‚#& ¦AÁAÁ,BÂB	ÂB	Ú	lock_pathÚholderÚtimeout_secondsÚtimeout_messagec              #  ó’  K  — t          |dd¦  «        dk    r=|xj        dz  c_        	 dV — |xj        dz  c_        n# |xj        dz  c_        w xY wdS | j                             dd¬¦  «         t          €)t
          €"d|_        	 dV — d|_        n# d|_        w xY wdS t
          rH|                      ¦   «         r|                      ¦   «         j        dk    r|  	                    dd¬	¦  «         |  
                    t
          rd
ndd¬	¦  «        5 }t          j        ¦   «         t          d|¦  «        z   }	 	 t          r?t	          j        |                     ¦   «         t          j        t          j        z  ¦  «         nG|                     d¦  «         t          j        |                     ¦   «         t
          j        d¦  «         nX# t*          t,          t.          f$ r= t          j        ¦   «         |k    rt1          |¦  «        ‚t          j        d¦  «         Y nw xY wŒçd|_        	 dV — d|_        t          rL	 t	          j        |                     ¦   «         t          j        ¦  «         �nD# t,          t6          f$ r Y �n0w xY wt
          r`	 |                     d¦  «         t          j        |                     ¦   «         t
          j        d¦  «         nÜ# t,          t6          f$ r Y nÉw xY wnÄ# d|_        t          rJ	 t	          j        |                     ¦   «         t          j        ¦  «         w # t,          t6          f$ r Y w w xY wt
          r`	 |                     d¦  «         t          j        |                     ¦   «         t
          j        d¦  «         w # t,          t6          f$ r Y w w xY ww xY wddd¦  «         dS # 1 swxY w Y   dS )u¸  Cross-process advisory flock helper.

    Reentrant per-thread via ``holder.depth``. Falls back to a depth-only
    guard when neither ``fcntl`` nor ``msvcrt`` is available (rare).
    Callers supply their own ``threading.local`` so independent locks
    (e.g. profile auth.json vs shared Nous store) don't share reentrancy
    state â€” that would let one lock's reentrant acquisition silently skip
    the other's kernel-level flock.
    Údepthr   r"   NT©ÚparentsÚexist_okr-   r«  ©Úencodingzr+za+ç      ð?gš™™™™™©?)r  rö  ÚparentÚmkdirÚfcntlÚmsvcrtrÚ  ÚstatÚst_sizeÚ
write_textÚopenÚtimeÚ	monotonicÚmaxÚflockÚfilenoÚLOCK_EXÚLOCK_NBÚseekÚlockingÚLK_NBLCKÚBlockingIOErrorÚOSErrorÚPermissionErrorÚTimeoutErrorÚsleepÚLOCK_UNÚIOErrorÚLK_UNLCK)rñ  rò  ró  rô  Ú	lock_fileÚdeadlines         rB   Ú
_file_lockr  Z  s3  è è € õ  ˆv�w Ñ"Ô" QÒ&Ð&ØˆŒ˜ÑˆŒð	ØˆEˆEˆEàˆLŒL˜AÑˆLŒLˆLøˆFˆLŒL˜AÑˆLŒLˆLˆLˆLˆLØˆàÔ×Ò 4°$ÐÑ7Ô7Ð7å€}�˜ØˆŒð	ØˆEˆEˆEàˆFŒLˆLø˜1ˆFŒLÐÐÐÐØˆõ ð 4�y×'Ò'Ñ)Ô)ð 4¨Y¯^ª^Ñ-=Ô-=Ô-EÈÒ-JÐ-JØ×Ò˜S¨7ÐÑ3Ô3Ð3à	�Š¥Ð0˜˜¨D¸7ˆÑ	CÔ	Cð ÀyÝ”>Ñ#Ô#¥c¨#¨Ñ&?Ô&?Ñ?ˆð	!ð
!Ýð KÝ”K 	× 0Ò 0Ñ 2Ô 2µE´MÅEÄMÑ4QÑRÔRÐRÐRà—N’N 1Ñ%Ô%Ð%Ý”N 9×#3Ò#3Ñ#5Ô#5µv´ÈÑJÔJÐJØøÝ#¥W­oÐ>ð !ð !ð !Ý”>Ñ#Ô# xÒ/Ð/Ý& Ñ7Ô7Ð7Ý”
˜4Ñ Ô Ð Ð Ð ð!øøøð	!ð ˆŒð	ØˆEˆEˆEàˆFŒLÝð 
ðÝ”K 	× 0Ò 0Ñ 2Ô 2µE´MÑBÔBÐBÑBøÝ¥Ð)ð ð ð Ø‘Dðøøøåð ðØ—N’N 1Ñ%Ô%Ð%Ý”N 9×#3Ò#3Ñ#5Ô#5µv´ÈÑJÔJÐJÐJøÝ¥Ð)ð ð ð Ø�Dðøøøð	øð ˆFŒLÝð 
ðÝ”K 	× 0Ò 0Ñ 2Ô 2µE´MÑBÔBÐBÐBøÝ¥Ð)ð ð ð Ø�Dðøøøåð ðØ—N’N 1Ñ%Ô%Ð%Ý”N 9×#3Ò#3Ñ#5Ô#5µv´ÈÑJÔJÐJÐJøÝ¥Ð)ð ð ð Ø�Dðøøøð	øøøð3ð ð ñ ô ð ð ð ð ð ð ð øøøð ð ð ð ð ð s÷   ©> ¾AÂB Â	BÄ&N<Ä7BGÇN<ÇAHÈN<ÈHÈN<È%K+È)N<È81I+É)N<É+J É<N<É?J Ê 
N<ÊAKËN<ËK'Ë$N<Ë&K'Ë'N<Ë+N,Ë;1L-Ì,N,Ì-M	Ì>N,Í M	Í
N,ÍANÎN,ÎN(	Î%N,Î'N(	Î(N,Î,N<Î<O ÏO ©ré  c             #  óð   K  — |�|nt          ¦   «         }|�|                     d¦  «        nt          ¦   «         }t          |t	          |¦  «        | d¦  «        5  dV — ddd¦  «         dS # 1 swxY w Y   dS )a\  Cross-process advisory lock for one auth.json read/write transaction.

    ``target_path`` is required for profile-to-global write-throughs. A profile
    lock does not protect the distinct global auth store; each path therefore
    uses its own reentrancy tracker and kernel lock.

    Lock ordering invariant: when this lock is held together with
    ``_nous_shared_store_lock``, acquire ``_auth_store_lock`` FIRST
    (outer) and the shared Nous lock SECOND (inner). All runtime
    refresh paths follow this order; violating it risks deadlock
    against a concurrent import on the shared store.
    Nrà  z%Timed out waiting for auth store lock)rÏ  rá  râ  r  rð  )ró  ré  Ú	auth_pathrñ  s       rB   rl  rl  ¢  sÒ   è è € ð$  +Ð6��½OÑ<MÔ<M€IØ2=Ð2I�	×%Ò% gÑ.Ô.Ð.ÍÑO`ÔO`€IÝ	ØÝ˜iÑ(Ô(ØØ/ñ	
ô 
ð ð ð 	ˆˆˆðð ð ñ ô ð ð ð ð ð ð ð øøøð ð ð ð ð ð s   ÁA+Á+A/Á2A/Ú	auth_filec                óÈ  — | pt          ¦   «         } |                      ¦   «         s
t          i dœS 	 t          j        |                      d¬¦  «        ¦  «        }nâ# t          $ r t                               d| d¬¦  «         ‚ t          $ r®}|  
                    d¦  «        }d}	 d	d l} |j        | |¦  «         d}n-# t          $ r  t                               d
|d¬¦  «         Y nw xY w|rt                               d| ||¦  «         nt                               d| ||¦  «         t          i dœcY d }~S d }~ww xY wt          |t          ¦  «        r¥t          |                     d¦  «        t          ¦  «        s(t          |                     d¦  «        t          ¦  «        rU|                     di ¦  «         t          |                     d¦  «        t          ¦  «        rt%          |d         ¦  «         |S t          |t          ¦  «        rPt          |                     d¦  «        t          ¦  «        r(|d         }i }d|v r|d         |d<   t          ||rdnd dœS t          i dœS )N)ÚversionÚ	providersú	utf-8-sigrú  zbauth: could not read %s, leaving the store on disk untouched rather than degrading to an empty oneT©Úexc_infoz.json.corruptFr   z:auth: could not preserve a copy of the corrupt store at %szVauth: failed to parse %s (%s), starting with empty store. Corrupt file preserved at %sz]auth: failed to parse %s (%s), starting with empty store. A copy could NOT be preserved at %sr   Úcredential_poolÚsystemsÚnous_portalrd   )r  r   Úactive_provider)rÏ  rÚ  ÚAUTH_STORE_VERSIONr;  ÚloadsÚ	read_textr  r  r  r@   rá  ÚshutilÚcopy2rA  r  rb   rg  rí  Ú_migrate_stale_nous_portal_url)r  r¶  r  Úcorrupt_pathÚ	preservedr+  r%  r   s           rB   re  re  ¿  sæ  € ØÐ.�_Ñ.Ô.€IØ×ÒÑÔð @Ý-¸BÐ?Ð?Ð?ð)@ÝŒj˜×,Ò,°kÐ,ÑBÔBÑCÔCˆˆøÝð ð ð õ 	�Šð4à ð 	ñ 	
ô 	
ð 	
ð
 	Ýð @ð @ð @à ×,Ò,¨_Ñ=Ô=ˆØˆ	ð	ØˆMˆMˆMØˆFŒL˜ LÑ1Ô1Ð1ØˆIˆIøÝð 	ð 	ð 	Ý�LŠLØLØ tð ñ ô ð ð ð ð	øøøð
 ð 	Ý�NŠNð/à˜3 ñô ð ð õ �NŠNð6à˜3 ñô ð õ
 .¸BÐ?Ð?Ð?Ð?Ð?Ð?Ð?Ð?øøøøð5@øøøõ8 �#•tÑÔð Ý�3—7’7˜;Ñ'Ô'­Ñ.Ô.ðå�c—g’gÐ/Ñ0Ô0µ$Ñ7Ô7ðð 	�Š�{ BÑ'Ô'Ð'Ý�c—g’g˜kÑ*Ô*­DÑ1Ô1ð 	=Ý*¨3¨{Ô+;Ñ<Ô<Ð<Øˆ
õ �#•tÑÔð B¥¨C¯GªG°IÑ,>Ô,>ÅÑ!EÔ!Eð BØ�i”.ˆØˆ	Ø˜GÐ#Ð#Ø '¨Ô 6ˆI�fÑÝ-¸IØ-6Ð#@ 6 6¸DðBð Bð 	Bõ *¸Ð;Ð;Ð;sB   °(A Á1D8Â
D3Â"B:Â9D3Â:'C$Ã!D3Ã#C$Ã$A	D3Ä-D8Ä3D8rp  c                ó  — |�|nt          ¦   «         }|j                             dd¬¦  «         t          |¦  «         t          | d<   t          j        t          j        ¦  «         	                    ¦   «         | d<   t          j        | d¬¦  «        dz   }|                     |j        › dt          j        ¦   «         › d	t!          j        ¦   «         j        › �¦  «        }	 t          j        t)          |¦  «        t          j        t          j        z  t          j        z  t0          j        t0          j        z  ¦  «        }t          j        |d
d¬¦  «        5 }|                     |¦  «         |                     ¦   «          t          j        |                     ¦   «         ¦  «         d d d ¦  «         n# 1 swxY w Y   tA          ||¦  «         	 t          j        t)          |j        ¦  «        t          j!        ¦  «        }n# tD          $ r d }Y nw xY w|�C	 t          j        |¦  «         t          j#        |¦  «         n# t          j#        |¦  «         w xY w	 | $                    ¦   «         r| %                    ¦   «          nO# tD          $ r Y nCw xY w# 	 | $                    ¦   «         r| %                    ¦   «          w w # tD          $ r Y w w xY wxY w	 | &                    t0          j        t0          j        z  ¦  «         n# tD          $ r Y nw xY w|S )NTr÷  r  Ú
updated_até   )ÚindentÚ
ú.tmp.r8   Úwr«  rú  )'rÏ  rý  rþ  r   r(  r   Únowr   ÚutcÚ	isoformatr;  rÀ  Ú	with_namerP   r´  ÚgetpidÚuuidÚuuid4Úhexr  r3   ÚO_WRONLYÚO_CREATÚO_EXCLr  ÚS_IRUSRÚS_IWUSRÚfdopenÚwriteÚflushÚfsyncr	  r   ÚO_RDONLYr  ÚcloserÚ  ÚunlinkÚchmod)rp  ré  r  rÁ  Útmp_pathÚfdÚhandleÚdir_fds           rB   rn  rn    s(  € ð  +Ð6��½OÑ<MÔ<M€IØÔ×Ò 4°$ÐÑ7Ô7Ð7õ �iÑ Ô Ð Ý.€JˆyÑÝ'œ|­H¬LÑ9Ô9×CÒCÑEÔE€Jˆ|ÑÝŒj˜¨AÐ.Ñ.Ô.°Ñ5€GØ×"Ò" i¤nÐ#[Ð#[½2¼9¹;¼;Ð#[Ð#[ÍÌÉÌÔIYÐ#[Ð#[Ñ\Ô\€Hðõ
 ŒWÝ�‰MŒMÝŒK�"œ*Ñ$¥r¤yÑ0ÝŒL�4œ<Ñ'ñ
ô 
ˆõ
 ŒY�r˜3¨Ð1Ñ1Ô1ð 	&°VØ�LŠL˜Ñ!Ô!Ð!Ø�LŠL‰NŒNˆNÝŒH�V—]’]‘_”_Ñ%Ô%Ð%ð	&ð 	&ð 	&ñ 	&ô 	&ð 	&ð 	&ð 	&ð 	&ð 	&ð 	&øøøð 	&ð 	&ð 	&ð 	&õ 	�x Ñ+Ô+Ð+ð	Ý”W�S Ô!1Ñ2Ô2µB´KÑ@Ô@ˆFˆFøÝð 	ð 	ð 	ØˆFˆFˆFð	øøøàÐð!Ý”˜Ñ Ô Ð å”˜Ñ Ô Ð Ð ø•”˜Ñ Ô Ð Ð øøøð	Ø�ŠÑ Ô ð "Ø—’Ñ!Ô!Ð!øøÝð 	ð 	ð 	ØˆDð	øøøøð	Ø�ŠÑ Ô ð "Ø—’Ñ!Ô!Ð!Ð!ð"øåð 	ð 	ð 	ØˆDð	øøøøøøðØ�Š�œ¥t¤|Ñ3Ñ4Ô4Ð4Ð4øÝð ð ð ØˆðøøøàÐs¶   ÃA5J ÅAF/Æ#J Æ/F3Æ3J Æ6F3Æ7J Ç1G= Ç<J Ç=HÈ	J ÈHÈJ ÈH; È&J È;IÉJ É(I> É>
JÊ
JÊK
Ê(J:Ê8K
Ê:
KËK
ËKËK
Ë,K; Ë;
LÌLú/tuple[Optional[Dict[str, Any]], Optional[Path]]c                óî  — |                       d¦  «        }t          |t          ¦  «        rG|                      |¦  «        }t          |t          ¦  «        rt          |¦  «        t          ¦   «         fS t	          ¦   «         }t          ¦   «         }|re|                      d¦  «        }t          |t          ¦  «        r;|                      |¦  «        }t          |t          ¦  «        rt          |¦  «        |fS dS )aü  Return a provider state plus the auth.json path it came from.

    Most callers only need the state, but refresh paths that rotate single-use
    OAuth refresh tokens must write the updated token chain back to the same
    store they read. In profile mode ``_load_provider_state`` can read a
    global-root fallback state; persisting a rotated Nous refresh token only to
    the profile would leave the global/root store stale and cause the next
    process to replay an already-consumed refresh token.
    r   ©NN)rg  r  rb   rÏ  r×  rÞ  )rp  r  r   rq  rÛ  Úglobal_storeÚglobal_providersÚglobal_states           rB   Ú _load_provider_state_with_sourcerV  :  sã   € ð —’˜{Ñ+Ô+€IÝ�)�TÑ"Ô"ð 2Ø—’˜kÑ*Ô*ˆÝ�e�TÑ"Ô"ð 	2Ý˜‘;”;¥Ñ 1Ô 1Ð1Ð1å(Ñ*Ô*€KÝ*Ñ,Ô,€LØð 7Ø'×+Ò+¨KÑ8Ô8ÐÝÐ&­Ñ-Ô-ð 	7Ø+×/Ò/°Ñ<Ô<ˆLÝ˜,­Ñ-Ô-ð 7Ý˜LÑ)Ô)¨;Ð6Ð6Øˆ:rc   c              #  óJ  K  — t          ¦   «         5  t          ¦   «         }t          || ¦  «        \  }}t          ¦   «         }|�t	          ||¦  «        r|||fV — 	 ddd¦  «         dS t          |¬¦  «        5  t          |¦  «        }|                     d¦  «        }d}t          |t          ¦  «        r9|                     | ¦  «        }t          |t          ¦  «        rt          |¦  «        }|||fV — ddd¦  «         n# 1 swxY w Y   ddd¦  «         dS # 1 swxY w Y   dS )ay  Lock the active auth store and any global fallback source in order.

    Profile-backed refresh paths must take the global auth-store lock before
    any provider-specific shared-store lock. Re-reading the source after the
    target lock is acquired prevents both stale refreshes and whole-file lost
    updates without inverting the documented auth -> shared lock order.
    Nr  r   )rl  re  rV  rÏ  rè  rg  r  rb   )	r  rp  rq  Úsource_pathÚactive_pathÚsource_storeÚsource_providersÚsource_stateÚ	raw_states	            rB   Ú_provider_state_transactionr^  X  sá  è è € õ 
Ñ	Ô	ð 8ð 8Ý%Ñ'Ô'ˆ
Ý=ØØñ
ô 
Ñˆˆ{õ &Ñ'Ô'ˆØÐ¥*¨[¸+Ñ"FÔ"FÐØ˜e [Ð0Ð0Ð0Ð0Øð8ð 8ð 8ñ 8ô 8ð 8ð 8ð 8õ ¨+Ð6Ñ6Ô6ð 	8ð 	8Ý+¨KÑ8Ô8ˆLØ+×/Ò/°Ñ<Ô<ÐØˆLÝÐ*­DÑ1Ô1ð 3Ø,×0Ò0°Ñ=Ô=�	Ý˜i­Ñ.Ô.ð 3Ý#'¨	¡?¤?�LØ˜l¨KÐ7Ð7Ð7Ð7ð	8ð 	8ð 	8ñ 	8ô 	8ð 	8ð 	8ð 	8ð 	8ð 	8ð 	8øøøð 	8ð 	8ð 	8ð 	8ð8ð 8ð 8ñ 8ô 8ð 8ð 8ð 8ð 8ð 8ð 8ð 8øøøð 8ð 8ð 8ð 8ð 8ð 8s=   ‘A
DÁ(DÁ8A<D Ã4DÄ D	ÄDÄD	ÄDÄDÄDúOptional[Dict[str, Any]]c                ó,   — t          | |¦  «        \  }}|S )a  Return a provider's persisted state.

    In profile mode, falls back to the global-root ``auth.json`` when the
    profile has no entry for ``provider_id``. This mirrors the per-provider
    shadowing already used by ``read_credential_pool``: workers spawned in a
    profile can see providers (e.g. ``nous``) that were only authenticated at
    global scope. Once the user runs ``hermes auth login <provider>`` inside
    the profile, the profile state fully shadows the global state on the next
    read. See issue #18594 follow-up.
    )rV  )rp  r  rq  Ú_source_paths       rB   rf  rf  w  s   € õ ;¸:À{ÑSÔSÑ€Eˆ<Ø€Lrc   rq  c                óŠ   — |                       di ¦  «        }t          |t          ¦  «        si | d<   | d         }|||<   || d<   d S ©Nr   r'  ©rí  r  rb   )rp  r  rq  r   s       rB   Ú_save_provider_statere  †  sX   € Ø×%Ò% k°2Ñ6Ô6€IÝ�i¥Ñ&Ô&ð ,Ø"$ˆ
�;ÑØ˜{Ô+ˆ	Ø"€IˆkÑØ$/€JÐ Ñ!Ð!Ð!rc   rX  c                ó$  — t          ¦   «         }|€|}	 |                     d¬¦  «        |                     d¬¦  «        k    }n# t          $ r	 ||k    }Y nw xY w|r"t          | ||¦  «         t	          | ¦  «         dS t          |||d¬¦  «         dS )z?Persist provider state back to the auth store it was read from.NFrÇ  Trc  )rÏ  rË  r@   re  rn  Ú _persist_provider_state_to_store)rp  r  rq  rX  rY  Ú
same_stores         rB   Ú_save_provider_state_to_sourceri  �  sÑ   € õ "Ñ#Ô#€KØÐØ!ˆð0Ø ×(Ò(°Ð(Ñ6Ô6¸+×:MÒ:MÐUZÐ:MÑ:[Ô:[Ò[ˆ
ˆ
øÝð 0ð 0ð 0Ø  KÒ/ˆ
ˆ
ˆ
ð0øøøàð Ý˜Z¨°eÑ<Ô<Ð<Ý˜Ñ$Ô$Ð$Øˆå$ØØØØð	ñ ô ð ð ð s   ”.A ÁAÁATrc  rd  c               ó’   — |                       di ¦  «        }t          |t          ¦  «        si | d<   | d         }|||<   |r|| d<   d S d S rc  rd  )rp  r  rq  rd  r   s        rB   rm  rm  ª  sl   € ð ×%Ò% k°2Ñ6Ô6€IÝ�i¥Ñ&Ô&ð ,Ø"$ˆ
�;ÑØ˜{Ô+ˆ	Ø"€IˆkÑØð 4Ø(3ˆ
Ð$Ñ%Ð%Ð%ð4ð 4rc   Fc               óÖ   — t          |¬¦  «        5  t          |¦  «        }t          || t          |¦  «        |¬¦  «         t	          ||¬¦  «        cddd¦  «         S # 1 swxY w Y   dS )zFMerge one provider into a specific auth store under that store's lock.r  rc  N)rl  re  rm  rb   rn  )r  rq  ré  rd  rp  s        rB   rg  rg  º  sÕ   € õ 
 kÐ	2Ñ	2Ô	2ð Eð EÝ% kÑ2Ô2ˆ
ÝØØÝ�‰KŒKØ!ð		
ñ 	
ô 	
ð 	
õ   
¸ÐDÑDÔDðEð Eð Eð Eñ Eô Eð Eð Eð Eð Eð Eð Eøøøð Eð Eð Eð Eð Eð Es   ‘A AÁA"Á%A"c                óê   — t          ¦   «         5  t          ¦   «         }|                     d¦  «        pd                     ¦   «         s| |d<   t	          |¦  «         ddd¦  «         dS # 1 swxY w Y   dS )a5  Set ``active_provider`` to *provider_id* only when none is set yet.

    Used by ``hermes auth add`` OAuth paths that create credential-pool
    entries directly (no singleton ``providers.<id>`` block). Adding the
    very first credential for a provider should make it the active provider
    so the setup wizard's ``_model_section_has_credentials()`` check (which
    consults ``get_active_provider()``) does not report "No inference
    provider configured". Subsequent adds for an already-active setup leave
    the user's chosen active provider untouched.
    r'  r7   N)rl  re  rg  rG   rn  ©r  rp  s     rB   Úmark_provider_active_if_unsetrn  Í  s¾   € õ 
Ñ	Ô	ð )ð )Ý%Ñ'Ô'ˆ
Ø—’Ð0Ñ1Ô1Ð7°R×>Ò>Ñ@Ô@ð 	)Ø,7ˆJÐ(Ñ)Ý˜ZÑ(Ô(Ð(ð	)ð )ð )ñ )ô )ð )ð )ð )ð )ð )ð )ð )øøøð )ð )ð )ð )ð )ð )s   �AA(Á(A,Á/A,c                óv   — | pd                      ¦   «                              ¦   «         }|t          v p|t          v S ©Nr7   )rG   r>   rÖ   r1   ©r  Ú
normalizeds     rB   Úis_known_auth_providerrs  ß  s;   € ØÐ# ×*Ò*Ñ,Ô,×2Ò2Ñ4Ô4€JØÕ*Ð*ÐR¨jÕ<RÐ.RÐRrc   c                ó¾   — | pd                      ¦   «                              ¦   «         }|t          v rt          |         j        S t                               || ¦  «        S rp  )rG   r>   rÖ   rP   r1   rg  rq  s     rB   Úget_auth_provider_display_nameru  ä  sT   € ØÐ# ×*Ò*Ñ,Ô,×2Ò2Ñ4Ô4€JØÕ&Ð&Ð&Ý  Ô,Ô1Ð1Ý!×%Ò% j°+Ñ>Ô>Ð>rc   c                óÜ   — | pd                      ¦   «                              ¦   «         }|sdS |dv rdS |                     d¦  «        rdS 	 t          |¦  «         n# t          $ r Y dS w xY wdS )a.  Return whether runtime resolution recognizes a provider identity.

    This is a capability check, not a credential check. It follows the same
    alias/plugin-aware normalization as ``resolve_provider`` while preserving
    special runtime identities that intentionally live outside the registry.
    r7   F>   ÚmoaÚautorÙ   rÚ   Tzcustom:)rG   r>   rð   Úresolve_providerr|  rq  s     rB   Úis_runtime_provider_routablerz  ë  sœ   € ð Ð# ×*Ò*Ñ,Ô,×2Ò2Ñ4Ô4€JØð ØˆuØÐ<Ð<Ð<ØˆtØ×Ò˜YÑ'Ô'ð ØˆtðÝ˜Ñ$Ô$Ð$Ð$øÝð ð ð Øˆuˆuðøøøàˆ4s   ÁA Á
A)Á(A)c                óê  — t          ¦   «         }|                     d¦  «        }t          |t          ¦  «        si }i }t	          ¦   «         }|r|                     d¦  «        nd}t          |t          ¦  «        r|}| €‚t          |¦  «        }|                     ¦   «         D ]\\  }}t          |t          ¦  «        r|sŒ|                     |¦  «        }	t          |	t          ¦  «        r|	rŒJt          |¦  «        ||<   Œ]|S |                     | ¦  «        }
t          |
t          ¦  «        r|
rt          |
¦  «        S |                     | ¦  «        }t          |t          ¦  «        rt          |¦  «        ng S )uý  Return the persisted credential pool, or one provider slice.

    In profile mode, the profile's credential pool is authoritative. If a
    provider has no entries in the profile, entries from the global-root
    ``auth.json`` are used as a read-only fallback â€” so workers spawned in a
    profile can see providers that were only authenticated at global scope.

    Profile entries always win: the global fallback only applies per-provider
    when the profile has zero entries for that provider. Once the user runs
    ``hermes auth add <provider>`` inside the profile, profile entries
    fully shadow global for that provider on the next read.

    Writes always go to the profile (``write_credential_pool`` is unchanged).
    See issue #18594 follow-up.
    r$  N)re  rg  r  rb   rÞ  rU  Úlist)r  rp  r"  Úglobal_poolrS  Úmaybe_global_poolÚmergedÚgp_keyÚ
gp_entriesÚexistingÚprovider_entriesÚglobal_entriess               rB   Úread_credential_poolr…     s�  € õ  "Ñ#Ô#€JØ�>Š>Ð+Ñ,Ô,€DÝ�d�DÑ!Ô!ð Øˆà"$€KÝ*Ñ,Ô,€LØ?KÐU˜×(Ò(Ð):Ñ;Ô;Ð;ÐQUÐÝÐ#¥TÑ*Ô*ð (Ø'ˆàÐÝ�d‘”ˆØ"-×"3Ò"3Ñ"5Ô"5ð 	.ð 	.ÑˆF�JÝ˜j­$Ñ/Ô/ð °zð Øà—z’z &Ñ)Ô)ˆHÝ˜(¥DÑ)Ô)ð ¨hð ØÝ! *Ñ-Ô-ˆF�6‰NˆNØˆà—x’x Ñ,Ô,ÐÝÐ"¥DÑ)Ô)ð &Ð.>ð &ÝÐ$Ñ%Ô%Ð%à —_’_ [Ñ1Ô1€NÝ#-¨n½dÑ#CÔ#CÐK�4�ÑÔÐÈÐKrc   )Úlast_statusÚlast_status_atÚlast_error_codeÚlast_error_reasonÚlast_error_messageÚlast_error_reset_atr#  Ú
disk_entryc                ó–  — t          |t          ¦  «        s| S 	 ddlm}m}m}m}m} |                     d¦  «        }|||fvr| S |                      d¦  «        pd}	|                     d¦  «        pd}
|	r
|
r|	|
k    r| S  ||                     d¦  «        ¦  «        pd} ||                      d¦  «        ¦  «        pd}||k    r| S ||k    r: || 	                    ||¦  «        ¦  «        }|�|t          j
        ¦   «         k    r| S t          | ¦  «        }t          D ]}|                     |¦  «        ||<   Œ|S # t          $ r | cY S w xY w)uÜ  Keep a newer on-disk cooldown/quarantine over a stale in-memory one.

    ``write_credential_pool`` callers persist an in-memory snapshot that may
    predate another process marking the same credential exhausted or dead
    (last-writer-wins lost update).  Without this merge, process B's later
    rewrite resurrects a rate-limited key as healthy and both processes
    resume hammering it.  Adopt the on-disk status fields only when they are
    strictly more recent (by ``last_status_at``) AND still binding â€” a DEAD
    marker, or an EXHAUSTED cooldown that has not yet expired.  Expired
    cooldowns are not resurrected, so the pool's own expiry-clear (which
    resets ``last_status_at`` to None) is never overridden.
    r   )ÚPooledCredentialÚSTATUS_DEADÚSTATUS_EXHAUSTEDÚ_exhausted_untilÚ_parse_absolute_timestampr†  r  r7   r‡  ç        )r  rb   r  rŽ  r�  r�  r‘  r’  rg  Ú	from_dictr  Ú_POOL_STATUS_FIELDSr@   )r#  rŒ  r  rŽ  r�  r�  r‘  r’  Údisk_statusÚ
mem_accessÚdisk_accessÚdisk_tsÚmem_tsÚuntilÚmerged_entryÚstatus_fields                   rB   Ú_merge_disk_cooldown_staterž  9  sÜ  € õ" �j¥$Ñ'Ô'ð Øˆð#ð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð !—n’n ]Ñ3Ô3ˆØ˜{Ð,<Ð=Ð=Ð=ØˆLð
 —Y’Y˜~Ñ.Ô.Ð4°"ˆ
Ø —n’n ^Ñ4Ô4Ð:¸ˆØð 	˜+ð 	¨*¸Ò*CÐ*CØˆLØ+Ð+¨J¯NªNÐ;KÑ,LÔ,LÑMÔMÐTÐQTˆØ*Ð*¨5¯9ª9Ð5EÑ+FÔ+FÑGÔGÐNÈ3ˆØ�fÒÐØˆLØÐ*Ò*Ð*Ø$Ð$Ø ×*Ò*¨;¸
ÑCÔCñô ˆEð ˆ} ­¬©¬Ò 4Ð 4Ø�Ý˜E‘{”{ˆÝ/ð 	Fð 	FˆLØ)3¯ª¸Ñ)EÔ)EˆL˜Ñ&Ð&ØÐøÝð ð ð Øˆˆˆðøøøs*   ™*D9 Á9D9 Á>AD9 Ã?D9 Ä2D9 Ä9EÅE)Úremoved_idsÚentriesúList[Dict[str, Any]]rŸ  úOptional[Iterable[str]]c               óš  ‡ ‡— d„ |pdD ¦   «         }t          ¦   «         5  t          ¦   «         }|                     d¦  «        }t          |t          ¦  «        si }||d<   ˆ fd„|D ¦   «         }|                     ‰ ¦  «        }t          |t
          ¦  «        r|ng }d„ |D ¦   «         Šd„ |D ¦   «         }	ˆˆ fd„|D ¦   «         }
|D ][}t          |t          ¦  «        sŒ|                     d¦  «        }|r||	v s||v rŒ8|
                     t          |‰ ¦  «        ¦  «         Œ\|
|‰ <   t          |¦  «        cd	d	d	¦  «         S # 1 swxY w Y   d	S )
a¨  Persist one provider's credential pool under auth.json.

    This is the final disk-boundary guard for borrowed/reference-only
    credentials. Callers may pass raw dictionaries, so sanitize here even when
    ``PooledCredential.to_dict()`` already did the same work upstream.

    Re-read the on-disk pool under the same lock and merge entries present on
    disk but missing from ``entries``. Those were added by another process after
    the caller loaded its in-memory snapshot; without this merge a later
    rotation/exhaustion rewrite drops the concurrent credential.

    For entries present on BOTH sides, status fields are merged by
    ``last_status_at`` recency via ``_merge_disk_cooldown_state`` so a stale
    snapshot cannot erase a cooldown/quarantine another process just wrote.

    Pass ``removed_ids`` for entries the caller intentionally removed, so the
    merge does not resurrect them from the on-disk copy.
    c                ó   — h | ]}|¯|’ŒS rY   rY   )râ   Úrids     rB   ú	<setcomp>z(write_credential_pool.<locals>.<setcomp>Š  s   € Ð9Ð9Ð9�s°SÐ9ˆsÐ9Ð9Ð9rc   rY   r$  c                ó^   •— g | ])}t          |t          ¦  «        rt          |‰¦  «        n|‘Œ*S rY   )r  rb   r   )râ   r#  r  s     €rB   ú
<listcomp>z)write_credential_pool.<locals>.<listcomp>‘  sM   ø€ ð 
ð 
ð 
ð õ ˜%¥Ñ&Ô&ð2Õ0°¸ÑDÔDÐDØ,1ð
ð 
ð 
rc   c                óŽ   — i | ]B}t          |t          ¦  «        ¯|                     d ¦  «        ¯,|                     d ¦  «        |“ŒCS ©rO   ©r  rb   rg  ©râ   r#  s     rB   rO  z)write_credential_pool.<locals>.<dictcomp>˜  sX   € ð 
ð 
ð 
àÝ˜%¥Ñ&Ô&ð
ð ,1¯9ª9°T©?¬?ð
Ø�IŠI�d‰OŒO˜Uð
ð 
ð 
rc   c                óŒ   — h | ]A}t          |t          ¦  «        ¯|                     d ¦  «        ¯,|                     d ¦  «        ’ŒBS rª  r«  r¬  s     rB   r¦  z(write_credential_pool.<locals>.<setcomp>�  sV   € ð 
ð 
ð 
àÝ˜%¥Ñ&Ô&ð
ð ,1¯9ª9°T©?¬?ð
Ø�IŠI�d‰OŒOð
ð 
ð 
rc   c           
     ó¬   •— g | ]P}t          |t          ¦  «        r7t          |‰                     |                     d ¦  «        ¦  «        ‰¦  «        n|‘ŒQS rª  )r  rb   rž  rg  )râ   r#  Úexisting_by_idr  s     €€rB   r¨  z)write_credential_pool.<locals>.<listcomp>¢  sp   ø€ ð (
ð (
ð (
ð õ ˜%¥Ñ&Ô&ðÕ&Ø�~×)Ò)¨%¯)ª)°D©/¬/Ñ:Ô:¸Kñô ð ð ð(
ð (
ð (
rc   rO   N)	rl  re  rg  r  rb   r|  Úappendr   rn  )r  r   rŸ  Úremovedrp  r"  Úsanitized_entriesr‚  Úexisting_listÚnew_idsr  rŒ  Údisk_idr¯  s   `            @rB   Úwrite_credential_poolr¶  r  s  øø€ ð0 :Ð9˜{Ð0¨bÐ9Ñ9Ô9€GÝ	Ñ	Ô	ð ',ð ',Ý%Ñ'Ô'ˆ
Ø�~Š~Ð/Ñ0Ô0ˆÝ˜$¥Ñ%Ô%ð 	1ØˆDØ,0ˆJÐ(Ñ)ð
ð 
ð 
ð 
ð !ð
ñ 
ô 
Ðð
 —8’8˜KÑ(Ô(ˆÝ$.¨x½Ñ$>Ô$>ÐF˜˜ÀBˆð
ð 
à&ð
ñ 
ô 
ˆð

ð 
à*ð
ñ 
ô 
ˆð
(
ð (
ð (
ð (
ð (
ð +ð(
ñ (
ô (
ˆð (ð 	Yð 	YˆJÝ˜j­$Ñ/Ô/ð ØØ —n’n TÑ*Ô*ˆGØð ˜g¨Ð0Ð0°G¸wÐ4FÐ4FØØ�MŠMÕ>¸zÈ;ÑWÔWÑXÔXÐXÐXØ"ˆˆ[ÑÝ 
Ñ+Ô+ðO',ð ',ð ',ð ',ñ ',ô ',ð ',ð ',ð ',ð ',ð ',ð ',øøøð ',ð ',ð ',ð ',ð ',ð ',s   ŸDE Å EÅEr  c                ó  — t          ¦   «         5  t          ¦   «         }|                     di ¦  «        }|                     | g ¦  «        }||vr|                     |¦  «         t	          |¦  «         ddd¦  «         dS # 1 swxY w Y   dS )z@Mark a credential source as suppressed so it won't be re-seeded.Úsuppressed_sourcesN)rl  re  rí  r°  rn  ©r  r  rp  Ú
suppressedÚprovider_lists        rB   Úsuppress_credential_sourcer¼  µ  sÕ   € å	Ñ	Ô	ð %ð %Ý%Ñ'Ô'ˆ
Ø×*Ò*Ð+?ÀÑDÔDˆ
Ø"×-Ò-¨k¸2Ñ>Ô>ˆØ˜Ð&Ð&Ø× Ò  Ñ(Ô(Ð(Ý˜Ñ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %ð %ð %s   �A#A?Á?BÂBc                óž   — 	 t          ¦   «         }|                     di ¦  «        }||                     | g ¦  «        v S # t          $ r Y dS w xY w)z=Check if a credential source has been suppressed by the user.r¸  F)re  rg  r@   )r  r  rp  rº  s       rB   Úis_source_suppressedr¾  À  sa   € ðÝ%Ñ'Ô'ˆ
Ø—^’^Ð$8¸"Ñ=Ô=ˆ
Ø˜Ÿš¨°RÑ8Ô8Ð8Ð8øÝð ð ð Øˆuˆuðøøøs   ‚;> ¾
AÁAc                ó  — t          ¦   «         5  t          ¦   «         }|                     d¦  «        }t          |t          ¦  «        s	 ddd¦  «         dS |                     | ¦  «        }t          |t
          ¦  «        r||vr	 ddd¦  «         dS |                     |¦  «         |s|                     | d¦  «         |s|                     dd¦  «         t          |¦  «         	 ddd¦  «         dS # 1 swxY w Y   dS )z˜Clear a suppression marker so the source will be re-seeded on the next load.

    Returns True if a marker was cleared, False if no marker existed.
    r¸  NFT)	rl  re  rg  r  rb   r|  ÚremoveÚpoprn  r¹  s        rB   Úunsuppress_credential_sourcerÂ  Ê  sˆ  € õ
 
Ñ	Ô	ð ð Ý%Ñ'Ô'ˆ
Ø—^’^Ð$8Ñ9Ô9ˆ
Ý˜*¥dÑ+Ô+ð 	Øð	ð ð ñ ô ð ð ð ð
 #Ÿš {Ñ3Ô3ˆÝ˜-­Ñ.Ô.ð 	°&ÀÐ2MÐ2MØðð ð ñ ô ð ð ð ð 	×Ò˜VÑ$Ô$Ð$Øð 	.Ø�NŠN˜;¨Ñ-Ô-Ð-Øð 	7Ø�NŠNÐ/°Ñ6Ô6Ð6Ý˜Ñ$Ô$Ð$Øðð ð ñ ô ð ð ð ð ð ð ð øøøð ð ð ð ð ð s   �:C4Á/C4ÂAC4Ã4C8Ã;C8c                ó>   — t          ¦   «         }t          || ¦  «        S )uÊ  Return persisted auth state for a provider, or None.

    In profile mode, ``_load_provider_state`` already falls back to the
    global-root ``auth.json`` per-provider when the profile has no entry â€”
    so this is now a thin convenience wrapper. Profile state always wins
    when present. Writes (``_save_auth_store`` / ``persist_*_credentials``)
    are unchanged â€” they still target the profile only. This mirrors
    ``read_credential_pool``'s per-provider shadowing semantics so that
    ``_seed_from_singletons`` can reseed a profile's credential pool from
    global-scope provider state (e.g. a globally-authenticated Anthropic
    OAuth or Nous device-code session). See issue #18594 follow-up.
    )re  rf  rm  s     rB   Úget_provider_auth_staterÄ  à  s   € õ "Ñ#Ô#€JÝ 
¨KÑ8Ô8Ð8rc   c                 óH   — t          ¦   «         } |                      d¦  «        S )z8Return the currently active provider ID from auth store.r'  )re  rg  ©rp  s    rB   Úget_active_providerrÇ  ñ  s    € å!Ñ#Ô#€JØ�>Š>Ð+Ñ,Ô,Ð,rc   c                ó’  ‡— | pd                      ¦   «                              ¦   «         Š	 t          ¦   «         }|                     d¦  «        pd                      ¦   «                              ¦   «         }|r|‰k    rdS n# t          $ r Y nw xY w	 ddlm}  |¦   «         }|                     d¦  «        }t          |t          ¦  «        rC|                     d¦  «        pd                      ¦   «                              ¦   «         }|‰k    rdS ˆfd„}|                     d	¦  «        }t          |t          ¦  «        ré|                     d
¦  «        pg D ]}	 ||	¦  «        r dS Œ ||                     d¦  «        ¦  «        rdS |                     d¦  «        }
t          |
t          ¦  «        rw|
 	                    ¦   «         D ]b}t          |t          ¦  «        sŒ|                     d
¦  «        pg D ]}	 ||	¦  «        r  dS Œ ||                     d¦  «        ¦  «        r dS Œcn# t          $ r Y nw xY wdh}t                               ‰¦  «        }|€ddlm}  |‰¦  «        }|r?|j        dk    r4|j        D ],}||v rŒt          t!          j        |d¦  «        ¦  «        r dS Œ-	 t%          ‰¦  «        D ]þ}t          |t          ¦  «        sŒt'          |                     d¦  «        pd¦  «                              ¦   «                              ¦   «         }|sŒc|                     d¦  «        rj|                     dd¦  «                             dd¦  «        d                               ¦   «         }|r%t          t!          j        |d¦  «        ¦  «        r dS Œâ|dv s|                     d¦  «        r dS Œÿn# t          $ r Y nw xY wdS )a÷  Return True only if the user has explicitly configured this provider.

    Checks:
      1. active_provider in auth.json matches
      2. model.provider in config.yaml matches
      3. Provider-specific env vars are set (e.g. ANTHROPIC_API_KEY)

    This is used to gate auto-discovery of external credentials (e.g.
    Claude Code's ~/.claude/.credentials.json) so they are never used
    without the user's explicit choice.  See PR #4210 for the same
    pattern applied to the setup wizard gate.
    r7   r'  Tr   ©Úload_configr6  r~  c                ó¬   •— t          | t          ¦  «        o>|                      d¦  «        pd                     ¦   «                              ¦   «         ‰k    S )Nr~  r7   )r  rb   rg  rG   r>   )Úslotrr  s    €rB   Ú_slot_matches_providerzAis_provider_explicitly_configured.<locals>._slot_matches_provider   sL   ø€ å˜4¥Ñ&Ô&ð OØ—X’X˜jÑ)Ô)Ð/¨R×6Ò6Ñ8Ô8×>Ò>Ñ@Ô@ÀJÒNðrc   rw  Úreference_modelsÚ
aggregatorÚpresetsr¡   N)Úget_providerrh   r  zenv:ú:r"   >   Úmanualr%   Úhermes_pkceÚloopback_pkceúmanual:F)rG   r>   re  rg  r@   ré   rÊ  r  rb   ÚvaluesrÖ   Úhermes_cli.providersrÑ  rQ   r[   r  r´  rµ  r…  r3   rð   Úsplit)r  rp  ÚactiverÊ  ÚcfgÚ	model_cfgÚcfg_providerrÍ  Úmoa_cfgrÌ  rÐ  ÚpresetÚ_IMPLICIT_ENV_VARSr	  rÑ  r   r#  r  rr  s                     @rB   Ú!is_provider_explicitly_configuredrá  ÷  s�  ø€ ð Ð# ×*Ò*Ñ,Ô,×2Ò2Ñ4Ô4€JðÝ%Ñ'Ô'ˆ
Ø—.’.Ð!2Ñ3Ô3Ð9°r×@Ò@ÑBÔB×HÒHÑJÔJˆØð 	�f 
Ò*Ð*Ø�4øøÝð ð ð Øˆðøøøð(Ø1Ð1Ð1Ð1Ð1Ð1Øˆk‰mŒmˆØ—G’G˜GÑ$Ô$ˆ	Ý�i¥Ñ&Ô&ð 	Ø%ŸMšM¨*Ñ5Ô5Ð;¸×BÒBÑDÔD×JÒJÑLÔLˆLØ˜zÒ)Ð)Ø�tð	ð 	ð 	ð 	ð 	ð —'’'˜%‘.”.ˆÝ�g�tÑ$Ô$ð 	$ØŸšÐ$6Ñ7Ô7Ð=¸2ð  ð  �Ø)Ð)¨$Ñ/Ô/ð  Ø˜4˜4ð à%Ð% g§k¢k°,Ñ&?Ô&?Ñ@Ô@ð Ø�tØ—k’k )Ñ,Ô,ˆGÝ˜'¥4Ñ(Ô(ð $Ø%ŸnšnÑ.Ô.ð $ð $�FÝ% f­dÑ3Ô3ð !Ø Ø &§
¢
Ð+=Ñ >Ô >Ð DÀ"ð (ð (˜Ø1Ð1°$Ñ7Ô7ð (Ø#' 4 4 4ð(à-Ð-¨f¯jªj¸Ñ.FÔ.FÑGÔGð $Ø#˜t˜tð$øøåð ð ð Øˆðøøøð 4Ð4ÐÝ×#Ò# JÑ/Ô/€Gð €Ø5Ð5Ð5Ð5Ð5Ð5Ø�,˜zÑ*Ô*ˆØð �7Ô$¨	Ò1Ð1ØÔ/ð 	ð 	ˆGØÐ,Ð,Ð,ØÝ ¥¤¨7°BÑ!7Ô!7Ñ8Ô8ð Ø�t�tððÝ)¨*Ñ5Ô5ð 	ð 	ˆEÝ˜e¥TÑ*Ô*ð ØÝ˜Ÿš 8Ñ,Ô,Ð2°Ñ3Ô3×9Ò9Ñ;Ô;×AÒAÑCÔCˆFØð ØØ× Ò  Ñ(Ô(ð ð  Ÿ)š) H¨bÑ1Ô1×7Ò7¸¸QÑ?Ô?ÀÔB×HÒHÑJÔJ�Øð  Õ0µ´¸7ÀBÑ1GÔ1GÑHÔHð  Ø˜4˜4ØàÐSÐSÐSØ×$Ò$ YÑ/Ô/ð Tð �t�tð Tð	øõ& ð ð ð Øˆðøøøð ˆ5sd   «AA? Á?
BÂBÂA;H& ÄAH& Å#H& ÆA<H& È H& È$H& È&
H3È2H3Ê(C.N7 ÎN7 Î5N7 Î7
OÏOc                ó(  — t          ¦   «         5  t          ¦   «         }| p|                     d¦  «        }|s	 ddd¦  «         dS |                     di ¦  «        }t          |t          ¦  «        si }||d<   |                     d¦  «        }t          |t          ¦  «        si }||d<   d}||v r||= d}||v r||= d}|                     d¦  «        |k    rd|d<   d}|s	 ddd¦  «         dS t          |¦  «         ddd¦  «         n# 1 swxY w Y   dS )z¦
    Clear auth state for a provider. Used by `hermes logout`.
    If provider_id is None, clears the active provider.
    Returns True if something was cleared.
    r'  NFr   r$  T)rl  re  rg  r  rb   rn  )r  rp  Útargetr   r"  Úcleareds         rB   Úclear_provider_authrå  j  sÈ  € õ 
Ñ	Ô	ð %ð %Ý%Ñ'Ô'ˆ
ØÐA 
§¢Ð/@Ñ AÔ AˆØð 	Øð	%ð %ð %ñ %ô %ð %ð %ð %ð —N’N ;°Ñ3Ô3ˆ	Ý˜)¥TÑ*Ô*ð 	0ØˆIØ&/ˆJ�{Ñ#à�~Š~Ð/Ñ0Ô0ˆÝ˜$¥Ñ%Ô%ð 	1ØˆDØ,0ˆJÐ(Ñ)àˆØ�YÐÐØ˜&Ð!ØˆGØ�Tˆ>ˆ>Ø�V�ØˆGà�>Š>Ð+Ñ,Ô,°Ò6Ð6Ø,0ˆJÐ(Ñ)ØˆGàð 	Øð;%ð %ð %ñ %ô %ð %ð %ð %õ< 	˜Ñ$Ô$Ð$ð=%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %ð> ˆ4s   �)DÁBDÃ,DÄDÄDc                 ó˜   — t          ¦   «         5  t          ¦   «         } d| d<   t          | ¦  «         ddd¦  «         dS # 1 swxY w Y   dS )z×
    Clear active_provider in auth.json without deleting credentials.
    Used when the user switches to a non-OAuth provider (OpenRouter, custom)
    so auto-resolution doesn't keep picking the OAuth provider.
    Nr'  )rl  re  rn  rÆ  s    rB   Údeactivate_providerrç  ’  s˜   € õ 
Ñ	Ô	ð %ð %Ý%Ñ'Ô'ˆ
Ø(,ˆ
Ð$Ñ%Ý˜Ñ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %ð %ð %s   �#?¿AÁAÚprovider_namec                ój  — 	 ddl m}  |¦   «         }|sdS dg}|D ]s}|j        dk    rdnd}|                     d|› d	|j        › �¦  «         |j        r|j                             ¦   «         d         nd}|r|                     d
|› �¦  «         Œtd                     |¦  «        S # t          $ r Y dS w xY w)zßReturn a helpful hint string when provider resolution fails.

    Checks for common config.yaml mistakes (malformed custom_providers, etc.)
    and returns a human-readable diagnostic, or empty string if nothing found.
    r   )Úvalidate_config_structurer7   uC   Config issue detected â€” run 'hermes doctor' for full diagnostics:r‹  ÚERRORÚWARNINGz  [z] u       â†’ r4  )	ré   rê  Úseverityr°  r�  ÚhintÚ
splitlinesÚjoinr@   )rè  rê  ÚissuesÚlinesÚciÚprefixÚ
first_hints          rB   Ú%_get_config_hint_for_unknown_providerrö  £  s  € ðØ?Ð?Ð?Ð?Ð?Ð?Ø*Ð*Ñ,Ô,ˆØð 	Ø�2àVÐWˆØð 	6ð 	6ˆBØ "¤¨wÒ 6Ð 6�W�W¸IˆFØ�LŠLÐ5˜vÐ5Ð5¨¬Ð5Ð5Ñ6Ô6Ð6à46´GÐC˜œ×+Ò+Ñ-Ô-¨aÔ0Ð0ÀˆJØð 6Ø—’Ð4¨
Ð4Ð4Ñ5Ô5Ð5øØ�yŠy˜ÑÔÐøÝð ð ð Øˆrˆrðøøøs   ‚B$ –BB$ Â$
B2Â1B2)Úexplicit_api_keyÚexplicit_base_urlÚ	requestedr÷  rø  c               óª	  — | pd                      ¦   «                              ¦   «         }i dd“dd“dd“dd“dd“d	d“d
d“dd“dd“dd“dd“dd“dd“dd“dd“dd“dd“i dd“dd“dd“dd“dd“dd“d d!“d"d!“d#d$“d%d$“d&d$“d'd(“d)d(“d*d+“d,d+“d-d+“d.d/“¥i d0d/“d1d/“d2d3“d4d3“d5d6“d7d6“d8d6“d9d6“d:d;“d<d;“d=d>“d?d>“d@d>“dAdB“dCdB“dDdE“dFdE“¥i dEdE“dGdH“dIdH“dJdH“dKdL“dMdL“dNdO“dPdO“dQdO“dRdO“dSdT“dUdT“dVdT“dWdT“dXdY“dZdY“d[d\“¥d\d\d]d]d]d^d_d^d^d^d^d`œ¥}	 dadblm}  |¦   «         D ]}|j        D ]}||vr
|j        ||<   ŒŒn# t          $ r Y nw xY w|                     ||¦  «        }|dck    rdcS |d^k    rd^S |t          v r|S |dk    r6t          |¦  «        }dd|› de�}	|r	|	df|› �z  }	n|	dgz  }	t          |	dh¬i¦  «        ‚|s|rdcS dj}
	 dadklm}  |¦   «         pi                      dl¦  «        }
t          |
t          ¦  «        r}|
                     dm¦  «        }t          |t          ¦  «        rS|                      ¦   «                              ¦   «         t          v r&|                      ¦   «                              ¦   «         S n2# t          $ r%}t                                dn|¦  «         Y dj}~ndj}~ww xY wt%          t'          j        do¦  «        ¦  «        s!t%          t'          j        dp¦  «        ¦  «        rdcS 	 dadqlm}  |dc¦  «                             ¦   «         rdcS n2# t          $ r%}t                                dr|¦  «         Y dj}~ndj}~ww xY wdj}	 t1          ¦   «         }|                     ds¦  «        }|r-|t          v r$t3          |¦  «                             dt¦  «        r|}n2# t          $ r%}t                                du|¦  «         Y dj}~ndj}~ww xY wt                               ¦   «         D ]n\  }}|j        dvk    rŒ|dwv rŒ|j        D ]P}t%          t'          j        |dx¦  «        ¦  «        r,|r$||k    rt                                dy||||¦  «         |c c S ŒQŒo|rIt          |
t          ¦  «        r2|
r0|
                     dm¦  «        st                                dz|¦  «         |S 	 dad{lm}  |¦   «         rdTS n# t@          $ r Y nw xY wt          d|d}¬i¦  «        ‚)~uX  
    Determine which inference provider to use.

    Priority (when requested="auto" or None) â€” explicit user intent wins over a
    stale logged-in OAuth provider (#29285):
    1. Explicit CLI api_key/base_url -> "openrouter"
    2. config.yaml `model.provider`
    3. OPENAI_API_KEY / OPENROUTER_API_KEY env vars -> "openrouter"
    4. OpenRouter credential pool
    5. Provider-specific API keys (GLM, Kimi, MiniMax, ...) -> that provider
    6. auth.json `active_provider` (logged-in OAuth) â€” last-resort fallback
    7. AWS Bedrock credential chain
    8. Error (no provider configured)
    rx  Úglmr|   zz-aizz.aiÚzhipuÚgooglerx   zgoogle-geminizgoogle-ai-studiozx-air°   úx.aiÚgrokrk   z
x-ai-oauthz
grok-oauthzxai-grok-oauthÚkimir�   zkimi-for-codingÚmoonshotzkimi-cnr…   zmoonshot-cnÚstepr‡   zstepfun-coding-planzarcee-airŠ   Úarceeaiz	gmi-cloudr�   Úgmicloudzactual-computerr�   ÚactualcomputerÚacizminimax-chinar©   Ú
minimax_cnzminimax-portalr—   zminimax-globalÚminimax_oauthÚalibaba_codingr¦   zalibaba-codingÚalibaba_coding_planÚclauder�   zclaude-codeÚgithubrp   zgithub-copilotzgithub-modelszgithub-modelzgithub-copilot-acpru   zcopilot-acp-agentÚ	aigatewayr·   Úvercelzvercel-ai-gatewayÚopencoderº   Úzenzqwen-portalrl   úqwen-cliÚhfrÃ   zhugging-facezhuggingface-hubÚmimorÆ   zxiaomi-mimoÚtencentrÉ   Útokenhubztencent-cloudÚtencentmaasÚawsrÏ   zaws-bedrockzamazon-bedrockÚamazonÚgor½   zopencode-go-subÚkilorÀ   rm   rÙ   rÌ   )z	kilo-codezkilo-gatewayrm   z	lm-studioÚ	lm_studioÚollamaÚollama_cloudÚvllmÚllamacppz	llama.cppz	llama-cppr   r×   rÚ   zUnknown provider 'z'.z

z` Check 'hermes model' for available providers, or run 'hermes doctor' to diagnose config issues.Úinvalid_provider)r  NrÉ  r6  r~  zACould not read config.yaml model.provider for auto-resolution: %sri   ÚOPENROUTER_API_KEYr  z.Could not check OpenRouter credential pool: %sr'  Ú	logged_inz+Could not pre-read active auth provider: %srh   >   rp   rm   r7   zžProvider resolved to %r via %s, preempting your logged-in OAuth provider %r. If you meant to use the OAuth login, unset %s or set `model.provider` explicitly.z§Provider resolved to logged-in OAuth provider %r because config.yaml `model` has no `provider` key. If you meant a different provider, set `model.provider` explicitly.©Úhas_aws_credentialsz¤No inference provider configured. Run 'hermes model' to choose a provider and model, or set an API key (OPENROUTER_API_KEY, OPENAI_API_KEY, etc.) in ~/.hermes/.env.Úno_provider_configured)!rG   r>   r   rØ   ÚaliasesrP   r@   rg  rÖ   rö  r|  ré   rÊ  r  rb   r3   r  rA  r  r´  rµ  r  r  r  re  Úget_auth_statusrU  rQ   r[   r  Úagent.bedrock_adapterr$  ÚImportError)rù  r÷  rø  rr  Ú_PROVIDER_ALIASESÚ_lpÚ_ppÚ_aliasÚ_config_hintÚmsgÚ
_model_cfgrÊ  Ú_cfg_providerÚeÚ
_load_poolÚ_oauth_activeÚ_storeÚ_maybeÚpidr	  r   r$  s                         rB   ry  ry  ¼  sý  € ð( Ð%˜v×,Ò,Ñ.Ô.×4Ò4Ñ6Ô6€Jð#Øˆuð#Ø˜eð#Ø%+¨Uð#Ø4;¸Uð#à�(ð#à+¨Xð#à7IÈ8ð#ð 	�ð#ð ˜uð#ð '-¨eð#ð 	�[ð	#ð #/°ð	#ð
 	�kð#ð
 $4°[ð#ð 	�ð#ð  1°-ð#ð BLÈ]ð#ð #ð 	Ð#ð#ð &3Ð4Dð#ð 	�	ð#ð 1°)ð#ð 	�Gð#ð '¨ð#ð 	�Uð#ð '¨ð#ð 	˜8ð#ð &6°xð#ð BGÈð#ð 	˜ð#ð (4°\ð#ð 	˜/ð#ð ,<¸_ð#ð O^Ð_nð#ð 	Ð/ð#ð #ð #ð 2BÐCXð#ð 	Ð4ð#ð  	�+ð!#ð   -¨kð!#ð" 	�)ð##ð" .¨yð##ð$ 	˜ð%#ð$ %3°Ið%#ð& 	˜mð'#ð& .AÀ-ð'#ð( 	�\ð)#ð( $,¨\ð)#ð( <OÐP\ð)#ð* 	�Nð+#ð* %*¨>ð+#ð, 	�|ð-#ð, &0°ð-#ð #ð #ð, @LÈ\ð-#ð. 	ˆmð/#ð. ,¨]ð/#ð. =NÈ}ð/#ð0 	�ð1#ð0 (¨ð1#ð2 	Ð%ð3#ð2 (2Ð3Eð3#ð4 	Ð+ð5#ð4 .;Ð<Nð5#ð6 	ˆyð7#ð6 (¨ð7#ð6 5EÀið7#ð6 RZÐ[dð7#ð8 	ˆmð9#ð8 /°ð9#ð: 	�
ð;#ð #ð: *4ÀZØ¨ZÀjà¨NØ hØ¨HðE#ð #ð #ÐðNØ3Ð3Ð3Ð3Ð3Ð3Ø�3‘5”5ð 	9ð 	9ˆCØœ+ð 9ð 9�ØÐ!2Ð2Ð2Ø03´Ð% fÑ-øð9ð	9øõ ð ð ð Øˆðøøøà"×&Ò& z°:Ñ>Ô>€Jà�\Ò!Ð!Øˆ|Ø�XÒÐØˆxØÕ&Ð&Ð&ØÐØ�VÒÐå<¸ZÑHÔHˆØ1 :Ð1Ð1Ð1ˆØð 	vØÐ(˜,Ð(Ð(Ñ(ˆCˆCàÐuÑuˆCÝ˜Ð"4Ð5Ñ5Ô5Ð5ð ð Ð,ð Øˆ|ð €Jð	]Ø1Ð1Ð1Ð1Ð1Ð1à!�k‘m”mÐ) r×.Ò.¨wÑ7Ô7ˆ
Ý�j¥$Ñ'Ô'ð 	5Ø&ŸNšN¨:Ñ6Ô6ˆMÝ˜-­Ñ-Ô-ð 5°-×2EÒ2EÑ2GÔ2G×2MÒ2MÑ2OÔ2OÕSdÐ2dÐ2dØ$×*Ò*Ñ,Ô,×2Ò2Ñ4Ô4Ð4øøÝð ]ð ]ð ]Ý�ŠÐXÐZ[Ñ\Ô\Ð\Ð\Ð\Ð\Ð\Ð\øøøøð]øøøõ �œÐ#3Ñ4Ô4Ñ5Ô5ð Õ9JÍ2Ì9ÐUiÑKjÔKjÑ9kÔ9kð Øˆ|ðJØAÐAÐAÐAÐAÐAàˆ:�lÑ#Ô#×3Ò3Ñ5Ô5ð 	 Ø�<ð	 øåð Jð Jð JÝ�ŠÐEÀqÑIÔIÐIÐIÐIÐIÐIÐIøøøøðJøøøð $(€MðGÝ!Ñ#Ô#ˆØ—’Ð-Ñ.Ô.ˆØð 	#�fÕ 1Ð1Ð1µoÀfÑ6MÔ6M×6QÒ6QÐR]Ñ6^Ô6^Ð1Ø"ˆMøøÝð Gð Gð GÝ�ŠÐBÀAÑFÔFÐFÐFÐFÐFÐFÐFøøøøðGøøøõ *×/Ò/Ñ1Ô1ð ð ‰ˆˆWØÔ 	Ò)Ð)Øð Ð)Ð)Ð)ØØÔ/ð 	ð 	ˆGÝ ¥¤¨7°BÑ!7Ô!7Ñ8Ô8ð ð
 !ð  ]°cÒ%9Ð%9Ý—N’Nð&ð ˜W m°Wñô ð ð �
�
�
�
�
ðð	ð* ð 
õ �j¥$Ñ'Ô'ð 	¨Jð 	¸z¿~º~ÈjÑ?YÔ?Yð 	Ý�NŠNðGð ñ	ô ð ð ÐðØ=Ð=Ð=Ð=Ð=Ð=ØÐÑ Ô ð 	Ø�9ð	øåð ð ð Øˆðøøøõ ð	3ð &ð	ñ ô ð sn   Ä+D8 Ä8
EÅEÆ>B6I6 É6
J%Ê J Ê J%Ë-#L Ì
MÌL=Ì=MÍAN Î
O
Î%OÏO
Ò!R4 Ò4
SÓ SúOptional[float]c                ól  — t          | t          ¦  «        r| sd S |                      ¦   «         }|sd S |                     d¦  «        r|d d…         dz   }	 t	          j        |¦  «        }n# t          $ r Y d S w xY w|j        € |                     t          j
        ¬¦  «        }|                     ¦   «         S )NÚZéÿÿÿÿú+00:00©Útzinfo)r  r3   rG   rà   r   Úfromisoformatr@   r>  Úreplacer   r8  Ú	timestamp)rë   ÚtextrK   s      rB   Ú_parse_iso_timestamprC  �  sÈ   € Ý�e�SÑ!Ô!ð ¨ð ØˆtØ�;Š;‰=Œ=€DØð ØˆtØ‡}‚}�SÑÔð $Ø�C�R�CŒy˜8Ñ#ˆðÝÔ'¨Ñ-Ô-ˆˆøÝð ð ð Øˆtˆtðøøøà„}ÐØ—’¥x¤|�Ñ4Ô4ˆØ×ÒÑÔÐs   ÁA* Á*
A8Á7A8Úexpires_at_isoÚskew_secondsc                ó\   — t          | ¦  «        }|€dS |t          j        ¦   «         |z   k    S )NT)rC  r  )rD  rE  Úexpires_epochs      rB   Ú_is_expiringrH  ž  s0   € Ý(¨Ñ8Ô8€MØÐØˆtØ�TœY™[œ[¨<Ñ7Ò8Ð8rc   Ú
expires_inc                óh   — 	 t          | ¦  «        }n# t          $ r d}Y nw xY wt          d|¦  «        S )Nr   )r  r@   r  )rI  Úttls     rB   Ú_coerce_ttl_secondsrL  ¥  sF   € ðÝ�*‰oŒoˆˆøÝð ð ð Øˆˆˆðøøøåˆq�#‰;Œ;Ðó   ‚ ’! !c                óŠ   — t          | t          ¦  «        sd S |                      ¦   «                              d¦  «        }|r|nd S )NrE   )r  r3   rG   r?   )rë   r  s     rB   Ú_optional_base_urlrO  ­  sC   € Ý�e�SÑ!Ô!ð ØˆtØ�kŠk‰mŒm×"Ò" 3Ñ'Ô'€GØÐ'ˆ7ˆ7 4Ð'rc   zapi.nousresearch.comzFrozenSet[str]Ú_NOUS_STALE_PORTAL_HOSTS>   úportal.nousresearch.comr:   r<   Ú_NOUS_PORTAL_ALLOWED_HOSTSr   c                óL  — |                       d¦  «        }t          |t          ¦  «        sd S |                      d¦  «        pd                     ¦   «         }|rJt	          |¦  «        }|j        t          v r/t                               d|t          ¦  «         t          |d<   d S d S d S )Nrd   rR   r7   z3auth: migrating stale nous portal_base_url %s -> %s)
rg  r  rb   rG   r   r=   rP  r  r  ÚDEFAULT_NOUS_PORTAL_URL)r   rd   ÚstoredrK   s       rB   r-  r-  Â  s²   € Ø�=Š=˜Ñ Ô €DÝ�d�DÑ!Ô!ð ØˆØ�hŠhÐ(Ñ)Ô)Ð/¨R×6Ò6Ñ8Ô8€FØð >Ý˜&Ñ!Ô!ˆØŒ?Õ6Ð6Ð6Ý�NŠNØEØÕ/ñô ð õ '>ˆDÐ"Ñ#Ð#Ð#ð>ð >à6Ð6rc   zinference-api.nousresearch.comÚ_ALLOWED_NOUS_INFERENCE_HOSTSrJ   c                óˆ  — t          | t          ¦  «        sdS |                      ¦   «         }|sdS 	 t          |¦  «        }n# t          $ r Y dS w xY w|j        dk    r"t                               d|j        ¦  «         dS |j        t          vr"t                               d|j        ¦  «         dS | 
                    d¦  «        S )u  Validate a Portal-returned inference URL against the host allowlist.

    Returns ``url`` (normalised by stripping trailing slashes) if it's a
    well-formed ``https://<allowlisted-host>/...`` URL. Returns ``None``
    if the URL is missing, malformed, non-https, or points at an
    unexpected host â€” letting the caller fall back to the configured
    default rather than persist or forward a poisoned value.

    Defense-in-depth: a compromised refresh response from the Portal API
    (MITM, malicious response injection) could otherwise redirect every
    subsequent proxy request â€” bearing the user's inference JWT â€” to an
    attacker-controlled endpoint.
    Validating scheme + host at the source closes that loop before the
    poisoned URL ever lands in ``auth.json``.

    The env-var override path (``NOUS_INFERENCE_BASE_URL``) bypasses
    this â€” env values come from the trusted OS user, not from the
    network, and the override is documented for staging/dev use.

    Co-authored-by: memosr <mehmet.sr35@gmail.com>
    NÚhttpszEnous: refusing non-https inference URL scheme %r from Portal responsezenous: refusing inference URL host %r from Portal response (not in allowlist); falling back to defaultrE   )r  r3   rG   r   r@   Úschemer  r  r=   rV  r?   )rJ   r  rK   s      rB   Ú)_validate_nous_inference_url_from_networkrZ  Þ  sä   € õ, �c�3ÑÔð ØˆtØ�iŠi‰kŒk€GØð ØˆtðÝ˜'Ñ"Ô"ˆˆøÝð ð ð Øˆtˆtðøøøà„}˜ÒÐÝ�ŠØSØŒMñ	
ô 	
ð 	
ð ˆtØ„Õ;Ð;Ð;Ý�Šð:àŒOñ	
ô 	
ð 	
ð
 ˆtØ�>Š>˜#ÑÔÐs   ±A Á
AÁAc                 óD   — t          t          j        d¦  «        ¦  «        S )u‰  Return the user-set ``NOUS_INFERENCE_BASE_URL`` override, if any.

    This is the documented dev/staging escape hatch. The env source is
    trusted (the OS user set it themselves), so it is intentionally NOT
    gated by the network host allowlist â€” unlike Portal-returned URLs.

    Returns a trailing-slash-stripped non-empty string, or ``None`` when
    the env var is unset/blank.
    ÚNOUS_INFERENCE_BASE_URL©rO  r´  rµ  rY   rc   rB   Ú_nous_inference_env_overrider^  	  s   € õ �bœiÐ(AÑBÔBÑCÔCÐCrc   c                 ól   — t          t          j        d¦  «        pt          j        d¦  «        ¦  «        S )u¥  Return the user/deployment-set Portal base URL override, if any.

    Mirrors ``_nous_inference_env_override()``: ``HERMES_PORTAL_BASE_URL`` /
    ``NOUS_PORTAL_BASE_URL`` are the documented dev/staging escape hatch for
    pointing Hermes at a non-production Nous Portal (e.g. a hosted agent
    provisioned on nous-account-service's `staging` environment, which stamps
    ``HERMES_PORTAL_BASE_URL=https://portal.staging-nousresearch.com`` into
    the container env). The env source is trusted (the OS user/deployment
    set it themselves), so â€” like the inference override â€” it must NOT be
    gated by ``_NOUS_PORTAL_ALLOWED_HOSTS``: that allowlist exists to reject
    an untrusted NETWORK-provided value (a poisoned portal_base_url
    persisted to auth.json), not a value the operator explicitly configured.

    Returns a trailing-slash-stripped non-empty string, or ``None`` when
    neither env var is set/blank.
    ÚHERMES_PORTAL_BASE_URLÚNOUS_PORTAL_BASE_URLr]  rY   rc   rB   Ú_nous_portal_env_overriderb  	  s4   € õ" Ý
Œ	Ð*Ñ+Ô+ÐP­r¬yÐ9OÑ/PÔ/Pñô ð rc   c                óÊ  — t          | t          ¦  «        r|                      d¦  «        dk    ri S |                      d¦  «        d         }|ddt	          |¦  «        dz  z
  dz  z  z  }	 t          j        |                     d¦  «        ¦  «        }t          j	        | 
                    d¦  «        ¦  «        }n# t          $ r i cY S w xY wt          |t          ¦  «        r|ni S )Nr8   r2  r"   Ú=rÿ   r«  )r  r3   ÚcountrÙ  r  Úbase64Úurlsafe_b64decoderj  r;  r)  Údecoder@   rb   )r  rÁ  r¶  Úclaimss       rB   Ú_decode_jwt_claimsrj  0	  sä   € Ý�e�SÑ!Ô!ð  U§[¢[°Ñ%5Ô%5¸Ò%:Ð%:Øˆ	Ø�kŠk˜#ÑÔ˜qÔ!€GØˆs�q�3˜w™<œ<¨!Ñ+Ñ+¨qÑ0Ñ1Ñ1€GðÝÔ& w§~¢~°gÑ'>Ô'>Ñ?Ô?ˆÝ”˜CŸJšJ wÑ/Ô/Ñ0Ô0ˆˆøÝð ð ð Øˆ	ˆ	ˆ	ðøøøå ­Ñ-Ô-Ð5ˆ6ˆ6°2Ð5s   Á+AB: Â:C	ÃC	Ú	raw_scopeúset[str]c                óÂ  — t          ¦   «         }t          | t          ¦  «        rW|                      dd¦  «                             ¦   «         D ]-}|                     ¦   «         }|r|                     |¦  «         Œ.ndt          | t          t          t           t          f¦  «        r<| D ]9}t          |t          ¦  «        r"| 
                    t          |¦  «        ¦  «         Œ:|S )NÚ,r-   )Úsetr  r3   r@  rÙ  rG   Úaddr|  rZ   Ú	frozensetr¿  Ú_scope_values)rk  ÚscopesÚpartr  Úitems        rB   rr  rr  =	  sÕ   € õ ‘u”u€FÝ�)�SÑ!Ô!ð 3Ø×%Ò% c¨3Ñ/Ô/×5Ò5Ñ7Ô7ð 	$ð 	$ˆDØ—j’j‘l”lˆGØð $Ø—
’
˜7Ñ#Ô#Ð#øð	$õ 
�I¥¥e­Sµ)Ð<Ñ	=Ô	=ð 3Øð 	3ð 	3ˆDÝ˜$¥Ñ$Ô$ð 3Ø—’�m¨DÑ1Ô1Ñ2Ô2Ð2øØ€Mrc   ©rU   Ú
expires_atÚmin_ttl_secondsrU   rw  rx  c               ó  — t          | ¦  «        }|sdS t          |¦  «        t          |                     d¦  «        ¦  «        z  t          |                     d¦  «        ¦  «        z  }t          |vrdS |                     d¦  «        }t	          dt          |¦  «        ¦  «        }t          |t
          t          f¦  «        r+t          |¦  «        t          j        ¦   «         |z   k    rdS dS t          ||¦  «        rd	S dS )
zDReturn None when the token can be used for inference, else a reason.Úaccess_token_not_jwtrU   ÚscpÚmissing_inference_invoke_scopeÚexpr   Úinvoke_jwt_expiringNÚ%invoke_jwt_expiry_unknown_or_expiring)
rj  rr  rg  ÚNOUS_INFERENCE_INVOKE_SCOPEr  r  r  r+  r  rH  )r  rU   rw  rx  ri  rs  r}  Úskews           rB   Ú_nous_invoke_jwt_statusr‚  M	  sü   € õ   Ñ&Ô&€FØð &Ø%Ð%å�eÑÔÝ
˜Ÿ
š
 7Ñ+Ô+Ñ
,Ô
,ñ	-å
˜Ÿ
š
 5Ñ)Ô)Ñ
*Ô
*ñ	+ð õ
 #¨&Ð0Ð0Ø/Ð/Ø
�*Š*�UÑ
Ô
€CÝˆq•#�oÑ&Ô&Ñ'Ô'€DÝ�#��U�|Ñ$Ô$ð Ý�‰:Œ:�$œ)™+œ+¨Ñ,Ò-Ð-Ø(Ð(ØˆtÝ�J Ñ%Ô%ð 7Ø6Ð6Øˆ4rc   c               ó,   — t          | |||¬¦  «        d u S )Nrv  )r‚  )r  rU   rw  rx  s       rB   Ú_nous_invoke_jwt_is_usabler„  j	  s1   € õ 	 ØØØ!Ø+ð		
ñ 	
ô 	
ð ð	ðrc   ©r  r  c               óÚ   — |€|                       d¦  «        n|}t          ||                       d¦  «        |                       d¦  «        ¬¦  «        }|€d S t          d|› d�d|d¬	¦  «        ‚)
Nr  rU   rw  ©rU   rw  ú8Nous Portal access token is not a usable inference JWT (z-). Re-authenticate with: hermes auth add nousrd   Tr}  )rg  r‚  r|  )rq  r  r  Úreasons       rB   Ú!_assert_nous_inference_jwt_usablerŠ  |	  s›   € ð
 *6Ð)=ˆE�IŠI�nÑ%Ô%Ð%À<€EÝ$ØØ�iŠi˜Ñ Ô Ø—9’9˜\Ñ*Ô*ðñ ô €Fð
 €~ØˆÝ
ð	BØð	Bð 	Bð 	BàØØðñ ô ð rc   c                óx   — t                                d¦  «         t          d|t          | ¦  «        ¬¦  «         d S )Nz)Nous inference auth: using NAS invoke JWTÚnous_invoke_jwt_selected)r¸  Úaccess_token_fp)r  rA  rÂ  r­  ©r  r¸  s     rB   Ú_log_nous_invoke_jwt_selectedr�  ’	  sI   € õ
 ‡L‚LÐ<Ñ=Ô=Ð=ÝØ"ØÝ*¨<Ñ8Ô8ðñ ô ð ð ð rc   Úfallback_expires_atc                óT  — t          | ¦  «        }|                     d¦  «        }t          |t          t          f¦  «        rP	 t          j        t	          |¦  «        t          j        ¬¦  «         	                    ¦   «         S # t          $ r Y nw xY wt          |t          ¦  «        r|nd S )Nr}  ©Útz)rj  rg  r  r  r+  r   Úfromtimestampr   r8  r9  r@   r3   )r  r�  ri  r}  s       rB   Ú_nous_jwt_expires_atr•  Ÿ	  s¡   € Ý Ñ&Ô&€FØ
�*Š*�UÑ
Ô
€CÝ�#��U�|Ñ$Ô$ð ð	ÝÔ)­%°©*¬*½¼ÐFÑFÔF×PÒPÑRÔRÐRøÝð 	ð 	ð 	ØˆDð	øøøå",Ð-@Å#Ñ"FÔ"FÐPÐÐÈDÐPs   Á>B Â
BÂB)Úobtained_atr–  c               ó
  — |                       d¦  «        }t          |t          ¦  «        r|                     ¦   «         sd S t	          j        t          j        ¦  «        }|                       d¦  «        }|r|}nY|                       d¦  «        |k    r,t          |t          ¦  «        r|                     ¦   «         r|}n|                     ¦   «         }t          ||                       d¦  «        ¦  «        }t          |¦  «        }|�1t          dt          |t          j        ¦   «         z
  ¦  «        ¦  «        n!t          |                       d¦  «        ¦  «        }|r
|| d<   || d<   || d<   d | d<   || d<   || d	<   d
| d<   || d<   d S )Nr  Úagent_key_obtained_atÚ	agent_keyrw  r   rI  Úagent_key_idÚagent_key_expires_atÚagent_key_expires_inFÚagent_key_reused)rg  r  r3   rG   r   r7  r   r8  r9  r•  rC  r  r  r  rL  )	rq  r–  r  r7  Úexisting_obtained_atÚeffective_obtained_atrw  rG  rI  s	            rB   Ú#_set_nous_agent_key_from_invoke_jwtr   ª	  s   € ð
 —9’9˜^Ñ,Ô,€LÝ�l¥CÑ(Ô(ð °×0BÒ0BÑ0DÔ0Dð ØˆÝ
Œ,•x”|Ñ
$Ô
$€CØ Ÿ9š9Ð%<Ñ=Ô=ÐØð 	0Ø +ÐÐà�	Š	�+ÑÔ ,Ò.Ð.ÝÐ+­SÑ1Ô1ð 	/à ×&Ò&Ñ(Ô(ð 	/ð !5ÐÐà #§¢¡¤ÐÝ% l°E·I²I¸lÑ4KÔ4KÑLÔL€JÝ(¨Ñ4Ô4€Mð Ð$õ 	ˆA�s�=¥4¤9¡;¤;Ñ.Ñ/Ô/Ñ0Ô0Ð0å  §¢¨<Ñ!8Ô!8Ñ9Ô9ð ð
 ð )Ø(ˆˆlÑØ(ˆˆlÑØ%€Eˆ+ÑØ €Eˆ.ÑØ$.€EÐ
 Ñ!Ø$.€EÐ
 Ñ!Ø %€EÐ
ÑØ%:€EÐ
!Ñ"Ð"Ð"rc   rŽ  c               óÈ   — t          |t          ¦  «        r|                     ¦   «         r|| d<   t          | ¦  «         t	          |                      d¦  «        |¬¦  «         d S )Nr  rŽ  )r  r3   rG   r   r�  rg  )rq  r  r¸  s      rB   Ú_select_nous_invoke_jwtr¢  Ð	  st   € õ �,¥Ñ$Ô$ð -¨×);Ò);Ñ)=Ô)=ð -Ø ,ˆˆnÑÝ'¨Ñ.Ô.Ð.Ý!Ø—Y’Y˜~Ñ.Ô.Øðñ ô ð ð ð rc   rœ  c                ó>   — d„ |                       ¦   «         D ¦   «         S )Nc                ó,   — i | ]\  }}|t           v¯||“ŒS rY   )Ú"_NOUS_EFFECTIVE_STATE_IGNORED_KEYS)râ   r$  rë   s      rB   rO  z2_nous_effective_provider_state.<locals>.<dictcomp>é	  s4   € ð ð ð áˆC�ØÕ8Ð8Ð8ð 	ˆUà8Ð8Ð8rc   )rU  ©rq  s    rB   Ú_nous_effective_provider_stater§  è	  s+   € ðð àŸ+š+™-œ-ðñ ô ð rc   c                ó
  — t          | ¦  «        }|                     d¦  «        }t          |t          t          f¦  «        sdS t	          |¦  «        t          j        ¦   «         t          dt          |¦  «        ¦  «        z   k    S )Nr}  Fr   )rj  rg  r  r  r+  r  r  )r  rE  ri  r}  s       rB   Ú_codex_access_token_is_expiringr©  ð	  si   € Ý Ñ-Ô-€FØ
�*Š*�UÑ
Ô
€CÝ�c�C¥˜<Ñ(Ô(ð ØˆuÝ�‰:Œ:�$œ)™+œ+­¨A­s°<Ñ/@Ô/@Ñ(AÔ(AÑAÒBÐBrc   c                 ó4   — t          j        ¦   «         dz  dz  S )Nz.qwenzoauth_creds.json)r   rÊ  rY   rc   rB   Ú_qwen_cli_auth_pathr«  ø	  s   € ÝŒ9‰;Œ;˜Ñ Ð#5Ñ5Ð5rc   c                 ón  — t          ¦   «         } |                      ¦   «         st          ddd¬¦  «        ‚	 t          j        |                      d¬¦  «        ¦  «        }n+# t          $ r}t          d| › d|› �dd	¬¦  «        |‚d }~ww xY wt          |t          ¦  «        st          d
| › d�dd¬¦  «        ‚|S )NzAQwen CLI credentials not found. Run 'qwen auth qwen-oauth' first.rl   Úqwen_auth_missing©r~  r  r«  rú  z)Failed to read Qwen CLI credentials from ú: Úqwen_auth_read_failedz Invalid Qwen CLI credentials in r8   Úqwen_auth_invalid)	r«  rÚ  r|  r;  r)  r*  r@   r  rb   )r  Údatar  s      rB   Ú_read_qwen_cli_tokensr³  ü	  s  € Ý#Ñ%Ô%€IØ×ÒÑÔð 
ÝØOØ!Ø$ð
ñ 
ô 
ð 	
ð
ÝŒz˜)×-Ò-°wÐ-Ñ?Ô?Ñ@Ô@ˆˆøÝð ð ð ÝØJ¸	ÐJÐJÀSÐJÐJØ!Ø(ð
ñ 
ô 
ð ð		øøøøðøøøõ �d�DÑ!Ô!ð 
ÝØ;¨yÐ;Ð;Ð;Ø!Ø$ð
ñ 
ô 
ð 	
ð
 €Ks   ¶(A Á
BÁ)BÂBÚtokensc                ó  — t          ¦   «         }|j                             dd¬¦  «         t          |¦  «         |                     |j        › dt          j        ¦   «         › dt          j	        ¦   «         j
        › �¦  «        }t          j        t          |¦  «        t          j        t          j        z  t          j        z  t           j        t           j        z  ¦  «        }	 t          j        |dd¬¦  «        5 }|                     t+          j        | dd¬	¦  «        d
z   ¦  «         |                     ¦   «          t          j        |                     ¦   «         ¦  «         d d d ¦  «         n# 1 swxY w Y   t5          ||¦  «         	 |                     ¦   «         r|                     ¦   «          nO# t:          $ r Y nCw xY w# 	 |                     ¦   «         r|                     ¦   «          w w # t:          $ r Y w w xY wxY w|S )NTr÷  r5  r8   r6  r«  rú  r2  ©r3  r½  r4  )r«  rý  rþ  r   r:  rP   r´  r;  r<  r=  r>  r  r3   r?  r@  rA  r  rB  rC  rD  rE  r;  rÀ  rF  rG  r	  r   rÚ  rJ  r  )r´  r  rL  rM  Úfhs        rB   Ú_save_qwen_cli_tokensr¸  
  s  € Ý#Ñ%Ô%€IØÔ×Ò 4°$ÐÑ7Ô7Ð7å�iÑ Ô Ð ð ×"Ò" i¤nÐ#[Ð#[½2¼9¹;¼;Ð#[Ð#[ÍÌÉÌÔIYÐ#[Ð#[Ñ\Ô\€Hõ 
ŒÝˆH‰ŒÝ
Œ•b”jÑ ¥2¤9Ñ,ÝŒ•t”|Ñ#ñ
ô 
€Bð
ÝŒY�r˜3¨Ð1Ñ1Ô1ð 	"°RØ�HŠH•T”Z ¨q¸DÐAÑAÔAÀDÑHÑIÔIÐIØ�HŠH‰JŒJˆJÝŒH�R—Y’Y‘[”[Ñ!Ô!Ð!ð	"ð 	"ð 	"ñ 	"ô 	"ð 	"ð 	"ð 	"ð 	"ð 	"ð 	"øøøð 	"ð 	"ð 	"ð 	"õ 	�x Ñ+Ô+Ð+ð	Ø�ŠÑ Ô ð "Ø—’Ñ!Ô!Ð!øøÝð 	ð 	ð 	ØˆDð	øøøøð	Ø�ŠÑ Ô ð "Ø—’Ñ!Ô!Ð!Ð!ð"øåð 	ð 	ð 	ØˆDð	øøøøøøàÐsg   Ã"G Ã9A(E-Å!G Å-E1Å1G Å4E1Å5G Æ	(F2 Æ2
F?Æ>F?ÇG>Ç(G.Ç,G>Ç.
G;Ç8G>Ç:G;Ç;G>Úexpiry_date_msc                ó¶   — 	 t          | ¦  «        }n# t          $ r Y dS w xY wt          j        ¦   «         t          dt          |¦  «        ¦  «        z   dz  |k    S )NTr   éè  )r  r@   r  r  )r¹  rE  Ú	expiry_mss      rB   Ú_qwen_access_token_is_expiringr½  4
  se   € ðÝ˜Ñ'Ô'ˆ	ˆ	øÝð ð ð ØˆtˆtðøøøåŒI‰KŒK�#˜a¥ \Ñ!2Ô!2Ñ3Ô3Ñ3°tÑ;¸yÒHÐHs   ‚ ’
 Ÿ ç      4@c                óþ  — t          |                      dd¦  «        pd¦  «                             ¦   «         }|st          ddd¬¦  «        ‚	 t	          j        t          ddd	œd|t          d
œ|¬¦  «        }n(# t          $ r}t          d|› �dd¬¦  «        |‚d }~ww xY w|j	        dk    r5|j
                             ¦   «         }t          d|rd|› �ndz   dd¬¦  «        ‚	 |                     ¦   «         }n(# t          $ r}t          d|› �dd¬¦  «        |‚d }~ww xY wt          |t          ¦  «        r7t          |                     dd¦  «        pd¦  «                             ¦   «         st          ddd¬¦  «        ‚|                     d¦  «        }	 t          |¦  «        }n# t          $ r d}Y nw xY wt          |                     dd¦  «        pd¦  «                             ¦   «         t          |                     d|¦  «        p|¦  «                             ¦   «         t          |                     d|                      dd¦  «        ¦  «        pd¦  «                             ¦   «         pdt          |                     d|                      dd¦  «        ¦  «        pd¦  «                             ¦   «         t          t          j        ¦   «         dz  ¦  «        t!          d|¦  «        dz  z   dœ}	t#          |	¦  «         |	S )NÚrefresh_tokenr7   z@Qwen OAuth refresh token missing. Re-run 'qwen auth qwen-oauth'.rl   Úqwen_refresh_token_missingr®  ú!application/x-www-form-urlencodedr/  ©r1  ÚAccept©Ú
grant_typerÀ  rT   ©r:  r²  r*  zQwen OAuth refresh failed: Úqwen_refresh_failedé�  z9Qwen OAuth refresh failed. Re-run 'qwen auth qwen-oauth'.ú Response: z*Qwen OAuth refresh returned invalid JSON: Úqwen_refresh_invalid_jsonr  z1Qwen OAuth refresh response missing access_token.Úqwen_refresh_invalid_responserI  i`T  Ú
token_typeÚBearerÚresource_urlzportal.qwen.air»  r"   )r  rÀ  rÍ  rÏ  Úexpiry_date)r3   rg  rG   r|  r>  r?  ÚQWEN_OAUTH_TOKEN_URLÚQWEN_OAUTH_CLIENT_IDr@   r@  rB  r;  r  rb   r  r  r  r¸  )
r´  ró  rÀ  Úresponser  ÚbodyrÁ  rI  Úexpires_in_secondsÚ	refresheds
             rB   Ú_refresh_qwen_cli_tokensr×  <
  s…  € Ý˜Ÿ
š
 ?°BÑ7Ô7Ð=¸2Ñ>Ô>×DÒDÑFÔF€MØð 
ÝØNØ!Ø-ð
ñ 
ô 
ð 	
ðÝ”:Ý à CØ,ðð ð
 .Ø!.Ý1ðð ð
 $ð
ñ 
ô 
ˆˆøõ ð ð ð ÝØ/¨#Ð/Ð/Ø!Ø&ð
ñ 
ô 
ð ð		øøøøðøøøð Ô˜sÒ"Ð"ØŒ}×"Ò"Ñ$Ô$ˆÝØGØ'+Ð3Ð#˜TÐ#Ð#Ð#°ñ5à!Ø&ð	
ñ 
ô 
ð 	
ðØ—-’-‘/”/ˆˆøÝð ð ð ÝØ>¸Ð>Ð>Ø!Ø,ð
ñ 
ô 
ð ð		øøøøðøøøõ �g�tÑ$Ô$ð 
­C°·²¸NÈBÑ0OÔ0OÐ0UÐSUÑ,VÔ,V×,\Ò,\Ñ,^Ô,^ð 
ÝØ?Ø!Ø0ð
ñ 
ô 
ð 	
ð —’˜\Ñ*Ô*€Jð)Ý  ™_œ_ÐÐøÝð )ð )ð )Ø(ÐÐÐð)øøøõ ˜GŸKšK¨¸Ñ;Ô;ÐA¸rÑBÔB×HÒHÑJÔJÝ˜WŸ[š[¨¸-ÑHÔHÐYÈMÑZÔZ×`Ò`ÑbÔbÝ˜'Ÿ+š+ l°F·J²J¸|ÈXÑ4VÔ4VÑWÔWÐcÐ[cÑdÔd×jÒjÑlÔlÐxÐpxÝ˜GŸKšK¨¸¿
º
À>ÐScÑ8dÔ8dÑeÔeÐyÐiyÑzÔz÷  Aò  Añ  Cô  CÝ�4œ9™;œ;¨Ñ-Ñ.Ô.µ°QÐ8JÑ1KÔ1KÈdÑ1RÑRðð €Iõ ˜)Ñ$Ô$Ð$ØÐsB   Á)A7 Á7
BÂBÂBÃ C5 Ã5
DÃ?DÄDÆF! Æ!F0Æ/F0Úcredsc                ó  — t          ¦   «         5  t          ¦   «         }i }|                      d¦  «        rt          | d         ¦  «        |d<   t	          |d|¦  «         t          |¦  «         ddd¦  «         dS # 1 swxY w Y   dS )a³  Set active_provider to qwen-oauth in auth.json.

    Qwen OAuth tokens live in the Qwen CLI credential file managed by
    _save_qwen_cli_tokens / resolve_qwen_runtime_credentials. This function
    only writes a minimal provider-state entry (base_url for display) and
    sets active_provider so that get_active_provider() and
    _model_section_has_credentials() detect the provider for the setup wizard
    and status commands.
    r2   rl   N)rl  re  rg  r3   re  rn  )rØ  rp  rq  s      rB   Ú_mark_qwen_oauth_activerÚ  „
  sÏ   € õ 
Ñ	Ô	ð %ð %Ý%Ñ'Ô'ˆ
Ø "ˆØ�9Š9�ZÑ Ô ð 	7Ý # E¨*Ô$5Ñ 6Ô 6ˆE�*ÑÝ˜Z¨°uÑ=Ô=Ð=Ý˜Ñ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %ð %ð %s   �AA:Á:A>ÂA>)Úforce_refreshÚrefresh_if_expiringÚrefresh_skew_secondsrÛ  rÜ  rÝ  c           	     óœ  — t          ¦   «         }t          |                     dd¦  «        pd¦  «                             ¦   «         }t	          | ¦  «        }|s%|r#t          |                     d¦  «        |¦  «        }|rFt          |¦  «        }t          |                     dd¦  «        pd¦  «                             ¦   «         }|st          ddd¬¦  «        ‚t          j	        dd¦  «                             ¦   «          
                    d	¦  «        pt          }d||d
|                     d¦  «        t          t          ¦   «         ¦  «        dœS )Nr  r7   rÐ  z?Qwen OAuth access token missing. Re-run 'qwen auth qwen-oauth'.rl   Úqwen_access_token_missingr®  ÚHERMES_QWEN_BASE_URLrE   r  )r~  r2   rh   r  Úexpires_at_msr  )r³  r3   rg  rG   r5   r½  r×  r|  r´  rµ  r?   ÚDEFAULT_QWEN_BASE_URLr«  )rÛ  rÜ  rÝ  r´  r  Úshould_refreshr2   s          rB   Ú resolve_qwen_runtime_credentialsrä  —
  sP  € õ #Ñ$Ô$€FÝ�v—z’z .°"Ñ5Ô5Ð;¸Ñ<Ô<×BÒBÑDÔD€LÝ˜-Ñ(Ô(€NØð iÐ1ð iÝ7¸¿
º
À=Ñ8QÔ8QÐSgÑhÔhˆØð IÝ)¨&Ñ1Ô1ˆÝ˜6Ÿ:š: n°bÑ9Ô9Ð?¸RÑ@Ô@×FÒFÑHÔHˆØð 
ÝØMØ!Ø,ð
ñ 
ô 
ð 	
õ ŒyÐ/°Ñ4Ô4×:Ò:Ñ<Ô<×CÒCÀCÑHÔHÐaÕLa€Hà ØØØØŸš MÑ2Ô2ÝÕ,Ñ.Ô.Ñ/Ô/ðð ð rc   c                 óJ  — t          ¦   «         } 	 t          d¬¦  «        }dt          | ¦  «        |                     d¦  «        |                     d¦  «        |                     d¦  «        dœS # t          $ r*}dt          | ¦  «        t          |¦  «        dœcY d }~S d }~ww xY w)	NT)rÜ  r  rh   rá  )r"  r  r  rh   rá  F)r"  r  r‹  )r«  rä  r3   rg  r|  )r  rØ  r  s      rB   Úget_qwen_auth_statusræ  ·
  sÊ   € Ý#Ñ%Ô%€Ið
õ 1ÀTÐJÑJÔJˆàÝ˜Y™œØ—i’i Ñ)Ô)Ø—y’y Ñ+Ô+Ø"ŸYšY Ñ7Ô7ð
ð 
ð 	
øõ ð 
ð 
ð 
àÝ˜Y™œÝ˜‘X”Xð
ð 
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
øøøøð
øøøs   �AA. Á.
B"Á8BÂB"ÂB"ú	List[str]c                óþ   — | pt                                ¦   «         }d„ |                     ¦   «         D ¦   «         }t          ¦   «         }g }|D ]0}||vr*|                     |¦  «         |                     |¦  «         Œ1|S )Nc                ó   — g | ]}|¯|‘ŒS rY   rY   )râ   rt  s     rB   r¨  z'_spotify_scope_list.<locals>.<listcomp>Ô
  s   € Ð:Ð:Ð:�t°TÐ:ˆdÐ:Ð:Ð:rc   )ÚDEFAULT_SPOTIFY_SCOPErG   rÙ  ro  rp  r°  )rk  Ú
scope_textrs  ÚseenÚorderedrU   s         rB   Ú_spotify_scope_listrî  Ò
  s‡   € ØÐ4Õ4×;Ò;Ñ=Ô=€JØ:Ð:˜z×/Ò/Ñ1Ô1Ð:Ñ:Ô:€FÝ‘U”U€DØ€GØð "ð "ˆØ˜ÐÐØ�HŠH�U‰OŒOˆOØ�NŠN˜5Ñ!Ô!Ð!øØ€Nrc   c                óF   — d                      t          | ¦  «        ¦  «        S )Nr-   )rð  rî  )rk  s    rB   Ú_spotify_scope_stringrð  Þ
  s   € Ø�8Š8Õ'¨	Ñ2Ô2Ñ3Ô3Ð3rc   Úexplicitc                ó  — ddl m} |  |d¦  «         |d¦  «        t          |t          ¦  «        r|                     d¦  «        nd f}|D ]+}t          |pd¦  «                             ¦   «         }|r|c S Œ,t          ddd	¬
¦  «        ‚)Nr   ©Úget_env_valueÚHERMES_SPOTIFY_CLIENT_IDÚSPOTIFY_CLIENT_IDrT   r7   zPSpotify client_id is required. Set HERMES_SPOTIFY_CLIENT_ID or pass --client-id.r.   Úspotify_client_id_missingr®  )ré   rô  r  rb   rg  r3   rG   r|  ©rñ  rq  rô  Ú
candidatesÚ	candidater  s         rB   Ú_spotify_client_idrû  â
  sÅ   € ð 0Ð/Ð/Ð/Ð/Ð/ð 	ØˆÐ0Ñ1Ô1ØˆÐ)Ñ*Ô*Ý",¨UµDÑ"9Ô"9ÐCˆ�	Š	�+ÑÔÐ¸tð	€Jð  ð ð ˆ	Ý�i�o 2Ñ&Ô&×,Ò,Ñ.Ô.ˆØð 	ØˆNˆNˆNð	å
ØZØØ(ðñ ô ð rc   c                ó  — ddl m} |  |d¦  «         |d¦  «        t          |t          ¦  «        r|                     d¦  «        nd t
          f}|D ]+}t          |pd¦  «                             ¦   «         }|r|c S Œ,t
          S )Nr   ró  ÚHERMES_SPOTIFY_REDIRECT_URIÚSPOTIFY_REDIRECT_URIÚredirect_urir7   )ré   rô  r  rb   rg  ÚDEFAULT_SPOTIFY_REDIRECT_URIr3   rG   rø  s         rB   Ú_spotify_redirect_urir  ù
  s®   € ð 0Ð/Ð/Ð/Ð/Ð/ð 	ØˆÐ3Ñ4Ô4ØˆÐ,Ñ-Ô-Ý%/°µtÑ%<Ô%<ÐFˆ�	Š	�.Ñ!Ô!Ð!À$Ý$ð€Jð  ð ð ˆ	Ý�i�o 2Ñ&Ô&×,Ò,Ñ.Ô.ˆØð 	ØˆNˆNˆNð	å'Ð'rc   c                ó  — ddl m}  |d¦  «        t          | t          ¦  «        r|                      d¦  «        nd t
          f}|D ]>}t          |pd¦  «                             ¦   «                              d¦  «        }|r|c S Œ?t
          S )Nr   ró  ÚHERMES_SPOTIFY_API_BASE_URLÚapi_base_urlr7   rE   )	ré   rô  r  rb   rg  ÚDEFAULT_SPOTIFY_API_BASE_URLr3   rG   r?   ©rq  rô  rù  rú  r  s        rB   Ú_spotify_api_base_urlr    s©   € Ø/Ð/Ð/Ð/Ð/Ð/ð 	ˆÐ3Ñ4Ô4Ý%/°µtÑ%<Ô%<ÐFˆ�	Š	�.Ñ!Ô!Ð!À$Ý$ð€Jð
  ð ð ˆ	Ý�i�o 2Ñ&Ô&×,Ò,Ñ.Ô.×5Ò5°cÑ:Ô:ˆØð 	ØˆNˆNˆNð	å'Ð'rc   c                ó  — ddl m}  |d¦  «        t          | t          ¦  «        r|                      d¦  «        nd t
          f}|D ]>}t          |pd¦  «                             ¦   «                              d¦  «        }|r|c S Œ?t
          S )Nr   ró  Ú HERMES_SPOTIFY_ACCOUNTS_BASE_URLÚaccounts_base_urlr7   rE   )	ré   rô  r  rb   rg  Ú!DEFAULT_SPOTIFY_ACCOUNTS_BASE_URLr3   rG   r?   r  s        rB   Ú_spotify_accounts_base_urlr    sª   € Ø/Ð/Ð/Ð/Ð/Ð/ð 	ˆÐ8Ñ9Ô9Ý*4°U½DÑ*AÔ*AÐKˆ�	Š	Ð%Ñ&Ô&Ð&ÀtÝ)ð€Jð
  ð ð ˆ	Ý�i�o 2Ñ&Ô&×,Ò,Ñ.Ô.×5Ò5°cÑ:Ô:ˆØð 	ØˆNˆNˆNð	å,Ð,rc   é@   Úlengthc                ó®   — t          j        t          j        | ¦  «        ¦  «                             d¦  «        }|                     d¦  «        d d…         S ©NÚasciird  é€   ©rf  Úurlsafe_b64encoder´  Úurandomrh  r?   ©r  r¶  s     rB   Ú_spotify_code_verifierr  +  óC   € Ý
Ô
"¥2¤:¨fÑ#5Ô#5Ñ
6Ô
6×
=Ò
=¸gÑ
FÔ
F€CØ�:Š:�c‰?Œ?˜4˜C˜4Ô Ð rc   Úcode_verifierc                óè   — t          j        |                      d¦  «        ¦  «                             ¦   «         }t	          j        |¦  «                             d¦  «                             d¦  «        S ©Nr«  r  rd  ©rh  ri  rj  Údigestrf  r  rh  r?   ©r  r  s     rB   Ú_spotify_code_challenger  0  óX   € ÝŒ^˜M×0Ò0°Ñ9Ô9Ñ:Ô:×AÒAÑCÔC€FÝÔ# FÑ+Ô+×2Ò2°7Ñ;Ô;×BÒBÀ3ÑGÔGÐGrc   c                ó®   — t          j        t          j        | ¦  «        ¦  «                             d¦  «        }|                     d¦  «        d d…         S r  r  r  s     rB   Ú_oauth_pkce_code_verifierr"  5  r  rc   c                óè   — t          j        |                      d¦  «        ¦  «                             ¦   «         }t	          j        |¦  «                             d¦  «                             d¦  «        S r  r  r  s     rB   Ú_oauth_pkce_code_challenger$  :  r   rc   rT   rÿ  Úcode_challenger
  c           
     ó>   — t          | d|||d|dœ¦  «        }|› d|› �S )Nr  ÚS256)rT   Úresponse_typerÿ  rU   rq  Úcode_challenge_methodr%  z/authorize?)r   )rT   rÿ  rU   rq  r%  r
  Úquerys          rB   Ú_spotify_build_authorize_urlr+  ?  sH   € õ ØØØ$ØØØ!'Ø(ðð ñ ô €Eð  Ð3Ð3¨EÐ3Ð3Ð3rc   útuple[str, int, str]c                óì   — t          | ¦  «        }|j        dk    rt          ddd¬¦  «        ‚|j        pd}|dvrt          ddd¬¦  «        ‚|j        st          d	dd¬¦  «        ‚||j        |j        pd
fS )NÚhttpzHSpotify PKCE redirect_uri must use http://localhost or http://127.0.0.1.r.   Úspotify_redirect_invalidr®  r7   >   r:   r<   z?Spotify PKCE redirect_uri must point to localhost or 127.0.0.1.zBSpotify PKCE redirect_uri must include an explicit localhost port.rE   )r   rY  r|  r=   ÚportrI   )rÿ  rK   rA   s      rB   Ú_spotify_validate_redirect_urir1  T  sº   € Ý�lÑ#Ô#€FØ„}˜ÒÐÝØVØØ+ð
ñ 
ô 
ð 	
ð
 Œ?Ð ˜b€DØÐ-Ð-Ð-ÝØMØØ+ð
ñ 
ô 
ð 	
ð
 Œ;ð 
ÝØPØØ+ð
ñ 
ô 
ð 	
ð
 �”˜fœkÐ0¨SÐ0Ð0rc   Úexpected_pathú3tuple[type[BaseHTTPRequestHandler], dict[str, Any]]c                óH   ‡ ‡— d d d d dœŠ G ˆ ˆfd„dt           ¦  «        }|‰fS )N)r  rq  r‹  Úerror_descriptionc                  ó&   •— e Zd Zd
ˆ ˆfd„Zdd„Zd	S )ú?_make_spotify_callback_handler.<locals>._SpotifyCallbackHandlerr4   rƒ  c                óê  •— t          | j        ¦  «        }|j        ‰k    rE|                      d¦  «         |                      ¦   «          | j                             d¦  «         d S t          |j        ¦  «        }|                     dd g¦  «        d         ‰d<   |                     dd g¦  «        d         ‰d<   |                     dd g¦  «        d         ‰d<   |                     dd g¦  «        d         ‰d<   |                      d¦  «         |  	                    d	d
¦  «         |                      ¦   «          ‰d         rd}nd}| j                             | 
                    d¦  «        ¦  «         d S )Né”  s
   Not found.r  r   rq  r‹  r5  r<  r1  ztext/html; charset=utf-8zW<html><body><h1>Spotify authorization failed.</h1>You can close this tab.</body></html>zY<html><body><h1>Spotify authorization received.</h1>You can close this tab.</body></html>r«  )r   rI   Úsend_responseÚend_headersÚwfilerE  r   r*  rg  Úsend_headerrj  )rˆ  rK   ÚparamsrÔ  r2  rV  s       €€rB   Údo_GETzF_make_spotify_callback_handler.<locals>._SpotifyCallbackHandler.do_GETu  si  ø€ Ý˜dœiÑ(Ô(ˆFØŒ{˜mÒ+Ð+Ø×"Ò" 3Ñ'Ô'Ð'Ø× Ò Ñ"Ô"Ð"Ø”
× Ò  Ñ/Ô/Ð/Ø�å˜fœlÑ+Ô+ˆFØ#ŸZšZ¨°°Ñ7Ô7¸Ô:ˆF�6‰NØ$Ÿjšj¨°4°&Ñ9Ô9¸!Ô<ˆF�7‰OØ$Ÿjšj¨°4°&Ñ9Ô9¸!Ô<ˆF�7‰OØ*0¯*ª*Ð5HÈ4È&Ñ*QÔ*QÐRSÔ*TˆFÐ&Ñ'à×Ò˜sÑ#Ô#Ð#Ø×Ò˜^Ð-GÑHÔHÐHØ×ÒÑÔÐØ�gŒð sØp��àr�ØŒJ×Ò˜TŸ[š[¨Ñ1Ô1Ñ2Ô2Ð2Ð2Ð2rc   Úformatr3   Úargsr   c                ó   — d S r…  rY   )rˆ  r@  rA  s      rB   Úlog_messagezK_make_spotify_callback_handler.<locals>._SpotifyCallbackHandler.log_messageŒ  s   € ØˆFrc   N©r4   rƒ  )r@  r3   rA  r   r4   rƒ  )r]   r^   r_   r?  rC  )r2  rV  s   €€rB   Ú_SpotifyCallbackHandlerr7  t  sL   ø€ € € € € ð	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð.	ð 	ð 	ð 	ð 	ð 	rc   rE  )r	   )r2  rE  rV  s   ` @rB   Ú_make_spotify_callback_handlerrF  l  sc   øø€ àØØØ!ð	ð €Fðð ð ð ð ð ð ð Õ"8ñ ô ð ð6 # FÐ*Ð*rc   ç     €f@©ró  údict[str, Any]c          	     óè  — t          | ¦  «        \  }}}t          |¦  «        \  }} G d„ dt          ¦  «        }	  |||f|¦  «        }n.# t          $ r!}	t	          d|› d|› d|	› �dd¬¦  «        |	‚d }	~	ww xY wt          j        |j        d	d
id¬¦  «        }
|
                     ¦   «          t          j
        ¦   «         t          d|¦  «        z   }	 t          j
        ¦   «         |k     r{|d         s|d         r@||                     ¦   «          |                     ¦   «          |
                     d¬¦  «         S t          j        d
¦  «         t          j
        ¦   «         |k     °{|                     ¦   «          |                     ¦   «          |
                     d¬¦  «         nC# |                     ¦   «          |                     ¦   «          |
                     d¬¦  «         w xY wt	          ddd¬¦  «        ‚)Nc                  ó   — e Zd ZdZdS )ú4_spotify_wait_for_callback.<locals>._ReuseHTTPServerTN)r]   r^   r_   Úallow_reuse_addressrY   rc   rB   Ú_ReuseHTTPServerrL  š  s   € € € € € Ø"ÐÐÐrc   rN  z*Could not bind Spotify callback server on rÒ  r¯  r.   Úspotify_callback_bind_failedr®  Úpoll_intervalgš™™™™™¹?T)rã  ÚkwargsÚdaemonç      @r  r‹  rü  ©r*  z?Spotify authorization timed out waiting for the local callback.Úspotify_callback_timeout)r1  rF  r
   r  r|  rî  ÚThreadÚserve_foreverÚstartr  r  r  rX  Úserver_closerð  r  )rÿ  ró  rA   r0  rI   Úhandler_clsrV  rN  Úserverr  Úthreadr  s               rB   Ú_spotify_wait_for_callbackr]  ’  sD  € õ
 6°lÑCÔCÑ€Dˆ$�Ý8¸Ñ>Ô>Ñ€K�ð#ð #ð #ð #ð #�:ñ #ô #ð #ðØ!Ð! 4¨ ,°Ñ<Ô<ˆˆøÝð ð ð ÝØM¸ÐMÐMÀÐMÐMÈÐMÐMØØ/ð
ñ 
ô 
ð ð		øøøøðøøøõ Ô VÔ%9À?ÐTWÐBXÐaeÐfÑfÔf€FØ
‡L‚L�N„N€NÝŒ~ÑÔ¥# c¨?Ñ";Ô";Ñ;€Hð!ÝŒnÑÔ Ò)Ð)Ø�fŒ~ð  ¨¤ð Øð 	�ŠÑÔÐØ×ÒÑÔÐØ�Š˜CˆÑ Ô Ð Ð õ	 ŒJ�s‰OŒOˆOõ ŒnÑÔ Ò)Ð)ð
 	�ŠÑÔÐØ×ÒÑÔÐØ�Š˜CˆÑ Ô Ð Ð øð 	�ŠÑÔÐØ×ÒÑÔÐØ�Š˜CˆÑ Ô Ð Ð øøøÝ
ØIØØ'ðñ ô ð s*   ºA	 Á	
A4ÁA/Á/A4Ã(F Ä5+F ÆA G)Úprevious_stateÚtoken_payloadÚrequested_scoper  r^  c               ót  — t          j        t          j        ¦  «        }t	          |                      dd¦  «        ¦  «        }t          j        |                     ¦   «         |z   t          j        ¬¦  «        }	t          |pi ¦  «        }
|
 	                    |||||t          |                      d¦  «        p|¦  «                             ¦   «         t          |                      dd¦  «        pd¦  «                             ¦   «         pdt          |                      dd¦  «        pd¦  «                             ¦   «         t          |                      d	¦  «        p|
                     d	¦  «        pd¦  «                             ¦   «         |                     ¦   «         |	                     ¦   «         |d
dœ¦  «         |
S )NrI  r   r’  rU   rÍ  rÎ  r  r7   rÀ  Ú
oauth_pkce)rT   rÿ  r
  r  rU   Úgranted_scoperÍ  r  rÀ  r–  rw  rI  rQ   )r   r7  r   r8  rL  rg  r”  rA  rb   r¿  r3   rG   r9  )r_  rT   rÿ  r`  r
  r  r^  r7  rI  rw  rq  s              rB   Ú_spotify_token_payload_to_staterd  ¹  s‹  € õ Œ,•x”|Ñ
$Ô
$€CÝ$ ]×%6Ò%6°|ÀQÑ%GÔ%GÑHÔH€JÝÔ'¨¯ª©¬¸*Ñ(DÍÌÐVÑVÔV€JÝ�Ð% 2Ñ&Ô&€EØ	‡L‚LØØ$Ø.Ø$Ø Ý˜]×.Ò.¨wÑ7Ô7ÐJ¸?ÑKÔK×QÒQÑSÔSÝ˜-×+Ò+¨L¸(ÑCÔCÐOÀxÑPÔP×VÒVÑXÔXÐdÐ\dÝ˜M×-Ò-¨n¸bÑAÔAÐGÀRÑHÔH×NÒNÑPÔPÝØ×Ò˜oÑ.Ô.ð Ø�yŠy˜Ñ)Ô)ðàñ
ô 
÷ Š%‰'Œ'Ø—}’}‘”Ø ×*Ò*Ñ,Ô,Ø Ø!ð#ð ñ ô ð ð& €Lrc   r  c           
     ó  — 	 t          j        |› d�ddi| d|||dœ|¬¦  «        }n(# t          $ r}t          d|› �dd	¬
¦  «        |‚d }~ww xY w|j        dk    r5|j                             ¦   «         }t          d|rd|› �ndz   dd	¬
¦  «        ‚|                     ¦   «         }	t          |	t          ¦  «        r7t          |	                     dd¦  «        pd¦  «                             ¦   «         st          ddd¬
¦  «        ‚|	S )Nú
/api/tokenr1  rÂ  Úauthorization_code)rT   rÆ  r  rÿ  r  rÇ  zSpotify token exchange failed: r.   Úspotify_token_exchange_failedr®  rÉ  zSpotify token exchange failed.rÊ  r7   r  z7Spotify token response did not include an access_token.Úspotify_token_exchange_invalid)r>  r?  r@   r|  r@  rB  rG   r;  r  rb   r3   rg  )
rT   r  rÿ  r  r
  ró  rÓ  r  ÚdetailrÁ  s
             rB   Ú!_spotify_exchange_code_for_tokensrk  Ý  su  € ðÝ”:Ø Ð,Ð,Ð,Ø#Ð%HÐIà&Ø2ØØ ,Ø!.ðð ð $ð
ñ 
ô 
ˆˆøõ ð ð ð ÝØ3¨cÐ3Ð3ØØ0ð
ñ 
ô 
ð ð		øøøøðøøøð Ô˜sÒ"Ð"Ø”×$Ò$Ñ&Ô&ˆÝØ,Ø)/Ð7Ð%˜VÐ%Ð%Ð%°Rñ9àØ0ð	
ñ 
ô 
ð 	
ð �mŠm‰oŒo€GÝ�g�tÑ$Ô$ð 
­C°·²¸NÈBÑ0OÔ0OÐ0UÐSUÑ,VÔ,V×,\Ò,\Ñ,^Ô,^ð 
ÝØEØØ1ð
ñ 
ô 
ð 	
ð
 €Ns   ‚#& ¦
A°AÁAc          
     ó†  — t          |                      dd¦  «        pd¦  «                             ¦   «         }|st          dddd¬¦  «        ‚t	          | ¬¦  «        }t          | ¦  «        }	 t          j        |› d	�d
did||dœ|¬¦  «        }n(# t          $ r}t          d|› �dd¬¦  «        |‚d }~ww xY w|j	        dk    r6|j
                             ¦   «         }t          d|rd|› �ndz   ddd¬¦  «        ‚|                     ¦   «         }t          |t          ¦  «        r7t          |                     dd¦  «        pd¦  «                             ¦   «         st          dddd¬¦  «        ‚t          ||t          | ¬¦  «        t          |                      d¦  «        pt           ¦  «        |t#          | ¦  «        | ¬¦  «        S )NrÀ  r7   z?Spotify refresh token missing. Run `hermes auth spotify` again.r.   Úspotify_refresh_token_missingTr}  r¦  rf  r1  rÂ  rÅ  rÇ  zSpotify token refresh failed: Úspotify_refresh_failedr®  rÉ  z>Spotify token refresh failed. Run `hermes auth spotify` again.rÊ  r  z9Spotify refresh response did not include an access_token.Úspotify_refresh_invalidrU   )rT   rÿ  r`  r
  r  r^  )r3   rg  rG   r|  rû  r  r>  r?  r@   r@  rB  r;  r  rb   rd  r  rê  r  )	rq  ró  rÀ  rT   r
  rÓ  r  rj  rÁ  s	            rB   Ú_refresh_spotify_oauth_staterp    sB  € õ
 ˜Ÿ	š	 /°2Ñ6Ô6Ð<¸"Ñ=Ô=×CÒCÑEÔE€MØð 
ÝØMØØ0Ø!ð	
ñ 
ô 
ð 	
õ #¨Ð/Ñ/Ô/€IÝ2°5Ñ9Ô9ÐðÝ”:Ø Ð,Ð,Ð,Ø#Ð%HÐIà-Ø!.Ø&ðð ð
 $ð	
ñ 	
ô 	
ˆˆøõ ð ð ð ÝØ2¨SÐ2Ð2ØØ)ð
ñ 
ô 
ð ð		øøøøðøøøð Ô˜sÒ"Ð"Ø”×$Ò$Ñ&Ô&ˆÝØLØ)/Ð7Ð%˜VÐ%Ð%Ð%°Rñ9àØ)Ø!ð
ñ 
ô 
ð 	
ð �mŠm‰oŒo€GÝ�g�tÑ$Ô$ð 
­C°·²¸NÈBÑ0OÔ0OÐ0UÐSUÑ,VÔ,V×,\Ò,\Ñ,^Ô,^ð 
ÝØGØØ*Ø!ð	
ñ 
ô 
ð 	
õ +ØØÝ*°Ð7Ñ7Ô7Ý˜EŸIšI gÑ.Ô.ÐGÕ2GÑHÔHØ+Ý*¨5Ñ1Ô1Øðñ ô ð s   Á-!B Â
B4ÂB/Â/B4c                óÔ  — t          ¦   «         5  t          ¦   «         }t          |d¦  «        }|st          dddd¬¦  «        ‚t	          | ¦  «        }|s%|r#t          |                     d¦  «        |¦  «        }|�r!	 t          |¦  «        }t          |d|d¬¦  «         t          |¦  «         nî# t          $ rá}|j
        rÔ|                     d	¦  «        r¿d
D ]}|                     |d ¦  «         Œd|j        pdt          |¦  «        ddt          j        t           j        ¦  «                             ¦   «         dœ|d<   	 t          |d|d¬¦  «         t          |¦  «         n2# t&          $ r%}t(                               d|¦  «         Y d }~nd }~ww xY w‚ d }~ww xY wd d d ¦  «         n# 1 swxY w Y   t          |                     dd¦  «        pd¦  «                             ¦   «         }	|	st          dddd¬¦  «        ‚d|	|	t          |                     dd¦  «        pd¦  «        t/          |¦  «        t          |                     d¦  «        p|                     d¦  «        pd¦  «                             ¦   «         t1          |¬¦  «        t3          |¬¦  «        |                     d¦  «        t          |                     d	d¦  «        pd¦  «                             ¦   «         dœ
S )Nr.   z>Spotify is not authenticated. Run `hermes auth spotify` first.Úspotify_auth_missingTr}  rw  Frc  rÀ  ©r  rÀ  rw  rI  r–  Úrefresh_failedÚruntime_refresh_failure©r~  r  r�  r‰  r€  ÚatÚlast_auth_errorz6Spotify OAuth: failed to persist quarantined state: %sr  r7   z>Spotify access token missing. Run `hermes auth spotify` again.Úspotify_access_token_missingrÍ  rÎ  rc  rU   r¦  )
r~  r  rh   rÍ  r2   rU   rT   rÿ  rw  rÀ  )rl  re  rf  r|  r5   rH  rg  rp  rm  rn  r€  rÁ  r  r3   r   r7  r   r8  r9  r@   r  rA  rG   r  rû  r  )
rÛ  rÜ  rÝ  rp  rq  rã  r  Ú_kÚ	_save_excr  s
             rB   Ú#resolve_spotify_runtime_credentialsr|  L  s€  € õ 
Ñ	Ô	ð 'ð 'Ý%Ñ'Ô'ˆ
Ý$ Z°Ñ;Ô;ˆØð 	ÝØPØ"Ø+Ø!%ð	ñ ô ð õ ˜mÑ,Ô,ˆØð 	YÐ"5ð 	YÝ)¨%¯)ª)°LÑ*AÔ*AÐCWÑXÔXˆNØñ 	ðÝ4°UÑ;Ô;�Ý% j°)¸UÈuÐUÑUÔUÐUÝ  Ñ,Ô,Ð,Ð,øÝð ð ð ØÔ'ð j¨E¯IªI°oÑ,FÔ,Fð jð kð ,ð ,˜ØŸ	š	 " dÑ+Ô+Ð+Ð+à$-Ø #¤Ð <Ð,<Ý#& s¡8¤8Ø";Ø,0Ý&œl­8¬<Ñ8Ô8×BÒBÑDÔDð0ð 0�EÐ+Ñ,ðjÝ-¨j¸)ÀUÐW\Ð]Ñ]Ô]Ð]Ý(¨Ñ4Ô4Ð4Ð4øÝ$ð jð jð jÝŸšÐ%]Ð_hÑiÔiÐiÐiÐiÐiÐiÐiøøøøðjøøøàøøøøð)øøøð''ð 'ð 'ñ 'ô 'ð 'ð 'ð 'ð 'ð 'ð 'øøøð 'ð 'ð 'ð 'õR �u—y’y °Ñ4Ô4Ð:¸Ñ;Ô;×AÒAÑCÔC€LØð 
ÝØLØØ/Ø!ð	
ñ 
ô 
ð 	
ð Ø$ØÝ˜%Ÿ)š) L°(Ñ;Ô;ÐG¸xÑHÔHÝ)¨%Ñ0Ô0Ý�U—Y’Y˜Ñ/Ô/ÐK°5·9²9¸WÑ3EÔ3EÐKÈÑLÔL×RÒRÑTÔTÝ'¨eÐ4Ñ4Ô4Ý-°EÐ:Ñ:Ô:Ø—i’i Ñ-Ô-Ý˜UŸYšY ¸Ñ;Ô;ÐA¸rÑBÔB×HÒHÑJÔJðð ð sa   �A-F)Á=1B/Â.F)Â/
FÂ9BFÄ?"E"Å!FÅ"
FÅ,FÆFÆFÆFÆFÆF)Æ)F-Æ0F-c            
     ó  — t          d¦  «        } | sddiS |                      d¦  «        }t          |                      dd¦  «        pd¦  «                             ¦   «         }t	          |pt          |d¦  «         ¦  «        |                      dd	¦  «        |                      d
¦  «        |                      d¦  «        |                      d¦  «        p|                      d¦  «        ||                      d¦  «        t	          |¦  «        dœS )Nr.   r"  Frw  rÀ  r7   r   rQ   rb  rT   rÿ  rc  rU   r  )r"  rQ   rT   rÿ  rU   rw  r  Úhas_refresh_token)rÄ  rg  r3   rG   r5   rH  )rq  rw  rÀ  s      rB   Úget_spotify_auth_statusr  ’  s÷   € Ý# IÑ.Ô.€EØð $Ø˜UÐ#Ð#à—’˜<Ñ(Ô(€JÝ˜Ÿ	š	 /°2Ñ6Ô6Ð<¸"Ñ=Ô=×CÒCÑEÔE€Må˜-ÐJ­|¸JÈÑ/JÔ/JÐ+JÑKÔKØ—Y’Y˜{¨LÑ9Ô9Ø—Y’Y˜{Ñ+Ô+ØŸ	š	 .Ñ1Ô1Ø—’˜?Ñ+Ô+ÐA¨u¯yªy¸Ñ/AÔ/AØ ØŸ	š	 .Ñ1Ô1Ý! -Ñ0Ô0ð	ð 	ð 	rc   Úredirect_uri_hintc                óî  — ddl m} t          ¦   «          t          d¦  «         t          d¦  «         t          d¦  «         t          ¦   «          t          d¦  «         t          d¦  «         t          d¦  «         t          ¦   «          t          dt          › �¦  «         t          ¦   «          t          d	¦  «         t          d
t          › d�¦  «         t          d¦  «         t          d¦  «         t          d¦  «         t          d| › �¦  «         t          d¦  «         t          d¦  «         t          d¦  «         t          d¦  «         t          ¦   «          t          ¦   «         s+	 t          j        t          ¦  «         n# t          $ r Y nw xY w	 t          d¦  «         
                    ¦   «         }n2# t          t          f$ r t          ¦   «          t          d¦  «        ‚w xY w|s5t          ¦   «          t          dt          › d�¦  «         t          d¦  «        ‚ |d|¦  «         | r| t          k    r |d| ¦  «         t          ¦   «          t          d¦  «         t          ¦   «          |S )zÇWalk the user through creating a Spotify developer app, persist the
    resulting client_id to ~/.hermes/.env, and return it.

    Raises SystemExit if the user aborts or submits an empty value.
    r   )Úsave_env_valuezF======================================================================zSpotify first-time setupz=Spotify requires every user to register their own lightweightz>developer app. This takes about two minutes and only has to bezdone once per machine.zFull guide: zSteps:z  1. Opening z in your browser...z$  2. Click 'Create app' and fill in:z1       App name:     anything (e.g. hermes-agent)z       Description:  anythingz       Redirect URI: z       API/SDK:      Web APIz$  3. Agree to the terms, click Save.z9  4. Open the app's Settings page and copy the Client ID.z  5. Paste it below.zSpotify Client ID: zSpotify setup cancelled.zNo Client ID entered. See z for the full guide.z)Spotify setup cancelled: empty Client ID.rõ  rý  z0Saved HERMES_SPOTIFY_CLIENT_ID to ~/.hermes/.env)ré   r‚  ÚprintÚSPOTIFY_DOCS_URLÚSPOTIFY_DASHBOARD_URLÚ_is_remote_sessionÚ
webbrowserr  r@   ÚinputrG   ÚEOFErrorÚKeyboardInterruptÚ
SystemExitr   )r€  r‚  r¶  s      rB   Ú_spotify_interactive_setuprŒ  ¥  s™  € ð 1Ð0Ð0Ð0Ð0Ð0å	�G„G€GÝ	ˆ(�O„O€OÝ	Ð
$Ñ%Ô%Ð%Ý	ˆ(�O„O€OÝ	�G„G€GÝ	Ð
IÑJÔJÐJÝ	Ð
JÑKÔKÐKÝ	Ð
"Ñ#Ô#Ð#Ý	�G„G€GÝ	Ð
+Õ)Ð
+Ð
+Ñ,Ô,Ð,Ý	�G„G€GÝ	ˆ(�O„O€OÝ	Ð
DÕ/Ð
DÐ
DÐ
DÑEÔEÐEÝ	Ð
0Ñ1Ô1Ð1Ý	Ð
=Ñ>Ô>Ð>Ý	Ð
)Ñ*Ô*Ð*Ý	Ð
5Ð"3Ð
5Ð
5Ñ6Ô6Ð6Ý	Ð
(Ñ)Ô)Ð)Ý	Ð
0Ñ1Ô1Ð1Ý	Ð
EÑFÔFÐFÝ	Ð
 Ñ!Ô!Ð!Ý	�G„G€GåÑÔð ð	ÝŒOÕ1Ñ2Ô2Ð2Ð2øÝð 	ð 	ð 	ØˆDð	øøøð5ÝÐ)Ñ*Ô*×0Ò0Ñ2Ô2ˆˆøÝÕ'Ð(ð 5ð 5ð 5Ý‰ŒˆÝÐ3Ñ4Ô4Ð4ð5øøøð ð FÝ‰ŒˆÝÐQÕ+;ÐQÐQÐQÑRÔRÐRÝÐDÑEÔEÐEð €NÐ-¨sÑ3Ô3Ð3ð ð IÐ.Õ2NÒNÐNØˆÐ4Ð6GÑHÔHÐHå	�G„G€GÝ	Ð
<Ñ=Ô=Ð=Ý	�G„G€GØ€Js   Å/F	 Æ	
FÆFÆ!F< Æ</G+c                ó,  — t          d¦  «        pi }t          | dd ¦  «        }	 t          ||¦  «        }nS# t          $ rF}t          |dd¦  «        dk    r‚ t	          t          | dd ¦  «        pt
          ¬¦  «        }Y d }~nd }~ww xY wt          t          | dd ¦  «        |¦  «        }t          t          | dd ¦  «        p|                     d¦  «        ¦  «        }t          |¦  «        }t          |¦  «        }t          | d	d
¦  «         }	t          ¦   «         }
t          |
¦  «        }t          j        ¦   «         j        }t!          ||||||¬¦  «        }t#          d¦  «         t#          d|› �¦  «         t#          d|› �¦  «         t#          d¦  «         t#          ¦   «          t#          d¦  «         t#          |¦  «         t#          ¦   «          t#          dt$          › �¦  «         t#          ¦   «          t'          |t$          ¬¦  «         |	ret)          ¦   «         sWt+          ¦   «         rI	 t-          j        |¦  «        }n# t0          $ r d
}Y nw xY w|rt#          d¦  «         nt#          d¦  «         t3          |t5          t          | dd ¦  «        pd¦  «        ¬¦  «        }|                     d¦  «        r/|                     d¦  «        p|d         }t7          d|› �¦  «        ‚|                     d¦  «        |k    rt7          d¦  «        ‚t9          |t;          |                     d¦  «        pd¦  «        ||
|t5          t          | dd ¦  «        pd¦  «        ¬¦  «        }t=          ||||||¬¦  «        }t?          ¦   «         5  tA          ¦   «         }tC          |d|d
¬ ¦  «         tE          |¦  «        }d d d ¦  «         n# 1 swxY w Y   t#          d!¦  «         t#          d"|› �¦  «         t#          d#¦  «         t#          d$t$          › �¦  «         d S )%Nr.   rT   r  r7   r÷  rÿ  )r€  rU   Ú
no_browserF)rT   rÿ  rU   rq  r%  r
  zStarting Spotify PKCE login...zClient ID: zRedirect URI: zIMake sure this redirect URI is allow-listed in your Spotify app settings.z"Open this URL to authorize Hermes:zFull setup guide: ©Údocs_urlz)Browser opened for Spotify authorization.z<Could not open the browser automatically; use the URL above.r*  rG  rH  r‹  r5  zSpotify authorization failed: rq  z-Spotify authorization failed: state mismatch.r¾  )rT   r  rÿ  r  r
  ró  )rT   rÿ  r`  r
  r  rc  zSpotify login successful!ú  Auth state: z.  Provider state saved under providers.spotifyz  Docs: )#rÄ  r  rû  r|  rŒ  r   r  rð  rg  r  r  r  r  r<  r=  r>  r+  rƒ  r„  Ú_print_loopback_ssh_hintr†  Ú_can_open_graphical_browserr‡  r  r@   r]  r+  r‹  rk  r3   rd  rl  re  rm  rn  )rA  Úexisting_stateÚexplicit_client_idrT   r  rÿ  rU   r
  r  Úopen_browserr  r%  Ústate_nonceÚauthorize_urlÚopenedÚcallbackrj  r_  Úspotify_staterp  Úsaved_tos                        rB   Úlogin_spotify_commandr�  â  s¸  € Ý,¨YÑ7Ô7Ð=¸2€Nõ
 !  {°DÑ9Ô9Ðð
Ý&Ð'9¸>ÑJÔJˆ	ˆ	øÝð 
ð 
ð 
Ý�3˜ Ñ#Ô#Ð'BÒBÐBØÝ.Ý% d¨N¸DÑAÔAÐaÕEað
ñ 
ô 
ˆ	ˆ	ˆ	ˆ	ˆ	ˆ	øøøøð
øøøõ )­°°~ÀtÑ)LÔ)LÈnÑ]Ô]€LÝ!¥'¨$°¸Ñ">Ô">Ð"]À.×BTÒBTÐU\ÑB]ÔB]Ñ^Ô^€EÝ2°>ÑBÔBÐÝ(¨Ñ8Ô8€LÝ˜t \°5Ñ9Ô9Ð9€Lå*Ñ,Ô,€MÝ,¨]Ñ;Ô;€NÝ”*‘,”,Ô"€KÝ0ØØ!ØØØ%Ø+ðñ ô €Mõ 
Ð
*Ñ+Ô+Ð+Ý	Ð
#˜	Ð
#Ð
#Ñ$Ô$Ð$Ý	Ð
)˜<Ð
)Ð
)Ñ*Ô*Ð*Ý	Ð
UÑVÔVÐVÝ	�G„G€GÝ	Ð
.Ñ/Ô/Ð/Ý	ˆ-ÑÔÐÝ	�G„G€GÝ	Ð
1Õ/Ð
1Ð
1Ñ2Ô2Ð2Ý	�G„G€Gå˜\Õ4DÐEÑEÔEÐEàð RÕ.Ñ0Ô0ð RÕ5PÑ5RÔ5Rð Rð	Ý”_ ]Ñ3Ô3ˆFˆFøÝð 	ð 	ð 	ØˆFˆFˆFð	øøøàð 	RÝÐ=Ñ>Ô>Ð>Ð>åÐPÑQÔQÐQå)ØÝ�g d¨I°tÑ<Ô<ÐEÀÑFÔFðñ ô €Hð ‡|‚|�GÑÔð DØ—’Ð1Ñ2Ô2ÐG°h¸wÔ6GˆÝÐB¸&ÐBÐBÑCÔCÐCØ‡|‚|�GÑÔ Ò+Ð+ÝÐHÑIÔIÐIå5ØÝ�—’˜fÑ%Ô%Ð+¨Ñ,Ô,Ø!Ø#Ø+Ý�g d¨I°tÑ<Ô<ÐDÀÑEÔEðñ ô €Mõ 4ØØØ!ØØ+Ø!ðñ ô €Mõ 
Ñ	Ô	ð 0ð 0Ý%Ñ'Ô'ˆ
Ý˜j¨)°]ÈuÐUÑUÔUÐUÝ# JÑ/Ô/ˆð0ð 0ð 0ñ 0ô 0ð 0ð 0ð 0ð 0ð 0ð 0øøøð 0ð 0ð 0ð 0õ
 
Ð
%Ñ&Ô&Ð&Ý	Ð
%˜8Ð
%Ð
%Ñ&Ô&Ð&Ý	Ð
:Ñ;Ô;Ð;Ý	Ð
'Õ%Ð
'Ð
'Ñ(Ô(Ð(Ð(Ð(s8   ¤5 µ
B¿<B Â BÈ*H? È?IÉIÎ1OÏOÏ	Oc                 ó’   — t          j        d¦  «        st          j        d¦  «        rdS dD ]} t          j        | ¦  «        r dS ŒdS )uH  Detect environments where loopback OAuth can't reach the local browser.

    Historically only SSH was checked, but #26923 surfaced that
    **browser-only remote consoles** (GCP Cloud Shell, GitHub
    Codespaces, AWS EC2 Instance Connect, Gitpod, Replit, etc.) hit
    the exact same problem â€” the user has a browser on their laptop
    but the loopback listener is bound on the remote VM that the
    laptop's browser can't reach.  These environments typically don't
    set ``SSH_CLIENT`` / ``SSH_TTY``, so the SSH-only check left
    them with no guidance and no fallback.
    Ú
SSH_CLIENTÚSSH_TTYT)ÚCLOUD_SHELLÚ
CODESPACESÚCODESPACE_NAMEÚGITPOD_WORKSPACE_IDÚREPL_IDÚ
STACKBLITZF)r´  rµ  )rê   s    rB   r†  r†  D  s`   € õ 
„y�ÑÔð ¥"¤)¨IÑ"6Ô"6ð Øˆtðð 	ð 	ˆõ Œ9�S‰>Œ>ð 	Ø�4�4ð	àˆ5rc   >   úwww-browserÚw3mÚlynxÚlinksÚbrowshÚelinksÚlinks2Ú_CONSOLE_BROWSER_NAMESc                 ó  — ddl } dd„}t          j                             dd	¦  «        }|r ||¦  «        rd
S t          j                             d¦  «        rQt          t          j                             d¦  «        pt          j                             d¦  «        ¦  «        }|s|sd
S 	 |                      ¦   «         }n# t          $ r Y d
S w xY wt          |dd	¦  «        pt          |dd	¦  «        pd	}|r ||¦  «        rd
S dS )uë  Return True only when a *graphical* browser is likely to open.

    ``webbrowser.open()`` resolves to whatever the platform offers, and on a
    headless / CLI-only Linux box with no GUI browser installed that is often
    a text-mode browser (w3m/lynx/links) which launches inside the terminal
    and takes over the user's session.  This guard distinguishes "a real
    windowed browser will pop up" from "a console browser will hijack the
    TTY", so callers can fall back to printing the URL instead.

    Heuristics:
      * Respect ``$BROWSER`` â€” if it names a known console browser, refuse.
      * On Linux, require a display server (``$DISPLAY`` / ``$WAYLAND_DISPLAY``)
        unless ``$BROWSER`` points at something graphical; no display server
        almost always means no GUI browser.
      * Ask ``webbrowser.get()`` what it resolved to and refuse when the
        underlying command is a known console browser.
      * macOS and Windows always have a usable default GUI browser.
    r   Nrë   r3   r4   r5   c                óú   — |                       ¦   «         r,|                       ¦   «                              ¦   «         d         nd}t          j                             |¦  «                             ¦   «         }|t          v S )Nr   r7   )rG   rÙ  r´  rI   Úbasenamer>   r®  )rë   r  Úbases      rB   Ú_names_console_browserz;_can_open_graphical_browser.<locals>._names_console_browser‹  s_   € Ø,1¯KªK©M¬MÐA�—’‘”×#Ò#Ñ%Ô% aÔ(Ð(¸rˆÝŒw×Ò Ñ&Ô&×,Ò,Ñ.Ô.ˆØÕ-Ð-Ð-rc   ÚBROWSERr7   FÚlinuxÚDISPLAYÚWAYLAND_DISPLAYrP   r±  T)rë   r3   r4   r5   )
r‡  r´  rÉ  rg  ÚsysÚplatformrð   r5   r@   r  )Ú_webbrowserr³  Úbrowser_envÚhas_displayÚ
controllerrú  s         rB   r“  r“  v  sN  € ð& %Ð$Ð$Ð$ð.ð .ð .ð .õ
 ”*—.’. ¨BÑ/Ô/€KØð Ð-Ð-¨kÑ:Ô:ð Øˆuå
„|×Ò˜wÑ'Ô'ð ÝÝŒJ�NŠN˜9Ñ%Ô%ÐJ­¬¯ªÐ8IÑ)JÔ)Jñ
ô 
ˆð ð 	 ;ð 	Ø�5ðØ —_’_Ñ&Ô&ˆ
ˆ
øÝð ð ð àˆuˆuðøøøõ
 	�
˜F BÑ'Ô'ð 	Ý�:˜z¨2Ñ.Ô.ð	àð ð
 ð Ð+Ð+¨IÑ6Ô6ð Øˆuàˆ4s   Â)B> Â>
CÃCc                 óÀ   — 	 ddl } |                      ¦   «         pd}n# t          $ r d}Y nw xY wt          j        d¦  «        pt          j        d¦  «        pd}|› d|› �S )zÝReturn best-effort 'user@hostname' for the SSH tunnel hint command.

    Falls back to placeholder tokens when the values cannot be determined so
    the hint is always syntactically valid even if not copy-pasteable.
    r   Nz<this-host>ÚUSERÚLOGNAMEz<user>ú@)ÚsocketÚgethostnamer  r´  rµ  )Ú_socketr=   r2  s      rB   Ú_ssh_user_at_hostrÅ  ¯  s†   € ð!Ø Ð Ð Ð Ø×&Ò&Ñ(Ô(Ð9¨MˆˆøÝð !ð !ð !Ø ˆˆˆð!øøøåŒ9�VÑÔÐ@¥¤	¨)Ñ 4Ô 4Ð@¸€DØÐÐ�XÐÐÐs   ‚ �,«,r�  r�  ú
str | Nonec          	     ó¢  — t          ¦   «         sdS 	 t          | ¦  «        }n# t          $ r Y dS w xY w|j        pd}|j        }|dvs|sdS d}t          ¦   «          t          |¦  «         t          d¦  «         t          |¦  «         t          d| › �¦  «         t          d¦  «         t          d¦  «         t          ¦   «          t          d	|› d
|› dt          ¦   «         › �¦  «         t          ¦   «          t          d¦  «         |rt          d|› �¦  «         t          dt          › �¦  «         t          |¦  «         t          ¦   «          dS )ap  Print an SSH tunnel hint when running a loopback-redirect OAuth flow on a
    remote host. The auth server (Spotify, MCP servers, ...) will redirect the
    user's browser to ``127.0.0.1:<port>/callback``. If the browser is on a
    different machine than the loopback listener (the usual SSH case), the
    redirect can't reach the listener without a local port forward.

    The hint is best-effort: silent if we don't think we're remote, or if we
    can't parse a host/port out of the redirect URI.

    Pass ``docs_url`` for a provider-specific guide; the generic OAuth-over-SSH
    guide is always shown after it.
    Nr7   >   r:   r;   r<   z<------------------------------------------------------------u/   Remote session detected â€” SSH tunnel requiredz,Hermes is waiting for the OAuth callback on z<but your browser is on a different machine. Run this commandz?in a NEW terminal on your local machine BEFORE opening the URL:z  ssh -N -L z:127.0.0.1:r-   z8Then open the authorize URL above in your local browser.zProvider docs:      zSSH/jump-box guide: )r†  r   r@   r=   r0  rƒ  rÅ  ÚOAUTH_OVER_SSH_DOCS_URL)rÿ  r�  rK   rA   r0  Údividers         rB   r’  r’  ¾  s|  € õ ÑÔð ØˆðÝ˜,Ñ'Ô'ˆˆøÝð ð ð ØˆˆðøøøàŒ?Ð ˜b€DØŒ;€DØÐ4Ð4Ð4¸DÐ4ØˆØ€GÝ	�G„G€GÝ	ˆ'�N„N€NÝ	Ð
;Ñ<Ô<Ð<Ý	ˆ'�N„N€NÝ	Ð
G¸Ð
GÐ
GÑHÔHÐHÝ	Ð
HÑIÔIÐIÝ	Ð
KÑLÔLÐLÝ	�G„G€GÝ	Ð
F˜Ð
FÐ
F¨$Ð
FÐ
FÕ1BÑ1DÔ1DÐ
FÐ
FÑGÔGÐGÝ	�G„G€GÝ	Ð
DÑEÔEÐEØð 1ÝÐ/ XÐ/Ð/Ñ0Ô0Ð0Ý	Ð
:Õ!8Ð
:Ð
:Ñ;Ô;Ð;Ý	ˆ'�N„N€NÝ	�G„G€G€G€Gs   ’" ¢
0¯0©Ú_lockrË  c                óÄ  — | r5t          ¦   «         5  t          ¦   «         }ddd¦  «         n# 1 swxY w Y   nt          ¦   «         }t          |d¦  «        }|st          dddd¬¦  «        ‚|                     d¦  «        }t          |t          ¦  «        st          ddd	d¬¦  «        ‚|                     d
¦  «        }|                     d¦  «        }t          |t          ¦  «        r|                     ¦   «         st          dddd¬¦  «        ‚t          |t          ¦  «        r|                     ¦   «         st          dddd¬¦  «        ‚||                     d¦  «        dœS )zÔRead Codex OAuth tokens from Hermes auth store (~/.hermes/auth.json).
    
    Returns dict with 'tokens' (access_token, refresh_token) and 'last_refresh'.
    Raises AuthError if no Codex tokens are stored.
    Nrf   ú?No Codex credentials stored. Run `hermes auth` to authenticate.Úcodex_auth_missingTr}  r´  zICodex auth state is missing tokens. Run `hermes auth` to re-authenticate.Úcodex_auth_invalid_shaper  rÀ  zICodex auth is missing access_token. Run `hermes auth` to re-authenticate.Úcodex_auth_missing_access_tokenúJCodex auth is missing refresh_token. Run `hermes auth` to re-authenticate.Ú codex_auth_missing_refresh_tokenÚlast_refresh©r´  rÓ  )	rl  re  rf  r|  rg  r  rb   r3   rG   )rË  rp  rq  r´  r  rÀ  s         rB   Ú_read_codex_tokensrÕ  ð  sá  € ð ð (ÝÑÔð 	,ð 	,Ý)Ñ+Ô+ˆJð	,ð 	,ð 	,ñ 	,ô 	,ð 	,ð 	,ð 	,ð 	,ð 	,ð 	,øøøð 	,ð 	,ð 	,ð 	,øõ &Ñ'Ô'ˆ
Ý  ¨^Ñ<Ô<€EØð 
ÝØMØ#Ø%Ø!ð	
ñ 
ô 
ð 	
ð �YŠY�xÑ Ô €FÝ�f�dÑ#Ô#ð 
ÝØWØ#Ø+Ø!ð	
ñ 
ô 
ð 	
ð —:’:˜nÑ-Ô-€LØ—J’J˜Ñ/Ô/€MÝ�l¥CÑ(Ô(ð 
°×0BÒ0BÑ0DÔ0Dð 
ÝØWØ#Ø2Ø!ð	
ñ 
ô 
ð 	
õ �m¥SÑ)Ô)ð 
°×1DÒ1DÑ1FÔ1Fð 
ÝØXØ#Ø3Ø!ð	
ñ 
ô 
ð 	
ð ØŸ	š	 .Ñ1Ô1ðð ð ó   ‘,¬0³0rÓ  Úprevious_singleton_tokensc                óª  — |                      d¦  «        }|sdS |                      d¦  «        }|                       d¦  «        }t          |t          ¦  «        sdS |                      d¦  «        }t          |t          ¦  «        sdS d}t          |t          ¦  «        r|                      d¦  «        pd}|D ]›}	t          |	t          ¦  «        sŒ|	                      d¦  «        }
|
dk    rd}n1|
d	k    r)t	          |o|	                      d¦  «        |k    ¦  «        }nd
}|sŒj||	d<   |r||	d<   |r||	d<   d|	d<   d|	d<   d|	d<   d|	d<   d|	d<   d|	d<   ŒœdS )u„	  Mirror a fresh Codex re-auth into the credential_pool OAuth entries.

    The runtime selects credentials from ``credential_pool.openai-codex``, not
    from ``providers.openai-codex.tokens``.  A re-auth invalidates the prior
    OAuth pair server-side, but pool entries keep holding the now-consumed
    refresh token plus any stale error markers â€” so the next request spends a
    dead token and gets a 401 ``token_invalidated``.

    What gets refreshed:

    * ``device_code`` â€” the singleton-seeded entry written by the device-code
      OAuth flow when the user logged in via ``hermes setup`` / the model
      picker.  Always synced with the fresh tokens.
    * ``manual:device_code`` â€” entries created by ``hermes auth add openai-codex``
      that use the same device-code OAuth mechanism.  ONLY synced if the
      entry's existing access_token matches the *previous* singleton
      access_token (i.e. the entry is a legacy singleton-alias from the
      #33000 workaround era).  Manual entries whose tokens never matched the
      singleton represent INDEPENDENT accounts added via
      ``hermes auth add openai-codex`` and must not be overwritten by a
      re-auth that targeted a different account (regression for #39236).

      The original #33538 fix refreshed every ``manual:device_code`` entry
      unconditionally.  That worked when ``manual:device_code`` only meant
      "legacy alias of the singleton", but the same source string is now
      also produced by independent-account additions, and the broad sync
      silently clobbered distinct accounts with the latest-authenticated
      token pair.  The access_token-match check distinguishes the two cases
      without changing the source-string contract.

    What does NOT get refreshed:

    * ``manual:api_key`` and any other non-device-code manual sources â€” those
      are independent credentials (an explicit API key, a different ChatGPT
      account, etc.) and must not be overwritten by a single re-auth.
    * ``manual:device_code`` entries whose access_token does NOT match the
      previous singleton â€” see above; these are independent accounts.

    Error markers (``last_status``, ``last_error_*``) are cleared ONLY on
    entries that actually had their tokens rewritten by this re-auth.
    Independent entries keep their own error state (their 401/429 markers
    belong to that account's own auth flow, not this re-auth).
    r  NrÀ  r$  rf   r  r%   Tzmanual:device_codeFrÓ  r†  r‡  rˆ  r‰  rŠ  r‹  )rg  r  rb   r|  r5   )rp  r´  rÓ  r×  r  rÀ  r"  r   Úprev_atr#  r  Úrefresh_this_entrys               rB   Ú_sync_codex_pool_entriesrÛ  !  sÊ  € ðb —:’:˜nÑ-Ô-€LØð ØˆØ—J’J˜Ñ/Ô/€MØ�>Š>Ð+Ñ,Ô,€DÝ�d�DÑ!Ô!ð ØˆØ�hŠh�~Ñ&Ô&€GÝ�g�tÑ$Ô$ð Øˆð €GÝÐ+­TÑ2Ô2ð HØ+×/Ò/°Ñ?Ô?ÐGÀ4ˆØð ,ð ,ˆÝ˜%¥Ñ&Ô&ð 	ØØ—’˜8Ñ$Ô$ˆØ�]Ò"Ð"à!%ÐÐØÐ+Ò+Ð+õ "&ØÐ@˜EŸIšI nÑ5Ô5¸Ò@ñ"ô "ÐÐð
 "'ÐØ!ð 	ØØ ,ˆˆnÑØð 	3Ø%2ˆE�/Ñ"Øð 	1Ø$0ˆE�.Ñ!Ø#ˆˆmÑØ"&ˆÐÑØ#'ˆÐÑ Ø%)ˆÐ!Ñ"Ø&*ˆÐ"Ñ#Ø'+ˆÐ#Ñ$Ð$ð?,ð ,rc   r=  c                ó°  — |€Dt          j        t          j        ¦  «                             ¦   «                              dd¦  «        }t          ¦   «         5  t          ¦   «         }t          |d¦  «        pi }t          | 
                    d¦  «        t          ¦  «        r| 
                    d¦  «        nd}| |d<   ||d<   d|d<   |rEt          |¦  «                             ¦   «         r$t          |¦  «                             ¦   «         |d	<   t          |d|¦  «         t          || ||¬
¦  «         t!          |¦  «         ddd¦  «         dS # 1 swxY w Y   dS )zCSave Codex OAuth tokens to Hermes auth store (~/.hermes/auth.json).Nr<  r:  rf   r´  rÓ  ÚchatgptÚ	auth_moder=  )r×  )r   r7  r   r8  r9  r@  rl  re  rf  r  rg  rb   r3   rG   re  rÛ  rn  )r´  rÓ  r=  rp  rq  r×  s         rB   Ú_save_codex_tokensrß  †  s›  € àÐÝ”|¥H¤LÑ1Ô1×;Ò;Ñ=Ô=×EÒEÀhÐPSÑTÔTˆÝ	Ñ	Ô	ð %ð %Ý%Ñ'Ô'ˆ
Ý$ Z°Ñ@Ô@ÐFÀBˆõ <FÀeÇiÂiÐPXÑFYÔFYÕ[_Ñ;`Ô;`Ð$j E§I¢I¨hÑ$7Ô$7Ð$7ÐfjÐ!Ø ˆˆh‰Ø ,ˆˆnÑØ&ˆˆkÑØð 	0•S˜‘Z”Z×%Ò%Ñ'Ô'ð 	0Ý  ™ZœZ×-Ò-Ñ/Ô/ˆE�'‰NÝ˜Z¨¸Ñ?Ô?Ð?Ý ØØØØ&?ð		
ñ 	
ô 	
ð 	
õ 	˜Ñ$Ô$Ð$ð+%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %ð %ð %s   ÁC)EÅEÅEr‰  c                ót  — t          ¦   «         }|rnt          |                     dd¦  «        pd¦  «                             ¦   «         r7t          |                     dd¦  «        pd¦  «                             ¦   «         sdS t                               d| ¦  «         t          |¦  «         t          |¦  «        S )zBAdopt a valid Codex CLI token pair into Hermes auth, if available.r  r7   rÀ  Nz3Codex auth recovered from Codex CLI auth.json (%s).)Ú_import_codex_cli_tokensr3   rg  rG   r  ro  rß  rb   )r‰  Úimporteds     rB   Ú_recover_codex_tokens_from_clirã  ¢  s­   € å'Ñ)Ô)€Hð 	ðå�—’˜^¨RÑ0Ô0Ð6°BÑ7Ô7×=Ò=Ñ?Ô?ðõ �—’˜_¨bÑ1Ô1Ð7°RÑ8Ô8×>Ò>Ñ@Ô@ðð
 ˆtÝ
‡K‚KÐEÀvÑNÔNÐNÝ�xÑ Ô Ð Ý�‰>Œ>Ðrc   rÀ  c          	     óø  — ~ t          |t          ¦  «        r|                     ¦   «         st          dddd¬¦  «        ‚t	          j        t          dt          |¦  «        ¦  «        ¦  «        }t	          j        |dt          dœ¬	¦  «        5 }| 
                    t          d
did|t          dœ¬¦  «        }ddd¦  «         n# 1 swxY w Y   |j        dk    rAt          t          |dd¦  «        ¦  «        }|�d|› d�}nd}t          |dt           d¬¦  «        ‚|j        dk    �r	d}d|j        › d�}d}		 |                     ¦   «         }
t          |
t$          ¦  «        �rŽ|
                     d¦  «        }t          |t$          ¦  «        r½|                     d¦  «        p|                     d¦  «        }t          |t          ¦  «        r(|                     ¦   «         r|                     ¦   «         }|                     d¦  «        }t          |t          ¦  «        r+|                     ¦   «         rd|                     ¦   «         › �}n§t          |t          ¦  «        r’|                     ¦   «         r~|                     ¦   «         }|
                     d¦  «        p|
                     d¦  «        }t          |t          ¦  «        r+|                     ¦   «         rd|                     ¦   «         › �}n# t(          $ r Y nw xY w|d v rd}	|d!k    rd"}d}	|j        d#v r|	sd}	t          |d||	¬¦  «        ‚	 |                     ¦   «         }n&# t(          $ r}t          d$dd%d¬¦  «        |‚d}~ww xY w|                     d&¦  «        }t          |t          ¦  «        r|                     ¦   «         st          d'dd(d¬¦  «        ‚|                     ¦   «         |                     ¦   «         t+          j        t.          j        ¦  «                             ¦   «                              d)d*¦  «        d+œ}|                     d¦  «        }t          |t          ¦  «        r+|                     ¦   «         r|                     ¦   «         |d<   |S ),z>Refresh Codex OAuth tokens without mutating Hermes auth state.rÑ  rf   rÒ  Tr}  rS  r/  )rÄ  ú
User-Agent©r*  r:  r1  rÂ  rÀ  rÅ  ©r:  r²  Né­  r:  ú2Codex provider quota exhausted (429); retry after ús. Credentials are still valid.úfCodex provider quota exhausted (429). Credentials are still valid; retry after the usage limit resets.Fr<  Úcodex_refresh_failedz'Codex token refresh failed with status r8   r‹  r  Útyper�  zCodex token refresh failed: r5  >   Úinvalid_grantÚinvalid_tokenÚinvalid_requestÚrefresh_token_reusedzÃCodex refresh token was already consumed by another client (e.g. Codex CLI or VS Code extension). Run `codex` in your terminal to generate fresh tokens, then run `hermes auth` to re-authenticate.>   é‘  é“  z*Codex token refresh returned invalid JSON.Úcodex_refresh_invalid_jsonr  z6Codex token refresh response was missing access_token.Ú"codex_refresh_missing_access_tokenr<  r:  )r  rÀ  rÓ  )r  r3   rG   r|  r>  ÚTimeoutr  r+  ÚClientÚCODEX_OAUTH_USER_AGENTr?  ÚCODEX_OAUTH_TOKEN_URLÚCODEX_OAUTH_CLIENT_IDr@  r•  r  r�  r;  rb   rg  r@   r   r7  r   r8  r9  r@  )r  rÀ  ró  r*  ÚclientrÓ  Úretry_afterr�  r  r€  ÚerrÚerr_objÚnested_codeÚ
nested_msgÚerr_descÚrefresh_payloadr  Úrefreshed_accessÚupdatedÚnext_refreshs                       rB   Úrefresh_codex_oauth_purer  ²  sM  € ð 	Ý�m¥SÑ)Ô)ð 
°×1DÒ1DÑ1FÔ1Fð 
ÝØXØ#Ø3Ø!ð	
ñ 
ô 
ð 	
õ Œm�C ¥U¨?Ñ%;Ô%;Ñ<Ô<Ñ=Ô=€GÝ	ŒØà(Ý0ð
ð 
ð
ñ 
ô 
ð 
ð 
Ø—;’;Ý!Ø#Ð%HÐIà-Ø!.Ý2ðð ð ñ 
ô 
ˆð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
ð" Ô˜sÒ"Ð"õ 1µ¸À9ÈdÑ1SÔ1SÑTÔTˆØÐ"ð/À[ð /ð /ð /ð ˆGð6ð õ ØØ#Ý(Ø"ð	
ñ 
ô 
ð 	
ð Ô˜sÒ"Ñ"Ø%ˆØS¸HÔ<PÐSÐSÐSˆØ Ðð	Ø—-’-‘/”/ˆCÝ˜#�tÑ$Ô$ñ TØŸ'š' 'Ñ*Ô*�å˜g¥tÑ,Ô,ð TØ")§+¢+¨fÑ"5Ô"5Ð"L¸¿ºÀVÑ9LÔ9L�KÝ! +­sÑ3Ô3ð 3¸×8IÒ8IÑ8KÔ8Kð 3Ø*×0Ò0Ñ2Ô2˜Ø!(§¢¨YÑ!7Ô!7�JÝ! *­cÑ2Ô2ð V°z×7GÒ7GÑ7IÔ7Ið VØ"UÀ×AQÒAQÑASÔASÐ"UÐ"U˜øå ­Ñ-Ô-ð T°'·-²-±/´/ð TØ"Ÿ=š=™?œ?�DØ"ŸwšwÐ':Ñ;Ô;ÐQ¸s¿wºwÀyÑ?QÔ?Q�HÝ! (­CÑ0Ô0ð T°X·^²^Ñ5EÔ5Eð TØ"SÀÇÂÑAQÔAQÐ"SÐ"S˜øøÝð 	ð 	ð 	ØˆDð	øøøàÐHÐHÐHØ#ÐØÐ)Ò)Ð)ð=ð ð  $Ðð Ô :Ð-Ð-Ð6FÐ-Ø#ÐÝØØ#ØØ-ð	
ñ 
ô 
ð 	
ðØ"Ÿ-š-™/œ/ˆˆøÝð ð ð ÝØ8Ø#Ø-Ø!ð	
ñ 
ô 
ð
 ð	øøøøðøøøð '×*Ò*¨>Ñ:Ô:ÐÝÐ&­Ñ,Ô,ð 
Ð4D×4JÒ4JÑ4LÔ4Lð 
ÝØDØ#Ø5Ø!ð	
ñ 
ô 
ð 	
ð )×.Ò.Ñ0Ô0Ø&×,Ò,Ñ.Ô.Ý œ¥X¤\Ñ2Ô2×<Ò<Ñ>Ô>×FÒFÀxÐQTÑUÔUðð €Gð
 #×&Ò& Ñ7Ô7€LÝ�,¥Ñ$Ô$ð 8¨×);Ò);Ñ)=Ô)=ð 8Ø#/×#5Ò#5Ñ#7Ô#7ˆ�Ñ Ø€Ns=   Â)C Ã CÃCÄ3F8K, Ë,
K9Ë8K9Ì-M Í
M%ÍM Í M%c           	     óÄ  — 	 t          t          |                      dd¦  «        pd¦  «        t          |                      dd¦  «        pd¦  «        |¬¦  «        }nQ# t          $ rD}t	          |dd¦  «        s‚ t          dt	          |dd	¦  «        pd
› �¦  «        }|s‚ |cY d	}~S d	}~ww xY wt          | ¦  «        }|d         |d<   |d         |d<   t          |¦  «         |S )zzRefresh Codex access token using the refresh token.
    
    Saves the new tokens to Hermes auth store automatically.
    r  r7   rÀ  rH  r€  Fzrefresh_token rejected: r  NÚ
auth_error)r  r3   rg  r|  r  rã  rb   rß  )r´  ró  rÖ  r  râ  Úupdated_tokenss         rB   Ú_refresh_codex_auth_tokensr
  8  s  € ðÝ,Ý�—
’
˜>¨2Ñ.Ô.Ð4°"Ñ5Ô5Ý�—
’
˜?¨BÑ/Ô/Ð5°2Ñ6Ô6Ø+ð
ñ 
ô 
ˆ	ˆ	øõ
 ð ð ð õ �sÐ.°Ñ6Ô6ð 	ØÝ1ØS¥w¨s°F¸DÑ'AÔ'AÐ'QÀ\ÐSÐSñ
ô 
ˆð ð 	ØØˆˆˆˆˆˆøøøøð)øøøõ, ˜&‘\”\€NØ%.¨~Ô%>€N�>Ñ"Ø&/°Ô&@€N�?Ñ#å�~Ñ&Ô&Ð&ØÐs   ‚AA Á
B)Á%9B$ÂB)Â$B)c                 ó²  — t          j        dd¦  «                             ¦   «         } | s#t          t	          j        ¦   «         dz  ¦  «        } t	          | ¦  «                             ¦   «         dz  }|                     ¦   «         sdS 	 t          j	        | 
                    d¬¦  «        ¦  «        }|                     d¦  «        }t          |t          ¦  «        sdS |                     d	¦  «        }|                     d
¦  «        }|r|sdS t          |d¦  «        rt                               d|¦  «         dS t          |¦  «        S # t"          $ r Y dS w xY w)z¶Try to read tokens from ~/.codex/auth.json (Codex CLI shared file).
    
    Returns tokens dict if valid and not expired, None otherwise.
    Does NOT write to the shared file.
    Ú
CODEX_HOMEr7   z.codexrÄ  Nr!  rú  r´  r  rÀ  r   u7   Codex CLI tokens at %s are expired â€” skipping import.)r´  rµ  rG   r3   r   rÊ  Ú
expanduserÚis_filer;  r)  r*  rg  r  rb   r©  r  rA  r@   )Ú
codex_homer  rÁ  r´  r  rÀ  s         rB   rá  rá  d  s_  € õ ”˜<¨Ñ,Ô,×2Ò2Ñ4Ô4€JØð 1Ý�œ™œ xÑ/Ñ0Ô0ˆ
Ý�ZÑ Ô ×+Ò+Ñ-Ô-°Ñ;€IØ×ÒÑÔð ØˆtðÝ”*˜Y×0Ò0¸+Ð0ÑFÔFÑGÔGˆØ—’˜XÑ&Ô&ˆÝ˜&¥$Ñ'Ô'ð 	Ø�4Ø—z’z .Ñ1Ô1ˆØŸ
š
 ?Ñ3Ô3ˆØð 	 =ð 	Ø�4õ +¨<¸Ñ;Ô;ð 	Ý�LŠLØIÈ9ñô ð ð �4Ý�F‰|Œ|ÐøÝð ð ð Øˆtˆtðøøøs%   ÂAE Ã.E Ä+E Ä9E Å
EÅEc           
     óü  — d}	 t          ¦   «         }nŠ# t          $ r}}|}t          |dd¦  «        r^t          |dd¦  «        dv rKt          t	          t          |dd¦  «        pd¦  «        ¦  «        }|r||                     d¦  «        dœ}nd}nd}Y d}~nd}~ww xY w|�€ìt          ¦   «         }|rJt          j        d	d
¦  «         	                    ¦   «          
                    d¦  «        pt          }d||ddddœS t          ¦   «         }	|	�rjt	          |	                     d¦  «        pd
¦  «         	                    ¦   «         }
|
r¦t          |
|	                     d¦  «        ¬¦  «        r‚t                               d¦  «         t!          ¦   «          t          ¦   «         }|rJt          j        d	d
¦  «         	                    ¦   «          
                    d¦  «        pt          }d||ddddœS |	                     d¦  «        }t#          |t$          t&          f¦  «        rA|t)          j        ¦   «         k    r*t%          |t)          j        ¦   «         z
  ¦  «        }d|› d�}nd}t          |dt*          d¬¦  «        ‚|�|‚t          dddd¬¦  «        ‚t-          |d         ¦  «        }t	          |                     dd
¦  «        pd
¦  «         	                    ¦   «         }t/          dd¦  «        }t1          | ¦  «        }|s|rt3          ||¦  «        }|�rt5          t7          t'          t8          ¦  «        |dz   ¦  «        ¬ ¦  «        5  t          d¬!¦  «        }t-          |d         ¦  «        }t	          |                     dd
¦  «        pd
¦  «         	                    ¦   «         }t1          | ¦  «        }|s|rt3          ||¦  «        }|rGt;          ||¦  «        }t	          |                     dd
¦  «        pd
¦  «         	                    ¦   «         }ddd¦  «         n# 1 swxY w Y   t          j        d	d
¦  «         	                    ¦   «          
                    d¦  «        pt          }d||d"|                     d¦  «        ddœS )#uÊ  Resolve runtime credentials from Hermes's own Codex token store.

    Falls back to the credential pool when the singleton (``providers.openai-codex.tokens``)
    has no usable access_token but the pool (``credential_pool.openai-codex``) does. This
    closes the divergence between the chat path (singleton-only via this function) and
    the auxiliary path (pool-first via ``_read_codex_access_token``). Without this
    fallback, a user whose tokens live only in the pool â€” for example after a manual
    pool seed, a partial re-auth, or pool-only restoration from a backup â€” gets a bare
    HTTP 401 ``Missing Authentication header`` from the wire instead of a usable
    credential. See issue #32992.
    Nr€  Fr  >   rÏ  rÐ  rÒ  r  rÓ  rÔ  ÚHERMES_CODEX_BASE_URLr7   rE   rf   r$  rÝ  ©r~  r2   rh   r  rÓ  rÞ  r  r2   )r2   uB   Codex quota restored upstream â€” clearing stale pool cooldown(s).Úreset_atré  rê  rë  r}  rÍ  rÎ  Tr´  Ú$HERMES_CODEX_REFRESH_TIMEOUT_SECONDSé   rS  rH  rÊ  úhermes-auth-store)rÕ  r|  r  rã  r3   rg  Ú_pool_codex_access_tokenr´  rµ  rG   r?   ÚDEFAULT_CODEX_BASE_URLÚ_codex_pool_rate_limit_statusÚ_probe_codex_quota_restoredr  ro  Ú clear_codex_pool_quota_cooldownsr  r  r+  r  r�  rb   r    r5   r©  rl  r  ÚAUTH_LOCK_TIMEOUT_SECONDSr
  )rÛ  rÜ  rÝ  Ú
read_errorr²  r  râ  Ú
pool_tokenr2   Úpool_rate_limitÚstale_tokenr  Ú	remainingr�  r´  r  Úrefresh_timeout_secondsrã  s                     rB   Ú!resolve_codex_runtime_credentialsr#  †  sb  € ð" '+€JðÝ!Ñ#Ô#ˆˆøÝð ð ð Øˆ
Ý�3Ð*¨EÑ2Ô2ð 	µw¸sÀFÈDÑ7QÔ7Qð V
ð 8
ð 8
õ
 6µc½'À#ÀvÈtÑ:TÔ:TÐ:dÐXdÑ6eÔ6eÑfÔfˆHØð Ø"*¸H¿LºLÈÑ<XÔ<XÐYÐY��à��àˆDøøøøøøøøøðøøøð �|Ý-Ñ/Ô/ˆ
Øð 	å”	Ð1°2Ñ6Ô6×<Ò<Ñ>Ô>×EÒEÀcÑJÔJð *Ý)ð ð
 +Ø$Ø%Ø+Ø $Ø&ðð ð õ 8Ñ9Ô9ˆØñ .	õ ˜o×1Ò1°.ÑAÔAÐGÀRÑHÔH×NÒNÑPÔPˆKØð Õ:ØØ(×,Ò,¨ZÑ8Ô8ð ñ  ô  ð õ —’ØXñô ð õ 1Ñ2Ô2Ð2Ý5Ñ7Ô7�
Øð åœ	Ð"9¸2Ñ>Ô>×DÒDÑFÔF×MÒMÈcÑRÔRð 2Ý1ð ð
 %3Ø$,Ø#-Ø"3Ø(,Ø%.ðð ð ð '×*Ò*¨:Ñ6Ô6ˆHÝ˜(¥S­% LÑ1Ô1ð 
°hÅÄÁÄÒ6LÐ6LÝ ­4¬9©;¬;Ñ 6Ñ7Ô7�	ð3Èð 3ð 3ð 3ð �ð:ð õ ØØ'Ý,Ø!&ð	ñ ô ð ð Ð!ØÐÝØMØ#Ø%Ø!ð	
ñ 
ô 
ð 	
õ �$�x”.Ñ!Ô!€FÝ�v—z’z .°"Ñ5Ô5Ð;¸Ñ<Ô<×BÒBÑDÔD€LÝ'Ð(NÐPRÑSÔSÐå˜-Ñ(Ô(€NØð ]Ð 3ð ]Ý8¸ÐG[Ñ\Ô\ˆØñ Qå­cµ%Õ8QÑ2RÔ2RÐTkÐnqÑTqÑ.rÔ.rÐsÑsÔsð 	Qð 	QÝ%¨EÐ2Ñ2Ô2ˆDÝ˜$˜xœ.Ñ)Ô)ˆFÝ˜vŸzšz¨.¸"Ñ=Ô=ÐCÀÑDÔD×JÒJÑLÔLˆLå! -Ñ0Ô0ˆNØ"ð eÐ(;ð eÝ!@ÀÐOcÑ!dÔ!d�àð QÝ3°FÐ<SÑTÔT�Ý" 6§:¢:¨n¸bÑ#AÔ#AÐ#GÀRÑHÔH×NÒNÑPÔP�ð	Qð 	Qð 	Qñ 	Qô 	Qð 	Qð 	Qð 	Qð 	Qð 	Qð 	Qøøøð 	Qð 	Qð 	Qð 	Qõ 	Œ	Ð)¨2Ñ.Ô.×4Ò4Ñ6Ô6×=Ò=¸cÑBÔBð 	"Ý!ð ð #ØØØ%ØŸš Ñ0Ô0Øðð ð s(   „ “
B�A3BÂBÍC	PÐPÐPr�  c                óÊ   — t          |pd¦  «                             ¦   «         }t          |pd¦  «                             ¦   «         }| dk    pd|v pd|v pd|v pd|v pd|v pd|v S )zITrue when persisted pool-entry error metadata describes a 429/quota stop.r7   rè  Ú
rate_limitÚusage_limitÚquotaú
rate limitúusage limit)r3   r>   )r  r‰  r�  Úreason_lÚ	message_ls        rB   Ú_is_codex_rate_limit_shapedr,    s    € õ �6�<˜RÑ Ô ×&Ò&Ñ(Ô(€HÝ�G�M˜rÑ"Ô"×(Ò(Ñ*Ô*€Ià�Šð 	 Ø˜8Ð#ð	 à˜HÐ$ð	 ð �hÐð	 ð ˜9Ð$ð		 ð
 ˜IÐ%ð	 ð �iÐðrc   i,  z'Dict[str, Tuple[float, Optional[bool]]]Ú_codex_quota_probe_cachec                ón  — t          | pd¦  «                             ¦   «                              d¦  «        }|sAt          j        dd¦  «                             ¦   «                              d¦  «        pt
          }|                     d¦  «        r|dt          d¦  «         …         }|d|v rdndz   }|d	z   S )
a™  Resolve the Codex usage endpoint for a probe.

    Mirrors the Codex CLI's PathStyle split (codex-rs backend-client, same
    logic as ``agent.account_usage._codex_backend_urls``): base URLs
    containing ``/backend-api`` use the ChatGPT ``/wham/usage`` path;
    everything else uses ``/api/codex/usage``.  Kept local so this low-level
    auth module doesn't import the auxiliary account-usage module.
    r7   rE   r  z/codexNz/backend-apiz/whamz
/api/codexz/usage)r3   rG   r?   r´  rµ  r  rà   r  )r2   rr  rô  s      rB   Ú_codex_usage_probe_urlr/  1  sÁ   € õ �X�^ Ñ$Ô$×*Ò*Ñ,Ô,×3Ò3°CÑ8Ô8€JØð 
åŒIÐ-¨rÑ2Ô2×8Ò8Ñ:Ô:×AÒAÀ#ÑFÔFð &Ý%ð 	ð ×Ò˜8Ñ$Ô$ð 2ØÐ 0¥3 x¡=¤= .Ð 0Ô1ˆ
Ø n¸
Ð&BÐ&B˜7˜7ÈÑU€FØ�HÑÐrc   )r2   Úmin_interval_secondsr0  úOptional[bool]c               ó  — t          | pd¦  «                             ¦   «         }|sdS t          |¦  «        sdS t          j        |                     d¦  «        ¦  «                             ¦   «         dd…         }t          j        ¦   «         }t          5  t                               |¦  «        }|�#||d         z
  |k     r|d         cddd¦  «         S |dft          |<   ddd¦  «         n# 1 swxY w Y   d}	 d|› �dd	d
œ}t          |¦  «        }	t          |	                     d¦  «        t          ¦  «        r)|	                     di ¦  «                             d¦  «        nd}
t          |
t           ¦  «        r+|
                     ¦   «         r|
                     ¦   «         |d<   t          j        d¬¦  «        5 }|                     t!          |¦  «        |¬¦  «        }ddd¦  «         n# 1 swxY w Y   |j        dk    r¢|                     ¦   «         pi }|                     d¦  «        pi }d}dD ]g}|                     |¦  «        pi                      d¦  «        }t          |t&          t(          f¦  «        rt+          |pdt)          |¦  «        ¦  «        }Œh|�|dk     }n|j        dk    rd}n.# t,          $ r! t.                               dd¬¦  «         d}Y nw xY wt          5  ||ft          |<   ddd¦  «         n# 1 swxY w Y   |S )uò  Ask the Codex usage endpoint whether this account's quota is usable again.

    Hermes persists a Codex 429's ``reset_at`` locally and freezes the
    credential until it elapses â€” but the upstream window can reopen EARLY
    (the user redeems a banked rate-limit reset via the Codex CLI/ChatGPT UI,
    upgrades their plan, or OpenAI resets the window).  This probe detects
    that: it GETs the same ``/usage`` endpoint the Codex CLI uses and checks
    the reported windows.

    Returns:
      * ``True``  â€” every reported rate-limit window is below 100% used;
        the account can serve requests again and stale local cooldowns
        should be lifted.
      * ``False`` â€” a window is still fully used (or the probe itself 429'd);
        keep the cooldown.
      * ``None``  â€” indeterminate (no token, network error, unexpected
        payload/status); keep the cooldown.

    Probes are throttled per access token (module-local cache) so the hot
    selection path can fire this freely.
    r7   Nr«  ra  r   r"   r.  r/  z	codex-cli)r0  rÄ  rå  zhttps://api.openai.com/authÚchatgpt_account_idzChatGPT-Account-Idg      $@rT  ©r:  r<  r%  )Úprimary_windowÚsecondary_windowÚused_percentr“  g      Y@rè  FzCodex quota probe failedTr"  )r3   rG   rj  rh  ri  rj  rk  r  r  Ú_codex_quota_probe_lockr-  rg  r  rb   r>  r÷  r/  r@  r;  r  r+  r  r@   r  rA  )r  r2   r0  r  Ú	cache_keyr7  rr  rV  r:  ri  Ú
account_idrû  rÓ  rÁ  r%  Ú
worst_usedr$  Úuseds                     rB   r  r  F  s  € õ6 �Ð" Ñ#Ô#×)Ò)Ñ+Ô+€EØð Øˆtõ ˜eÑ$Ô$ð ØˆtÝ”˜uŸ|š|¨GÑ4Ô4Ñ5Ô5×?Ò?ÑAÔAÀ#À2À#ÔF€IÝ
Œ.Ñ
Ô
€CÝ	 ð :ð :Ý)×-Ò-¨iÑ8Ô8ˆØÐ 3¨°¬¡?Ð6JÒ"JÐ"JØ˜!”9ð:ð :ð :ð :ñ :ô :ð :ð :ð 03°D¨kÕ  Ñ+ð:ð :ð :ñ :ô :ð :ð :ð :ð :ð :ð :øøøð :ð :ð :ð :ð "€Fð à. uÐ.Ð.Ø(Ø%ð
ð 
ˆõ $ EÑ*Ô*ˆõ ˜&Ÿ*š*Ð%BÑCÔCÅTÑJÔJðˆF�JŠJÐ4°bÑ9Ô9×=Ò=Ð>RÑSÔSÐSàð 	õ
 �j¥#Ñ&Ô&ð 	?¨:×+;Ò+;Ñ+=Ô+=ð 	?Ø,6×,<Ò,<Ñ,>Ô,>ˆGÐ(Ñ)ÝŒ\ $Ð'Ñ'Ô'ð 	U¨6Ø—z’zÕ"8¸Ñ"BÔ"BÈG�zÑTÔTˆHð	Uð 	Uð 	Uñ 	Uô 	Uð 	Uð 	Uð 	Uð 	Uð 	Uð 	Uøøøð 	Uð 	Uð 	Uð 	UàÔ 3Ò&Ð&Ø—m’m‘o”oÐ+¨ˆGØ Ÿš \Ñ2Ô2Ð8°bˆJØ*.ˆJØ=ð Eð E�Ø"Ÿš sÑ+Ô+Ð1¨r×6Ò6°~ÑFÔF�Ý˜d¥S­% LÑ1Ô1ð EÝ!$ ZÐ%6°3½¸d¹¼Ñ!DÔ!D�JøØÐ%Ø# eÒ+�øØÔ! SÒ(Ð(ØˆFøøÝð ð ð Ý�ŠÐ/¸$ˆÑ?Ô?Ð?Øˆˆˆðøøøõ 
!ð <ð <Ø/2°F¨mÕ  Ñ+ð<ð <ð <ñ <ô <ð <ð <ð <ð <ð <ð <øøøð <ð <ð <ð <à€Msb   Â3C,ÃC,Ã,C0Ã3C0Ã:C J1 Æ:%G+ÇJ1 Ç+G/Ç/J1 Ç2G/Ç3B=J1 Ê1(KËKË&K?Ë?LÌLc           	     óT  — d}	 t          ¦   «         5  t          ¦   «         }|                     d¦  «        }t          |t          ¦  «        r|                     d¦  «        nd}t          |t
          ¦  «        s	 ddd¦  «         dS |D ]Ë}t          |t          ¦  «        sŒ|                     d¦  «        dk    rŒ2| r)t          |                     d¦  «        pd¦  «        | k    rŒ]t          |                     d	¦  «        |                     d
¦  «        |                     d¦  «        ¦  «        sŒ¨d|d<   d|d<   d|d	<   d|d
<   d|d<   d|d<   |dz  }ŒÌ|rt          |¦  «         ddd¦  «         n# 1 swxY w Y   n,# t          $ r t                               dd¬¦  «         Y nw xY w|S )u  Clear rate-limit cooldowns on persisted openai-codex pool entries.

    Called after the upstream quota is KNOWN to be restored (a successful
    ``/usage reset`` redemption, or a positive live probe) so auth.json stops
    freezing credentials behind a stale ``last_error_reset_at``.  Only lifts
    ``exhausted`` entries whose error metadata is 429/quota-shaped â€” DEAD
    (terminal auth) entries and non-rate-limit failures are untouched.

    When *access_token* is given, only the matching entry is cleared;
    otherwise every rate-limited entry clears (a redeemed banked reset
    restores the whole account, and any entry that is genuinely still
    exhausted just re-freezes with fresh metadata on its next 429).

    Returns the number of entries cleared.
    r   r$  rf   Nr†  Ú	exhaustedr  r7   rˆ  r‰  rŠ  r‡  r‹  r"   z*Failed to clear Codex pool quota cooldownsTr"  )rl  re  rg  r  rb   r|  r3   r,  rn  r@   r  rA  )r  rä  rp  r"  r   r#  s         rB   r  r  ›  sJ  € ð  €GðRÝÑÔð 	-ð 	-Ý)Ñ+Ô+ˆJØ—>’>Ð"3Ñ4Ô4ˆDÝ2<¸TÅ4Ñ2HÔ2HÐR�d—h’h˜~Ñ.Ô.Ð.ÈdˆGÝ˜g¥tÑ,Ô,ð Øð	-ð 	-ð 	-ñ 	-ô 	-ð 	-ð 	-ð 	-ð !ð ð �Ý! %­Ñ.Ô.ð ØØ—9’9˜]Ñ+Ô+¨{Ò:Ð:ØØð ¥C¨¯	ª	°.Ñ(AÔ(AÐ(GÀRÑ$HÔ$HÈLÒ$XÐ$XØÝ2Ø—I’IÐ/Ñ0Ô0Ø—I’IÐ1Ñ2Ô2Ø—I’IÐ2Ñ3Ô3ñô ð ð
 Ø'+��mÑ$Ø*.�Ð&Ñ'Ø+/�Ð'Ñ(Ø-1�Ð)Ñ*Ø.2�Ð*Ñ+Ø/3�Ð+Ñ,Ø˜1‘��Øð -Ý  Ñ,Ô,Ð,ð7	-ð 	-ð 	-ñ 	-ô 	-ð 	-ð 	-ð 	-ð 	-ð 	-ð 	-øøøð 	-ð 	-ð 	-ð 	-øøõ8 ð Rð Rð RÝ�ŠÐAÈDˆÑQÔQÐQÐQÐQðRøøøà€NsB   „E< ’A&E0Á8E< ÂCE0Å$E< Å0E4Å4E< Å7E4Å8E< Å<&F%Æ$F%c            
     ó   — dd„} 	 t          ¦   «         5  t          ¦   «         }ddd¦  «         n# 1 swxY w Y   |                     d¦  «        }t          |t          ¦  «        sdS |                     d¦  «        }t          |t
          ¦  «        sdS t          j        ¦   «         }|D �]¸}t          |t          ¦  «        sŒ|                     d	¦  «        }t          |t          ¦  «        r|                     ¦   «         sŒX|                     d
¦  «        dk    rŒr|                     d¦  «        }t          |                     d¦  «        pd¦  «         	                    ¦   «         }t          |                     d¦  «        pd¦  «         	                    ¦   «         }	|dk    pd|v pd|v pd|v pd|	v pd|	v pd|	v }
|
s�Œ | |                     d¦  «        ¦  «        }|�||k    r�Œ=|                     d¦  «        |                     d¦  «        ||                     d¦  «        |                     d¦  «        |                     ¦   «         |                     d¦  «        dœc S n,# t          $ r t                               dd¬¦  «         Y nw xY wdS )zCReturn metadata for a pool-only Codex credential in quota cooldown.rë   r   r4   r8  c                óð  — | �| dk    rd S t          | t          t          f¦  «        r$t          | ¦  «        }|dk    rd S |dk    r|dz  n|S t          | t          ¦  «        r–|                      ¦   «         }|sd S 	 t          |¦  «        }n# t
          $ r d }Y nw xY w|�|dk    r|dz  n|S 	 t          j        |                     dd¦  «        ¦  «         	                    ¦   «         S # t
          $ r Y d S w xY wd S )Nr7   r   l    J)£ç     @�@r:  r<  )
r  r  r+  r3   rG   r  r   r?  r@  rA  )rë   Únumericr¶  s      rB   Ú_parse_reset_atz6_codex_pool_rate_limit_status.<locals>._parse_reset_atÐ  s9  € Øˆ=˜E RšK˜KØ�4Ý�e�c¥5˜\Ñ*Ô*ð 	PÝ˜E‘l”lˆGØ˜!Š|ˆ|Ø�tØ'.Ð1BÒ'BÐ'B�7˜VÑ#Ð#ÈÐOÝ�e�SÑ!Ô!ð 	Ø—+’+‘-”-ˆCØð Ø�tðÝ ™*œ*��øÝð ð ð Ø���ðøøøàÐ"Ø+2Ð5FÒ+FÐ+F�w Ñ'Ð'ÈGÐSðÝÔ-¨c¯kªk¸#¸xÑ.HÔ.HÑIÔI×SÒSÑUÔUÐUøÝð ð ð Ø�t�tðøøøàˆts$   Á9B	 Â	BÂBÂ+9C% Ã%
C3Ã2C3Nr$  rf   r  r†  r>  rˆ  r‰  r7   rŠ  rè  r%  r&  r'  r(  r)  r‹  r=  rÓ  r2   )r=  rÓ  r  r‰  r�  r  r2   z#Codex pool rate-limit lookup failedTr"  ©rë   r   r4   r8  )rl  re  rg  r  rb   r|  r  r3   rG   r>   r@   r  rA  )rC  rp  r"  r   r7  r#  r  r  r‰  r�  Úis_rate_limitedr  s               rB   r  r  Î  s  € ðð ð ð ð0-KÝÑÔð 	,ð 	,Ý)Ñ+Ô+ˆJð	,ð 	,ð 	,ñ 	,ô 	,ð 	,ð 	,ð 	,ð 	,ð 	,ð 	,øøøð 	,ð 	,ð 	,ð 	,à�~Š~Ð/Ñ0Ô0ˆÝ˜$¥Ñ%Ô%ð 	Ø�4Ø—(’(˜>Ñ*Ô*ˆÝ˜'¥4Ñ(Ô(ð 	Ø�4ÝŒi‰kŒkˆØð !	ñ !	ˆEÝ˜e¥TÑ*Ô*ð ØØ—I’I˜nÑ-Ô-ˆEÝ˜e¥SÑ)Ô)ð °·²±´ð ØØ�yŠy˜Ñ'Ô'¨;Ò6Ð6ØØ—9’9Ð.Ñ/Ô/ˆDÝ˜ŸšÐ#6Ñ7Ô7Ð=¸2Ñ>Ô>×DÒDÑFÔFˆFÝ˜%Ÿ)š)Ð$8Ñ9Ô9Ð?¸RÑ@Ô@×FÒFÑHÔHˆGà˜’ð &Ø 6Ð)ð&à  FÐ*ð&ð ˜fÐ$ð&ð   7Ð*ð	&ð
 ! GÐ+ð&ð ˜gÐ%ð ð #ð ÙØ&� u§y¢yÐ1FÑ'GÔ'GÑHÔHˆHØÐ#¨°Cª¨ÙàŸš 7Ñ+Ô+Ø %§	¢	¨.Ñ 9Ô 9Ø$ØŸ)š)Ð$7Ñ8Ô8Ø Ÿ9š9Ð%9Ñ:Ô:Ø %§¢¡¤Ø!ŸIšI jÑ1Ô1ðð ð ð ð ð3!	øõD ð Kð Kð KÝ�ŠÐ:ÀTˆÑJÔJÐJÐJÐJðKøøøàˆ4s9   †I" ”/£I" ¯3³I" ¶3·-I" Á&*I" ÂGI" É"&JÊ
Jc                 ó  — 	 t          ¦   «         5  t          ¦   «         } ddd¦  «         n# 1 swxY w Y   |                      d¦  «        }t          |t          ¦  «        sdS |                     d¦  «        }t          |t
          ¦  «        sdS dd	„}|D ]D} ||¦  «        r7t          |                     d
d¦  «        ¦  «                             ¦   «         c S ŒEn,# t          $ r t           
                    dd¬¦  «         Y nw xY wdS )aÛ  Return the most-recent usable access_token from the openai-codex pool.

    Used as a fallback by ``resolve_codex_runtime_credentials`` when the
    singleton has no creds.  Reads ``credential_pool.openai-codex`` entries
    directly from auth.json and picks the first non-empty access_token,
    preferring entries that are not currently in an exhaustion cooldown.
    Returns ``""`` when no usable entry is found (caller handles by raising
    the original AuthError).
    Nr$  r7   rf   r#  rW   r4   r5   c                óH  — t          | t          ¦  «        sdS |                      d¦  «        }t          |t          ¦  «        r|                     ¦   «         sdS |                      d¦  «        }t          |t
          t          f¦  «        r|t          j        ¦   «         k    rdS dS )NFr  r‹  T)r  rb   rg  r3   rG   r  r+  r  )r#  r  r  s      rB   Ú_entry_usablez/_pool_codex_access_token.<locals>._entry_usable-  s’   € Ý˜e¥TÑ*Ô*ð Ø�uØ—I’I˜nÑ-Ô-ˆEÝ˜e¥SÑ)Ô)ð °·²±´ð Ø�uà—y’yÐ!6Ñ7Ô7ˆHÝ˜(¥S­% LÑ1Ô1ð °hÅÄÁÄÒ6LÐ6LØ�uØ�4rc   r  z!Codex pool fallback lookup failedTr"  )r#  rW   r4   r5   )rl  re  rg  r  rb   r|  r3   rG   r@   r  rA  )rp  r"  r   rH  r#  s        rB   r  r    s|  € ðIÝÑÔð 	,ð 	,Ý)Ñ+Ô+ˆJð	,ð 	,ð 	,ñ 	,ô 	,ð 	,ð 	,ð 	,ð 	,ð 	,ð 	,øøøð 	,ð 	,ð 	,ð 	,à�~Š~Ð/Ñ0Ô0ˆÝ˜$¥Ñ%Ô%ð 	Ø�2Ø—(’(˜>Ñ*Ô*ˆÝ˜'¥4Ñ(Ô(ð 	Ø�2ð
	ð 
	ð 
	ð 
	ð ð 	Bð 	BˆEØˆ}˜UÑ#Ô#ð BÝ˜5Ÿ9š9 ^°RÑ8Ô8Ñ9Ô9×?Ò?ÑAÔAÐAÐAÐAðBð	Bøõ ð Ið Ið IÝ�ŠÐ8À4ˆÑHÔHÐHÐHÐHðIøøøàˆ2s?   ‚C �+ŸC «/¯C ²/³-C Á"*C ÂA	C ÃC Ã&DÄDc                óŽ  — t          | d¦  «        }t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        rtt	          |                     dd¦  «        pd¦  «                             ¦   «         }t	          |                     dd¦  «        pd¦  «                             ¦   «         }|r|r|S |                      d¦  «        }t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        �r|D �]}t          |t          ¦  «        sŒt	          |                     dd¦  «        pd¦  «                             ¦   «         }t	          |                     dd¦  «        pd¦  «                             ¦   «         }|r|sŒŒt          |pi ¦  «        }||t	          |                     d¦  «        pd	¦  «        d
œ|d<   |                     d¦  «        r|                     d¦  «        |d<   |                     dd¦  «         |c S t          |t          ¦  «        r|ndS )zEReturn usable xAI OAuth state from provider state or credential pool.rk   r´  Nr  r7   rÀ  r$  rÍ  rÎ  )r  rÀ  rÍ  rÓ  rÞ  rb  )rf  r  rb   rg  r3   rG   r|  rí  )	rp  rq  r´  r  rÀ  r$  r   r#  r  s	            rB   Ú_xai_oauth_state_from_storerJ  E  s@  € å  ¨[Ñ9Ô9€EÝ$.¨uµdÑ$;Ô$;ÐEˆU�YŠY�xÑ Ô Ð À€FÝ�&�$ÑÔð Ý˜6Ÿ:š: n°bÑ9Ô9Ð?¸RÑ@Ô@×FÒFÑHÔHˆÝ˜FŸJšJ ¸Ñ;Ô;ÐA¸rÑBÔB×HÒHÑJÔJˆØð 	˜Mð 	ØˆLà —n’nÐ%6Ñ7Ô7€Oõ �o¥tÑ,Ô,ð	ˆ×Ò˜KÑ(Ô(Ð(àð õ
 �'�4Ñ Ô ñ Øð 	ñ 	ˆEÝ˜e¥TÑ*Ô*ð ØÝ˜uŸyšy¨¸Ñ<Ô<ÐBÀÑCÔC×IÒIÑKÔKˆLÝ §	¢	¨/¸2Ñ >Ô >Ð DÀ"ÑEÔE×KÒKÑMÔMˆMØð  }ð ØÝ˜%˜+ 2Ñ&Ô&ˆFà ,Ø!.Ý! %§)¢)¨LÑ"9Ô"9Ð"E¸XÑFÔFð ð  ˆF�8Ñð
 �yŠy˜Ñ(Ô(ð CØ).¯ª°>Ñ)BÔ)B��~Ñ&Ø×Ò˜k¨<Ñ8Ô8Ð8ØˆMˆMˆMå˜u¥dÑ+Ô+Ð5ˆ5ˆ5°Ð5rc   c                ó”  — t          | t          ¦  «        r|                      d¦  «        nd }t          |t          ¦  «        o‡t          t	          |                     dd¦  «        pd¦  «                             ¦   «         ¦  «        oCt          t	          |                     dd¦  «        pd¦  «                             ¦   «         ¦  «        S )Nr´  r  r7   rÀ  )r  rb   rg  r5   r3   rG   )rq  r´  s     rB   Ú"_xai_oauth_state_has_usable_tokensrL  k  s©   € Ý$.¨uµdÑ$;Ô$;ÐEˆU�YŠY�xÑ Ô Ð À€Få�6�4Ñ Ô ð 	EÝ•�V—Z’Z °Ñ3Ô3Ð9°rÑ:Ô:×@Ò@ÑBÔBÑCÔCð	Eå•�V—Z’Z °Ñ4Ô4Ð:¸Ñ;Ô;×AÒAÑCÔCÑDÔDðrc   c                óx  — | r5t          ¦   «         5  t          ¦   «         }d d d ¦  «         n# 1 swxY w Y   nt          ¦   «         }t          |¦  «        }t          |¦  «        s,t          t	          ¦   «         ¦  «        }t          |¦  «        r|}|st          dddd¬¦  «        ‚|                     d¦  «        }t          |t          ¦  «        st          dddd¬¦  «        ‚t          |                     d	d
¦  «        pd
¦  «         
                    ¦   «         }t          |                     dd
¦  «        pd
¦  «         
                    ¦   «         }|st          dddd¬¦  «        ‚|st          dddd¬¦  «        ‚||                     d¦  «        |                     d¦  «        pi |                     d¦  «        dœS )Nz`No xAI OAuth credentials stored. Select xAI Grok OAuth (SuperGrok / Premium+) in `hermes model`.rk   Úxai_auth_missingTr}  r´  zGxAI OAuth state is missing tokens. Re-authenticate with `hermes model`.Úxai_auth_invalid_shaper  r7   rÀ  zMxAI OAuth state is missing access_token. Re-authenticate with `hermes model`.Úxai_auth_missing_access_tokenzNxAI OAuth state is missing refresh_token. Re-authenticate with `hermes model`.Úxai_auth_missing_refresh_tokenrÓ  Ú	discoveryrÿ  )r´  rÓ  rR  rÿ  )rl  re  rJ  rL  rÞ  r|  rg  r  rb   r3   rG   )rË  rp  rq  rU  r´  r  rÀ  s          rB   Ú_read_xai_oauth_tokensrS  t  s5  € Øð (ÝÑÔð 	,ð 	,Ý)Ñ+Ô+ˆJð	,ð 	,ð 	,ñ 	,ô 	,ð 	,ð 	,ð 	,ð 	,ð 	,ð 	,øøøð 	,ð 	,ð 	,ð 	,øõ &Ñ'Ô'ˆ
Ý'¨
Ñ3Ô3€EÝ-¨eÑ4Ô4ð !Ý2Õ3JÑ3LÔ3LÑMÔMˆÝ-¨lÑ;Ô;ð 	!Ø ˆEØð 
ÝØnØ Ø#Ø!ð	
ñ 
ô 
ð 	
ð �YŠY�xÑ Ô €FÝ�f�dÑ#Ô#ð 
ÝØUØ Ø)Ø!ð	
ñ 
ô 
ð 	
õ �v—z’z .°"Ñ5Ô5Ð;¸Ñ<Ô<×BÒBÑDÔD€LÝ˜Ÿ
š
 ?°BÑ7Ô7Ð=¸2Ñ>Ô>×DÒDÑFÔF€MØð 
ÝØ[Ø Ø0Ø!ð	
ñ 
ô 
ð 	
ð ð 
ÝØ\Ø Ø1Ø!ð	
ñ 
ô 
ð 	
ð ØŸ	š	 .Ñ1Ô1Ø—Y’Y˜{Ñ+Ô+Ð1¨rØŸ	š	 .Ñ1Ô1ð	ð ð rÖ  c                ó¦   — |                       d¦  «        }t          |t          ¦  «        o't          |                      d¦  «        t          ¦  «        S )a  True when this store has its OWN ``providers.xai-oauth`` block.

    Distinguishes a profile that genuinely shadows the root xAI grant from
    one that only *reads* root via ``_load_provider_state``'s fallback. Only
    the latter needs the refresh write-through below.
    r   rk   )rg  r  rb   )rp  r   s     rB   Ú _profile_has_own_xai_oauth_staterU  ¦  sA   € ð —’˜{Ñ+Ô+€IÝ�i¥Ñ&Ô&ÐW­:°i·m²mÀKÑ6PÔ6PÕRVÑ+WÔ+WÐWrc   c                óê  — t          ¦   «         }|€dS t          j                             d¦  «        rzt          j                             dd¦  «        }|rXt	          |¦  «        dz  dz  }	 |                     d¬¦  «        |                     d¬¦  «        k    rdS n# t          $ r Y dS w xY w	 t          d	| |d¬
¦  «         dS # t          $ r&}t           	                    d|¦  «         Y d}~dS d}~ww xY w)u  Persist a rotated xAI OAuth ``state`` into the global-root auth.json.

    Best-effort write-through for the multi-profile rotation hazard (#43589):
    xAI rotates the refresh_token on every refresh, so when a profile session
    refreshes a grant it resolved from the root fallback, the rotated chain
    must land back in root. Otherwise root keeps a now-revoked refresh token
    and every other profile reading the stale root grant dies with
    ``invalid_grant`` once its access token expires.

    Only updates ``providers.xai-oauth`` in the root store; never touches the
    profile store (the caller already saved that). Swallows all errors â€” a
    failed write-through degrades to the pre-existing behavior (root stale),
    it must never break the profile's own successful save.
    NrÅ  rÙ  r7   rÆ  rÄ  FrÇ  rk   rc  z2xAI OAuth: write-through to global root failed: %s)
r×  r´  rÉ  rg  r   rË  r@   rg  r  rA  )rq  rÛ  rÜ  rÝ  r  s        rB   Ú'_write_through_xai_oauth_to_global_rootrW  ±  sF  € õ )Ñ*Ô*€KØÐàˆõ
 
„z‡~‚~Ð+Ñ,Ô,ð Ýœ
Ÿš v¨rÑ2Ô2ˆØð 	Ý˜]Ñ+Ô+¨iÑ7¸+ÑEˆIðØ×&Ò&¨eÐ&Ñ4Ô4¸	×8IÒ8IÐQVÐ8IÑ8WÔ8WÒWÐWØ�Fð Xøåð ð ð Ø��ðøøøðPÝ(ØØØØð		
ñ 	
ô 	
ð 	
ð 	
ð 	
øõ ð Pð Pð PÝ�ŠÐIÈ3ÑOÔOÐOÐOÐOÐOÐOÐOÐOøøøøðPøøøs*   Á*.B Â
B)Â(B)Â-C Ã
C2ÃC-Ã-C2©rR  rÿ  rÓ  rÞ  rd  rR  rÞ  c               ó2  — |€Dt          j        t          j        ¦  «                             ¦   «                              dd¦  «        }t          ¦   «         5  t          ¦   «         }t          |d¦  «        \  }}|€i }| |d<   ||d<   ||d<   |r||d<   |r||d	<   t          ¦   «         }	t          |duo|	duot          ||	¦  «        ¦  «        }
|
rt          |¦  «         n"t          |d||¬
¦  «         t          |¦  «         ddd¦  «         dS # 1 swxY w Y   dS )uo  Persist xAI OAuth tokens into the auth store.

    When *set_active* is True (default), also promote ``xai-oauth`` to
    ``active_provider`` â€” appropriate for intentional model/auth login.
    Pass ``set_active=False`` for side-tool credential bootstrap (TTS/setup,
    tools config, dashboard token save, token refresh) so inference routing
    is unchanged.
    Nr<  r:  rk   r´  rÓ  rÞ  rR  rÿ  rc  )r   r7  r   r8  r9  r@  rl  re  rV  r×  r5   rè  rW  rm  rn  )r´  rR  rÿ  rÓ  rÞ  rd  rp  rq  rX  rÕ  Úis_from_roots              rB   Ú_save_xai_oauth_tokensr[  Ü  s¬  € ð" ÐÝ”|¥H¤LÑ1Ô1×;Ò;Ñ=Ô=×EÒEÀhÐPSÑTÔTˆÝ	Ñ	Ô	ð ))ð ))Ý%Ñ'Ô'ˆ
õ >Ø˜ñ
ô 
Ñˆˆ{ð ˆ=ØˆEØ ˆˆh‰Ø ,ˆˆnÑØ&ˆˆkÑØð 	+Ø!*ˆE�+ÑØð 	1Ø$0ˆE�.Ñ!Ý,Ñ.Ô.ˆÝØ˜tÐ#ð 5Ø 4Ð'ð5å˜;¨Ñ4Ô4ñ
ô 
ˆð
 ð 	)õ
 4°EÑ:Ô:Ð:Ð:õ "Ø˜K¨¸:ðñ ô ð õ ˜ZÑ(Ô(Ð(ðS))ð ))ð ))ñ ))ô ))ð ))ð ))ð ))ð ))ð ))ð ))ð ))øøøð ))ð ))ð ))ð ))ð ))ð ))s   ÁB*DÄDÄDc                ót  — t          | t          ¦  «        rd| vrdS 	 |                      d¦  «        }t          |¦  «        dk     rdS |d         }|dt          |¦  «         dz  z  z  }t	          j        t          j        |                     d¦  «        ¦  «         	                    d¦  «        ¦  «        }| 
                    d	¦  «        }t          |t          t          f¦  «        sdS t          |¦  «        t          j        ¦   «         t          d
t          |¦  «        ¦  «        z   k    S # t          $ r Y dS w xY w)Nr8   Fr2  r"   rd  rÿ   r  r«  r}  r   )r  r3   rÙ  r  r;  r)  rf  rg  rj  rh  rg  r  r+  r  r  r@   )r  rE  ÚpartsÚpayload_b64rÁ  r}  s         rB   Ú_xai_access_token_is_expiringr_    s*  € Ý�l¥CÑ(Ô(ð ¨C°|Ð,CÐ,CØˆuðØ×"Ò" 3Ñ'Ô'ˆÝˆu‰:Œ:˜Š>ˆ>Ø�5Ø˜A”hˆØ�s�s ;Ñ/Ô/Ð/°!Ñ3Ñ4Ñ4ˆÝ”*�VÔ5°k×6HÒ6HÈÑ6QÔ6QÑRÔR×YÒYÐZaÑbÔbÑcÔcˆØ�kŠk˜%Ñ Ô ˆÝ˜#¥¥U˜|Ñ,Ô,ð 	Ø�5Ý�S‰zŒz�dœi™kœk­C°µ3°|Ñ3DÔ3DÑ,EÔ,EÑEÒFÐFøÝð ð ð Øˆuˆuðøøøs   �(D) ÁBD) Ã'AD) Ä)
D7Ä6D7c                ó†  — t           }t          | t          ¦  «        rd| vr|S 	 |                      d¦  «        }t	          |¦  «        dk     r|S |d         }|dt	          |¦  «         dz  z  z  }t          j        t          j        | 	                    d¦  «        ¦  «         
                    d¦  «        ¦  «        }|                     d¦  «        }t          |t          t          f¦  «        s|S t          |¦  «        t          j        ¦   «         z
  }|d	k    r|S |d
k    rt          d|¦  «        S |S # t           $ r |cY S w xY w)u.  How far before JWT ``exp`` to proactively refresh xAI OAuth tokens.

    SuperGrok sessions can still ship multi-hour access tokens, where the
    gateway-oriented :data:`XAI_ACCESS_TOKEN_REFRESH_SKEW_SECONDS` window
    makes sense. Device-code logins often return ~15-minute JWTs; applying
    the full hour-long skew to those forces a refresh on *every* credential
    resolution (chat turn, Imagine tool call, ``hermes auth status``, â€¦),
    which burns single-use refresh tokens and races concurrent callers into
    ``invalid_grant`` quarantine.
    r8   r2  r"   rd  rÿ   r  r«  r}  r   iŒ
  r'   )Ú%XAI_ACCESS_TOKEN_REFRESH_SKEW_SECONDSr  r3   rÙ  r  r;  r)  rf  rg  rj  rh  rg  r  r+  r  Úminr@   )r  Úmax_skewr]  r^  rÁ  r}  r!  s          rB   Ú#_xai_proactive_refresh_skew_secondsrd  -  sI  € õ 5€HÝ�l¥CÑ(Ô(ð ¨C°|Ð,CÐ,CØˆðØ×"Ò" 3Ñ'Ô'ˆÝˆu‰:Œ:˜Š>ˆ>ØˆOØ˜A”hˆØ�s�s ;Ñ/Ô/Ð/°!Ñ3Ñ4Ñ4ˆÝ”*�VÔ5°k×6HÒ6HÈÑ6QÔ6QÑRÔR×YÒYÐZaÑbÔbÑcÔcˆØ�kŠk˜%Ñ Ô ˆÝ˜#¥¥U˜|Ñ,Ô,ð 	ØˆOÝ˜#‘J”J¥¤¡¤Ñ,ˆ	Ø˜Š>ˆ>ØˆOØ˜ÒÐÝ�s˜HÑ%Ô%Ð%ØˆøÝð ð ð Øˆˆˆðøøøs*   ¤)D1 ÁBD1 Ã.*D1 ÄD1 Ä/D1 Ä1E Ä?E r   c               ó@  — t          | ¦  «        }|j        dk    rt          d|› d| ›d�dd¬¦  «        ‚|j        pd                     ¦   «         }|st          d	|› d
| ›d�dd¬¦  «        ‚|dk    r.|                     d¦  «        st          d	|› d|›d�dd¬¦  «        ‚| S )uI  Refuse any OIDC discovery endpoint that isn't HTTPS on the xAI origin.

    The OIDC discovery response is a long-lived, low-frequency request whose
    output is cached in ``~/.hermes/auth.json``. A single MITM during initial
    login could substitute a malicious ``token_endpoint``; that URL would
    then receive the refresh_token on every subsequent refresh â€” a permanent
    credential leak from a one-time MITM. Validating scheme + host pins the
    cached endpoint to the xAI auth origin (or a future ``*.x.ai`` subdomain
    if xAI migrates) so the cache poisoning loses its persistence guarantee.

    RFC 8414 Â§2 requires the issuer to be ``https://`` and SHOULD-keeps the
    token_endpoint on the same origin; we enforce both. ``x.ai`` is the
    bare apex, so we accept either exact host match or any ``.x.ai`` suffix.
    rX  z(xAI OIDC discovery returned a non-HTTPS r¯  r8   rk   Úxai_discovery_invalidr®  r7   zxAI OIDC discovery z is missing a hostname: rþ  ú.x.aiz 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.)r   rY  r|  r=   r>   rà   )rJ   r   rK   rA   s       rB   Ú_xai_validate_oauth_endpointrh  O  s  € õ �c‰]Œ]€FØ„}˜ÒÐÝØH°uÐHÐHÀÐHÐHÐHØ Ø(ð
ñ 
ô 
ð 	
ð
 ŒOÐ!˜r×(Ò(Ñ*Ô*€DØð 
ÝØI %ÐIÐIÀÐIÐIÐIØ Ø(ð
ñ 
ô 
ð 	
ð
 ˆv‚~€~˜dŸmšm¨GÑ4Ô4€~ÝðK %ð Kð K¨tð Kð Kð Kð !Ø(ð
ñ 
ô 
ð 	
ð €Jrc   Úfallbackc               ó  — | pd                      ¦   «                              d¦  «        }|s|S 	 t          |¦  «        }n.# t          $ r! t                               d||¦  «         |cY S w xY w|j        dk    rt                               d||¦  «         |S |j        pd                     ¦   «         }|st                               d||¦  «         |S |dk    r4| 	                    d¦  «        st                               d	|||¦  «         |S |S )
uÇ  Refuse a non-xAI base_url for the OAuth-authenticated inference path.

    The xAI Grok OAuth bearer is a high-value, long-lived credential tied to
    the user's SuperGrok subscription. ``XAI_BASE_URL`` / ``HERMES_XAI_BASE_URL``
    let users repoint the inference endpoint (handy for staging or a local
    proxy), but the env override is also a credential-leak vector: a tampered
    ``.env`` or hostile shell init that sets
    ``XAI_BASE_URL=https://attacker.example/v1`` would ship the OAuth access
    token to a third party on every request, silently.

    Pin the inference origin to ``api.x.ai`` (or any ``*.x.ai`` subdomain xAI
    may add). On rejection, fall back to the default and log a warning rather
    than raise â€” a bad env var should not deadlock authentication, but it
    should also never leak the bearer.

    ``value`` is the already-stripped, trailing-slash-trimmed candidate from
    env. Empty input returns ``fallback`` unchanged.
    r7   rE   z>Ignoring malformed xAI base_url override %r; using %s instead.rX  znRefusing non-HTTPS xAI base_url override %r (xai-oauth bearer would be sent in cleartext); falling back to %s.zEIgnoring xAI base_url override %r with no hostname; using %s instead.rþ  rg  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.)
rG   r?   r   r@   r  r  rY  r=   r>   rà   )rë   ri  rú  rK   rA   s        rB   Ú _xai_validate_inference_base_urlrk  x  sQ  € ð& �˜"×#Ò#Ñ%Ô%×,Ò,¨SÑ1Ô1€IØð ØˆðÝ˜)Ñ$Ô$ˆˆøÝð ð ð Ý�ŠØLØ�xñ	
ô 	
ð 	
ð ˆˆˆðøøøð „}˜ÒÐÝ�Šð9à�xñ	
ô 	
ð 	
ð
 ˆØŒOÐ!˜r×(Ò(Ñ*Ô*€DØð Ý�ŠØSØ�xñ	
ô 	
ð 	
ð ˆØˆv‚~€~˜dŸmšm¨GÑ4Ô4€~Ý�Šð2ð �t˜Xñ	
ô 	
ð 	
ð ˆØÐs   ¯? ¿(A*Á)A*c                óþ  — 	 t          j        t          ddi| ¬¦  «        }n(# t          $ r}t	          d|› �dd¬¦  «        |‚d }~ww xY w|j        dk    rt	          d	|j        › d
�dd¬¦  «        ‚	 |                     ¦   «         }n(# t          $ r}t	          d|› �dd¬¦  «        |‚d }~ww xY wt          |t          ¦  «        st	          ddd¬¦  «        ‚t          |                     dd¦  «        pd¦  «         
                    ¦   «         }t          |                     dd¦  «        pd¦  «         
                    ¦   «         }|r|st	          ddd¬¦  «        ‚t          |d¬¦  «         t          |d¬¦  «         ||dœS )NrÄ  r/  )r:  r*  zxAI OIDC discovery failed: rk   Úxai_discovery_failedr®  r<  z#xAI OIDC discovery returned status r8   z*xAI OIDC discovery returned invalid JSON: Úxai_discovery_invalid_jsonz2xAI OIDC discovery response was not a JSON object.Úxai_discovery_incompleteÚauthorization_endpointr7   Útoken_endpointz;xAI OIDC discovery response was missing required endpoints.©r   )rp  rq  )r>  rg  ÚXAI_OAUTH_DISCOVERY_URLr@   r|  r@  r;  r  rb   r3   rG   rh  )ró  rÓ  r  rÁ  rp  rq  s         rB   Ú_xai_oauth_discoveryrt  °  s  € ðÝ”9Ý#ØÐ1Ð2Ø#ð
ñ 
ô 
ˆˆøõ
 ð ð ð ÝØ/¨#Ð/Ð/Ø Ø'ð
ñ 
ô 
ð ð		øøøøðøøøð Ô˜sÒ"Ð"ÝØI°(Ô2FÐIÐIÐIØ Ø'ð
ñ 
ô 
ð 	
ð
Ø—-’-‘/”/ˆˆøÝð ð ð ÝØ>¸Ð>Ð>Ø Ø-ð
ñ 
ô 
ð ð		øøøøðøøøõ �g�tÑ$Ô$ð 
ÝØ@Ø Ø+ð
ñ 
ô 
ð 	
õ
 ! §¢Ð-EÀrÑ!JÔ!JÐ!PÈbÑQÔQ×WÒWÑYÔYÐÝ˜ŸšÐ%5°rÑ:Ô:Ð@¸bÑAÔA×GÒGÑIÔI€NØ!ð 
¨ð 
ÝØIØ Ø+ð
ñ 
ô 
ð 	
õ
 !Ð!7Ð?WÐXÑXÔXÐXÝ  Ð7GÐHÑHÔHÐHà"8Ø(ðð ð s,   ‚! ¡
A«AÁAÁ0B Â
B*ÂB%Â%B*©rq  ró  rq  c          	     ó:  — ~ t          |t          ¦  «        r|                     ¦   «         st          dddd¬¦  «        ‚|                     ¦   «         pt	          |¦  «        d         }t          |d¬¦  «         t          j        t          dt          |¦  «        ¦  «        ¦  «        }t          j
        |d	d
i¬¦  «        5 }|                     |ddidt          |dœ¬¦  «        }d d d ¦  «         n# 1 swxY w Y   |j        dk    rh|j                             ¦   «         }|j        dk    r t          d|rd|› �ndz   dz   ddd¬¦  «        ‚t          d|rd|› �ndz   dd|j        dv ¬¦  «        ‚	 |                     ¦   «         }	n(# t           $ r}
t          d|
› �dd¬¦  «        |
‚d }
~
ww xY wt          |	t"          ¦  «        st          ddd d¬¦  «        ‚t          |	                     d!d¦  «        pd¦  «                             ¦   «         }|st          d"dd#d¬¦  «        ‚|t          |	                     d¦  «        p|¦  «                             ¦   «         t          |	                     d$¦  «        pd¦  «                             ¦   «         |	                     d%¦  «        t          |	                     d&¦  «        pd'¦  «                             ¦   «         pd't'          j        t*          j        ¦  «                             ¦   «                              d(d)¦  «        d*œ}|S )+NzHxAI OAuth is missing refresh_token. Re-authenticate with `hermes model`.rk   rQ  Tr}  rq  rr  rS  rÄ  r/  ræ  r1  rÂ  rÀ  ©rÆ  rT   rÀ  rç  r<  ró  z'xAI token refresh failed with HTTP 403.rÊ  r7   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_failed>   rÉ  rò  z)xAI token refresh returned invalid JSON: Úxai_refresh_invalid_jsonr®  z1xAI token refresh response was not a JSON object.Úxai_refresh_invalid_responser  z4xAI token refresh response was missing access_token.Ú xai_refresh_missing_access_tokenÚid_tokenrI  rÍ  rÎ  r<  r:  )r  rÀ  r}  rI  rÍ  rÓ  )r  r3   rG   r|  rt  rh  r>  rö  r  r+  r÷  r?  ÚXAI_OAUTH_CLIENT_IDr@  rB  r;  r@   rb   rg  r   r7  r   r8  r9  r@  )r  rÀ  rq  ró  r)  r*  rû  rÓ  rj  rÁ  r  r  r  s                rB   Úrefresh_xai_oauth_purer  á  sÚ  € ð 	Ý�m¥SÑ)Ô)ð 
°×1DÒ1DÑ1FÔ1Fð 
ÝØVØ Ø1Ø!ð	
ñ 
ô 
ð 	
ð ×#Ò#Ñ%Ô%Ð`Õ)=¸oÑ)NÔ)NÐO_Ô)`€Hõ ! Ð1AÐBÑBÔBÐBÝŒm�C ¥U¨?Ñ%;Ô%;Ñ<Ô<Ñ=Ô=€GÝ	Œ˜g°Ð:LÐ/MÐ	NÑ	NÔ	Nð 	
ÐRXØ—;’;ØØ#Ð%HÐIà-Ý0Ø!.ðð ð ñ 
ô 
ˆð	
ð 	
ð 	
ñ 	
ô 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
øøøð 	
ð 	
ð 	
ð 	
ð Ô˜sÒ"Ð"Ø”×$Ò$Ñ&Ô&ˆð Ô 3Ò&Ð&ÝØ9Ø-3Ð;Ð) Ð)Ð)Ð)¸ñ=ðEñEð %Ø,Ø!&ðñ ô ð õ Ø'Ø)/Ð7Ð%˜VÐ%Ð%Ð%°Rñ9à Ø%Ø&Ô2°jÐ@ð
ñ 
ô 
ð 	
ðØ—-’-‘/”/ˆˆøÝð ð ð ÝØ=¸Ð=Ð=Ø Ø+ð
ñ 
ô 
ð ð		øøøøðøøøõ �g�tÑ$Ô$ð 
ÝØ?Ø Ø/Ø!ð	
ñ 
ô 
ð 	
õ ˜7Ÿ;š; ~°rÑ:Ô:Ð@¸bÑAÔA×GÒGÑIÔIÐØð 
ÝØBØ Ø3Ø!ð	
ñ 
ô 
ð 	
ð )Ý˜WŸ[š[¨Ñ9Ô9ÐJ¸]ÑKÔK×QÒQÑSÔSÝ˜Ÿš JÑ/Ô/Ð5°2Ñ6Ô6×<Ò<Ñ>Ô>Ø—k’k ,Ñ/Ô/Ý˜'Ÿ+š+ lÑ3Ô3Ð?°xÑ@Ô@×FÒFÑHÔHÐTÈHÝ œ¥X¤\Ñ2Ô2×<Ò<Ñ>Ô>×FÒFÀxÐQTÑUÔUðð €Gð €Ns*   Â?$C/Ã/C3Ã6C3Å.F Æ
F(ÆF#Æ#F()rÿ  c          	     ó¨  — 	 t          t          ¦   «         d¦  «        pi }t          |                     d¦  «        pd¦  «        }n# t          $ r d}Y nw xY wt          t          |                      dd¦  «        pd¦  «        t          |                      dd¦  «        pd¦  «        ||¬¦  «        }t          | ¦  «        }|d         |d<   |d         |d<   |                     d¦  «        r|d         |d<   |                     d	¦  «        �|d	         |d	<   |                     d
¦  «        r|d
         |d
<   t          |d|i||d         |d¬¦  «         |S )Nrk   rÞ  re   r  r7   rÀ  ru  r}  rI  rÍ  rq  rÓ  FrX  )rf  re  r3   rg  r@   r  rb   r[  )r´  rq  rÿ  ró  rq  rÞ  rÖ  r	  s           rB   Ú_refresh_xai_oauth_tokensr�  C  sŒ  € ð(Ý$Õ%5Ñ%7Ô%7¸ÑEÔEÐKÈˆÝ˜Ÿ	š	 +Ñ.Ô.ÐEÐ2EÑFÔFˆ	ˆ	øÝð (ð (ð (Ø'ˆ	ˆ	ˆ	ð(øøøå&ÝˆF�JŠJ�~ rÑ*Ô*Ð0¨bÑ1Ô1ÝˆF�JŠJ�¨Ñ+Ô+Ð1¨rÑ2Ô2Ø%Ø'ð	ñ ô €Iõ ˜&‘\”\€NØ%.¨~Ô%>€N�>Ñ"Ø&/°Ô&@€N�?Ñ#Ø‡}‚}�ZÑ Ô ð ;Ø%.¨zÔ%:ˆ�zÑ"Ø‡}‚}�\Ñ"Ô"Ð.Ø'0°Ô'>ˆ�|Ñ$Ø‡}‚}�\Ñ"Ô"ð ?Ø'0°Ô'>ˆ�|Ñ$ÝØØ# ^Ð4Ø!Ø˜~Ô.Øð ð	ñ 	ô 	ð 	ð Ðs   ‚AA ÁAÁAc           
     ó
  — t          ¦   «         }t          |d         ¦  «        }t          |                     dd¦  «        pd¦  «                             ¦   «         }t          dd¦  «        }t          |                     d¦  «        pi ¦  «        }t          |                     dd¦  «        pd¦  «                             ¦   «         }t          |                     dd¦  «        pd¦  «                             ¦   «         }	|�t          |¦  «        nt          |¦  «        }
t          | ¦  «        }|s|rt          ||
¦  «        }|�r t          t          t          t          ¦  «        |d	z   ¦  «        ¬
¦  «        5  t          d¬¦  «        }t          |d         ¦  «        }t          |                     dd¦  «        pd¦  «                             ¦   «         }t          |                     d¦  «        pi ¦  «        }t          |                     dd¦  «        pd¦  «                             ¦   «         }t          |                     dd¦  «        pd¦  «                             ¦   «         }	|�t          |¦  «        nt          |¦  «        }
t          | ¦  «        }|s|rt          ||
¦  «        }|�r¡|st          |¦  «        d         }	 t          |||	|¬¦  «        }t          |                     dd¦  «        pd¦  «                             ¦   «         }�n=# t           $ �r/}t#          |¦  «        �r	 t%          ¦   «         }t'          |d¦  «        pi }t          |                     d¦  «        pi ¦  «        }|                     dd ¦  «         |                     dd ¦  «         ||d<   d|j        pdt          |¦  «        ddt-          j        t0          j        ¦  «                             ¦   «         dœ|d<   t7          |d|d¬¦  «         t9          |¦  «         n2# t:          $ r%}t<                               d|¦  «         Y d }~nd }~ww xY w‚ d }~ww xY wd d d ¦  «         n# 1 swxY w Y   tA          tC          j"        dd¦  «                             ¦   «          #                    d¦  «        p9tC          j"        dd¦  «                             ¦   «          #                    d¦  «        tH          ¬¦  «        }d||d|                     d¦  «        ddœS )Nr´  r  r7   Ú"HERMES_XAI_REFRESH_TIMEOUT_SECONDSr  rR  rq  rÿ  rS  rH  FrÊ  )rq  rÿ  ró  rk   rÀ  ry  ru  Trv  rx  rc  z2xAI OAuth: failed to persist quarantined state: %sÚHERMES_XAI_BASE_URLrE   r³   ©ri  r  rÓ  re   r  )%rS  rb   r3   rg  rG   r    r  rd  r5   r_  rl  r  r+  r  rt  r�  r|  Ú$_is_terminal_xai_oauth_refresh_errorre  rf  rÁ  r  r   r7  r   r8  r9  rm  rn  r@   r  rA  rk  r´  rµ  r?   ÚDEFAULT_XAI_OAUTH_BASE_URL)rÛ  rÜ  rÝ  r²  r´  r  r"  rR  rq  rÿ  Úeffective_skewrã  r  Ú_q_storeÚ_q_stateÚ	_q_tokensr{  r2   s                     rB   Ú%resolve_xai_oauth_runtime_credentialsrŒ  n  sa  € õ "Ñ#Ô#€DÝ�$�x”.Ñ!Ô!€FÝ�v—z’z .°"Ñ5Ô5Ð;¸Ñ<Ô<×BÒBÑDÔD€LÝ'Ð(LÈbÑQÔQÐÝ�T—X’X˜kÑ*Ô*Ð0¨bÑ1Ô1€IÝ˜ŸšÐ'7¸Ñ<Ô<ÐBÀÑCÔC×IÒIÑKÔK€NÝ�t—x’x °Ñ3Ô3Ð9°rÑ:Ô:×@Ò@ÑBÔB€Lð  Ð+õ 	Ð Ñ!Ô!Ð!å0°Ñ>Ô>ð õ
 ˜-Ñ(Ô(€NØð UÐ 3ð UÝ6°|À^ÑTÔTˆØñ 5Ý­cµ%Õ8QÑ2RÔ2RÐTkÐnqÑTqÑ.rÔ.rÐsÑsÔsð 4	ð 4	Ý)°Ð6Ñ6Ô6ˆDÝ˜$˜xœ.Ñ)Ô)ˆFÝ˜vŸzšz¨.¸"Ñ=Ô=ÐCÀÑDÔD×JÒJÑLÔLˆLÝ˜TŸXšX kÑ2Ô2Ð8°bÑ9Ô9ˆIÝ  §¢Ð/?ÀÑ!DÔ!DÐ!JÈÑKÔK×QÒQÑSÔSˆNÝ˜tŸxšx¨¸Ñ;Ô;ÐA¸rÑBÔB×HÒHÑJÔJˆLð (Ð3õ Ð(Ñ)Ô)Ð)å8¸ÑFÔFð õ
 " -Ñ0Ô0ˆNØ"ð ]Ð(;ð ]Ý!>¸|È^Ñ!\Ô!\�Øñ %Ø%ð eÝ%9Ð:QÑ%RÔ%RÐScÔ%d�Nð"Ý6ØØ'5Ø%1Ø(?ð	ñ ô �Fõ $' v§z¢z°.À"Ñ'EÔ'EÐ'KÈÑ#LÔ#L×#RÒ#RÑ#TÔ#T�L‘LøÝ ð ñ ð Ý;¸CÑ@Ô@ñ ðÝ'7Ñ'9Ô'9˜HÝ';¸HÀkÑ'RÔ'RÐ'XÐVX˜HÝ(,¨X¯\ª\¸(Ñ-CÔ-CÐ-IÀrÑ(JÔ(J˜IØ%ŸMšM¨.¸$Ñ?Ô?Ð?Ø%ŸMšM¨/¸4Ñ@Ô@Ð@Ø1:˜H XÑ.à,7Ø(+¬Ð(HÐ4HÝ+.¨s©8¬8Ø*CØ48Ý&.¤lµ8´<Ñ&@Ô&@×&JÒ&JÑ&LÔ&Lð;ð ;˜HÐ%6Ñ7õ 2°(¸KÈÐ^cÐdÑdÔdÐdÝ,¨XÑ6Ô6Ð6Ð6øÝ(ð ð ð Ý"ŸLšLØ TÐV_ñô ð ð ð ð ð ð øøøøðøøøð øøøøð5øøøð54	ð 4	ð 4	ñ 4	ô 4	ð 4	ð 4	ð 4	ð 4	ð 4	ð 4	øøøð 4	ð 4	ð 4	ð 4	õl 0Ý
Œ	Ð'¨Ñ,Ô,×2Ò2Ñ4Ô4×;Ò;¸CÑ@Ô@ð 	=ÝŒ9�^ RÑ(Ô(×.Ò.Ñ0Ô0×7Ò7¸Ñ<Ô<Ý+ðñ ô €Hð  ØØØ%ØŸš Ñ0Ô0ð )ð
ð 
ð 
sc   Å6EQËA
LÌQÌQ	ÌQÌ+C%PÐQÐ
Q ÐP;Ð6QÐ;Q Ñ QÑQ	Ñ	QÑQÑQúbool | ssl.SSLContextc                 óž   — t           j        dk    r<	 ddl} t          j        |                      ¦   «         ¬¦  «        S # t          $ r Y nw xY wdS )a~  Platform-aware default SSL verify for httpx clients.

    On macOS with Homebrew Python, the system OpenSSL cannot locate the
    system trust store and valid public certs fail verification. When
    certifi is importable we pin its bundle explicitly; elsewhere we
    defer to httpx's built-in default (certifi via its own dependency).
    Mirrors the weixin fix in 3a0ec1d93.
    Údarwinr   N©ÚcafileT)r¸  r¹  ÚcertifiÚsslÚcreate_default_contextÚwherer)  )r’  s    rB   Ú_default_verifyr–  Ñ  s`   € õ „|�xÒÐð	ØˆNˆNˆNÝÔ-°W·]²]±_´_ÐEÑEÔEÐEøÝð 	ð 	ð 	ØˆDð	øøøàˆ4s   ’*= ½
A
Á	A
©ÚinsecureÚ	ca_bundleÚ
auth_stater˜  r™  rš  c                ó¢  — t          |t          ¦  «        r|                     d¦  «        ni }t          |t          ¦  «        r|ni }| �t          | d¬¦  «        n$t          |                     dd¦  «        d¬¦  «        }|pP|                     d¦  «        p;t	          j        d¦  «        p't	          j        d¦  «        pt	          j        d¦  «        }|rdS |rlt          |¦  «        }t          j                             |¦  «        s)t           
                    d	|¦  «         t          ¦   «         S t          j        |¬
¦  «        S t          ¦   «         S )NÚtlsF©Údefaultr˜  r™  ÚHERMES_CA_BUNDLEÚSSL_CERT_FILEÚREQUESTS_CA_BUNDLEuJ   CA bundle path does not exist: %s â€” falling back to default certificatesr�  )r  rb   rg  r!   r´  rµ  r3   rI   Úisfiler  r  r–  r“  r”  )r˜  r™  rš  Ú	tls_stateÚeffective_insecureÚeffective_caÚca_paths          rB   Ú_resolve_verifyr§  ã  s\  € õ *4°JÅÑ)EÔ)EÐM�
—’˜uÑ%Ô%Ð%È2€IÝ'¨	µ4Ñ8Ô8Ð@�	�	¸b€Ið 5=Ð4H�˜¨%Ð0Ñ0Ô0Ð0Ý˜YŸ]š]¨:°uÑ=Ô=ÀuÐMÑMÔMð ð
 	ð 	+Ø�=Š=˜Ñ%Ô%ð	+åŒ9Ð'Ñ(Ô(ð	+õ Œ9�_Ñ%Ô%ð	+õ Œ9Ð)Ñ*Ô*ð ð ð ØˆuØð :Ý�lÑ#Ô#ˆÝŒw�~Š~˜gÑ&Ô&ð 	%Ý�NŠNØ\Øñô ð õ #Ñ$Ô$Ð$ÝÔ)°Ð9Ñ9Ô9Ð9ÝÑÔÐrc   rû  úhttpx.ClientrR   c                ó  ‡— |                       |› d�d|i|rd|ini ¥¬¦  «        }|                     ¦   «          |                     ¦   «         Šg d¢}ˆfd„|D ¦   «         }|r%t          dd                     |¦  «        › �¦  «        ‚‰S )	zFPOST to the device code endpoint. Returns device_code, user_code, etc.z/api/oauth/device/coderT   rU   ©r²  ©r%   Ú	user_codeÚverification_uriÚverification_uri_completerI  Úintervalc                ó   •— g | ]}|‰v¯|‘Œ	S rY   rY   )râ   rQ  r²  s     €rB   r¨  z(_request_device_code.<locals>.<listcomp>  s   ø€ Ð;Ð;Ð;�Q¨Q°d¨]¨]ˆq¨]¨]¨]rc   z%Device code response missing fields: ú, )r?  Úraise_for_statusr;  r  rð  )rû  rR   rT   rU   rÓ  Úrequired_fieldsÚmissingr²  s          @rB   Ú_request_device_coderµ  
  sÈ   ø€ ð �{Š{ØÐ2Ð2Ð2à˜ð
à#(Ð0�˜ÐÐ¨bð
ð ñ ô €Hð ×ÒÑÔÐØ�=Š=‰?Œ?€Dðð ð €Oð <Ð;Ð;Ð;˜/Ð;Ñ;Ô;€GØð WÝÐUÀÇÂÈ7ÑASÔASÐUÐUÑVÔVÐVØ€Krc   c                óF   — | pt                                d¦  «        }d|› d�S )aa  Actionable timeout text for Nous device-code login failures.

    A bare "Timed out waiting for device authorization" gives the user
    nothing to act on. The most common cause is Portal sign-in failing in
    the opened browser tab (including the server-side CAPTCHA loop from
    #20605), so point at the Portal login page and the retry command.
    rE   a   Timed out waiting for device authorization.
  Portal sign-in is required before the device code can be approved.
  If the browser showed a CAPTCHA / 'You did not pass CAPTCHA' error,
  finish signing in at the Portal in a normal browser tab, then retry:
    hermes portal
  Portal login: z/login)rT  r?   )rR   Úportals     rB   Ú!_nous_device_auth_timeout_messager¸  %  s;   € ð Ð8Õ!8×@Ò@ÀÑEÔE€Fð	*ð
 "ð	*ð 	*ð 	*ðrc   rP  c                ó@  — t          j        ¦   «         t          d|¦  «        z   }t          dt          |t          ¦  «        ¦  «        }t          j        ¦   «         |k     �r$|                      |› d�d||dœ¬¦  «        }|j        dk    r)|                     ¦   «         }	d|	vrt          d¦  «        ‚|	S 	 |                     ¦   «         }
n1# t          $ r$ | 
                    ¦   «          t          d	¦  «        ‚w xY w|
                     d
d¦  «        }|dk    rt          j        |¦  «         Œâ|dk    r)t          |dz   d¦  «        }t          j        |¦  «         �Œ|
                     d¦  «        pd}t          |› d|› �¦  «        ‚t          t          |¦  «        ¦  «        ‚)zDPoll the token endpoint until the user approves or the code expires.r"   ú/api/oauth/tokenú,urn:ietf:params:oauth:grant-type:device_code©rÆ  rT   r%   rª  r<  r  z+Token response did not include access_tokenz1Token endpoint returned a non-JSON error responser‹  r7   Úauthorization_pendingÚ	slow_downé   r5  zUnknown authentication errorr¯  )r  r  r  rb  Ú%DEVICE_AUTH_POLL_INTERVAL_CAP_SECONDSr?  r@  r;  r  r@   r²  rÌ  rg  r  r  r¸  )rû  rR   rT   r%   rI  rP  r  Úcurrent_intervalrÓ  rÁ  Úerror_payloadÚ
error_codeÚdescriptions                rB   Ú_poll_for_tokenrÅ  8  sÑ  € õ Œ~ÑÔ¥# a¨Ñ"4Ô"4Ñ4€HÝ˜1�c -Õ1VÑWÔWÑXÔXÐå
Œ.Ñ
Ô
˜XÒ
%Ñ
%Ø—;’;ØÐ0Ð0Ð0àLØ&Ø*ðð ð ñ 
ô 
ˆð Ô 3Ò&Ð&Ø—m’m‘o”oˆGØ WÐ,Ð,Ý Ð!NÑOÔOÐOØˆNð	TØ$ŸMšM™OœOˆMˆMøÝð 	Tð 	Tð 	TØ×%Ò%Ñ'Ô'Ð'ÝÐRÑSÔSÐSð	Tøøøð #×&Ò& w°Ñ3Ô3ˆ
ØÐ0Ò0Ð0ÝŒJÐ'Ñ(Ô(Ð(ØØ˜Ò$Ð$Ý"Ð#3°aÑ#7¸Ñ<Ô<ÐÝŒJÐ'Ñ(Ô(Ð(Ùà#×'Ò'Ð(;Ñ<Ô<Ð^Ð@^ˆÝ˜jÐ9Ð9¨KÐ9Ð9Ñ:Ô:Ð:õ
 Õ8¸ÑIÔIÑ
JÔ
JÐJs   Â3C Ã.C6znous_auth.jsonc                 ó¼   — t          j        dd¦  «                             ¦   «         } | r!t          | ¦  «                             ¦   «         S ddlm}  |¦   «         dz  S )uz  Resolve the directory that holds the shared Nous token store.

    Honors ``HERMES_SHARED_AUTH_DIR`` so tests can redirect it to a tmp
    path without touching the real user's home. Defaults to
    ``<hermes-root>/shared/``, where ``<hermes-root>`` is what
    :func:`hermes_constants.get_default_hermes_root` returns â€” so
    Linux/macOS classic installs land at ``~/.hermes/shared/``, native
    Windows installs at ``%LOCALAPPDATA%\hermes\shared\``, and
    Docker / custom ``HERMES_HOME`` deployments at
    ``<HERMES_HOME>/shared/``. Sits outside any named profile so all
    profiles under the same root share the store.
    ÚHERMES_SHARED_AUTH_DIRr7   r   rÒ  Úshared)r´  rµ  rG   r   r  rÔ  rÓ  )ÚoverriderÓ  s     rB   Ú_nous_shared_auth_dirrÊ  ‡  sh   € õ ŒyÐ1°2Ñ6Ô6×<Ò<Ñ>Ô>€HØð +Ý�H‰~Œ~×(Ò(Ñ*Ô*Ð*Ø8Ð8Ð8Ð8Ð8Ð8Ø"Ð"Ñ$Ô$ xÑ/Ð/rc   c                 óT  — t          ¦   «         t          z  } t          j                             d¦  «        rrddlm}  |¦   «         dz  t          z                       d¬¦  «        }	 |                      d¬¦  «        }n# t          $ r | }Y nw xY w||k    rt          d| › d�¦  «        ‚| S )	NrÅ  r   rÒ  rÈ  FrÇ  zDRefusing to touch real user shared Nous auth store during test run: z@. Set HERMES_SHARED_AUTH_DIR to a tmp_path in your test fixture.)
rÊ  ÚNOUS_SHARED_STORE_FILENAMEr´  rÉ  rg  rÔ  rÓ  rË  r@   rÌ  )rI   rÓ  Úreal_home_sharedrÎ  s       rB   Ú_nous_shared_store_pathrÎ  ›  sç   € Ý Ñ"Ô"Õ%?Ñ?€Dõ 
„z‡~‚~Ð+Ñ,Ô,ð Ø<Ð<Ð<Ð<Ð<Ð<à#Ð#Ñ%Ô%¨Ñ0Õ3MÑMß
Š'˜ˆ'Ñ
Ô
ð 	ð	Ø—|’|¨5�|Ñ1Ô1ˆHˆHøÝð 	ð 	ð 	ØˆHˆHˆHð	øøøàÐ'Ò'Ð'ÝðZØðZð Zð Zñô ð ð €Ks   Á&A= Á=BÂBc              #  óâ   K  — 	 t          ¦   «                              d¦  «        }n# t          $ r dV — Y dS w xY wt          |t          | d¦  «        5  dV — ddd¦  «         dS # 1 swxY w Y   dS )a  Cross-profile lock for the shared Nous OAuth store.

    Lock ordering invariant: if both this and ``_auth_store_lock`` need
    to be held, acquire ``_auth_store_lock`` FIRST. All runtime refresh
    paths follow this order. The one exception is
    ``_try_import_shared_nous_state``, which holds this lock alone for
    the entire refresh cycle so concurrent imports on sibling profiles
    can't race on the single-use shared refresh token; that helper must
    NOT be called with ``_auth_store_lock`` already held.
    rà  Nz+Timed out waiting for shared Nous auth lock)rÎ  rá  rÌ  r  Ú_nous_shared_lock_holder)ró  rñ  s     rB   Ú_nous_shared_store_lockrÑ  ´  sÞ   è è € ðÝ+Ñ-Ô-×9Ò9¸'ÑBÔBˆ	ˆ	øÝð ð ð àˆˆˆØˆˆðøøøõ
 
ØÝ ØØ5ñ	
ô 
ð ð ð 	ˆˆˆðð ð ñ ô ð ð ð ð ð ð ð øøøð ð ð ð ð ð s   „!& ¦8·8ÁA$Á$A(Á+A(c                ó4  — t          ¦   «         }|sdS |                     d¦  «        }t          |t          ¦  «        r|                     ¦   «         sdS |                      d¦  «        }t          |                     d¦  «        ¦  «        pd}t          |                      d¦  «        ¦  «        pd}|                     ¦   «         t          |pd¦  «                             ¦   «         k    }||k    }|s|sdS dD ] }|                     |¦  «        }	|	dvr|	| |<   Œ!dS )	zACopy fresher shared OAuth tokens into a profile-local Nous state.FrÀ  rw  r“  r7   )	r  rÀ  rÍ  rU   rT   rR   rS   r–  rw  >   Nr7   T)Ú_read_shared_nous_staterg  r  r3   rG   rC  )
rq  rÈ  Úshared_refreshÚlocal_refreshÚshared_access_expÚlocal_access_expÚrefresh_changedÚfresher_accessr$  rë   s
             rB   Ú_merge_shared_nous_oauth_staterÚ  Ð  s.  € å$Ñ&Ô&€FØð Øˆuà—Z’Z Ñ0Ô0€NÝ�n¥cÑ*Ô*ð °.×2FÒ2FÑ2HÔ2Hð Øˆuà—I’I˜oÑ.Ô.€MÝ,¨V¯ZªZ¸Ñ-EÔ-EÑFÔFÐMÈ#ÐÝ+¨E¯IªI°lÑ,CÔ,CÑDÔDÐKÈÐØ$×*Ò*Ñ,Ô,µ°MÐ4GÀRÑ0HÔ0H×0NÒ0NÑ0PÔ0PÒP€OØ&Ð)9Ò9€NØð  >ð Øˆuð
ð ð ˆð —
’
˜3‘”ˆØ˜
Ð"Ð"ØˆE�#‰JøØˆ4rc   c                óÔ  — |                       d¦  «        }|                       d¦  «        }t          |t          ¦  «        r|                     ¦   «         sdS t          |t          ¦  «        r|                     ¦   «         sdS d|||                       d¦  «        pd|                       d¦  «        pt          |                       d¦  «        pt
          |                       d	¦  «        pt          |                       d
¦  «        pt          |                       d¦  «        |                       d¦  «        t          j	        t          j        ¦  «                             ¦   «         dœ}	 t          ¦   «         5  t          ¦   «         }|j                             dd¬¦  «         t#          |¦  «         |                     |j        › dt)          j        ¦   «         › dt-          j        ¦   «         j        › �¦  «        }t)          j        t          |¦  «        t(          j        t(          j        z  t(          j        z  t:          j        t:          j        z  ¦  «        }	 t)          j         |dd¬¦  «        5 }| !                    tE          j#        |dd¬¦  «        ¦  «         | $                    ¦   «          t)          j%        | &                    ¦   «         ¦  «         ddd¦  «         n# 1 swxY w Y   t)          j'        ||¦  «         	 | (                    ¦   «         r| )                    ¦   «          nO# tT          $ r Y nCw xY w# 	 | (                    ¦   «         r| )                    ¦   «          w w # tT          $ r Y w w xY wxY wddd¦  «         n# 1 swxY w Y   tW          dt          |¦  «        tY          |¦  «        ¬¦  «         dS # tZ          $ r&}t\           /                    d|¦  «         Y d}~dS d}~ww xY w)ao  Persist a minimal copy of the Nous OAuth state to the shared store.

    Best-effort: any failure is swallowed after logging. The shared store
    is a convenience layer; the per-profile auth.json remains the source
    of truth.

    We deliberately omit the runtime ``agent_key`` compatibility field;
    the OAuth tokens are the cross-profile source of truth.
    rÀ  r  Nr"   rÍ  rÎ  rU   rT   rR   rS   r–  rw  )Ú_schemar  rÀ  rÍ  rU   rT   rR   rS   r–  rw  r1  Tr÷  r5  r8   r6  r«  rú  r2  r¶  Únous_shared_store_written)rI   Úrefresh_token_fpz*Failed to write shared Nous auth store: %s)0rg  r  r3   rG   ÚDEFAULT_NOUS_SCOPEÚDEFAULT_NOUS_CLIENT_IDrT  ÚDEFAULT_NOUS_INFERENCE_URLr   r7  r   r8  r9  rÑ  rÎ  rý  rþ  r   r:  rP   r´  r;  r<  r=  r>  r  r?  r@  rA  r  rB  rC  rD  rE  r;  rÀ  rF  rG  r	  r@  rÚ  rJ  r  rÂ  r­  r@   r  rA  )	rq  rÀ  r  rÈ  rI   ÚtmprM  r·  r  s	            rB   Ú_write_shared_nous_staterã  ó  s"  € ð —I’I˜oÑ.Ô.€MØ—9’9˜^Ñ,Ô,€LÝ�}¥cÑ*Ô*ð ¨}×/BÒ/BÑ/DÔ/Dð àˆÝ�|¥SÑ)Ô)ð ¨l×.@Ò.@Ñ.BÔ.Bð Øˆð Ø$Ø&Ø—i’i Ñ-Ô-Ð9°Ø—’˜7Ñ#Ô#Ð9Õ'9Ø—Y’Y˜{Ñ+Ô+ÐEÕ/EØ Ÿ9š9Ð%6Ñ7Ô7ÐRÕ;RØ#ŸišiÐ(<Ñ=Ô=Ð[ÕA[Ø—y’y Ñ/Ô/Ø—i’i Ñ-Ô-Ý”l¥8¤<Ñ0Ô0×:Ò:Ñ<Ô<ðð €Fð!HÝ$Ñ&Ô&ð 	ð 	Ý*Ñ,Ô,ˆDØŒK×Ò d°TÐÑ:Ô:Ð:å˜dÑ#Ô#Ð#Ø—.’. D¤IÐ!TÐ!TµB´I±K´KÐ!TÐ!TÅ$Ä*Á,Ä,ÔBRÐ!TÐ!TÑUÔUˆCõ ”Ý�C‘”Ý”�bœjÑ(­2¬9Ñ4Ý”�tœ|Ñ+ñô ˆBð
Ý”Y˜r 3°Ð9Ñ9Ô9ð *¸RØ—H’H�TœZ¨°qÀDÐIÑIÔIÑJÔJÐJØ—H’H‘J”J�JÝ”H˜RŸYšY™[œ[Ñ)Ô)Ð)ð*ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *õ ”
˜3 Ñ%Ô%Ð%ðØ—z’z‘|”|ð %ØŸ
š
™œ˜øøÝð ð ð Ø�DðøøøøðØ—z’z‘|”|ð %ØŸ
š
™œ˜˜ð%øåð ð ð Ø�Dðøøøøøøð1	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	õ4 	Ø'Ý�T‘”Ý/°Ñ>Ô>ð	
ñ 	
ô 	
ð 	
ð 	
ð 	
øõ
 ð Hð Hð HÝ�ŠÐAÀ3ÑGÔGÐGÐGÐGÐGÐGÐGÐGøøøøðHøøøs¼   Å!N7 Å/C!M>ÉL3É(A%KËL3ËK	ËL3Ë K	Ë!L3Ë:(L#Ì"M>Ì#
L0Ì-M>Ì/L0Ì0M>Ì3M/Ì5(MÍM/Í
M,	Í)M/Í+M,	Í,M/Í/M>Í2N7 Í>NÎN7 ÎNÎ/N7 Î7
O'ÏO"Ï"O'c                 ól  — 	 t          ¦   «         } n# t          $ r Y dS w xY w|                      ¦   «         sdS 	 t          j        |                      d¬¦  «        ¦  «        }n;# t          t          f$ r'}t           	                    d| |¦  «         Y d}~dS d}~ww xY wt          |t          ¦  «        sdS |                     d¦  «        }|                     d¦  «        }t          |t          ¦  «        r|                     ¦   «         sdS t          |t          ¦  «        r|                     ¦   «         sdS |S )u  Return the shared Nous OAuth state if present and well-formed.

    Returns ``None`` when the file is missing, unreadable, malformed, or
    lacks required fields. Callers should treat ``None`` as "no shared
    credentials available â€” fall through to device-code".
    Nr!  rú  z.Shared Nous auth store at %s is unreadable: %srÀ  r  )rÎ  rÌ  r  r;  r)  r*  r  r  r  rA  r  rb   rg  r3   rG   )rI   rÁ  r  rÀ  r  s        rB   rÓ  rÓ  6  sM  € ðÝ&Ñ(Ô(ˆˆøÝð ð ð àˆtˆtðøøøð �<Š<‰>Œ>ð ØˆtðÝ”*˜TŸ^š^°[˜^ÑAÔAÑBÔBˆˆøÝ•ZÐ ð ð ð Ý�ŠÐEÀtÈSÑQÔQÐQØˆtˆtˆtˆtˆtøøøøðøøøõ �g�tÑ$Ô$ð ØˆtØ—K’K Ñ0Ô0€MØ—;’;˜~Ñ.Ô.€LÝ�}¥cÑ*Ô*ð ¨}×/BÒ/BÑ/DÔ/Dð ØˆtÝ�|¥SÑ)Ô)ð ¨l×.@Ò.@Ñ.BÔ.Bð ØˆtØ€Ns#   ‚ ‘
ž¹(A" Á"BÁ3BÂBc                óD  — 	 t          ¦   «         5  t          ¦   «         }	 |                     ¦   «          n# t          $ r Y nw xY wddd¦  «         n# 1 swxY w Y   t	          d| ¬¦  «         dS # t
          $ r&}t                               d|¦  «         Y d}~dS d}~ww xY w)zBRemove the shared Nous OAuth store after a terminal token failure.NÚnous_shared_store_cleared©r‰  z*Failed to clear shared Nous auth store: %s)rÑ  rÎ  rJ  ÚFileNotFoundErrorrÂ  r@   r  rA  )r‰  rI   r  s      rB   Ú_clear_shared_nous_stateré  T  s  € ð	HÝ$Ñ&Ô&ð 	ð 	Ý*Ñ,Ô,ˆDðØ—’‘”��øÝ$ð ð ð Ø�ðøøøð		ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	õ 	Ð0¸Ð@Ñ@Ô@Ð@Ð@Ð@øÝð Hð Hð HÝ�ŠÐAÀ3ÑGÔGÐGÐGÐGÐGÐGÐGÐGøøøøðHøøøsY   ‚A/ �A 5´Aµ
A¿AÁAÁAÁA/ ÁAÁA/ ÁAÁA/ Á/
BÁ9BÂBr  c                ó|   — t          | t          ¦  «        o'| j        dk    o| j        dv ot	          | j        ¦  «        S )z>True when retrying the same Nous refresh token cannot succeed.rd   >   rî  rï  rñ  ©r  r|  r~  r  r5   r€  ©r  s    rB   Ú_is_terminal_nous_refresh_errorrí  b  sJ   € õ 	�3�	Ñ"Ô"ð 	'ØŒL˜FÒ"ð	'àŒHÐRÐRð	'õ �Ô%Ñ&Ô&ð	rc   c                ó|   — t          | t          ¦  «        o'| j        dk    o| j        dv ot	          | j        ¦  «        S )u˜  True when retrying the same xAI OAuth refresh token cannot succeed.

    ``xai_refresh_failed`` covers HTTP 400/401/403 from the token endpoint
    (invalid_grant, token revoked, refresh_token_reused).
    ``xai_auth_missing_refresh_token`` means the pool entry has no refresh
    token at all â€” retrying will never work.
    Both carry ``relogin_required=True``; transient failures (429, 5xx) do not.
    rk   >   ry  rQ  rë  rì  s    rB   r†  r†  l  sJ   € õ 	�3�	Ñ"Ô"ð 	'ØŒL˜KÒ'ð	'àŒHÐPÐPð	'õ �Ô%Ñ&Ô&ð	rc   c                ó|   — t          | t          ¦  «        o'| j        dk    o| j        dv ot	          | j        ¦  «        S )už  True when retrying the same Codex OAuth refresh token cannot succeed.

    ``codex_refresh_failed`` covers HTTP 400/401/403 from the token endpoint
    (invalid_grant, token revoked, refresh_token_reused).
    ``codex_auth_missing_refresh_token`` means the pool entry has no refresh
    token at all â€” retrying will never work.
    Both carry ``relogin_required=True``; transient failures (429, 5xx) do not.
    rf   >   rî  rï  rì  rñ  rÒ  rë  rì  s    rB   Ú&_is_terminal_codex_oauth_refresh_errorrð  }  sN   € õ 	�3�	Ñ"Ô"ð 		'ØŒL˜NÒ*ð		'àŒHð 
ð 
ð		'õ �Ô%Ñ&Ô&ðrc   c          	     óz  — ||j         |                      d¦  «        |                      d¦  «        t          |                      d¦  «        ¦  «        dœ}	 t          ¦   «         }t	          |¦  «        |d<   	 t          j        |¦  «        }|j        |d<   |j        |d<   d|d	<   n# t          $ r d
|d	<   Y nw xY wn)# t          $ r}t          |¦  «        |d<   Y d}~nd}~ww xY wd}|                      d¦  «        }t          |t          ¦  «        rs|rq	 t          j        |¦  «        }	|	j        € |	                     t"          j        ¬¦  «        }	|	t          j        t"          j        ¦  «        k     }n# t(          $ r d}Y nw xY w||d<   t*                               dt/          j        |dd
¬¦  «        ¦  «         dD ]}
|                      |
d¦  «         Œd|j         t	          |¦  «        |dt          j        t"          j        ¦  «                             ¦   «         dœ| d<   t7          |¦  «         t9          ¦   «          dS )zKKeep routing metadata but remove dead OAuth material so it is not replayed.rT   rš  rÀ  )r‰  rÃ  rT   rš  rÞ  Úauth_json_pathÚauth_json_sizeÚauth_json_mtimeTÚauth_json_existsFÚauth_json_stat_errorNrw  r=  Útoken_already_expiredz6Nous OAuth state quarantined (terminal auth death): %sr¼  )r  rÀ  rw  rI  r–  r™  rš  r›  rœ  r�  r˜  rd   rv  rx  )r  rg  r­  rÏ  r3   r´  r  r  Úst_mtimerè  r@   Úreprr  r   r?  r>  r@  r   r8  r7  r  r  r  r;  rÀ  rÁ  r9  ré  Ú!invalidate_nous_auth_status_cache)rq  r‹  r‰  Úforensicr  Ústr  Úalready_expiredÚexpires_at_rawrK   r$  s              rB   Ú_quarantine_nous_oauth_staterÿ  ”  s  € ð$ Ø”jð —Y’Y˜{Ñ+Ô+ØŸ	š	 .Ñ1Ô1Ý.¨u¯yªy¸Ñ/IÔ/IÑJÔJð ð  €Hð5Ý#Ñ%Ô%ˆ	Ý%(¨¡^¤^ˆÐ!Ñ"ð	1Ý”˜Ñ#Ô#ˆBØ)+¬ˆHÐ%Ñ&Ø*,¬+ˆHÐ&Ñ'Ø+/ˆHÐ'Ñ(Ð(øÝ ð 	1ð 	1ð 	1Ø+0ˆHÐ'Ñ(Ð(Ð(ð	1øøøøøåð 5ð 5ð 5Ý+/°©9¬9ˆÐ'Ñ(Ð(Ð(Ð(Ð(Ð(øøøøð5øøøð '+€OØ—Y’Y˜|Ñ,Ô,€NÝ�.¥#Ñ&Ô&ð #¨>ð #ð	#ÝÔ+¨NÑ;Ô;ˆFØŒ}Ð$ØŸš­x¬|˜Ñ<Ô<�Ø$¥x¤|µH´LÑ'AÔ'AÒAˆOˆOøÝð 	#ð 	#ð 	#Ø"ˆOˆOˆOð	#øøøà(7€HÐ$Ñ%å
‡N‚NØ@ÝŒ
�8 t¸%Ð@Ñ@Ô@ñô ð ð
ð ð ˆð 	�	Š	�#�tÑÔÐÐàØ”
Ý�u‘:”:ØØ ÝŒl�8œ<Ñ(Ô(×2Ò2Ñ4Ô4ð ð  €EÐ
Ñõ ˜VÑ$Ô$Ð$Ý%Ñ'Ô'Ð'Ð'Ð'sO   Á B: Á6-B$ Â#B: Â$B6Â3B: Â5B6Â6B: Â:
C ÃCÃC ÄAE0 Å0E?Å>E?c               ó®  — |                       d¦  «        }t          |t          ¦  «        sdS |                      d¦  «        }t          |t          ¦  «        sdS g }d}t          dt          › �h}|D ]F}t          |t          ¦  «        r|                      d¦  «        |v rd}Œ1|                     |¦  «         ŒG|r||d<   t          d||j        ¬¦  «         |S )	zHRemove singleton-seeded Nous pool entries that contain dead OAuth state.r$  Frd   rÖ  r  TÚ!nous_pool_device_code_quarantined)r‰  rÃ  )rg  r  rb   r|  ÚNOUS_DEVICE_CODE_SOURCEr°  rÂ  r  )	rp  r‹  r‰  r"  r   Úretainedr±  Úsingleton_sourcesr#  s	            rB   Ú_quarantine_nous_pool_entriesr  é  s  € ð �>Š>Ð+Ñ,Ô,€DÝ�d�DÑ!Ô!ð ØˆuØ�hŠh�vÑÔ€GÝ�g�tÑ$Ô$ð Øˆuà€HØ€GÝ0Ð2UÕ<SÐ2UÐ2UÐVÐØð ð ˆÝ�e�TÑ"Ô"ð 	 u§y¢y°Ñ':Ô':Ð>OÐ'OÐ'OØˆGØØ�Š˜ÑÔÐÐàð 
ØˆˆV‰ÝØ/ØØ”zð	
ñ 	
ô 	
ð 	
ð
 €Nrc   c                ón  — 	 t          t          | dz   t          ¦  «        ¬¦  «        5  t          ¦   «         }|s	 ddd¦  «         dS |                     d¦  «        |                     d¦  «        |                     d¦  «        pt
          |                     d¦  «        pt          |                     d¦  «        pt          |                     d	¦  «        pd
|                     d¦  «        pt          |                     d¦  «        |                     d¦  «        dddddœdœ}d d„}t          || d|¬¦  «        }t          |¦  «         ddd¦  «         n# 1 swxY w Y   nÕ# t          $ rw}t          dt          |¦  «        j        t          |dd¦  «        ¬¦  «         t!          |¦  «        rt#          d¦  «         t$                               d|¦  «         Y d}~dS d}~wt(          $ rI}t          dt          |¦  «        j        ¬¦  «         t$                               d|¦  «         Y d}~dS d}~ww xY w|S )!u  Attempt to rehydrate Nous OAuth state from the shared store.

    Reads the shared file (if present), runs a forced refresh using the
    stored refresh_token to produce a fresh inference JWT scoped to this
    profile, and returns the full auth_state dict ready
    for ``persist_nous_credentials()``.

    Returns ``None`` when no shared state is available or the rehydrate
    fails for any reason (expired refresh_token, portal unreachable,
    etc.) â€” caller should then fall through to the normal device-code
    flow.
    rS  rH  Nr  rÀ  rT   rR   rS   rÍ  rÎ  rU   r–  rw  F©r˜  r™  ©r  rÀ  rT   rR   rS   rÍ  rU   r–  rw  r™  r›  rœ  Úupdated_staterW   Ú_reasonr3   r4   rƒ  c                ó$   — t          | ¦  «         d S r…  )rã  )r	  r
  s     rB   Ú_persist_shared_refreshz>_try_import_shared_nous_state.<locals>._persist_shared_refresh2  s   € Ý(¨Ñ7Ô7Ð7Ð7Ð7rc   T©ró  rÛ  Úon_state_updateÚnous_shared_import_failedr  )Ú
error_typerÃ  Ú&shared_import_terminal_refresh_failurezShared Nous import failed: %s)r  )r	  rW   r
  r3   r4   rƒ  )rÑ  r  r  rÓ  rg  rà  rT  rá  rß  Úrefresh_nous_oauth_from_staterã  r|  rÂ  rí  r]   r  rí  ré  r  rA  r@   )ró  rÈ  rq  r  rÖ  r  s         rB   Ú_try_import_shared_nous_stater  
  sË  € ð 2Ý$µS¸È3Ñ9NÕPiÑ5jÔ5jÐkÑkÔkð  	0ð  	0Ý,Ñ.Ô.ˆFØð Øð 	0ð  	0ð  	0ñ  	0ô  	0ð  	0ð  	0ð  	0ð !'§
¢
¨>Ñ :Ô :Ø!'§¢¨OÑ!<Ô!<Ø#ŸZšZ¨Ñ4Ô4ÐNÕ8NØ#)§:¢:Ð.?Ñ#@Ô#@Ð#[ÕD[Ø&,§j¢jÐ1EÑ&FÔ&FÐ&dÕJdØ$Ÿjšj¨Ñ6Ô6ÐB¸(ØŸš GÑ,Ô,ÐBÕ0BØ%Ÿzšz¨-Ñ8Ô8Ø$Ÿjšj¨Ñ6Ô6Ø!Ø(,Ø$)¸Ð=Ð=ð%ð %ˆEð8ð 8ð 8ð 8õ 6ØØ /Ø"Ø 7ð	ñ ô ˆIõ % YÑ/Ô/Ð/ðA 	0ð  	0ð  	0ñ  	0ô  	0ð  	0ð  	0ð  	0ð  	0ð  	0ð  	0øøøð  	0ð  	0ð  	0ð  	0øøõB ð 	ð 	ð 	ÝØ'Ý˜C‘y”yÔ)Ý˜s F¨DÑ1Ô1ð	
ñ 	
ô 	
ð 	
õ
 +¨3Ñ/Ô/ð 	OÝ$Ð%MÑNÔNÐNÝ�ŠÐ4°cÑ:Ô:Ð:ØˆtˆtˆtˆtˆtøøøøÝð ð ð ÝØ'Ý˜C‘y”yÔ)ð	
ñ 	
ô 	
ð 	
õ 	�ŠÐ4°cÑ:Ô:Ð:Øˆtˆtˆtˆtˆtøøøøðøøøð ÐsS   ‚&E  ¨EºE  ÁDEÅE  ÅEÅE  ÅEÅE  Å 
H2Å*A,GÇH2Ç)>H-È-H2c                ó0  — |                       |› d�d|id|dœ¬¦  «        }|j        dk    r-|                     ¦   «         }d|vrt          dd	d
d¬¦  «        ‚|S 	 |                     ¦   «         }n%# t          $ r}t          dd	d¬¦  «        |‚d }~ww xY wt          |                     dd¦  «        ¦  «        }t          |                     d¦  «        pd¦  «        }	|dv }
|	                     ¦   «         }|dk    sd|v sd|v rd}	d}
t          |	d	||
¬¦  «        ‚)Nrº  zx-nous-refresh-tokenrÀ  )rÆ  rT   rç  r<  r  z%Refresh response missing access_tokenrd   rï  Tr}  zRefresh token exchange failed©r~  r€  r‹  rî  r5  >   rî  rï  rñ  rñ  Úreusezreuse detecteduá  Nous Portal detected refresh-token reuse and revoked this session.
This usually means an external process (monitoring script, custom self-heal hook, or another Hermes install sharing ~/.hermes/auth.json) called POST /api/oauth/token with Hermes's refresh token without persisting the rotated token back.
Nous refresh tokens are single-use â€” only Hermes may call the refresh endpoint. For health checks, use `hermes auth status` instead.
Re-authenticate with: hermes auth add nous)r?  r@  r;  r|  r@   r3   rg  r>   )rû  rR   rT   rÀ  rÓ  rÁ  rÂ  r  r  rÄ  ÚreloginÚlowereds               rB   Ú_refresh_access_tokenr  Q  sš  € ð �{Š{ØÐ,Ð,Ð,Ø'¨Ð7à)Ø"ð
ð 
ð ñ ô €Hð Ô˜sÒ"Ð"Ø—-’-‘/”/ˆØ Ð(Ð(ÝÐCØ%+°/ÐTXðZñ Zô Zð ZàˆðIØ Ÿš™œˆˆøÝð Ið Ið IÝÐ7Ø!'¸$ð@ñ @ô @ØEHð	IøøøøðIøøøõ ˆ}× Ò  ¨/Ñ:Ô:Ñ;Ô;€DÝ�m×'Ò'Ð(;Ñ<Ô<Ð_Ð@_Ñ`Ô`€KØÐPÐP€Gð ×ÒÑ!Ô!€GØÐ%Ò%Ð%¨°GÐ);Ð);Ð?OÐSZÐ?ZÐ?Zð9ð 	ð ˆå
�K¨&°tÈgÐ
VÑ
VÔ
VÐVs   ÁA/ Á/
BÁ9BÂB)ró  ÚverifyrS   r  ú
bool | strc                óx  — t          j        |¦  «        }t          j        |ddi|¬¦  «        5 }|                     |                      d¦  «        › d�dd|› �i¬¦  «        }d	d	d	¦  «         n# 1 swxY w Y   |j        d
k    r�d|j        › �}	 |                     ¦   «         }t          |                     d¦  «        p|                     d¦  «        p|¦  «        }n2# t          $ r%}	t           
                    d|	¦  «         Y d	}	~	nd	}	~	ww xY wt          |dd¬¦  «        ‚|                     ¦   «         }
|
                     d¦  «        }t          |t          ¦  «        sg S g }|D ]–}t          |t          ¦  «        sŒ|                     d¦  «        }t          |t          ¦  «        rT|                     ¦   «         r@|                     ¦   «         }d|                     ¦   «         v rŒ�|                     |¦  «         Œ—dd„}|                     |¬¦  «         t          t                               |¦  «        ¦  «        S )z6Fetch available model IDs from the Nous inference API.rÄ  r/  ©r*  r:  r  rE   z/modelsr0  r.  r4  Nr<  z#/models request failed with status r5  r‹  z'Could not parse error response JSON: %srd   Úmodels_fetch_failedr®  r²  rO   ÚhermesÚmidr3   r4   rZ   c                ój   — |                       ¦   «         }d|v rd| fS d|v rd|vrd| fS d|v rd| fS d| fS )NÚopusr   ÚproÚsonnetr"   é   r2  )r>   )r   Úlows     rB   Ú_model_priorityz*fetch_nous_models.<locals>._model_priority¶  sX   € Ø�iŠi‰kŒkˆØ�Sˆ=ˆ=Ø�s�8ˆOØ�Cˆ<ˆ<˜H¨CÐ/Ð/Ø�s�8ˆOØ�sˆ?ˆ?Ø�s�8ˆOØ�3ˆxˆrc   ©r$  )r   r3   r4   rZ   )r>  rö  r÷  rg  r?   r@  r;  r3   r@   r  rA  r|  r  r|  rb   rG   r>   r°  ÚsortÚfromkeys)rS   rh   ró  r  r*  rû  rÓ  rÄ  rý  r2  rÁ  r²  Ú	model_idsru  Úmodel_idr   r'  s                    rB   Úfetch_nous_modelsr-  ‹  s˜  € õ Œm˜OÑ,Ô,€GÝ	Œ˜g°Ð:LÐ/MÐV\Ð	]Ñ	]Ô	]ð 
ÐagØ—:’:Ø!×(Ò(¨Ñ-Ô-Ð6Ð6Ð6Ø$Ð&9°Ð&9Ð&9Ð:ð ñ 
ô 
ˆð
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
ð Ô˜sÒ"Ð"ØR¸HÔ<PÐRÐRˆð	GØ—-’-‘/”/ˆCÝ˜cŸgšgÐ&9Ñ:Ô:Ð]¸c¿gºgÀgÑ>NÔ>NÐ]ÐR]Ñ^Ô^ˆKˆKøÝð 	Gð 	Gð 	GÝ�LŠLÐBÀAÑFÔFÐFÐFÐFÐFÐFÐFøøøøð	Gøøøå˜¨fÐ;PÐQÑQÔQÐQà�mŠm‰oŒo€GØ�;Š;�vÑÔ€DÝ�d�DÑ!Ô!ð Øˆ	à€IØð 	"ð 	"ˆÝ˜$¥Ñ%Ô%ð 	ØØ—8’8˜D‘>”>ˆÝ�h¥Ñ$Ô$ð 	"¨¯ªÑ)9Ô)9ð 	"Ø—.’.Ñ"Ô"ˆCà˜3Ÿ9š9™;œ;Ð&Ð&ØØ×Ò˜SÑ!Ô!Ð!øðð ð ð ð ‡N‚N�€NÑ'Ô'Ð'Ý•—’˜iÑ(Ô(Ñ)Ô)Ð)s*   ®3A-Á-A1Á4A1ÂAC Ã
DÃ&DÄDc                ó*  — |                       d¦  «        }t          |t          ¦  «        r|                     ¦   «         sdS t	          ||                       d¦  «        |                       d¦  «        t          dt          |¦  «        ¦  «        ¬¦  «        S )Nr™  FrU   r›  r   rv  )rg  r  r3   rG   r„  r  r  )rq  rx  r$  s      rB   Ú_agent_key_is_usabler/  Ä  s‡   € Ø
�)Š)�KÑ
 Ô
 €CÝ�c�3ÑÔð  s§y¢y¡{¤{ð ØˆuÝ%ØØ�iŠi˜Ñ Ô Ø—9’9Ð3Ñ4Ô4Ý˜A�s ?Ñ3Ô3Ñ4Ô4ð	ñ ô ð rc   z'tuple[float, str] | None'Ú_RESOLVE_TOKEN_CACHErS  )ró  r˜  r™  rÝ  c           
     ó°
  — |s_|€]t           5  t          �7t          \  }}t          j        ¦   «         |z
  t          k     r|cddd¦  «         S ddd¦  «         n# 1 swxY w Y   t          d¦  «        5 \  }}}|st          ddd¬¦  «        ‚t          ¦   «         }	|	r|	                     d¦  «        }
nˆt          | 
                    d¦  «        ¦  «        pt                               d¦  «        }
t          |
¦  «        }|j        r6|j        t          vr(t                               d|
|j        ¦  «         t          }
t#          | 
                    d	¦  «        pt$          ¦  «        }t'          |||¬
¦  «        }t)          t+          | dz   t,          ¦  «        ¬¦  «        5  t/          |¦  «        }| 
                    d¦  «        }| 
                    d¦  «        }t1          |t"          ¦  «        r|st          ddd¬¦  «        ‚t3          | 
                    d¦  «        |¦  «        sf|rt5          |d||¦  «         |s6|€4t           5  t          j        ¦   «         |faddd¦  «         n# 1 swxY w Y   |cddd¦  «         cddd¦  «         S t1          |t"          ¦  «        r|st          ddd¬¦  «        ‚t7          j        | r| nd¦  «        }t7          j        |ddi|¬¦  «        5 }	 t=          ||
||¬¦  «        }nX# t          $ rK}t?          |¦  «        r6tA          ||d¬¦  «         tC          ||d¬¦  «         t5          |d||¦  «         ‚ d}~ww xY w	 ddd¦  «         n# 1 swxY w Y   tE          j#        tH          j%        ¦  «        }tM          | 
                    d¦  «        ¦  «        }|d         |d<   | 
                    d¦  «        p||d<   | 
                    d¦  «        p| 
                    d¦  «        pd|d<   | 
                    d¦  «        p| 
                    d¦  «        |d<   | '                    ¦   «         |d<   ||d<   tE          j(        | )                    ¦   «         |z   tH          j%        ¬¦  «         '                    ¦   «         |d<   |
|d<   ||d	<   |du t1          |t"          ¦  «        r|ndd œ|d!<   t5          |d||¦  «         tU          |¦  «         |d         }|s6|€4t           5  t          j        ¦   «         |faddd¦  «         n# 1 swxY w Y   |cddd¦  «         cddd¦  «         S # 1 swxY w Y   	 ddd¦  «         dS # 1 swxY w Y   dS )"zKResolve a refresh-aware Nous Portal access token for managed tool gateways.Nrd   ú&Hermes is not logged into Nous Portal.Tr  rE   rR   zSauth: ignoring invalid portal_base_url %r (host %r not in allowlist), using defaultrT   r—  rS  rH  r  rÀ  ú,No access token found for Nous Portal login.rw  z2Session expired and no refresh token is available.r#   rÄ  r/  r  ©rû  rR   rT   rÀ  Ú$managed_access_token_refresh_failurerç  rI  rÍ  rÎ  rU   r–  r’  Fr  rœ  )+Ú_RESOLVE_TOKEN_CACHE_LOCKr0  r  r  Ú_RESOLVE_TOKEN_CACHE_TTL_Sr^  r|  rb  r?   rO  rg  rT  r   r=   rR  r  r  r3   rà  r§  rÑ  r  r  rÚ  r  rH  ri  r>  rö  r÷  r  rí  rÿ  r  r   r7  r   r8  rL  r9  r”  rA  rã  )ró  r˜  r™  rÝ  Ú	cached_atÚcached_tokenrp  rq  Ústate_source_pathÚenv_portal_overriderR   Úparsed_portal_urlrT   r  Úmerged_sharedr  rÀ  r*  rû  rÖ  r  r7  Ú
access_ttlrÎ  s                           rB   Úresolve_nous_access_tokenr?  Ü  sE  € ð ð (˜	Ð)Ý&ð 	(ð 	(Ý#Ð/Ý*>Ñ'�	˜<Ý”NÑ$Ô$ yÑ0Õ4NÒNÐNØ'ð		(ð 	(ð 	(ð 	(ñ 	(ô 	(ð 	(ð 	(ð 	(ð 	(ð 	(ñ 	(ô 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(øøøð 	(ð 	(ð 	(ð 	(õ
 
% VÑ	,Ô	,ð |ñ 1ØØØð ð 	ÝØ8ØØ!%ðñ ô ð õ 8Ñ9Ô9ÐØð 	:Ø1×8Ò8¸Ñ=Ô=ˆOˆOõ # 5§9¢9Ð->Ñ#?Ô#?Ñ@Ô@ð +Ý*ßŠf�S‰kŒkð õ
 !)¨Ñ 9Ô 9ÐØ Ô)ð :Ð.?Ô.HÕPjÐ.jÐ.jÝ—’ØiØ#Ð%6Ô%?ñô ð õ #:�å˜Ÿ	š	 +Ñ.Ô.ÐHÕ2HÑIÔIˆ	Ý ¨(¸iÐTYÐZÑZÔZˆå$µS¸È3Ñ9NÕPiÑ5jÔ5jÐkÑkÔkð T	ð T	Ý:¸5ÑAÔAˆMØ Ÿ9š9 ^Ñ4Ô4ˆLØ!ŸIšI oÑ6Ô6ˆMÝ˜l­CÑ0Ô0ð ¸ð ÝØBØ#Ø%)ðñ ô ð õ   §	¢	¨,Ñ 7Ô 7Ð9MÑNÔNð $Ø ð aÝ2°:¸vÀuÐN_Ñ`Ô`Ð`ð  ð P IÐ$5Ý2ð Pð PÝ04´Ñ0@Ô0@À,Ð/OÐ,ðPð Pð Pñ Pô Pð Pð Pð Pð Pð Pð Pøøøð Pð Pð Pð Pà#ð/T	ð T	ð T	ð T	ñ T	ô T	ð T	ðQ|ð |ð |ð |ñ |ô |ð |ð |õB ˜m­SÑ1Ô1ð ¸ð ÝØHØ#Ø%)ðñ ô ð õ ”m°Ð$P O OÈDÑQÔQˆGÝ”ØØ!Ð#5Ð6Øðñ ô ð ð ðÝ 5Ø%Ø(7Ø"+Ø&3ð	!ñ !ô !�I�Iøõ !ð ð ð Ý6°sÑ;Ô;ð eÝ4Ø!ØØ#Iðñ ô ð õ
 6Ø&ØØ#Iðñ ô ð õ
 7°zÀ6È5ÐRcÑdÔdÐdØøøøøðøøøð ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð õ6 ”,�xœ|Ñ,Ô,ˆCÝ,¨Y¯]ª]¸<Ñ-HÔ-HÑIÔIˆJØ$-¨nÔ$=ˆE�.Ñ!Ø%.§]¢]°?Ñ%CÔ%CÐ%TÀ}ˆE�/Ñ"Ø"+§-¢-°Ñ"=Ô"=Ð"dÀÇÂÈ<ÑAXÔAXÐ"dÐ\dˆE�,ÑØ&Ÿ]š]¨7Ñ3Ô3ÐI°u·y²yÀÑ7IÔ7IˆE�'‰NØ#&§=¢=¡?¤?ˆE�-Ñ Ø",ˆE�,ÑÝ"*Ô"8Ø—’‘” *Ñ,Ý”<ð#ñ #ô #÷ Ši‰kŒkð �,Ñð (7ˆEÐ#Ñ$Ø!*ˆE�+Ñà" e˜OÝ'1°&½#Ñ'>Ô'>ÐH˜V˜VÀDðð ˆE�%‰Lõ +¨:°v¸uÐFWÑXÔXÐXÝ$ UÑ+Ô+Ð+Ø˜^Ô,ˆHØð H 	Ð 1Ý.ð Hð HÝ,0¬NÑ,<Ô,<¸hÐ+GÐ(ðHð Hð Hñ Hô Hð Hð Hð Hð Hð Hð Høøøð Hð Hð Hð HàðiT	ð T	ð T	ð T	ñ T	ô T	ð T	ðQ|ð |ð |ð |ñ |ô |ð |ð |ðPT	ð T	ð T	ð T	øøøð T	ð T	ð T	ð T	ð T	ðQ|ð |ð |ñ |ô |ð |ð |ð |ð |ð |ð |ð |øøøð |ð |ð |ð |ð |ð |sè   Œ2AÁAÁAÁ1D(UÆB%T2È>I ÉT2É I$É$T2É'I$É(T2É,UÊAT2ËMË!K5Ë4MË5
M
	Ë?AM	ÍM
	Í
MÍT2ÍMÍT2Í!MÍ"F	T2Ó+TÔT2ÔTÔT2ÔTÔT2ÔUÔ2T6	Ô6UÔ9T6	Ô:UÕUÕUrÎ  ©rÍ  rU   r–  rw  r™  r›  ró  r˜  r™  rÛ  r  rÍ  r™  r›  r  ú/Optional[Callable[[Dict[str, Any], str], None]]c               ó*  — | ||pt           |pt                               d¦  «        |pt                               d¦  «        |pd|pt          |||	|
t          |¦  «        |dœdœ}t          |||¬¦  «        }t          j        |r|nd¦  «        }t          j	        |ddi|¬	¦  «        5 }t          |                     d
¦  «        |                     d¦  «        |                     d¦  «        ¬¦  «        }|s|��æ|                     d¦  «        }t          |t          ¦  «        r|s+|�t          d|› d�d|d¬¦  «        ‚t          ddd¬¦  «        ‚t          ||d         |d         |¬¦  «        }t!          j        t$          j        ¦  «        }t)          |                     d¦  «        ¦  «        }|d
         |d
<   |                     d¦  «        p||d<   |                     d¦  «        p|                     d¦  «        pd|d<   |                     d¦  «        p|                     d¦  «        |d<   t+          |                     d¦  «        ¦  «        }|pt          |d<   |                     ¦   «         |d<   ||d<   t!          j        |                     ¦   «         |z   t$          j        ¬¦  «                             ¦   «         |d<   |� |t3          |¦  «        d¦  «         t5          |¦  «         t7          |¦  «         ddd¦  «         n# 1 swxY w Y   |S ) a  Refresh Nous OAuth state without mutating auth.json directly.

    ``on_state_update`` is called after a successful access-token refresh.
    Callers that own persistent state can use it to save the newly rotated
    refresh token before later validation can fail.
    rE   rÎ  r  r  r—  r#   rÄ  r/  r  r  rU   rw  r‡  NrÀ  rˆ  úO) and no refresh token is available. Re-authenticate with: hermes auth add nousrd   Tr}  z.No refresh token is available for Nous Portal.r  rR   rT   r4  rI  rÍ  rS   r–  r’  Úpost_refresh_access_token)rà  rT  r?   rá  rß  r5   r§  r>  rö  r÷  r‚  rg  r  r3   r|  r  r   r7  r   r8  rL  rZ  r9  r”  rA  rb   rŠ  r¢  )r  rÀ  rT   rR   rS   rÍ  rU   r–  rw  r™  r›  ró  r˜  r™  rÛ  r  rq  r  r*  rû  Úcurrent_invoke_jwt_statusÚrefresh_token_valuerÖ  r7  r>  Úrefreshed_urls                             rB   Úrefresh_nous_oauth_purerH  m  s©  € ð4 %Ø&ØÐ8Õ"8Ø+ÐFÕ/F×NÒNÈsÑSÔSØ1ÐOÕ5O×WÒWÐX[Ñ\Ô\Ø Ð, HØÐ,Õ,Ø"Ø ØØ 4å˜X™œØ"ð
ð 
ðð €Eõ"  h¸)ÐPUÐVÑVÔV€FÝŒm¨ÐH˜O˜OÀDÑIÔI€Gå	Œ˜g°Ð:LÐ/MÐV\Ð	]Ñ	]Ô	]ð 5'ÐagÝ$;Ø�IŠI�nÑ%Ô%Ø—)’)˜GÑ$Ô$Ø—y’y Ñ.Ô.ð%
ñ %
ô %
Ð!ð
 ð ,	JÐ5ÑAØ"'§)¢)¨OÑ"<Ô"<ÐÝÐ1µ3Ñ7Ô7ð Ð?Rð Ø,Ð8Ý#ðEØ5ðEð Eð Eð "(Ø6Ø)-ðñ ô ð õ  ØDØ#Ø%)ðñ ô ð õ
 .ØØ %Ð&7Ô 8Ø Ô,Ø1ð	ñ ô ˆIõ ”,�xœ|Ñ,Ô,ˆCÝ,¨Y¯]ª]¸<Ñ-HÔ-HÑIÔIˆJØ$-¨nÔ$=ˆE�.Ñ!Ø%.§]¢]°?Ñ%CÔ%CÐ%ZÐGZˆE�/Ñ"Ø"+§-¢-°Ñ"=Ô"=Ð"dÀÇÂÈ<ÑAXÔAXÐ"dÐ\dˆE�,ÑØ&Ÿ]š]¨7Ñ3Ô3ÐI°u·y²yÀÑ7IÔ7IˆE�'‰Nõ FÀiÇmÂmÐThÑFiÔFiÑjÔjˆMØ*7Ð*UÕ;UˆEÐ&Ñ'Ø#&§=¢=¡?¤?ˆE�-Ñ Ø",ˆE�,ÑÝ"*Ô"8Ø—’‘” *Ñ,µ´ð#ñ #ô #çŠi‰kŒkð �,Ñð Ð*Ø�¥ U¡¤Ð-HÑIÔIÐIå)¨%Ñ0Ô0Ð0Ý Ñ&Ô&Ð&ðk5'ð 5'ð 5'ñ 5'ô 5'ð 5'ð 5'ð 5'ð 5'ð 5'ð 5'øøøð 5'ð 5'ð 5'ð 5'ðn €Ls   Â'ILÌLÌLr  c               óˆ  — |                       d¦  «        pi }t          |                       dd¦  «        |                       dd¦  «        |                       dd¦  «        |                       dt          ¦  «        |                       dt          ¦  «        |                       d	d
¦  «        |                       dt          ¦  «        |                       d¦  «        |                       d¦  «        |                       d¦  «        |                       d¦  «        ||                      d¦  «        |                      d¦  «        ||¬¦  «        S )zRRefresh Nous OAuth from a state dict. Thin wrapper around refresh_nous_oauth_pure.rœ  r  r7   rÀ  rT   r$   rR   rS   rÍ  rÎ  rU   r–  rw  r™  r›  r˜  r™  r@  )rg  rH  rT  rá  rß  )rq  ró  rÛ  r  rœ  s        rB   r  r  Ô  s  € ð �)Š)�EÑ
Ô
Ð
 ˜b€CÝ"Ø�	Š	�. "Ñ%Ô%Ø�	Š	�/ 2Ñ&Ô&Ø�	Š	�+˜|Ñ,Ô,Ø�	Š	Ð#Õ%<Ñ=Ô=Ø�	Š	Ð&Õ(BÑCÔCØ—9’9˜\¨8Ñ4Ô4Ø�iŠi˜Õ!3Ñ4Ô4Ø—I’I˜mÑ,Ô,Ø—9’9˜\Ñ*Ô*Ø—)’)˜KÑ(Ô(Ø"ŸYšYÐ'=Ñ>Ô>Ø'Ø—’˜Ñ$Ô$Ø—'’'˜+Ñ&Ô&Ø#Ø'ð!ñ ô ð rc   )r=  c               óî  — ddl m} t          | ¦  «        }|rEt          |¦  «                             ¦   «         r$t          |¦  «                             ¦   «         |d<   t          ¦   «         5  t          ¦   «         }t          |d|¦  «         t          |¦  «         ddd¦  «         n# 1 swxY w Y   t          |¦  «          |d¦  «        }t          d„ |                     ¦   «         D ¦   «         d¦  «        S )u-  Persist Nous OAuth credentials as the singleton provider state
    and ensure the credential pool is in sync.

    Nous credentials are read at runtime from two independent locations:

    - ``providers.nous``: singleton state read by
      ``resolve_nous_runtime_credentials()`` during 401 recovery and by
      ``_seed_from_singletons()`` during pool load.
    - ``credential_pool.nous``: used by the runtime ``pool.select()`` path.

    Historically ``hermes auth add nous`` wrote a ``manual:device_code`` pool
    entry only, skipping ``providers.nous``. When the runtime credential
    expired, the recovery path read the empty singleton state and raised
    ``AuthError`` silently (``logger.debug`` at INFO level).

    This helper writes ``providers.nous`` then calls ``load_pool("nous")`` so
    ``_seed_from_singletons`` materialises the canonical ``device_code`` pool
    entry from the singleton.  Re-running login upserts the same entry in
    place; the pool never accumulates duplicate device_code rows.

    ``label`` is an optional user-chosen display name (from
    ``hermes auth add nous --label <name>``).  It gets embedded in the
    singleton state so that ``_seed_from_singletons`` uses it as the pool
    entry's label on every subsequent ``load_pool("nous")`` instead of the
    auto-derived token fingerprint.  When ``None``, the auto-derived label
    via ``label_from_token`` is used (unchanged default behaviour).

    Returns the upserted :class:`PooledCredential` entry (or ``None`` if
    seeding somehow produced no match â€” shouldn't happen).
    r   r  r=  rd   Nc              3  ó:   K  — | ]}|j         t          k    ¯|V — Œd S r…  )r  r  )râ   r2  s     rB   rä   z+persist_nous_credentials.<locals>.<genexpr>'  s/   è è € ÐJÐJˆq a¤hÕ2IÒ&IÐ&IˆÐ&IÐ&IÐ&IÐ&IÐJÐJrc   )r  r  rb   r3   rG   rl  re  re  rn  rã  Únextr   )rØ  r=  r  rq  rp  r"  s         rB   Úpersist_nous_credentialsrM  ñ  s7  € ðF 0Ð/Ð/Ð/Ð/Ð/å�‰KŒK€EØð ,•�U‘”×!Ò!Ñ#Ô#ð ,Ý˜U™œ×)Ò)Ñ+Ô+ˆˆg‰å	Ñ	Ô	ð %ð %Ý%Ñ'Ô'ˆ
Ý˜Z¨°Ñ7Ô7Ð7Ý˜Ñ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %õ ˜UÑ#Ô#Ð#àˆ9�VÑÔ€DÝØJÐJ�D—L’L‘N”NÐJÑJÔJØñô ð s   Á+/B&Â&B*Â-B*c                 ó�   — 	 ddl m}   | d¦  «         dS # t          $ r&}t                               d|¦  «         Y d}~dS d}~ww xY w)zGBest-effort pool reseed after providers.nous changes; never fail login.r   r  rd   z7Failed to sync Nous credential pool from auth store: %sN)r  r  r@   r  rA  )r  r  s     rB   Ú_sync_nous_pool_from_auth_storerO  ,  s{   € ðUØ3Ð3Ð3Ð3Ð3Ð3àˆ	�&ÑÔÐÐÐøÝð Uð Uð UÝ�ŠÐNÐPSÑTÔTÐTÐTÐTÐTÐTÐTÐTøøøøðUøøøs   ‚ •
AŸA Á A)ró  r˜  r™  rÛ  c                ó
  ‡‡‡‡‡ ‡!— t          j        ¦   «         j        dd…         Št          d¦  «        5 \  ŠŠŠ!‰st	          ddd¬¦  «        ‚t          ‰¦  «        ŠdŠ dDˆfd
„} |¦   «         \  }}}}dEˆˆˆˆˆ ˆ!fd„}	t          ||‰¬¦  «        }
t          j        | r| nd¦  «        }t          d‰t          ‰                     d¦  «        ¦  «        ¬¦  «         t          j        |ddi|
¬¦  «        5 }‰                     d¦  «        }‰                     d¦  «        }t          |t          ¦  «        r|s‘t          t!          | dz   t"          ¦  «        ¬¦  «        5  t%          ‰¦  «        rD‰                     d¦  «        }‰                     d¦  «        } |¦   «         \  }}}} |	d¦  «         ddd¦  «         n# 1 swxY w Y   t          |t          ¦  «        r|st	          ddd¬¦  «        ‚t'          |‰                     d¦  «        ‰                     d¦  «        ¬¦  «        }|s|��@t          t!          | dz   t"          ¦  «        ¬¦  «        5  t%          ‰¦  «        r|‰                     d¦  «        }‰                     d¦  «        } |¦   «         \  }}}}t'          |‰                     d¦  «        ‰                     d¦  «        ¬¦  «        } |	d¦  «         |s|��rt          |t          ¦  «        r|s|pd }t	          d!|› d"�d|d¬#¦  «        ‚|rd n|pd$}t          d%‰|t          |¦  «        ¬&¦  «         	 t)          ||||¬'¦  «        }nQ# t          $ rD}t+          |¦  «        r/t-          ‰|d(¬)¦  «         t/          ‰|d(¬)¦  «          |	d*¦  «         ‚ d}~ww xY wt1          j        t4          j        ¦  «        }t9          |                     d+¦  «        ¦  «        }|}|d         ‰d<   |                     d¦  «        p|‰d<   |                     d,¦  «        p‰                     d,¦  «        pd-‰d,<   |                     d¦  «        p‰                     d¦  «        ‰d<   t;          |                     d.¦  «        ¦  «        }|pt<          }t?          ¦   «         p|}|‰d.<   |                      ¦   «         ‰d/<   |‰d+<   t1          j!        | "                    ¦   «         |z   t4          j        ¬0¦  «                              ¦   «         ‰d<   ‰d         }‰d         }t          d1‰|t          |¦  «        t          |¦  «        ¬2¦  «          |	d3¦  «         ddd¦  «         n# 1 swxY w Y   tG          ‰|¬4¦  «         tI          ‰|‰¬5¦  «         |‰d6<   |‰d.<   |‰d7<   |
du t          |
t          ¦  «        r|
ndd8œ‰d9<   ddd¦  «         n# 1 swxY w Y    |	d:¦  «         ddd¦  «         n# 1 swxY w Y   ‰ rtK          ¦   «          ‰                     d;¦  «        }t          |t          ¦  «        r|st	          d<dd=¬>¦  «        ‚‰                     d?¦  «        }tM          |¦  «        }|�1t!          d@tO          |tQ          j(        ¦   «         z
  ¦  «        ¦  «        n!t9          ‰                     dA¦  «        ¦  «        }d||‰                     dB¦  «        ||tR          tR          t          ‰!ptU          ¦   «         ¦  «        dCœ	S )FaX  
    Resolve Nous inference credentials for runtime use.

    Ensures access_token is a valid inference-scoped JWT, refreshing it when
    needed. Concurrent processes coordinate through the auth store file lock.

    Returns dict with: provider, base_url, api_key, key_id, expires_at,
    expires_in, source ("invoke_jwt"), and auth_path.
    Nr¬  rd   r2  Tr  Fr4   útuple[str, str, str, str]c                 óÆ  •— t          ‰	                     d¦  «        ¦  «        p.t          j        d¦  «        pt          j        d¦  «        pt                               d¦  «        } t          ¦   «         }|r|                     d¦  «        } nbt          | ¦  «        }|j        }|j	        dk    o|dv }|j	        dk    p|}|r|t          vs|s#t                               d| |¦  «         t          } t          t          ‰	                     d	¦  «        ¦  «        ¦  «        pt          }t          ¦   «         p|}t!          ‰	                     d
¦  «        pt"          ¦  «        }| |||fS )z@Resolve every routing value that shared OAuth state can replace.rR   r`  ra  rE   r.  >   r:   r<   rX  zXauth: ignoring invalid portal_base_url %r (host %r or scheme not allowed), using defaultrS   rT   )rO  rg  r´  rµ  rT  r?   rb  r   r=   rY  rR  r  r  rZ  rá  r^  r3   rà  )
Ú
portal_urlr;  r<  Úportal_hostÚloopback_httpÚtrusted_schemeÚstored_inference_urlÚeffective_inference_urlÚeffective_client_idrq  s
            €rB   Ú#_resolve_effective_routing_metadatazMresolve_nous_runtime_credentials.<locals>._resolve_effective_routing_metadataU  s©  ø€ õ # 5§9¢9Ð->Ñ#?Ô#?Ñ@Ô@ð +Ý”9Ð5Ñ6Ô6ð+å”9Ð3Ñ4Ô4ð+õ +ßŠf�S‰kŒkð õ #<Ñ"=Ô"=ÐØ"ð 9Ø0×7Ò7¸Ñ<Ô<�
�
å$,¨ZÑ$8Ô$8Ð!Ø/Ô8�à%Ô,°Ò6ð BØ#Ð'AÐAð ð
 &Ô,°Ò7ÐH¸=ð ð $ð9à"Õ*DÐDÐDØ)ð Eõ —N’NðIà"Ø#ñ	ô ð õ "9�Jõ
 :Ý& u§y¢yÐ1EÑ'FÔ'FÑGÔGñô ð .õ .ð	 !õ -Ñ.Ô.ÐFÐ2Fð $õ #&Ø—	’	˜+Ñ&Ô&Ð@Õ*@ñ#ô #Ðð Ø$Ø'Ø#ð	ð rc   r‰  r3   rƒ  c                óð  •— t          ‰¦  «        t          ‰¦  «        k    rt          d‰| ¬¦  «         d S 	 t          ‰d‰‰¦  «         n8# t          $ r+}t          d‰| t	          |¦  «        j        ¬¦  «         ‚ d }~ww xY wt          d‰| t          ‰                     d¦  «        ¦  «        t          ‰                     d¦  «        ¦  «        ¬	¦  «         t          ‰¦  «        Šd
Št          ‰¦  «         d S )NÚnous_state_persist_skipped)r¸  r‰  rd   Únous_state_persist_failed)r¸  r‰  r  Únous_state_persistedrÀ  r  )r¸  r‰  rÞ  r�  T)
r§  rÂ  ri  r@   rí  r]   r­  rg  rb   rã  )r‰  r  rp  Úpersisted_stater¸  rq  Ústate_persistedr:  s     €€€€€€rB   Ú_persist_statez8resolve_nous_runtime_credentials.<locals>._persist_state˜  s5  ø€ õ
 /¨uÑ5Ô5Ý1°/ÑBÔBòCð Cõ Ø0Ø +Ø!ðñ ô ð ð
 �ð	Ý.¨z¸6À5ÐJ[Ñ\Ô\Ð\Ð\øÝð ð ð ÝØ/Ø +Ø!Ý# C™yœyÔ1ð	ñ ô ð ð øøøøðøøøõ Ø&Ø'ØÝ!3°E·I²I¸oÑ4NÔ4NÑ!OÔ!OÝ 2°5·9²9¸^Ñ3LÔ3LÑ MÔ Mðñ ô ð õ # 5™kœkˆOØ"ˆOõ
 % UÑ+Ô+Ð+Ð+Ð+s   ·A
 Á

A?Á&A:Á:A?r—  r#   Únous_runtime_credentials_startrÀ  )r¸  rÞ  rÄ  r/  r  r  rS  rH  Ú)runtime_shared_merge_missing_access_tokenr3  rU   rw  r‡  Ú!post_shared_merge_access_unusablerÛ  rˆ  rC  r}  Úaccess_unusableÚrefresh_start)r¸  r‰  rÞ  r4  Úruntime_access_refresh_failurerç  Ú'terminal_runtime_access_refresh_failurerI  rÍ  rÎ  rS   r–  r’  Úrefresh_success)r¸  r‰  Úprevious_refresh_token_fpÚnew_refresh_token_fprD  r…  rŽ  rR   rT   r  rœ  Ú&resolve_nous_runtime_credentials_finalr™  z*Failed to resolve a Nous inference API keyÚserver_errorr®  r›  r   rœ  rš  )	r~  r2   rh   Úkey_idrw  rI  r  r  Ú
state_path)r4   rQ  ©r‰  r3   r4   rƒ  )+r<  r=  r>  r^  r|  rb   r§  r>  rö  rÂ  r­  rg  r÷  r  r3   rÑ  r  r  rÚ  r‚  r  rí  rÿ  r  r   r7  r   r8  rL  rZ  rá  r^  r9  r”  rA  rŠ  r¢  rO  rC  r  r  ÚNOUS_AUTH_PATH_INVOKE_JWTrÏ  )"ró  r˜  r™  rÛ  rZ  rR   Ústored_inference_base_urlrS   rT   ra  r  r*  rû  r  rÀ  Úinvoke_jwt_statusr‰  Úrefresh_reasonrÖ  r  r7  r>  Úprevious_refresh_tokenrG  rh   rw  rG  rI  rp  r_  r¸  rq  r`  r:  s"                               @@@@@@rB   Ú resolve_nous_runtime_credentialsrv  6  s
  øøøøøø€ õ  ”*‘,”,Ô" 3 B 3Ô'€Kå	$ VÑ	,Ô	,ð RAñ 1ØØØð ð 	DÝÐDØ%+¸dðDñ Dô Dð Dõ ˜u™+œ+ˆØˆð:	ð :	ð :	ð :	ð :	ð :	ðB 0Ð/Ñ1Ô1ñ	
ØØ%ØØð%	,ð %	,ð %	,ð %	,ð %	,ð %	,ð %	,ð %	,ð %	,ð %	,ð %	,õN !¨(¸iÐTYÐZÑZÔZˆÝ”-°?Ð L  ÈÑMÔMˆÝØ,Ø#Ý/°·	²	¸/Ñ0JÔ0JÑKÔKð	
ñ 	
ô 	
ð 	
õ Œ\ '°HÐ>PÐ3QÐZ`ÐaÑaÔað Q	ÐekØ Ÿ9š9 ^Ñ4Ô4ˆLØ!ŸIšI oÑ6Ô6ˆMå˜l­CÑ0Ô0ð T¸ð TÝ,Ý$'¨¸#Ñ(=Õ?XÑ$YÔ$Yðñ ô ð Tð Tõ 6°eÑ<Ô<ð 	TØ',§y¢y°Ñ'@Ô'@˜Ø(-¯	ª	°/Ñ(BÔ(B˜ð @Ð?ÑAÔAñØ+Ø5Ø.Ø%à&˜Ð'RÑSÔSÐSðTð Tð Tñ Tô Tð Tð Tð Tð Tð Tð Tøøøð Tð Tð Tð Tõ ˜l­CÑ0Ô0ð H¸ð HÝÐ NØ)/À$ðHñ Hô Hð Hõ !8ØØ—i’i Ñ(Ô(Ø Ÿ9š9 \Ñ2Ô2ð!ñ !ô !Ðð
 ð _DÐ 1Ñ =Ý,½SÀÐSVÑAVÕXqÑ=rÔ=rÐsÑsÔsð ^Dð ^DÝ5°eÑ<Ô<ð LØ',§y¢y°Ñ'@Ô'@˜Ø(-¯	ª	°/Ñ(BÔ(B˜ð @Ð?ÑAÔAñØ+Ø5Ø.Ø%å,CØ(Ø"'§)¢)¨GÑ"4Ô"4Ø',§y¢y°Ñ'>Ô'>ð-ñ -ô -Ð)ð
 '˜Ð'JÑKÔKÐKà$ð MDÐ(9Ñ(EÝ)¨-½Ñ=Ô=ð 	À]ð 	Ø%6Ð%I¸/˜FÝ"+ð!MØ$*ð!Mð !Mð !Mð *0Ø%+Ø15ð#ñ #ô #ð ð =JÐ)w¨¨ÐPaÐPvÐev˜Ý$Ø+Ø(3Ø#1Ý-?ÀÑ-NÔ-Nð	ñ ô ð ð"Ý(=Ø'-¸Ø*3À=ð)ñ )ô )˜I˜Iøõ  )ð "ð "ð "Ý>¸sÑCÔCð ZÝ <Ø$)Ø$'Ø+Kð!"ñ !"ô !"ð !"õ
 !>Ø$.Ø$'Ø+Kð!"ñ !"ô !"ð !"ð
 !/ Ð/XÑ YÔ YÐ YØ!øøøøð"øøøõ 'œl­8¬<Ñ8Ô8˜Ý%8¸¿ºÀ|Ñ9TÔ9TÑ%UÔ%U˜
Ø1>Ð.Ø09¸.Ô0I˜˜nÑ-Ø1:·²¸Ñ1OÔ1OÐ1`ÐS`˜˜oÑ.Ø.7¯mªm¸LÑ.IÔ.IÐ.pÈUÏYÊYÐWcÑMdÔMdÐ.pÐhp˜˜lÑ+Ø)2¯ª°wÑ)?Ô)?Ð)UÀ5Ç9Â9ÈWÑCUÔCU˜˜g™õ )RÐR[×R_ÒR_Ð`tÑRuÔRuÑ(vÔ(v˜Ø4AÐ4_ÕE_Ð1å8Ñ:Ô:ÐWÐ>Wð +ð 7P˜Ð2Ñ3Ø/2¯}ª}©¬˜˜mÑ,Ø.8˜˜lÑ+Ý.6Ô.DØŸMšM™OœO¨jÑ8½X¼\ð/ñ /ô /ç#š)™+œ+ð ˜lÑ+ð (-¨^Ô'<˜Ø(-¨oÔ(>˜Ý$Ø-Ø(3Ø#1Ý6HÐI_Ñ6`Ô6`Ý1CÀMÑ1RÔ1Rðñ ô ð ð '˜Ð'BÑCÔCÐCð}^Dð ^Dð ^Dñ ^Dô ^Dð ^Dð ^Dð ^Dð ^Dð ^Dð ^Døøøð ^Dð ^Dð ^Dð ^Dõ@ .ØØ)ðñ ô ð õ $ØØ)Ø'ðñ ô ð ð (7ˆEÐ#Ñ$Ø*CˆEÐ&Ñ'Ø!*ˆE�+Ñà" e˜OÝ'1°&½#Ñ'>Ô'>ÐH˜V˜VÀDðð ˆE�%‰Lð]Q	ð Q	ð Q	ñ Q	ô Q	ð Q	ð Q	ð Q	ð Q	ð Q	ð Q	øøøð Q	ð Q	ð Q	ð Q	ðf 	ˆÐ?Ñ@Ô@Ð@ðeRAð RAð RAñ RAô RAð RAð RAð RAð RAð RAð RAøøøð RAð RAð RAð RAðh ð *Ý'Ñ)Ô)Ð)à�iŠi˜Ñ$Ô$€GÝ�g�sÑ#Ô#ð >¨7ð >ÝÐDØ!'¨nð>ñ >ô >ð 	>ð —’Ð1Ñ2Ô2€JÝ(¨Ñ4Ô4€Mð Ð$õ 	ˆA�s�=¥4¤9¡;¤;Ñ.Ñ/Ô/Ñ0Ô0Ð0å  §¢Ð+AÑ!BÔ!BÑCÔCð ð Ø&ØØ—)’)˜NÑ+Ô+Ø Ø Ý+õ /ÝÐ+Ð@­Ñ/@Ô/@ÑAÔAðð ð s¨   ¶B?W/Ã5A(WÅAF=Æ1WÆ=GÇWÇGÇBWÉC+U#Í MÍU#Í
N"	Í?N	ÎN"	Î"F5U#ÕWÕ#U'Õ'WÕ*U'Õ+AW×W/×W	×W/×W	×W/×/W3×6W3c            	     ó   — dd d d d ddd dœS )NF)r"  rR   rS   Úaccess_expires_atr›  r~  Úinference_credential_presentÚcredential_sourcerY   rY   rc   rB   Ú_empty_nous_auth_statusr{  €  s)   € àØØ"Ø!Ø $Ø"Ø(-Ø!ð	ð 	ð 	rc   c                 óê  — 	 ddl m}   | d¦  «        }|r|                     ¦   «         st          ¦   «         S t	          |                     ¦   «         ¦  «        }|st          ¦   «         S dd„}t          ||¬	¦  «        }t          |d
d¦  «        }|st          ¦   «         S t          |dd¦  «        }t          t          |dd¦  «        pd¦  «         	                    ¦   «          
                    ¦   «         }t          |dd¦  «        }t          |¦  «        o#|                     d¦  «        pt          |¦  «        }	t          |dd¦  «        }
d}|	rt          |dd¦  «        pt          }|	|t          |dd¦  «        p!t          |dd¦  «        pt          |dd¦  «        |	r|ndt          |dd¦  «        t          |dd¦  «        t          |¦  «        dd|
› �d|
› �dœ
S # t          $ r t          ¦   «         cY S w xY w)zÕBest-effort status from the credential pool.

    This is a fallback only. The auth-store provider state is the runtime source
    of truth because it is what ``resolve_nous_runtime_credentials()`` refreshes.
    r   r  rd   r#  r   r4   útuple[float, float, int]c                óÎ   — t          t          | dd ¦  «        ¦  «        pd}t          t          | dd ¦  «        ¦  «        pd}t          t          | dd¦  «        pd¦  «        }||| fS )Nr›  r“  rw  Úpriorityr   )rC  r  r  )r#  Ú	agent_expÚ
access_expr  s       rB   Ú_entry_sort_keyz3_snapshot_nous_pool_status.<locals>._entry_sort_keyž  so   € Ý,­W°UÐ<RÐTXÑ-YÔ-YÑZÔZÐaÐ^aˆIÝ-­g°e¸\È4Ñ.PÔ.PÑQÔQÐXÐUXˆJÝ�7 5¨*°aÑ8Ô8Ð=¸AÑ>Ô>ˆHØ˜z¨H¨9Ð5Ð5rc   r(  r  Nr  rQ   r7   rÀ  Úoauthr=  r+   rR   rS   Úruntime_base_urlr2   rw  r›  Túpool:©
r"  rR   rS   r  rx  r›  r~  ry  rz  r  )r#  r   r4   r}  )r  r  r  r{  r|  r   r  r  r3   rG   r>   r5   rð   rT  r@   )r  r"  r   r‚  r#  Úruntime_keyr  rQ   rÀ  Úis_portal_oauthr=  Úportal_status_urls               rB   Ú_snapshot_nous_pool_statusrŠ  �  sY  € ð2)Ø3Ð3Ð3Ð3Ð3Ð3àˆy˜Ñ Ô ˆØð 	-˜4×/Ò/Ñ1Ô1ð 	-Ý*Ñ,Ô,Ð,å�t—|’|‘~”~Ñ&Ô&ˆØð 	-Ý*Ñ,Ô,Ð,ð	6ð 	6ð 	6ð 	6õ �G Ð1Ñ1Ô1ˆÝ˜eÐ%6¸Ñ=Ô=ˆØð 	-Ý*Ñ,Ô,Ð,Ý˜u n°dÑ;Ô;ˆÝ�  {°BÑ7Ô7Ð=¸2Ñ>Ô>×DÒDÑFÔF×LÒLÑNÔNˆ	Ý  ¸Ñ=Ô=ˆÝ˜|Ñ,Ô,ð 
Ø× Ò  Ñ)Ô)Ð@­T°-Ñ-@Ô-@ð 	õ ˜˜w¨	Ñ2Ô2ˆØ ÐØð 	å˜Ð0°$Ñ7Ô7ð +Ý*ð ð )Ø0Ý")¨%Ð1EÀtÑ"LÔ"Lð #0Ý�uÐ0°$Ñ7Ô7ð#0å�u˜j¨$Ñ/Ô/Ø,;ÐE˜L˜LÀÝ!(¨°¸dÑ!CÔ!CÝ$+¨EÐ3IÈ4Ñ$PÔ$PÝ!% mÑ!4Ô!4Ø,0Ø!0¨  Ø%˜e�o�oð
ð 
ð 	
øõ ð )ð )ð )Ý&Ñ(Ô(Ð(Ð(Ð(ð)øøøs#   ‚4G ·0G Á(5G ÂD8G ÇG2Ç1G2z<Optional[Tuple[float, str, Optional[float], Dict[str, Any]]]Ú_nous_auth_status_cacheúTuple[str, Optional[float]]c                 ó$  — t          ¦   «         } 	 t          |                      d¬¦  «        ¦  «        }n# t          $ r t          | ¦  «        }Y nw xY w	 ||                      ¦   «         j        fS # t          $ r |d fcY S t          $ r |d fcY S w xY wrç  )rÏ  r3   rË  r@   r  rø  rè  )r  Úauth_file_keys     rB   Ú_auth_file_cache_keyr�  Õ  sÈ   € ÝÑ!Ô!€Ið'Ý˜I×-Ò-°UÐ-Ñ;Ô;Ñ<Ô<ˆˆøÝð 'ð 'ð 'Ý˜I™œˆˆˆð'øøøð#Ø˜iŸnšnÑ.Ô.Ô7Ð7Ð7øÝð #ð #ð #Ø˜dÐ"Ð"Ð"Ð"Ýð #ð #ð #Ø˜dÐ"Ð"Ð"Ð"ð#øøøs'   �#4 ´AÁAÁA/ Á/BÁ?BÂBc                 ó
   — da dS )u`  Clear the get_nous_auth_status() process-level memo.

    Call this from any code path that mutates Nous auth state without going
    through resolve_nous_runtime_credentials() (e.g. tests). Login/logout
    flows touch auth.json, so the mtime check below invalidates them
    automatically â€” explicit invalidation is the belt-and-braces option.
    N)r‹  rY   rc   rB   rú  rú  ã  s   € ð #ÐÐÐrc   c                 ó  — t          j        ¦   «         } t          ¦   «         \  }}t          }|�0|\  }}}}||k    r#||k    r| |z
  t          k     rt          |¦  «        S t          ¦   «         }| ||t          |¦  «        fa|S )aè  Status snapshot for Nous auth.

    Prefer the auth-store provider state, because that is the live source of
    truth for refresh operations. When provider state exists, validate it
    by resolving runtime credentials so revoked refresh sessions do not show up
    as a healthy login. If provider state is absent, fall back to the credential
    pool for the just-logged-in / not-yet-promoted case.

    The returned snapshot is memoised for ~15s keyed on the auth.json mtime,
    so menu/status surfaces that ask repeatedly don't trigger one refresh POST
    per call. Login/logout flows write to auth.json and therefore invalidate
    the cache automatically; tests can also call
    ``invalidate_nous_auth_status_cache()`` explicitly.
    )r  r  r�  r‹  Ú_NOUS_AUTH_STATUS_CACHE_TTLrb   Ú_compute_nous_auth_status)	r7  rŽ  Úmtimerr  r8  Úcached_auth_file_keyÚcached_mtimeÚcached_statusÚstatuss	            rB   Úget_nous_auth_statusr™  ï  s”   € õ  Œ.Ñ
Ô
€CÝ/Ñ1Ô1Ñ€M�5Ý$€FØÐØGMÑDˆ	Ð'¨°}à  MÒ1Ð1Ø Ò%Ð%Ø�y‘Õ$?Ò?Ð?å˜Ñ&Ô&Ð&å&Ñ(Ô(€FØ" M°5½$¸v¹,¼,ÐGÐØ€Mrc   c                 ó†  — t          d¦  «        } | �r¢t          |                      d¦  «        ¦  «        |                      d¦  «        |                      d¦  «        |                      d¦  «        |                      d¦  «        t          |                      d¦  «        ¦  «        |                      d¦  «        t          |                      d¦  «        p|                      d¦  «        ¦  «        d	d	d
œ
}	 t          ¦   «         }t          d¦  «        p| }|                     d|                     d¦  «        p|                     d¦  «        |                     d¦  «        p)|                     d¦  «        p|                     d¦  «        |                     d¦  «        p|                     d¦  «        |                     d¦  «        p)|                     d¦  «        p|                     d¦  «        t          |                     d¦  «        ¦  «        dd	d|                     dd¦  «        › �|                     d¦  «        dœ
¦  «         |S # t
          $ r^}|                     dt          |¦  «        t          t          |dd¦  «        ¦  «        t          |dd¦  «        dœ¦  «         |cY d}~S d}~ww xY wt          ¦   «         S )zEUncached implementation of get_nous_auth_status(). See that function.rd   r  rR   rS   rw  r›  rÀ  r™  rp  )
r"  rR   rS   rx  r›  r~  r  ry  rz  r  Tr2   rx  zruntime:r  r·  rn  )
r"  rR   rS   rx  r›  r~  ry  rz  r  rn  Fr€  r  N)r"  r‹  r€  rÃ  )	rÄ  r5   rg  rv  r¿  r|  r3   r  rŠ  )rq  Úbase_statusrØ  Úrefreshed_stater  s        rB   r“  r“    sÃ  € å# FÑ+Ô+€EØñ ,å˜eŸiši¨Ñ7Ô7Ñ8Ô8Ø$ŸyšyÐ):Ñ;Ô;Ø"'§)¢)Ð,@Ñ"AÔ"AØ!&§¢¨<Ñ!8Ô!8Ø$)§I¢IÐ.DÑ$EÔ$EÝ!% e§i¢i°Ñ&@Ô&@Ñ!AÔ!AØ!ŸIšI nÑ5Ô5Ý,0Ø—	’	˜.Ñ)Ô)ÐC¨U¯YªY°{Ñ-CÔ-Cñ-ô -ð ".Ø"ð
ð 
ˆð	Ý4Ñ6Ô6ˆEÝ5°fÑ=Ô=ÐFÀˆOØ×Òà!%Ø'6×':Ò':Ð;LÑ'MÔ'MÐ'sÐQ\×Q`ÒQ`ÐarÑQsÔQsØ*/¯)ª)°JÑ*?Ô*?ð +=Ø&×*Ò*Ð+?Ñ@Ô@ð+=à"—’Ð';Ñ<Ô<Ø)8×)<Ò)<¸\Ñ)JÔ)JÐ)rÈkÏoÊoÐ^qÑNrÔNrØ,1¯IªI°lÑ,CÔ,Cð -?Ø&×*Ò*Ð+AÑBÔBð-?à"—’Ð'=Ñ>Ô>Ý)-¨o×.AÒ.AÀ/Ñ.RÔ.RÑ)SÔ)SØ48Ø)5ØH¨¯ª°8¸XÑ)FÔ)FÐHÐHØ#Ÿiši¨Ñ1Ô1ðð ñô ð ð$ ÐøÝð 	ð 	ð 	Ø×ÒØ"Ý˜S™œÝ$(­°Ð6HÈ%Ñ)PÔ)PÑ$QÔ$QÝ% c¨6°4Ñ8Ô8ð	 ð  ñ ô ð ð ÐÐÐÐÐÐøøøøð	øøøõ &Ñ'Ô'Ð's    Ã5EI
 É

J2ÉAJ-Ê'J2Ê-J2c                 óò  — 	 t          d¦  «        } n# t          $ r d} Y nw xY w| st          ¦   «         S |                      d¦  «        }t	          ||                      d¦  «        |                      d¦  «        ¬¦  «        }|                      d¦  «        }t          t          |t          ¦  «        o,|                     d¦  «        o|p|                      d	¦  «         ¦  «        }|du p$t          |                      d	¦  «        ¦  «        o| }||                      d
¦  «        |                      d¦  «        ||                      d¦  «        |                      d¦  «        t          |                      d	¦  «        ¦  «        t          |p|                      d¦  «        ¦  «        dddœ
}|rLt          |t          ¦  «        r7d|d<   |                     d¦  «        |d<   |                     d¦  «        pd|d<   |S )u…  Refresh-free Nous auth snapshot for read-only display surfaces.

    Unlike :func:`get_nous_auth_status`, this NEVER calls
    ``resolve_nous_runtime_credentials()`` and therefore never performs an
    OAuth refresh POST or consumes a single-use refresh token. It reports the
    persisted auth-store state, classifying the access token with a local
    invoke-JWT decode only.

    Use this from status panels, doctor checks, and polled dashboard
    endpoints. Explicit auth actions (login flows, portal operations that
    need a live credential) should keep using ``get_nous_auth_status()``.

    ``logged_in`` here means "a persisted login exists that the runtime can
    use or refresh": a currently-usable invoke JWT, or a refresh token that
    has not been terminally quarantined. It does not prove the refresh token
    is still accepted server-side â€” only a live resolve can do that.
    rd   Nr  rU   rw  r‡  rx  r€  rÀ  rR   rS   r›  r™  rp  Úauth_store_localr†  Tr  rÃ  r�  zre-login requiredr‹  )rÄ  r@   rŠ  rg  r‚  r5   r  rb   )rq  r  Ú
jwt_reasonÚlast_errÚterminalr"  r˜  s          rB   Úget_nous_auth_status_localr¢  D  s  € ð$Ý'¨Ñ/Ô/ˆˆøÝð ð ð Øˆˆˆðøøøð ð ,Ý)Ñ+Ô+Ð+à—9’9˜^Ñ,Ô,€LÝ(ØØ�iŠi˜Ñ Ô Ø—9’9˜\Ñ*Ô*ðñ ô €Jð
 �yŠyÐ*Ñ+Ô+€HÝÝ�8�TÑ"Ô"ð 	=Ø�LŠLÐ+Ñ,Ô,ð	=àÐ; §¢¨?Ñ!;Ô!;Ð<ñô €Hð
 ˜tÐ#ð ÝˆU�YŠY�Ñ'Ô'Ñ(Ô(Ð9°¨\ð ð
 Ø Ÿ9š9Ð%6Ñ7Ô7Ø#ŸišiÐ(<Ñ=Ô=Ø$Ø"ŸYšY |Ñ4Ô4Ø %§	¢	Ð*@Ñ AÔ AÝ! %§)¢)¨OÑ"<Ô"<Ñ=Ô=Ý(,ØÐ2˜EŸIšI kÑ2Ô2ñ)
ô )
ð *Ø$ðð €Fð ð I•J˜x­Ñ.Ô.ð IØ%)ˆÐ!Ñ"Ø'Ÿ|š|¨FÑ3Ô3ˆˆ|ÑØ"Ÿ,š, yÑ1Ô1ÐHÐ5Hˆˆw‰Ø€MrM  Úvalidr¡  c                 óø  — 	 t          d¦  «        } n# t          $ r
 t          cY S w xY w| st          S |                      d¦  «        }t	          |t
          ¦  «        rF|                     d¦  «        r1|                      d¦  «        s|                      d¦  «        st          S t          |                      d¦  «        |                      d¦  «        |                      d¦  «        ¬¦  «        	 €t          S t          S )	uà  Classify the Nous bootstrap session for the dashboard /api/status probe.

    Returns one of:
      - ``"valid"``    â€” a usable Nous credential is present (login healthy).
      - ``"terminal"`` â€” the Nous session has taken a terminal auth failure
        (invalid_grant / quarantined / relogin required). This is the sole
        signal NAS acts on to re-mint a hosted-agent bootstrap session.
      - ``"unknown"``  â€” indeterminate (no Nous provider state, or a transient/
        non-terminal error). Never triggers a re-mint.

    Determinable with NO working token â€” it reads local auth-store state only,
    which is exactly the condition a dead hosted box is in. This function is
    called by the frequently-polled public ``/api/status`` endpoint, so it must
    never resolve credentials or perform an OAuth refresh.

    ANTI-FLAP CONTRACT: only a *terminal* failure maps to "terminal". A normal
    mid-rotation blip, a transient network error, or a merely-expiring token
    must NOT report "terminal" (that would trigger a spurious NAS re-mint on a
    healthy box). We key "terminal" on the auth layer's own terminal signal
    (`relogin_required`) plus a persisted quarantine marker, never on a bare
    "not logged in".
    rd   rx  r€  r  rÀ  rU   rw  r‡  )	rÄ  r@   ÚNOUS_SESSION_UNKNOWNrg  r  rb   ÚNOUS_SESSION_TERMINALr‚  ÚNOUS_SESSION_VALID)rq  r   s     rB   Úget_nous_session_validityr¨  Œ  s  € ð8$Ý'¨Ñ/Ô/ˆˆøÝð $ð $ð $Ý#Ð#Ð#Ð#ð$øøøð ð $Ý#Ð#à�yŠyÐ*Ñ+Ô+€HÝ�(�DÑ!Ô!ð ) h§l¢lÐ3EÑ&FÔ&Fð )ð —	’	˜.Ñ)Ô)ð 	)¨U¯YªY°Ñ-GÔ-Gð 	)Ý(Ð(åØ�	Š	�.Ñ!Ô!Ø�iŠi˜Ñ Ô Ø—9’9˜\Ñ*Ô*ðñ ô ð 
ð	õ
 "Ð!õ
  Ðs   ‚ ’&¥&c                 ó,  — 	 ddl m}   | d¦  «        }|�r/|                     ¦   «         �r|                     ¦   «         }|�wt	          |dd¦  «        pt	          |dd¦  «        }|rSt          |d¦  «        sCdt          t          ¦   «         ¦  «        t	          |d	d¦  «        d
dt	          |dd¦  «        › �|dœS t          ¦   «         }|r}dt          t          ¦   «         ¦  «        | 	                    d	¦  «        d
d| 	                    d¦  «        pd› �dt          | 	                    d¦  «        pd| 	                    d¦  «        dœ	S n# t          $ r Y nw xY w	 t          ¦   «         }dt          t          ¦   «         ¦  «        | 	                    d	¦  «        | 	                    d¦  «        | 	                    d¦  «        | 	                    d¦  «        dœS # t          $ r6}dt          t          ¦   «         ¦  «        t          |¦  «        dœcY d}~S d}~ww xY w)zªStatus snapshot for Codex auth.
    
    Checks the credential pool first (where `hermes auth` stores credentials),
    then falls back to the legacy provider state.
    r   r  rf   Nr  r  r7   TrÓ  rÝ  r…  r=  r+   ©r"  rp  rÓ  rÞ  r  rh   r�  zCCodex provider quota exhausted; retry after the usage limit resets.r  )	r"  rp  rÓ  rÞ  r  Úrate_limitedrÃ  r‹  r  rÞ  r  rh   F©r"  rp  r‹  )r  r  r  Úselectr  r©  r3   rÏ  r  rg  r�  r@   r#  r|  )r  r"  r#  rh   r%  rØ  r  s          rB   Úget_codex_auth_statusr®  Å  su  € ð$Ø3Ð3Ð3Ð3Ð3Ð3Øˆy˜Ñ(Ô(ˆØñ 	�D×(Ò(Ñ*Ô*ñ 	Ø—K’K‘M”MˆEØÐ å˜EÐ#4°dÑ;Ô;ð :Ý˜u n°bÑ9Ô9ð ð ð Õ#BÀ7ÈAÑ#NÔ#Nð à%)Ý&)­/Ñ*;Ô*;Ñ&<Ô&<Ý(/°°~ÀtÑ(LÔ(LØ%.Ø"N­'°%¸À)Ñ*LÔ*LÐ"NÐ"NØ#*ðð ð õ 7Ñ8Ô8ˆJØð à!%Ý"%¥oÑ&7Ô&7Ñ"8Ô"8Ø$.§N¢N°>Ñ$BÔ$BØ!*ØL j§n¢n°WÑ&=Ô&=Ð&JÀÐLÐLØ$(Ý"9à"Ÿš yÑ1Ô1ð aØ`à *§¢¨zÑ :Ô :ðð ð øøõ ð ð ð Øˆðøøøð
Ý1Ñ3Ô3ˆàÝ�oÑ/Ô/Ñ0Ô0Ø!ŸIšI nÑ5Ô5ØŸš ;Ñ/Ô/Ø—i’i Ñ)Ô)Ø—y’y Ñ+Ô+ð
ð 
ð 	
øõ ð 
ð 
ð 
àÝ�oÑ/Ô/Ñ0Ô0Ý˜‘X”Xð
ð 
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
øøøøð
øøøs8   ‚B5E Â8BE Å
EÅEÅA;G Ç
HÇ+HÈHÈHc            
     ó  — 	 ddl m}   | d¦  «        }|r¡|                     ¦   «         r�|                     ¦   «         }|�wt	          |dd ¦  «        pt	          |dd¦  «        }|rSt          |d¦  «        sCdt          t          ¦   «         ¦  «        t	          |dd ¦  «        d	d
t	          |dd¦  «        › �|dœS n# t          $ r Y nw xY w	 t          ¦   «         }dt          t          ¦   «         ¦  «        | 
                    d¦  «        | 
                    d¦  «        | 
                    d¦  «        | 
                    d¦  «        dœS # t          $ r6}dt          t          ¦   «         ¦  «        t          |¦  «        dœcY d }~S d }~ww xY w)Nr   r  rk   r  r  r7   TrÓ  re   r…  r=  r+   rª  rÞ  r  rh   Fr¬  )r  r  r  r­  r  r_  r3   rÏ  r@   rŒ  rg  r|  )r  r"  r#  rh   rØ  r  s         rB   Úget_xai_oauth_auth_statusr°    sä  € ðØ3Ð3Ð3Ð3Ð3Ð3àˆy˜Ñ%Ô%ˆØð 	�D×(Ò(Ñ*Ô*ð 	Ø—K’K‘M”MˆEØÐ å˜EÐ#4°dÑ;Ô;ð :Ý˜u n°bÑ9Ô9ð ð ð Õ#@ÀÈ!Ñ#LÔ#Lð à%)Ý&)­/Ñ*;Ô*;Ñ&<Ô&<Ý(/°°~ÀtÑ(LÔ(Lð &9Ø"N­'°%¸À)Ñ*LÔ*LÐ"NÐ"NØ#*ð
ð 
ð 
øøõ ð ð ð Øˆðøøøð
Ý5Ñ7Ô7ˆàÝ�oÑ/Ô/Ñ0Ô0Ø!ŸIšI nÑ5Ô5ØŸš ;Ñ/Ô/Ø—i’i Ñ)Ô)Ø—y’y Ñ+Ô+ð
ð 
ð 	
øõ ð 
ð 
ð 
àÝ�oÑ/Ô/Ñ0Ô0Ý˜‘X”Xð
ð 
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
øøøøð
øøøs1   ‚B3B7 Â7
CÃCÃA;E Å
FÅ+E?Å9FÅ?Fc                óü  — t                                | ¦  «        }|r|j        dk    rddiS d}d}t          | |¦  «        \  }}d}|j        r,t          j        |j        d¦  «                             ¦   «         }| dv rt          ||j	        |¦  «        }n|r|}n|j	        }| dk    rt          |¦  «        }| dk    o| ot          |¦  «        }t          |¦  «        p|| |j        |p|rdnd|t          |¦  «        p|dœS )	z<Status snapshot for API-key providers (z.ai, Kimi, MiniMax).rh   Ú
configuredFr7   ¾   r�   r…   r�   úlocal-offline)r²  r~  rP   Ú
key_sourcer2   r"  )rÖ   rg  rQ   r%  r\   r´  rµ  rG   rò   rS   rL   rC   r5   rP   )r  r	  rh   rµ  Úenv_urlr2   Úactual_local_noauths          rB   Úget_api_key_provider_statusr¸  3  sK  € å×#Ò# KÑ0Ô0€GØð %�gÔ'¨9Ò4Ð4Ø˜eÐ$Ð$à€GØ€JÝ:¸;ÈÑPÔPÑ€GˆZà€GØÔð BÝ”)˜GÔ4°bÑ9Ô9×?Ò?ÑAÔAˆàÐ7Ð7Ð7Ý)¨'°7Ô3MÈwÑWÔWˆˆØ	ð .ØˆˆàÔ-ˆà�hÒÐÝ,¨XÑ6Ô6ˆð 	�xÒð 	/ØˆKð	/å$ XÑ.Ô.ð õ ˜7‘m”mÐ:Ð':ØØ”Ø ÐTÐ8KÐ%S _ _ÐQSØÝ˜'‘]”]Ð9Ð&9ðð ð rc   c                óÎ  — t                                | ¦  «        }|r|j        dk    rddiS t          j        dd¦  «                             ¦   «         p(t          j        dd¦  «                             ¦   «         pd}t          j        dd¦  «                             ¦   «         }|rt          j        |¦  «        nd	d
g}|j        r,t          j        |j        d¦  «                             ¦   «         nd}|s|j	        }|rt          j        |¦  «        nd}t          |p|                     d¦  «        ¦  «        | |j        ||||t          |p|                     d¦  «        ¦  «        dœS )z:Status snapshot for providers that run a local subprocess.rv   r²  FÚHERMES_COPILOT_ACP_COMMANDr7   ÚCOPILOT_CLI_PATHrp   ÚHERMES_COPILOT_ACP_ARGSú--acpú--stdioNú
acp+tcp://)r²  r~  rP   ÚcommandrA  Úresolved_commandr2   r"  )rÖ   rg  rQ   r´  rµ  rG   ÚshlexrÙ  r\   rS   r+  Úwhichr5   rð   rP   )r  r	  rÀ  Úraw_argsrA  r2   rÁ  s          rB   Ú$get_external_process_provider_statusrÅ  [  sy  € å×#Ò# KÑ0Ô0€GØð %�gÔ'Ð+=Ò=Ð=Ø˜eÐ$Ð$õ 	Œ	Ð.°Ñ3Ô3×9Ò9Ñ;Ô;ð 	ÝŒ9Ð'¨Ñ,Ô,×2Ò2Ñ4Ô4ð	àð õ
 ŒyÐ2°BÑ7Ô7×=Ò=Ñ?Ô?€HØ$,ÐF�5Œ;�xÑ Ô Ð °7¸IÐ2F€DØBIÔBZÐb�rŒy˜Ô1°2Ñ6Ô6×<Ò<Ñ>Ô>Ð>Ð`b€HØð .ØÔ-ˆà07ÐA•v”| GÑ,Ô,Ð,¸TÐåÐ+ÐP¨x×/BÒ/BÀ<Ñ/PÔ/PÑQÔQØØ”ØØØ,ØÝÐ*ÐO¨h×.AÒ.AÀ,Ñ.OÔ.OÑPÔPð	ð 	ð 	rc   c                óž  — | pt          ¦   «         pd                     ¦   «                              ¦   «         }|sddiS |dk    rt          ¦   «         S |dk    rt	          ¦   «         S |dk    rt          ¦   «         S |dk    rt          ¦   «         S |dk    rt          ¦   «         S |d	k    rt          ¦   «         S |d
k    rt          |¦  «        S |dk    rt          ¦   «         S t                               |¦  «        }|r|j        dk    rt          |¦  «        S |r5|j        dk    r*	 ddlm}  |¦   «         |dœS # t"          $ r	 d|ddœcY S w xY wddiS )zGeneric auth status dispatcher.r7   r"  Fr.   rd   rf   rk   rl   r—   ru   rÓ   rh   rÐ   r   r#  ©r"  r~  zboto3 not installed)r"  r~  r‹  )rÇ  rG   r>   r  r™  r®  r°  ræ  Úget_minimax_oauth_auth_statusrÅ  Ú_get_azure_foundry_auth_statusrÖ   rg  rQ   r¸  r(  r$  r)  )r  rã  r	  r$  s       rB   r'  r'  y  s¹  € àÐ8Õ0Ñ2Ô2Ð8°b×?Ò?ÑAÔA×GÒGÑIÔI€FØð $Ø˜UÐ#Ð#Ø�ÒÐÝ&Ñ(Ô(Ð(Ø�ÒÐÝ#Ñ%Ô%Ð%Ø�ÒÐÝ$Ñ&Ô&Ð&Ø�ÒÐÝ(Ñ*Ô*Ð*Ø�ÒÐÝ#Ñ%Ô%Ð%Ø�Ò Ð Ý,Ñ.Ô.Ð.Ø�ÒÐÝ3°FÑ;Ô;Ð;Ø�Ò Ð Ý-Ñ/Ô/Ð/å×#Ò# FÑ+Ô+€GØð 3�7Ô$¨	Ò1Ð1Ý*¨6Ñ2Ô2Ð2àð \�7Ô$¨	Ò1Ð1ð	\ØAÐAÐAÐAÐAÐAØ!4Ð!4Ñ!6Ô!6ÀFÐKÐKÐKøÝð 	\ð 	\ð 	\Ø!&°FÐEZÐ[Ð[Ð[Ð[Ð[ð	\øøøà˜ÐÐs   Ä"D5 Ä5EÅEc                 ó6  — ddi} 	 ddl m}m}  |¦   «         }n# t          $ r i }Y nw xY wt	          |t
          ¦  «        r|                     d¦  «        nd}d}d}t	          |t
          ¦  «        r€t          |                     d	¦  «        pd¦  «                             ¦   «          	                    ¦   «         pd}t          |                     d
¦  «        pd¦  «                             ¦   «         }|| d	<   || d
<   |dk    rÓ	 ddl
m}m}m}	  |	¦   «         }
i }t	          |t
          ¦  «        r0t	          |                     d¦  «        t
          ¦  «        r|d         }|                     ||¬¦  «        }|
| d<   |j        | d<   d| d<   d| d<   t!          |
¦  «        | d<   |
sd| d<   nd| d<   | S # t          $ r}d| d<   d|› �| d<   | cY d}~S d}~ww xY w	  |d¦  «        pd}n%# t          $ r t#          j        dd¦  «        }Y nw xY wt'          |¦  «        | d<   | S )uW  Return structural auth status for Azure Foundry.

    ``logged_in`` is structural, matching other non-OAuth provider status
    checks:

      * ``auth_mode == "entra_id"`` AND ``azure-identity`` is importable
        (we do NOT mint a token here; ``hermes doctor`` runs the live
        probe and reports whether the credential chain can acquire one).
      * ``auth_mode == "api_key"`` (default) AND ``AZURE_FOUNDRY_API_KEY``
        is set with a usable value.

    Never invokes the Entra credential chain â€” keeps CLI startup latency
    flat regardless of token-service / az login state.
    r~  rÓ   r   )rÊ  rè   r6  Nrh   r7   rÞ  r2   Úentra_id)ÚEntraIdentityConfigÚSCOPE_AI_AZURE_DEFAULTÚhas_azure_identity_installedÚentra)Údefault_scopeÚazure_identity_installedrU   Únot_runÚcredential_probeFÚcredential_verifiedr"  zwazure-identity not installed. Install with: pip install azure-identity  (or rely on Hermes' lazy-install at first use).rî  zyazure-identity is installed; live credential validation is skipped here. Run `hermes doctor` to verify token acquisition.zazure-identity check failed: r‹  rÔ   )ré   rÊ  rè   r@   r  rb   rg  r3   rG   r>   Úagent.azure_identity_adapterrÌ  rÍ  rÎ  r”  rU   r5   r´  rµ  r  )ro  rÊ  rè   rÛ  rÜ  rÞ  r2   rÌ  rÍ  rÎ  Ú	installedÚ	entra_cfgÚidentity_configr  rh   s                  rB   rÉ  rÉ  œ  sæ  € ð '¨Ð8€DðØNÐNÐNÐNÐNÐNÐNÐNØˆk‰mŒmˆˆøÝð ð ð Øˆˆˆðøøøõ %/¨sµDÑ$9Ô$9ÐC�—’˜Ñ Ô Ð ¸t€IØ€IØ€HÝ�)�TÑ"Ô"ð @Ý˜	Ÿš kÑ2Ô2Ð?°iÑ@Ô@×FÒFÑHÔH×NÒNÑPÔPÐ]ÐT]ˆ	Ý�y—}’} ZÑ0Ô0Ð6°BÑ7Ô7×=Ò=Ñ?Ô?ˆØ!€DˆÑØ€DˆÑà�JÒÐð"	ðð ð ð ð ð ð ð ð ð ð
 5Ð4Ñ6Ô6ˆIØˆIÝ˜)¥TÑ*Ô*ð /­z¸)¿-º-ÈÑ:PÔ:PÕRVÑ/WÔ/Wð /Ø% gÔ.�	Ø1×;Ò;ØØ4ð <ñ ô ˆOð 09ˆDÐ+Ñ,Ø+Ô1ˆD�‰MØ'0ˆDÐ#Ñ$Ø*/ˆDÐ&Ñ'Ý $ Y¡¤ˆD�ÑØð 
ð2ð �V‘�ðXð �V‘ð ˆKøÝð 	ð 	ð 	Ø %ˆD�ÑØA¸CÐAÐAˆD�‰MØˆKˆKˆKˆKˆKˆKøøøøð	øøøð9Ø-Ð-Ð.EÑFÔFÐLÈ"ˆˆøÝð 9ð 9ð 9Ý”)Ð3°RÑ8Ô8ˆˆˆð9øøøå)¨'Ñ2Ô2€DˆÑØ€Ks=   † ™(§(ÄB+F- Æ-
GÆ7GÇGÇGÇG" Ç"HÈHc                óF  — t                                | ¦  «        }|r|j        dk    rt          d| › d�| d¬¦  «        ‚d}d}t	          | |¦  «        \  }}|s| dk    rt
          }|pd}d}|j        r,t          j        |j        d¦  «         	                    ¦   «         }| d	v rt          ||j        |¦  «        }nÓ| d
k    rt          ||j        |¦  «        }n¶| dk    r‘|r|                     d¦  «        n|j        }	 ddlm}m}  |¦   «         \  }}	|r( ||¦  «        \  }	}
|
pd 	                    ¦   «         }
|
r|
}nQ# t"          $ r%}t$                               d|¦  «         Y d}~n'd}~ww xY w|r|                     d¦  «        }n|j        }| dk    rt)          |¦  «        }| dk    rt+          |¦  «        }t-          |t.          ¦  «        r| 	                    ¦   «         s|j        }|s | dk    rt1          |¦  «        rt2          }|pd}| ||                     d¦  «        |pddœS )zwResolve API key and base URL for an API-key provider.

    Returns dict with: provider, api_key, base_url, source.
    rh   ú
Provider 'z' is not an API-key provider.r   r®  r7   rm   rž  r³  r|   rp   rE   r   r  z4Copilot base URL resolution fell back to default: %sNr�   r´  ©r~  rh   r2   r  )rÖ   rg  rQ   r|  r%  ÚLMSTUDIO_NOAUTH_PLACEHOLDERr\   r´  rµ  rG   rò   rS   ru  r?   r  r  r  r@   r  rA  ry  rL   r  r3   rC   ÚACTUAL_LOCAL_NOAUTH_PLACEHOLDER)r  r	  rh   rµ  r¶  r2   r  r  Ú	raw_tokenÚ_rÎ  r  s               rB   Ú$resolve_api_key_provider_credentialsrà  é  sß  € õ
  ×#Ò# KÑ0Ô0€GØð 
�gÔ'¨9Ò4Ð4ÝØC˜ÐCÐCÐCØ Ø#ð
ñ 
ô 
ð 	
ð €GØ€JÝ:¸;ÈÑPÔPÑ€GˆZð
 ð -�{ jÒ0Ð0Ý-ˆØÐ, 9ˆ
à€GØÔð BÝ”)˜GÔ4°bÑ9Ô9×?Ò?ÑAÔAˆàÐ7Ð7Ð7Ý)¨'°7Ô3MÈwÑWÔWˆˆØ	˜Ò	Ð	Ý(¨°'Ô2LÈgÑVÔVˆˆØ	˜	Ò	!Ð	!ð +2ÐQ�7—>’> #Ñ&Ô&Ð&°wÔ7Qˆð	Vðð ð ð ð ð ð ð ð 1Ð0Ñ2Ô2‰LˆI�qØð (Ø3Ð3°IÑ>Ô>‘��8Ø$˜N¨×1Ò1Ñ3Ô3�Øð (Ø'�HøøÝð 	Vð 	Vð 	VÝ�LŠLÐOÐQTÑUÔUÐUÐUÐUÐUÐUÐUøøøøð	Vøøøà	ð .Ø—>’> #Ñ&Ô&ˆˆàÔ-ˆà�jÒ Ð Ý7¸ÑAÔAˆà�hÒÐÝ,¨XÑ6Ô6ˆõ
 �x¥Ñ%Ô%ð .¨(¯.ª.Ñ*:Ô*:ð .ØÔ-ˆàð 3�{ hÒ.Ð.Õ3KÈHÑ3UÔ3UÐ.Ý1ˆØÐ2 ?ˆ
ð  ØØ—O’O CÑ(Ô(ØÐ) 	ð	ð ð s   Ã:?D: Ä:
E)ÅE$Å$E)c                óà  — t                                | ¦  «        }|r|j        dk    rt          d| › d�| d¬¦  «        ‚|j        r,t          j        |j        d¦  «                             ¦   «         nd}|s|j        }t          j        dd¦  «                             ¦   «         p(t          j        dd¦  «                             ¦   «         pd	}t          j        d
d¦  «                             ¦   «         }|rt          j
        |¦  «        nddg}|rt          j        |¦  «        nd}|s+|                     d¦  «        st          d|› d�| d¬¦  «        ‚| d|                     d¦  «        |p||ddœS )z>Resolve runtime details for local subprocess-backed providers.rv   rÚ  z&' is not an external-process provider.r   r®  r7   rº  r»  rp   r¼  r½  r¾  Nr¿  z(Could not find the Copilot CLI command 'zQ'. Install GitHub Copilot CLI or set HERMES_COPILOT_ACP_COMMAND/COPILOT_CLI_PATH.Úmissing_copilot_cliru   rE   Úprocess)r~  rh   r2   rÀ  rA  r  )rÖ   rg  rQ   r|  r\   r´  rµ  rG   rS   rÂ  rÙ  r+  rÃ  rð   r?   )r  r	  r2   rÀ  rÄ  rA  rÁ  s          rB   Ú-resolve_external_process_provider_credentialsrä  :  sÄ  € å×#Ò# KÑ0Ô0€GØð 
�gÔ'Ð+=Ò=Ð=ÝØL˜ÐLÐLÐLØ Ø#ð
ñ 
ô 
ð 	
ð CJÔBZÐb�rŒy˜Ô1°2Ñ6Ô6×<Ò<Ñ>Ô>Ð>Ð`b€HØð .ØÔ-ˆõ 	Œ	Ð.°Ñ3Ô3×9Ò9Ñ;Ô;ð 	ÝŒ9Ð'¨Ñ,Ô,×2Ò2Ñ4Ô4ð	àð õ
 ŒyÐ2°BÑ7Ô7×=Ò=Ñ?Ô?€HØ$,ÐF�5Œ;�xÑ Ô Ð °7¸IÐ2F€DØ07ÐA•v”| GÑ,Ô,Ð,¸TÐØð 
 H×$7Ò$7¸Ñ$EÔ$Eð 
Ýð]°wð ]ð ]ð ]à Ø&ð	
ñ 
ô 
ð 	
ð  Ø Ø—O’O CÑ(Ô(Ø#Ð. wØØðð ð rc   Údefault_modelc                óF  — t          ¦   «         5  t          ¦   «         }| |d<   t          |¦  «         ddd¦  «         n# 1 swxY w Y   t          ¦   «         }|j                             dd¬¦  «         t          |¦  «         t          ¦   «         }|                     d¦  «        }t          |t          ¦  «        rt          |¦  «        }nBt          |t          ¦  «        r+|                     ¦   «         rd|                     ¦   «         i}ni }| |d<   |r-|                     ¦   «         r|                     d¦  «        |d	<   n|                     d	d¦  «         d
dlm}  ||¦  «         |r!|                     dd¦  «        }	|	rd|	v r||d<   ||d<   t#          ||d¬¦  «         |S )aÀ  Update config.yaml and auth.json to reflect the active provider.

    When *default_model* is provided the function also writes it as the
    ``model.default`` value.  This prevents a race condition where the
    gateway (which re-reads config per-message) picks up the new provider
    before the caller has finished model selection, resulting in a
    mismatched model/provider (e.g. ``anthropic/claude-opus-4.6`` sent to
    MiniMax's API).
    r'  NTr÷  r6  rž  r~  rE   r2   r   )Ú clear_model_endpoint_credentialsr7   F©r½  )rl  re  rn  r   rý  rþ  r   r   rg  r  rb   r3   rG   r?   rÁ  ré   rç  r   )
r  rS   rå  rp  Úconfig_pathÚconfigÚcurrent_modelrÜ  rç  Úcur_defaults
             rB   Ú_update_config_for_providerrí  f  s  € õ 
Ñ	Ô	ð %ð %Ý%Ñ'Ô'ˆ
Ø(3ˆ
Ð$Ñ%Ý˜Ñ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %õ "Ñ#Ô#€KØÔ×Ò T°DÐÑ9Ô9Ð9Ý(¨Ñ5Ô5Ð5åÑÔ€Fà—J’J˜wÑ'Ô'€MÝ�-¥Ñ&Ô&ð Ý˜Ñ'Ô'ˆ	ˆ	Ý	�M¥3Ñ	'Ô	'ð ¨M×,?Ò,?Ñ,AÔ,Að Ø × 3Ò 3Ñ 5Ô 5Ð6ˆ	ˆ	àˆ	à'€IˆjÑØð (Ð0×6Ò6Ñ8Ô8ð (Ø 2× 9Ò 9¸#Ñ >Ô >ˆ	�*ÑÐð 	�Š�j $Ñ'Ô'Ð'ð
 CÐBÐBÐBÐBÐBà$Ð$ YÑ/Ô/Ð/ð
 ð 1Ø—m’m I¨rÑ2Ô2ˆØð 	1˜c [Ð0Ð0Ø#0ˆI�iÑ à€Fˆ7�Oå�k 6°UÐ;Ñ;Ô;Ð;ØÐs   �#>¾AÁAc                 óP  — 	 t          ¦   «         } n# t          $ r Y dS w xY w| sdS |                      d¦  «        }t          |t          ¦  «        sdS |                     d¦  «        }t          |t
          ¦  «        sdS |                     ¦   «                              ¦   «         }|pdS )z?Return model.provider from config.yaml, normalized, if present.Nr6  r~  )r   r@   rg  r  rb   r3   rG   r>   )rê  r6  r~  s      rB   Ú_get_config_providerrï  ¥  s¹   € ðÝ Ñ"Ô"ˆˆøÝð ð ð Øˆtˆtðøøøàð ØˆtØ�JŠJ�wÑÔ€EÝ�e�TÑ"Ô"ð ØˆtØ�yŠy˜Ñ$Ô$€HÝ�h¥Ñ$Ô$ð ØˆtØ�~Š~ÑÔ×%Ò%Ñ'Ô'€HØÐ�tÐs   ‚ ‘
žc                óv   — | sdS t          ¦   «         |                      ¦   «                              ¦   «         k    S )z=Return True when config.yaml currently selects *provider_id*.F)rï  rG   r>   )r  s    rB   Ú_config_provider_matchesrñ  ·  s8   € àð ØˆuÝÑ!Ô! [×%6Ò%6Ñ%8Ô%8×%>Ò%>Ñ%@Ô%@Ò@Ð@rc   c                ó†   — | sdS |                       ¦   «                              ¦   «         }|t          v ot          |¦  «        S )z?Return True when logout should reset the model provider config.F)rG   r>   rÖ   rñ  rq  s     rB   Ú'_should_reset_config_provider_on_logoutró  ¾  sF   € àð ØˆuØ×"Ò"Ñ$Ô$×*Ò*Ñ,Ô,€JØÕ*Ð*ÐSÕ/GÈ
Ñ/SÔ/SÐSrc   c                 ó.   — t          ¦   «         } | dv r| S dS )a¼  Fallback logout target when auth.json has no active provider.

    `hermes logout` historically keyed off auth.json.active_provider only.
    That left users stuck when auth state had already been cleared but
    config.yaml still selected an OAuth provider such as openai-codex for the
    agent model: there was no active auth provider to target, so logout printed
    "No provider is currently logged in" and never reset model.provider.
    >   rd   rk   rf   N)rï  )r~  s    rB   Ú$_logout_default_provider_from_configrõ  Æ  s%   € õ $Ñ%Ô%€HØÐ8Ð8Ð8ØˆØˆ4rc   c                 ó.  — t          ¦   «         } |                      ¦   «         s| S t          | ¦  «         t          ¦   «         }|s| S |                     d¦  «        }t          |t          ¦  «        rd|d<   d|v r
t          |d<   t          | |d¬¦  «         | S )z5Reset config.yaml provider back to auto after logout.r6  rx  r~  r2   Frè  )	r   rÚ  r   r   rg  r  rb   r   r   )ré  rê  r6  s      rB   Ú_reset_config_providerr÷  Õ  s«   € å!Ñ#Ô#€KØ×ÒÑÔð ØÐÝ(¨Ñ5Ô5Ð5åÑÔ€FØð ØÐà�JŠJ�wÑÔ€EÝ�%�ÑÔð 4Ø"ˆˆjÑØ˜ÐÐÝ 3ˆE�*ÑÝ�k 6°UÐ;Ñ;Ô;Ð;ØÐrc   ©r~  r2   rh   r,  r~  c               óš  — 	 ddl m}  || |||¬¦  «        }n# t          $ r d}Y nw xY w|€dS t          ¦   «          t          d¦  «         t          |j        ¦  «         t          d¦  «         	 t          d¦  «                             ¦   «                              ¦   «         }n&# t          t          f$ r t          ¦   «          Y dS w xY w|d	v S )
zDPrompt before saving a model whose known pricing exceeds guardrails.r   )Úexpensive_model_warningrø  NTzH========================================================================zSwitch anyway? [y/N]: F>   Úyr²  )
Úhermes_cli.model_cost_guardrú  r@   rƒ  r�  rˆ  rG   r>   rŠ  r‰  )r,  r~  r2   rh   rú  r  rÓ  s          rB   Ú"_confirm_expensive_model_selectionrý  é  s  € ð
ØGÐGÐGÐGÐGÐGà)Ð)ØØØØð	
ñ 
ô 
ˆˆøõ ð ð ð Øˆˆˆðøøøà€Øˆtå	�G„G€GÝ	ˆ(�O„O€OÝ	ˆ'Œ/ÑÔÐÝ	ˆ(�O„O€OðÝÐ1Ñ2Ô2×8Ò8Ñ:Ô:×@Ò@ÑBÔBˆˆøÝ�xÐ(ð ð ð Ý‰ŒˆØˆuˆuðøøøð �|Ð#Ð#s   ‚ ˜'¦'Á/3B# Â#CÃCr+  rë  Úpricingú#Optional[Dict[str, Dict[str, str]]]Úunavailable_modelsúOptional[List[str]]rS  Úunavailable_messageÚconfirm_providerÚconfirm_base_urlÚconfirm_api_keyc	                ó²  ‡‡‡‡‡‡:‡;‡<‡=‡>‡?‡@— ddl m}	m}
 |pg }‰pd                     ¦   «                              ¦   «         dk    }dDˆˆˆfd	„}g }‰r‰| v r|                     ‰¦  «         | D ]}||vr|                     |¦  «         Œt          |¦  «        t          |¦  «        z   }t          ‰ot          ˆfd
„|D ¦   «         ¦  «        ¦  «        Š>|rdnd}‰>rt          d„ |D ¦   «         d¬¦  «        |z   ndŠ?i Š;dŠ@dŠ<dŠ=d}d}d}‰>�rq|D �][}‰ 
                    |¦  «        }d}dx}}|râ |	| 
                    dd¦  «        ¦  «        } |	| 
                    dd¦  «        ¦  «        }| 
                    dd¦  «        }|r |	|¦  «        nd}|rdŠ=|rx |
| 
                    dd¦  «        | 
                    dd¦  «        | 
                    d¦  «        ¦  «        }|�.d}|\  }}}|dk    r |	|¦  «        nd}|dk    r |	|¦  «        nd}nd\  }}}||||||f‰;|<   t          ‰@t          |¦  «        t          |¦  «        ¦  «        Š@t          ‰<t          |¦  «        ¦  «        Š<�Œ]‰=rt          ‰<d¦  «        Š<ˆ;ˆ<ˆˆ=ˆ>ˆ?ˆ@fd„Š:ˆ:fd„} d}!d}"‰>r8d}#d|#› dd ‰?› �›d!d"d ‰@› �›d#d$d ‰@› �›�}$‰=r|$d#d%d ‰<› �›�z  }$|"|$d&z   z  }"|r|"d'z  }"	 dd(lm}% ˆ:fd)„|D ¦   «         }&|&                     d*¦  «         |&                     d+¦  «         |pt                               d,¦  «        }'|                     ¦   «         }(|(s|rd-|'› d.�}(g })‰>rV|"                     dd/¦  «        }*t          |*¦  «        d/k    r-|)                     |*d/                              ¦   «         ¦  «         |r?|D ]#}|)                     d0 | |¦  «        › �¦  «         Œ$|)                     d1|(› d2�¦  «         |)rd                     |)¦  «        nd}+dd3lm}, g }-|D ]:} | |¦  «        }. |,|¦  «        }/|-                     |/|k    r|.n|.› d!|/› �¦  «         Œ;|-                     d*¦  «         |-                     d+¦  «          |%d|&|!d4|+d|-¬5¦  «        }0|0dk     rdS t-          ¦   «          |0t          |¦  «        k     r |||0         ¦  «        S |0t          |¦  «        k    rJ	 t/          d6¦  «                             ¦   «         }1n# t0          t2          f$ r Y dS w xY w|1r ||1¦  «        ndS dS # t4          t6          t8          t:          j        f$ r Y nw xY wdd7lm}2 dd8l m!}3m"}4 |"                     ¦   «         D ]I}5d9|5v r4t-          |5 #                    d9 |4d9|3j$        ¦  «        d/¦  «        ¦  «         Œ:t-          |5¦  «         ŒJt          tK          t          |¦  «        dz   ¦  «        ¦  «        }6tM          |d/¦  «        D ]0\  }7}t-          d#|7d |6› �›d: |2 ‰:|¦  «        ¦  «        › �¦  «         Œ1t          |¦  «        }8t-          d#|8d/z   d |6› �›d;�¦  «         t-          d#|8dz   d |6› �›d<�¦  «         |r‡|pt                               d,¦  «        }'|                     ¦   «         pd=|'› d>�}(t-          ¦   «          t-          d#|› d?|(› d2|› �¦  «         |D ](}t-          d#dd |6› �›d#|›  | |¦  «        › |› �¦  «         Œ)t-          ¦   «          	 	 t/          d@|8dz   › dA�¦  «                             ¦   «         }9|9sdS tO          |9¦  «        }0d/|0cxk    r|8k    rn n |||0d/z
           ¦  «        S |0|8d/z   k    r0t/          d6¦  «                             ¦   «         }1|1r ||1¦  «        ndS |0|8dz   k    rdS t-          dB|8dz   › �¦  «         n2# tP          $ r t-          dC¦  «         Y nt2          t0          f$ r Y dS w xY wŒí)Ea†  Interactive model selection. Puts current_model first with a marker. Returns chosen model ID or None.

    If *pricing* is provided (``{model_id: {prompt, completion}}``), a compact
    price indicator is shown next to each model in aligned columns.

    If *unavailable_models* is provided, those models are shown grayed out
    and unselectable, with an upgrade link to *portal_url*.
    r   )Ú_format_price_per_mtokÚcompute_sale_discountr7   rd   r   r3   r4   r‚  c                ó>   •— | sd S ‰rt          | ‰‰‰¬¦  «        sd S | S )Nrø  )rý  )r   r  r  r  s    €€€rB   Ú_confirmed_selectionz5_prompt_model_selection.<locals>._confirmed_selection(  sG   ø€ Øð 	Ø�4Øð 	Õ$FØØ%Ø%Ø#ð	%
ñ %
ô %
ð 	ð �4Øˆ
rc   c              3  óB   •K  — | ]}‰                      |¦  «        V — Œd S r…  ©rg  )râ   Úmrþ  s     €rB   rä   z*_prompt_model_selection.<locals>.<genexpr>@  s-   øè è € Ð&JÐ&J¸! w§{¢{°1¡~¤~Ð&JÐ&JÐ&JÐ&JÐ&JÐ&Jrc   r%  r2  c              3  ó4   K  — | ]}t          |¦  «        V — Œd S r…  )r  )râ   r  s     rB   rä   z*_prompt_model_selection.<locals>.<genexpr>D  s(   è è € Ð(Ð(˜�S�‰VŒVÐ(Ð(Ð(Ð(Ð(Ð(rc   r�  Fz[2mz[0mNÚpromptÚ
completionÚinput_cache_readTÚoriginalú?)r7   r7   r7   é   c                óÂ  •— ‰s"| dfg}| ‰k    r|                      d¦  «         |S ‰                     | d¦  «        \  }}}}}}|du}d}	|rd| d‰|	z
  › �›dfg}
n
| d‰› �›dfg}
d|d‰› �›d	|d‰› �›�}‰r|d	|d‰› �›�z  }g |
¢|df‘}|r8|                      d
|› d�df¦  «         |                      d|› d|› �df¦  «         | ‰k    r|                      d¦  «         |S )uA   Build a rich radiolist row: yellow â˜…/% , dim was, plain prices.N)u     â†� currently in useN)r7   r7   r7   Nr7   r7   r2  )u   â˜… ÚyellowÚ<r-   Ú>ú  z  -ú%r  z  was rE   Údim)r°  rg  )r   ÚsegsÚinpÚoutÚcacheÚpctÚwas_inpÚwas_outÚon_saleÚstar_wÚ	name_segsÚ
price_partÚ_price_cacheÚ	cache_colrë  Ú	has_cacheÚhas_pricingÚname_colÚ	price_cols               €€€€€€€rB   Ú_label_segmentsz0_prompt_model_selection.<locals>._label_segments|  s”  ø€ àð 	Ø36¸°+°ˆDØ�mÒ#Ð#Ø—’Ð<Ñ=Ô=Ð=ØˆKà1=×1AÒ1AØÐ+ñ2
ô 2
Ñ.ˆˆS�%˜˜g wð ˜T�/ˆàˆØð 	7à"ØÐ.˜( VÑ+Ð.Ð.Ð.°Ð5ð7ˆIˆIð
 !Ð. 8Ð.Ð.Ð.°Ð5Ð6ˆIà?˜Ð?˜yÐ?Ð?Ð?Ð?¨SÐ?°9Ð?Ð?Ð?Ð?ˆ
Øð 	4ØÐ3˜uÐ3 yÐ3Ð3Ð3Ð3Ñ3ˆJØ/�Ð/˜Z¨Ð.Ð/ˆØð 	?Ø�KŠK˜˜s˜˜˜ xÐ0Ñ1Ô1Ð1Ø�KŠKÐ5 'Ð5Ð5¨GÐ5Ð5°uÐ=Ñ>Ô>Ð>Ø�-ÒÐØ�KŠKÐ8Ñ9Ô9Ð9Øˆrc   c                óT   •— d                      d„  ‰| ¦  «        D ¦   «         ¦  «        S )Nr7   c              3  ó    K  — | ]	\  }}|V — Œ
d S r…  rY   )râ   rB  Ú_styles      rB   rä   z:_prompt_model_selection.<locals>._label.<locals>.<genexpr>ž  s&   è è € ÐEÐE¡  f�tÐEÐEÐEÐEÐEÐErc   )rð  )r   r-  s    €rB   Ú_labelz'_prompt_model_selection.<locals>._label�  s.   ø€ Ø�wŠwÐEÐE°°ÀÑ0DÔ0DÐEÑEÔEÑEÔEÐErc   zSelect default model:z     r4  r  r-   ÚInr  ÚOutÚCachez  $/Mtoku     â˜… = on sale)Úcurses_radiolistc                ó&   •— g | ]} ‰|¦  «        ‘ŒS rY   rY   )râ   r   r-  s     €rB   r¨  z+_prompt_model_selection.<locals>.<listcomp>»  s#   ø€ Ð;Ð;Ð;¨C�?�? 3Ñ'Ô'Ð;Ð;Ð;rc   zEnter custom model namezSkip (keep current)rE   úUpgrade at z for paid modelsr"   z   u	     â”€â”€ u    â”€â”€)Úmodel_search_textr;  )ÚselectedÚcancel_returnsrÄ  Ú
searchableÚsearch_labelszEnter model name: )Úformat_radio_item_ansi)ÚColorsÚcoloru   â˜…z. z. Enter custom model namez. Skip (keep current)u6   Unavailable models (requires paid tier â€” upgrade at ú)u   â”€â”€ z
Choice [1-z] (default: skip): zPlease enter 1-zPlease enter a number)r   r3   r4   r‚  ))Úhermes_cli.modelsr  r  rG   r>   r°  r|  r5   Úanyr  rg  r  Úhermes_cli.curses_uir5  rT  r?   rÙ  Úextendrï  rð  Úhermes_cli.model_searchr8  rƒ  rˆ  r‰  rŠ  r)  ÚNotImplementedErrorr  Ú
subprocessÚSubprocessErrorr=  Úhermes_cli.colorsr>  r?  r@  ÚYELLOWr3   Ú	enumerater  r  )Ar+  rë  rþ  r   rS  r  r  r  r  r  r  Ú_unavailableÚsale_chromer
  rí  r   Ú
all_modelsÚname_padÚany_on_saleÚ_DIMÚ_RESETÚpr   r!  r"  r  r  Ú
cache_readr  ÚsaleÚwas_prompt_rawÚwas_out_rawr1  Údefault_idxÚ
menu_titleÚpadÚheaderr5  ÚchoicesÚ_upgrade_urlÚunavailable_footerÚ
desc_linesÚheader_partrÄ  r8  Úmodel_search_labelsr=  ÚhaystackÚidxrÙ   r=  r>  r?  ÚlineÚ	num_widthÚiÚnÚchoicer-  r'  r(  r)  r*  r+  r,  sA    ``   ```                                                 @@@@@@@rB   Ú_prompt_model_selectionri    s@  øøøøøøøøøøøø€ ð&ð ð ð ð ð ð ð ð
 &Ð+¨€Lð $Ð) r×0Ò0Ñ2Ô2×8Ò8Ñ:Ô:¸fÒD€Kð
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð €GØð &˜¨)Ð3Ð3Ø�Š�}Ñ%Ô%Ð%Øð  ð  ˆØ�gÐÐØ�NŠN˜3ÑÔÐøõ �g‘”¥ lÑ!3Ô!3Ñ3€Jõ �wÐJ¥3Ð&JÐ&JÐ&JÐ&J¸zÐ&JÑ&JÔ&JÑ#JÔ#JÑKÔK€KàÐ&ˆqˆq Q€Hð ð	�Ð(Ð(˜ZÐ(Ñ(Ô(°!Ð4Ñ4Ô4°xÑ?Ð?àð ð KM€LØ€IØ€IØ€IØ€KØ€DØ€FØñ %*Øð "	3ñ "	3ˆCØ—’˜CÑ Ô ˆAØ"ˆCØ "Ð"ˆG�gØð -Ø,Ð,¨Q¯UªU°8¸RÑ-@Ô-@ÑAÔA�Ø,Ð,¨Q¯UªU°<ÀÑ-DÔ-DÑEÔE�ØŸUšUÐ#5°rÑ:Ô:�
Ø>HÐPÐ.Ð.¨zÑ:Ô:Ð:Èb�Øð %Ø $�IØð Ø0Ð0ØŸš˜h¨Ñ+Ô+ØŸš˜l¨BÑ/Ô/ØŸš˜jÑ)Ô)ñô �Dð
 Ð'Ø&*˜Ø;?Ñ8˜˜^¨[ð  .°Ò3Ð3ð 3Ð2°>ÑBÔBÐBà!$ð  ð  +¨bÒ0Ð0ð 3Ð2°;Ñ?Ô?Ð?à!$ð  øð #-‘��S˜%Ø!$ c¨5°#°wÀÐ HˆL˜ÑÝ˜I¥s¨3¡x¤xµ°S±´Ñ:Ô:ˆIÝ˜I¥s¨5¡z¤zÑ2Ô2ˆI‰IØð 	*Ý˜I qÑ)Ô)ˆIðð ð ð ð ð ð ð ð ð ð ðBFð Fð Fð Fð Fð €Kð )€JØð ,ð ˆØU�cÐU˜2ÐU ÐUÐUÐUÐU¨DÐU°9ÐUÐUÐUÐUÀÐUÈÐUÐUÐUÐUˆØð 	2ØÐ1˜7Ð1 YÐ1Ð1Ð1Ð1Ñ1ˆFð 	�f˜zÑ)Ñ)ˆ
Øð 	,ØÐ+Ñ+ˆJðBØ9Ð9Ð9Ð9Ð9Ð9à;Ð;Ð;Ð;°7Ð;Ñ;Ô;ˆØ�ŠÐ0Ñ1Ô1Ð1Ø�ŠÐ,Ñ-Ô-Ð-à"Ð=Õ&=×EÒEÀcÑJÔJˆØ0×6Ò6Ñ8Ô8ÐØ!ð 	N lð 	NØ!M¨|Ð!MÐ!MÐ!MÐð
 !#ˆ
Øð 	?ð %×*Ò*¨4°Ñ3Ô3ˆKÝ�;ÑÔ !Ò#Ð#Ø×!Ò! +¨a¤.×";Ò";Ñ"=Ô"=Ñ>Ô>Ð>Øð 	GØ#ð 7ð 7�Ø×!Ò!Ð"5¨¨¨s©¬Ð"5Ð"5Ñ6Ô6Ð6Ð6Ø×ÒÐEÐ*<ÐEÐEÐEÑFÔFÐFØ/9ÐC�d—i’i 
Ñ+Ô+Ð+¸tˆð 	>Ð=Ð=Ð=Ð=Ð=à ÐØð 	ð 	ˆCØ�F˜3‘K”KˆEØ(Ð(¨Ñ-Ô-ˆHð  ×&Ò&Ø! Sš˜��°Ð.CÐ.C¸Ð.CÐ.Cñô ð ð ð 	×"Ò"Ð#<Ñ=Ô=Ð=Ø×"Ò"Ð#8Ñ9Ô9Ð9àÐØ#ØØ ØØ#ØØ-ð
ñ 
ô 
ˆð �Š7ˆ7Ø�4Ý‰ŒˆØ•�W‘”ÒÐØ'Ð'¨°¬Ñ5Ô5Ð5Ø•C˜‘L”LÒ Ð ðÝÐ3Ñ4Ô4×:Ò:Ñ<Ô<��øÝÕ/Ð0ð ð ð Ø�t�tðøøøà39ÐCÐ'Ð'¨Ñ/Ô/Ð/¸tÐCØˆtøÝÕ,­gµzÔ7QÐRð ð ð Øˆðøøøð <Ð;Ð;Ð;Ð;Ð;Ø/Ð/Ð/Ð/Ð/Ð/Ð/Ð/à×%Ò%Ñ'Ô'ð ð ˆØ�Dˆ=ˆ=Ý�$—,’,˜u e e¨E°6´=Ñ&AÔ&AÀ1ÑEÔEÑFÔFÐFÐFå�$‰KŒKˆKˆKÝ•C�˜G™œ qÑ(Ñ)Ô)Ñ*Ô*€IÝ˜G QÑ'Ô'ð Uð U‰ˆˆ3ÝÐS�1ÐS�yÐSÐSÐSÐSÐ%;Ð%;¸O¸OÈCÑ<PÔ<PÑ%QÔ%QÐSÐSÑTÔTÐTÐTÝˆG‰Œ€AÝ	Ð
<ˆq�1‰uÐ
<�yÐ
<Ð
<Ð
<Ð
<Ð
<Ñ=Ô=Ð=Ý	Ð
8ˆq�1‰uÐ
8�yÐ
8Ð
8Ð
8Ð
8Ð
8Ñ9Ô9Ð9àð GØ"Ð=Õ&=×EÒEÀcÑJÔJˆØ0×6Ò6Ñ8Ô8ð 
ØTÀ\ÐTÐTÐTð 	õ 	‰ŒˆÝÐC�4ÐCÐCÐ 2ÐCÐC¸6ÐCÐCÑDÔDÐDØð 	Gð 	GˆCÝÐE�rÐE˜IÐEÐEÐEÐE¨$ÐE°°°s±´ÐE¸VÐEÐEÑFÔFÐFÐFÝ	�G„G€Gðð	ÝÐB¨¨A©ÐBÐBÐBÑCÔC×IÒIÑKÔKˆFØð Ø�tÝ�f‘+”+ˆCØ�Cˆ}ˆ}Š}ˆ}˜1Š}ˆ}ˆ}ˆ}ˆ}Ø+Ð+¨G°C¸!±GÔ,<Ñ=Ô=Ð=Ø˜˜A™’�ÝÐ3Ñ4Ô4×:Ò:Ñ<Ô<�Ø7=ÐGÐ+Ð+¨FÑ3Ô3Ð3À4ÐGØ˜˜A™’�Ø�tÝÐ+ A¨¡EÐ+Ð+Ñ,Ô,Ð,Ð,øÝð 	+ð 	+ð 	+ÝÐ)Ñ*Ô*Ð*Ð*Ð*Ý!¥8Ð,ð 	ð 	ð 	Ø�4�4ð	øøøð!ss   Ë
F3T Ñ?1T Ò1T Ó!S' Ó&T Ó'S<Ó8T Ó;S<Ó<T Ô"T5Ô4T5Û-*^& Ü2^& Ý8^& Þ	^& Þ^& Þ&_ß_ß_c                ó¶   — ddl m}m}  |¦   «         }t          |                     d¦  «        t
          ¦  «        r| |d         d<   nd| i|d<    ||¦  «         dS )uÛ   Save the selected model to config.yaml (single source of truth).

    The model is stored in config.yaml only â€” NOT in .env.  This avoids
    conflicts in multi-agent setups where env vars would stomp each other.
    r   )Úsave_configrÊ  r6  rž  N)ré   rk  rÊ  r  rg  rb   )r,  rk  rÊ  rê  s       rB   Ú_save_model_choicerl  +  sz   € ð ;Ð:Ð:Ð:Ð:Ð:Ð:Ð:àˆ[‰]Œ]€Få�&—*’*˜WÑ%Ô%¥tÑ,Ô,ð 0Ø%-ˆˆwŒ˜	Ñ"Ð"à$ hÐ/ˆˆw‰Ø€K�ÑÔÐÐÐrc   c                óz   — t          d¦  «         t          d¦  «         t          d¦  «         t          d¦  «        ‚)z9Deprecated: use 'hermes model' or 'hermes setup' instead.z,The 'hermes login' command has been removed.z(Use 'hermes auth' to manage credentials,zF'hermes model' to select a provider, or 'hermes setup' for full setup.r   )rƒ  r‹  )rA  s    rB   Úlogin_commandrn  <  s;   € å	Ð
8Ñ9Ô9Ð9Ý	Ð
4Ñ5Ô5Ð5Ý	Ð
RÑSÔSÐSÝ
�Q‰-Œ-Ðrc   )Úforce_new_loginro  c               ó‚  — ~ ~|�s)	 t          ¦   «         }|                     dd¦  «        }t          |t          ¦  «        rÏ|rÍt	          |d¦  «        s½t          d¦  «         	 t          d¦  «                             ¦   «                              ¦   «         }n# t          t          f$ r d}Y nw xY w|dv r[t          d|                     d	t          ¦  «        ¦  «        }t          ¦   «          t          d
¦  «         t          d|› d�¦  «         dS nt          d¦  «         n# t          $ r Y nw xY w|�s"t          ¦   «         }|�rt          d¦  «         t          d¦  «         	 t          d¦  «                             ¦   «                              ¦   «         }n# t          t          f$ r d}Y nw xY w|dv r¡t          |¦  «         t!          j        dd¦  «                             ¦   «                              d¦  «        pt          }	t          d|	¦  «        }t          ¦   «          t          d¦  «         t          d¦  «         t          d|› d�¦  «         dS t          ¦   «          t          d¦  «         t          d¦  «         t          ¦   «          t'          ¦   «         }
t          |
d         |
                     d¦  «        ¦  «         t          d|
                     d	t          ¦  «        ¦  «        }t          ¦   «          t          d
¦  «         ddlm} t          d |¦   «         › d�¦  «         t          d|› d�¦  «         dS ) zNOpenAI Codex login via device code flow. Tokens stored in ~/.hermes/auth.json.rh   r7   r(   z6Existing Codex credentials found in Hermes auth store.ú!Use existing credentials? [Y/n]: rû  >   r7   rû  r²  rf   r2   úLogin successful!ú  Config updated: z (model.provider=openai-codex)Nz?Existing Codex credentials are expired. Starting fresh login...z:Found existing Codex CLI credentials at ~/.codex/auth.jsonzOHermes will create its own session to avoid conflicts with Codex CLI / VS Code.zCImport these credentials? (a separate login is recommended) [y/N]: rg  >   rû  r²  r  rE   z=Credentials imported. Note: if Codex CLI refreshes its token,z<Hermes will keep working independently with its own session.zSigning in to OpenAI Codex...uF   (Hermes creates its own session â€” won't affect Codex CLI or VS Code)r´  rÓ  r   ©Údisplay_hermes_homer‘  ú
/auth.json)r#  rg  r  r3   r©  rƒ  rˆ  rG   r>   r‰  rŠ  rí  r  r|  rá  rß  r´  rµ  r?   Ú_codex_device_code_loginrÔ  ru  )rA  r	  ro  r‚  Ú_resolved_keyr  ré  Ú
cli_tokensÚ	do_importr2   rØ  Ú_dhhs               rB   Ú_login_openai_codexr|  D  s�  € ð 	ˆgð ñ ð	Ý8Ñ:Ô:ˆHð
 %ŸLšL¨°BÑ7Ô7ˆMÝ˜-­Ñ-Ô-ð Y°-ð YÕHgÐhuÐwyÑHzÔHzð YÝÐNÑOÔOÐOð Ý!Ð"EÑFÔF×LÒLÑNÔN×TÒTÑVÔV�E�EøÝ Õ"3Ð4ð  ð  ð  Ø�E�E�Eð øøøàÐ,Ð,Ð,Ý"=¸nÈhÏlÊlÐ[eÕg}ÑN~ÔN~Ñ"Ô"�KÝ‘G”G�GÝÐ-Ñ.Ô.Ð.ÝÐZ¨{ÐZÐZÐZÑ[Ô[Ð[Ø�Fð -õ ÐWÑXÔXÐXøøÝð 	ð 	ð 	ØˆDð	øøøð ñ Ý-Ñ/Ô/ˆ
Øñ 	ÝÐNÑOÔOÐOÝÐcÑdÔdÐdð Ý!Ð"gÑhÔh×nÒnÑpÔp×vÒvÑxÔx�	�	øÝÕ/Ð0ð  ð  ð  Ø�	�	�	ð øøøà˜LÐ(Ð(Ý" :Ñ.Ô.Ð.Ýœ9Ð%<¸bÑAÔA×GÒGÑIÔI×PÒPÐQTÑUÔUÐoÕYo�Ý9¸.È(ÑSÔS�Ý‘”�ÝÐUÑVÔVÐVÝÐTÑUÔUÐUÝÐV¨;ÐVÐVÐVÑWÔWÐWØ�õ 
�G„G€GÝ	Ð
)Ñ*Ô*Ð*Ý	Ð
RÑSÔSÐSÝ	�G„G€Gå$Ñ&Ô&€Eõ �u˜X”¨¯	ª	°.Ñ(AÔ(AÑBÔBÐBÝ-¨n¸e¿iºiÈ
ÕTjÑ>kÔ>kÑlÔl€KÝ	�G„G€GÝ	Ð
ÑÔÐØ<Ð<Ð<Ð<Ð<Ð<Ý	Ð
-˜4˜4™6œ6Ð
-Ð
-Ð
-Ñ.Ô.Ð.Ý	Ð
J˜{Ð
JÐ
JÐ
JÑKÔKÐKÐKÐKsO   ‡AD Á"3B ÂD ÂB,Â)D Â+B,Â,A D ÄD Ä
D,Ä+D,Å"3F ÆF,Æ+F,c               ó  — ~|�s	 t          ¦   «         }|                     dd¦  «        }t          |t          ¦  «        rÎ|rÌt	          |d¦  «        s¼t          d¦  «         	 t          d¦  «                             ¦   «                              ¦   «         }n# t          t          f$ r d}Y nw xY w|dv r[t          d|                     d	t          ¦  «        ¦  «        }t          ¦   «          t          d
¦  «         t          d|› d�¦  «         d S n# t          $ r Y nw xY wt          ¦   «          t          d¦  «         t          d¦  «         t          ¦   «          t          t          | dd ¦  «        pd¦  «        }t          | dd¦  «         }t!          ¦   «         rd}t#          ||¬¦  «        }	t%          |	d         |	                     d¦  «        |	                     dd¦  «        |	                     d¦  «        d¬¦  «         t'          dd¦  «         t          d|	                     d	t          ¦  «        ¦  «        }t          ¦   «          t          d
¦  «         ddlm}
 t          d |
¦   «         › d�¦  «         t          d|› d�¦  «         d S )Nrh   r7   r(   z:Existing xAI OAuth credentials found in Hermes auth store.rq  rû  >   r7   rû  r²  rk   r2   rr  rs  z (model.provider=xai-oauth)z6Signing in to xAI Grok OAuth (SuperGrok / Premium+)...z,(Hermes creates its own local OAuth session)r*  r¾  rŽ  F©ró  r–  r´  rR  rÿ  rÓ  re   )rR  rÿ  rÓ  rÞ  r%   r   rt  r‘  rv  )rŒ  rg  r  r3   r_  rƒ  rˆ  rG   r>   r‰  rŠ  rí  r‡  r|  r+  r  r†  Ú_xai_oauth_device_code_loginr[  rÂ  rÔ  ru  )rA  r	  ro  r‚  rh   r  ré  ró  r–  rØ  r{  s              rB   Ú_login_xai_oauthr€  Ž  sÌ  € ð 	àñ ð	Ý<Ñ>Ô>ˆHØ—l’l 9¨bÑ1Ô1ˆGÝ˜'¥3Ñ'Ô'ð ¨Gð Õ<YÐZaÐceÑ<fÔ<fð ÝÐRÑSÔSÐSð Ý!Ð"EÑFÔF×LÒLÑNÔN×TÒTÑVÔV�E�EøÝ Õ"3Ð4ð  ð  ð  Ø�E�E�Eð øøøàÐ,Ð,Ð,Ý"=Ø#Ø Ÿš ZÕ1KÑLÔLñ#ô #�Kõ ‘G”G�GÝÐ-Ñ.Ô.Ð.ÝÐW¨{ÐWÐWÐWÑXÔXÐXØ�FøøÝð 	ð 	ð 	ØˆDð	øøøõ 
�G„G€GÝ	Ð
BÑCÔCÐCÝ	Ð
8Ñ9Ô9Ð9Ý	�G„G€Gå�G D¨)°TÑ:Ô:ÐB¸dÑCÔC€OÝ˜t \°5Ñ9Ô9Ð9€LÝÑÔð Øˆå(Ø'Ø!ðñ ô €Eõ ØˆhŒØ—)’)˜KÑ(Ô(Ø—Y’Y˜~¨rÑ2Ô2Ø—Y’Y˜~Ñ.Ô.Ø%ðñ ô ð õ ! ¨mÑ<Ô<Ð<Ý-¨k¸5¿9º9ÀZÕQkÑ;lÔ;lÑmÔm€KÝ	�G„G€GÝ	Ð
ÑÔÐØ<Ð<Ð<Ð<Ð<Ð<Ý	Ð
-˜4˜4™6œ6Ð
-Ð
-Ð
-Ñ.Ô.Ð.Ý	Ð
G˜{Ð
GÐ
GÐ
GÑHÔHÐHÐHÐHs7   †AD Á!3B ÂD ÂB+Â(D Â*B+Â+A D Ä
DÄD)rU   c               óŒ  ‡— |                       t          dddœt          |dœ¬¦  «        }|j        dk    rAt	          d|j        › d�|j        rd	|j                             ¦   «         › �nd
z   dd¬¦  «        ‚|                     ¦   «         Šd}ˆfd„|D ¦   «         }|r(t	          dd                     |¦  «        › �dd¬¦  «        ‚‰S )NrÂ  r/  rÃ  )rT   rU   rç  r<  z%xAI device-code request failed (HTTP z).rÊ  r7   rk   Údevice_code_request_failedr®  r«  c                ó   •— g | ]}|‰v¯|‘Œ	S rY   rY   )râ   r$  rÁ  s     €rB   r¨  z2_xai_oauth_request_device_code.<locals>.<listcomp>ò  s#   ø€ Ð=Ð=Ð=�s¨#°WÐ*<Ð*<ˆsÐ*<Ð*<Ð*<rc   z)xAI device-code response missing fields: r±  Údevice_code_invalid)	r?  ÚXAI_OAUTH_DEVICE_CODE_URLr~  r@  r|  rB  rG   r;  rð  )rû  rU   rÓ  Úrequiredr´  rÁ  s        @rB   Ú_xai_oauth_request_device_coder‡  Ò  s   ø€ ð
 �{Š{Ý!à?Ø(ð
ð 
õ
 -Øð
ð 
ð ñ 
ô 
€Hð Ô˜sÒ"Ð"ÝØL°HÔ4HÐLÐLÐLØ8@¼ÐMÐ4˜Xœ]×0Ò0Ñ2Ô2Ð4Ð4Ð4È2ñOà Ø-ð	
ñ 
ô 
ð 	
ð �mŠm‰oŒo€Gð€Hð >Ð=Ð=Ð=˜hÐ=Ñ=Ô=€GØð 
ÝØL¸¿	º	À'Ñ8JÔ8JÐLÐLØ Ø&ð
ñ 
ô 
ð 	
ð
 €Nrc   c               ó  — t          j        ¦   «         t          dt          |¦  «        ¦  «        z   }t          dt          |¦  «        ¦  «        }t          j        ¦   «         |k     �r’|                      |dddœdt
          |dœ¬¦  «        }|j        dk    rd|                     ¦   «         }|                     d	¦  «        st          d
dd¬¦  «        ‚|                     d¦  «        st          ddd¬¦  «        ‚|S 	 |                     ¦   «         }	n4# t          $ r' |                     ¦   «          t          ddd¬¦  «        ‚w xY wt          |	                     d¦  «        pd¦  «        }
|
dk    rt          j        |¦  «         �Œ5|
dk    r)t          |dz   d¦  «        }t          j        |¦  «         �Œd|	                     d¦  «        p|	                     d¦  «        p|j        }t          d|› �dd¬¦  «        ‚t          ddd¬¦  «        ‚)Nr"   rÂ  r/  rÃ  r»  r¼  rç  r<  r  z?xAI device-code token response did not include an access_token.rk   Úxai_device_token_invalidr®  rÀ  z?xAI device-code token response did not include a refresh_token.zAxAI device-code token polling returned a non-JSON error response.Úxai_device_token_failedr‹  r7   r½  r¾  r¿  r5  z&xAI device-code token polling failed: z/Timed out waiting for xAI device authorization.Údevice_code_timeout)r  r  r  r  r?  r~  r@  r;  rg  r|  r@   r²  r3   r  rb  rB  )rû  rq  r%   rI  rP  r  rÁ  rÓ  rÁ  rÂ  rÃ  rÄ  s               rB   Ú_xai_oauth_poll_device_tokenrŒ  ü  s{  € õ Œ~ÑÔ¥# a­¨Z©¬Ñ"9Ô"9Ñ9€HÝ˜1�c -Ñ0Ô0Ñ1Ô1ÐÝ
Œ.Ñ
Ô
˜XÒ
%Ñ
%Ø—;’;Øà CØ,ðð ð
 MÝ0Ø*ðð ð ñ 
ô 
ˆð Ô 3Ò&Ð&Ø—m’m‘o”oˆGØ—;’;˜~Ñ.Ô.ð ÝØUØ(Ø3ðñ ô ð ð
 —;’;˜Ñ/Ô/ð ÝØUØ(Ø3ðñ ô ð ð
 ˆNð	Ø$ŸMšM™OœOˆMˆMøÝð 	ð 	ð 	Ø×%Ò%Ñ'Ô'Ð'ÝØSØ$Ø.ðñ ô ð ð	øøøõ ˜×*Ò*¨7Ñ3Ô3Ð9°rÑ:Ô:ˆ
ØÐ0Ò0Ð0ÝŒJÐ'Ñ(Ô(Ð(ÙØ˜Ò$Ð$Ý"Ð#3°aÑ#7¸Ñ<Ô<ÐÝŒJÐ'Ñ(Ô(Ð(Ùà×ÒÐ1Ñ2Ô2ð Ø× Ò  Ñ)Ô)ðàŒ}ð 	õ
 ØB°[ÐBÐBØ Ø*ð
ñ 
ô 
ð 	
õ
 Ø9ØØ"ðñ ô ð s   Ã;D Ä1Er~  r–  c           	     óZ  — t          | ¦  «        }|d         }t          j        t          d| ¦  «        ¦  «        }t          j        |ddi¬¦  «        5 }t          |¦  «        }t          |                     d¦  «        p|d         ¦  «        }t          |d         ¦  «        }t          |d	         ¦  «        }	t          |d
         ¦  «        }
t          ¦   «          t          d¦  «         t          d|› �¦  «         t          d|› �¦  «         |ret          ¦   «         sWt          ¦   «         rI	 t          j        |¦  «        }n# t          $ r d}Y nw xY w|rt          d¦  «         nt          d¦  «         t          dt          d|
¦  «        › d�¦  «         t          ||t          |d         ¦  «        |	|
¬¦  «        }d d d ¦  «         n# 1 swxY w Y   t          |                     dd¦  «        pd¦  «                             ¦   «         }t          |                     dd¦  «        pd¦  «                             ¦   «         }|r|st#          ddd¬¦  «        ‚t%          t'          j        dd¦  «                             ¦   «                              d¦  «        p9t'          j        dd¦  «                             ¦   «                              d¦  «        t,          ¬ ¦  «        }||t          |                     d!d¦  «        pd¦  «                             ¦   «         |                     d	¦  «        t          |                     d"¦  «        pd#¦  «                             ¦   «         pd#d$œ|d|t/          j        t2          j        ¦  «                             ¦   «                              d%d&¦  «        d'd(œS ))Nrq  r¾  rÄ  r/  ræ  r®  r­  r¬  rI  r¯  úTo continue:ú  1. Open: ú  2. If prompted, enter code: Fú#  (Opened browser for verification)ú<  Could not open browser automatically -- use the URL above.ú$Waiting for approval (polling every r"   ús)...r%   )rq  r%   rI  rP  r  r7   rÀ  z;xAI device-code token response was missing required tokens.rk   r‰  r®  r„  rE   r³   r…  r}  rÍ  rÎ  )r  rÀ  r}  rI  rÍ  r<  r:  zoauth-device-code)r´  rR  rÿ  r2   rÓ  r  )rt  r>  rö  r  r÷  r‡  r3   rg  r  rƒ  r†  r“  r‡  r  r@   rŒ  rG   r|  rk  r´  rµ  r?   r‡  r   r7  r   r8  r9  r@  )ró  r–  rR  rq  r*  rû  Údevice_dataÚverification_urlr¬  rI  r¯  r™  rÁ  r  rÀ  r2   s                   rB   r  r  E  sù  € õ
 % _Ñ5Ô5€IØÐ/Ô0€NÝŒm�C  oÑ6Ô6Ñ7Ô7€GÝ	Œ˜g°Ð:LÐ/MÐ	NÑ	NÔ	Nð 
ÐRXÝ4°VÑ<Ô<ˆÝØ�OŠOÐ7Ñ8Ô8ð /ØÐ-Ô.ñ
ô 
Ðõ ˜ KÔ0Ñ1Ô1ˆ	Ý˜ \Ô2Ñ3Ô3ˆ
Ý�{ :Ô.Ñ/Ô/ˆå‰ŒˆÝˆnÑÔÐÝÐ.Ð,Ð.Ð.Ñ/Ô/Ð/ÝÐ:¨yÐ:Ð:Ñ;Ô;Ð;Øð 	VÕ 2Ñ 4Ô 4ð 	VÕ9TÑ9VÔ9Vð 	VðÝ#œÐ)9Ñ:Ô:��øÝð ð ð Ø���ðøøøàð VÝÐ;Ñ<Ô<Ð<Ð<åÐTÑUÔUÐUÝÐLµS¸¸HÑ5EÔ5EÐLÐLÐLÑMÔMÐMå.ØØ)Ý˜K¨Ô6Ñ7Ô7Ø!Ø"ð
ñ 
ô 
ˆð3
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
õB �w—{’{ >°2Ñ6Ô6Ð<¸"Ñ=Ô=×CÒCÑEÔE€LÝ˜Ÿš O°RÑ8Ô8Ð>¸BÑ?Ô?×EÒEÑGÔG€MØð 
˜}ð 
ÝØIØ Ø+ð
ñ 
ô 
ð 	
õ
 0Ý
Œ	Ð'¨Ñ,Ô,×2Ò2Ñ4Ô4×;Ò;¸CÑ@Ô@ð 	=ÝŒ9�^ RÑ(Ô(×.Ò.Ñ0Ô0×7Ò7¸Ñ<Ô<Ý+ðñ ô €Hð )Ø*Ý˜GŸKšK¨
°BÑ7Ô7Ð=¸2Ñ>Ô>×DÒDÑFÔFØ!Ÿ+š+ lÑ3Ô3Ý˜gŸkšk¨,Ñ7Ô7ÐC¸8ÑDÔD×JÒJÑLÔLÐXÐPXð
ð 
ð ØØÝ œ¥X¤\Ñ2Ô2×<Ò<Ñ>Ô>×FÒFÀxÐQTÑUÔUØ%ðð ð s8   ÁCGÄ+E Ä?GÅ EÅGÅEÅA,GÇGÇGc            
     óö  — ddl } d}t          }d}d}t          d|dz   ¦  «        D �]}	 t          j        t          j        d¦  «        ¬¦  «        5 }|                     |› d�d	|id
di¬¦  «        }ddd¦  «         n# 1 swxY w Y   n'# t          $ r}t          d|› �dd¬¦  «        ‚d}~ww xY w|j	        dk    r n‚||k     rzt          t          |dd¦  «        ¦  «        }|�|nd|z  }	t          dt          t          |	¦  «        d¦  «        ¦  «        }	t          d|	› d�¦  «         |                      |	¦  «         �Œ|�M|j	        dk    rBt          t          |dd¦  «        ¦  «        }|�d|› d�nd}
t          d|
› �dt"          ¬¦  «        ‚|�|j	        dk    r!|�|j	        nd}t          d|› d�dd¬¦  «        ‚|                     ¦   «         }|                     d d!¦  «        }|                     d"d!¦  «        }t          d#t          |                     d$d%¦  «        ¦  «        ¦  «        }|r|st          d&dd'¬¦  «        ‚t          d(¦  «         t          d)¦  «         t          d*|› d+�¦  «         t          d,¦  «         t          d*|› d-�¦  «         t          d.¦  «         d/}|                      ¦   «         }d}	 t          j        t          j        d¦  «        ¬¦  «        5 }|                      ¦   «         |z
  |k     rz|                      |¦  «         |                     |› d0�||d1œd
di¬¦  «        }|j	        dk    r|                     ¦   «         }n%|j	        d2v rŒzt          d3|j	        › d�dd4¬¦  «        ‚ddd¦  «         n# 1 swxY w Y   n,# t*          $ r t          d5¦  «         t-          d6¦  «        ‚w xY w|€t          d7dd8¬¦  «        ‚|                     d9d!¦  «        }|                     d:d!¦  «        }|› d;�}|r|st          d<dd=¬¦  «        ‚	 t          j        t          j        d¦  «        ¬¦  «        5 }|                     t.          d9||||d>œd
d?i¬@¦  «        }ddd¦  «         n# 1 swxY w Y   n'# t          $ r}t          dA|› �ddB¬¦  «        ‚d}~ww xY w|j	        dk    rBt          t          |dd¦  «        ¦  «        }|�d|› d�nd}
t          dC|
› �dt"          ¬¦  «        ‚|j	        dk    rt          dD|j	        › d�ddE¬¦  «        ‚|                     ¦   «         }|                     dFd!¦  «        }|                     dGd!¦  «        }|st          dHddI¬¦  «        ‚t1          j        dJd!¦  «                             ¦   «                              dK¦  «        pt8          }||dLœ|t;          j        t>          j         ¦  «         !                    ¦   «          "                    dMdN¦  «        dOdPdQœS )RzBRun the OpenAI device code login flow and return credentials dict.r   Nzhttps://auth.openai.comrÿ   r"   r#   rT  z!/api/accounts/deviceauth/usercoderT   r1  r/  )r;  r:  zFailed to request device code: rf   r‚  r®  rè  r:  r2  r(   z:OpenAI is rate-limiting login requests (429); retrying in zs...z Try again in about zs.z' Wait a minute and run the login again.z�OpenAI is rate-limiting Codex login requests (HTTP 429). This is a temporary throttle on OpenAI's side, not a credential problem.r<  r+   z$Device code request returned status r8   Údevice_code_request_errorr¬  r7   Údevice_auth_idr%  r¯  Ú5z-Device code response missing required fields.Údevice_code_incompletez!To continue, follow these steps:
z#  1. Open this URL in your browser:z
     [94mz/codex/device[0m
z  2. Enter this code:z[0m
z/Waiting for sign-in... (press Ctrl+C to cancel)i„  z/api/accounts/deviceauth/token)r™  r¬  >   ró  r9  z$Device auth polling returned status Údevice_code_poll_errorú
Login cancelled.é‚   z!Login timed out after 15 minutes.r‹  rg  r  z/deviceauth/callbackzADevice auth response missing authorization_code or code_verifier.Údevice_code_incomplete_exchange)rÆ  r  rÿ  rT   r  rÂ  ©r²  r:  zToken exchange failed: Útoken_exchange_failedz—OpenAI is rate-limiting Codex login requests (HTTP 429) during token exchange. This is a temporary throttle on OpenAI's side, not a credential problem.zToken exchange returned status Útoken_exchange_errorr  rÀ  z.Token exchange did not return an access_token.Útoken_exchange_no_access_tokenr  rE   )r  rÀ  r<  r:  rÝ  zdevice-code)r´  r2   rÓ  rÞ  r  )#r  rú  Úranger>  r÷  rö  r?  r@   r|  r@  r•  r  r  rb  r  rƒ  r  r�  r;  rg  r  rŠ  r‹  rù  r´  rµ  rG   r?   r  r   r7  r   r8  r9  r@  )Ú_timeÚissuerrT   rD  Úmax_attemptsÚattemptrû  r  rü  ÚdelayÚ	wait_hintr˜  r•  r¬  r™  rP  Úmax_waitrX  Ú	code_respÚ	poll_resprg  r  rÿ  Ú
token_respr´  r  rÀ  r2   s                               rB   rw  rw  ‹  s~  € àÐÐÐà&€FÝ%€Ið €DØ€LÝ˜˜L¨1Ñ,Ñ-Ô-ð ñ ˆð	Ý”¥e¤m°DÑ&9Ô&9Ð:Ñ:Ô:ð ¸fØ—{’{ØÐ@Ð@Ð@Ø% yÐ1Ø+Ð-?Ð@ð #ñ ô �ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð øøõ ð 	ð 	ð 	ÝØ7°#Ð7Ð7Ø'Ð.Jðñ ô ð øøøøð	øøøð Ô˜sÒ"Ð"ØˆEà�\Ò!Ð!Ý4Ý˜˜i¨Ñ.Ô.ñô ˆKð
 $/Ð#:�K�KÀÀWÁˆEÝ˜�3�s 5™zœz¨2Ñ.Ô.Ñ/Ô/ˆEÝð2Ø&+ð2ð 2ð 2ñô ð ð �KŠK˜ÑÔÐùàÐ˜DÔ,°Ò3Ð3Ý0µ¸¸yÈ$Ñ1OÔ1OÑPÔPˆð Ð&ð 3 ;Ð2Ð2Ð2Ð2à:ð 	õ
 ð#à ð#ð #ð $Õ*Að	
ñ 
ô 
ð 	
ð €|�tÔ'¨3Ò.Ð.Ø%)Ð%5�Ô!Ð!¸9ˆÝØ<°6Ð<Ð<Ð<Ø#Ð*Eð
ñ 
ô 
ð 	
ð
 —)’)‘+”+€KØ—’ ¨RÑ0Ô0€IØ —_’_Ð%5°rÑ:Ô:€NÝ˜�3˜{Ÿš¨z¸3Ñ?Ô?Ñ@Ô@ÑAÔA€Màð 
˜Nð 
ÝØ;Ø#Ð*Bð
ñ 
ô 
ð 	
õ 
Ð
.Ñ/Ô/Ð/Ý	Ð
/Ñ0Ô0Ð0Ý	Ð
8˜&Ð
8Ð
8Ð
8Ñ9Ô9Ð9Ý	Ð
!Ñ"Ô"Ð"Ý	Ð
.˜)Ð
.Ð
.Ð
.Ñ/Ô/Ð/Ý	Ð
;Ñ<Ô<Ð<ð €HØ�OŠOÑÔ€EØ€IðÝŒ\¥%¤-°Ñ"5Ô"5Ð6Ñ6Ô6ð 	¸&Ø—/’/Ñ#Ô# eÑ+¨hÒ6Ð6Ø—’˜MÑ*Ô*Ð*Ø"ŸKšKØÐ=Ð=Ð=Ø,:ÈÐSÐSØ+Ð-?Ð@ð (ñ ô �	ð Ô(¨CÒ/Ð/Ø )§¢Ñ 0Ô 0�IØØÔ*¨jÐ8Ð8Øå#ØW¸yÔ?TÐWÐWÐWØ!/Ð6Nðñ ô ð ð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	øøõ& ð ð ð ÝÐ"Ñ#Ô#Ð#Ý˜‰oŒoÐðøøøð ÐÝØ/Ø#Ð*?ð
ñ 
ô 
ð 	
ð #ŸšÐ';¸RÑ@Ô@ÐØ—M’M /°2Ñ6Ô6€MØÐ2Ð2Ð2€Làð 
 ]ð 
ÝØOØ#Ð*Kð
ñ 
ô 
ð 	
ð

ÝŒ\¥%¤-°Ñ"5Ô"5Ð6Ñ6Ô6ð 	¸&ØŸšÝ%à"6Ø.Ø$0Ø!*Ø%2ðð ð (Ð)LÐMð %ñ 
ô 
ˆJð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	øøõ ð 
ð 
ð 
ÝØ+ cÐ+Ð+Ø#Ð*Að
ñ 
ô 
ð 	
øøøøð
øøøð Ô Ò$Ð$Ý0Ý�J 	¨4Ñ0Ô0ñ
ô 
ˆð
 Ð&ð 3 ;Ð2Ð2Ð2Ð2à:ð 	õ
 ð4à(1ð4ð 4ð $Õ*Að	
ñ 
ô 
ð 	
ð Ô Ò$Ð$ÝØG¨jÔ.DÐGÐGÐGØ#Ð*@ð
ñ 
ô 
ð 	
ð
 �_Š_ÑÔ€FØ—:’:˜n¨bÑ1Ô1€LØ—J’J˜°Ñ3Ô3€Màð 
ÝØ<Ø#Ð*Jð
ñ 
ô 
ð 	
õ 	Œ	Ð)¨2Ñ.Ô.×4Ò4Ñ6Ô6×=Ò=¸cÑBÔBð 	"Ý!ð ð )Ø*ð
ð 
ð Ý œ¥X¤\Ñ2Ô2×<Ò<Ñ>Ô>×FÒFÀxÐQTÑUÔUØØð	ð 	ð 	s¨   ©'BÁ A<Á0BÁ<B 	Â BÂB 	ÂBÂ
B,ÂB'Â'B,Ê='N Ë$BNÍ:N ÎN
Î
N ÎN
ÎN Î)N;Ð'Q? Ñ&Q3Ñ'Q? Ñ3Q7Ñ7Q? Ñ:Q7Ñ;Q? Ñ?
R#Ò	RÒR#i @  )ÚlimitrÓ  úhttpx.Responser¯  c               ó  — t          dt          |¦  «        ¦  «        }g }d}d}	 t          | dd¦  «        r=| j        }|d|…         t	          |¦  «        |k    rdndz   |                      ¦   «          S |                      ¦   «         D ]w}|sŒ|dz   |z
  }|dk    rd} nat	          |¦  «        |k    r&|                     |d|…         ¦  «         ||z  }d} n(|                     |¦  «         |t	          |¦  «        z  }Œxd	                     |¦  «        }t	          |¦  «        |k    r|d|…         }d}| j	        pd
}	| 
                    |	d¬¦  «        }||rdndz   |                      ¦   «          S # |                      ¦   «          w xY w)zCReturn a bounded error body from a streamed MiniMax OAuth response.r   FÚis_stream_consumedNz...[truncated]r7   r"   Trc   r«  r@  )Úerrors)r  r  r  rB  r  rI  Ú
iter_bytesr°  rð  rû  rh  )
rÓ  r¯  ÚchunksÚtotalÚ	truncatedrB  Úchunkr!  r¶  rû  s
             rB   Ú_minimax_response_error_textr¹  W   sÄ  € õ �•3�u‘:”:ÑÔ€EØ€FØ€EØ€IðÝ�8Ð1°5Ñ9Ô9ð 	RØ”=ˆDØ˜˜˜”<µs¸4±y´yÀ5Ò7HÐ7HÐ#3Ð#3ÈbÑQð0 	�ŠÑÔÐÐð- ×(Ò(Ñ*Ô*ð 	 ð 	 ˆEØð ØØ ™	 EÑ)ˆIØ˜AŠ~ˆ~Ø �	Ø�Ý�5‰zŒz˜IÒ%Ð%Ø—’˜e J Y JÔ/Ñ0Ô0Ð0Ø˜Ñ"�Ø �	Ø�Ø�MŠM˜%Ñ Ô Ð Ø•S˜‘Z”ZÑˆEˆEØ�hŠh�vÑÔˆÝˆs‰8Œ8�eÒÐØ�f�u�f”+ˆCØˆIØÔ$Ð/¨ˆØ�zŠz˜(¨9ˆzÑ5Ô5ˆØ¨9Ð<Ð'Ð'¸"Ñ=à�ŠÑÔÐÐøˆ�ŠÑÔÐÐøøøs   ¥9E0 Á3C(E0 Å0Fr²  c               ó¤   — |                       d|||¬¦  «        }|                      |d¬¦  «        }|j        dk    r|                     ¦   «          |S )z?POST a MiniMax OAuth form without eagerly reading error bodies.ÚPOSTr   T)r7  r<  )Úbuild_requestÚsendr@  Úread)rû  rJ   r²  r:  ÚrequestrÓ  s         rB   Ú_minimax_post_formrÀ     sa   € ð ×"Ò"ØØØØð	 #ñ ô €Gð �{Š{˜7¨4ˆ{Ñ0Ô0€HØÔ˜sÒ"Ð"Ø�Š‰ŒˆØ€Orc   c                 óV  — ddl } |                      d¦  «        dd…         }t          j        t	          j        |                     ¦   «         ¦  «                             ¦   «         ¦  «                             ¦   «          	                    d¦  «        }|                      d¦  «        }|||fS )zGGenerate (code_verifier, code_challenge_S256, state) for MiniMax OAuth.r   Nr  é`   rd  ra  )
ÚsecretsÚtoken_urlsaferf  r  rh  ri  rj  r  rh  r?   )rÃ  ÚverifierÚ	challengerq  s       rB   Ú_minimax_pkce_pairrÇ  ’   s”   € à€N€N€NØ×$Ò$ RÑ(Ô(¨¨"¨Ô-€HÝÔ(ÝŒ�x—’Ñ(Ô(Ñ)Ô)×0Ò0Ñ2Ô2ñô ç‚f�h„h�vŠv�c‰{Œ{ð ð ×!Ò! "Ñ%Ô%€EØ�Y Ð%Ð%rc   c               ó´  — t          | |› d�d|t          |d|dœddt          t          j        ¦   «         ¦  «        dœ¬¦  «        }|j        d	k    r+t          |¦  «        }t          d
|p|j        › �dd¬¦  «        ‚| 	                    ¦   «         }dD ]}||vrt          d|› �dd¬¦  «        ‚Œ| 
                    d¦  «        |k    rt          ddd¬¦  «        ‚|S )Nz/oauth/coder  r'  )r(  rT   rU   r%  r)  rq  rÂ  r/  )r1  rÄ  zx-request-idr   r<  z$MiniMax OAuth authorization failed: r—   Úauthorization_failedr®  )r¬  r­  Ú
expired_inz&MiniMax OAuth response missing field: Úauthorization_incompleterq  z-MiniMax OAuth state mismatch (possible CSRF).Ústate_mismatch)rÀ  ÚMINIMAX_OAUTH_SCOPEr3   r<  r=  r@  r¹  r|  Úreason_phraser;  rg  )	rû  rR   rT   r%  rq  rÓ  rÔ  rÁ  r   s	            rB   Ú_minimax_request_user_coderÏ  �   sJ  € õ "ØØÐ'Ð'Ð'à#Ø"Ý(Ø,Ø%+Øð
ð 
ð @Ø(Ý¥¤
¡¤Ñ-Ô-ð
ð 
ðñ ô €Hð" Ô˜sÒ"Ð"Ý+¨HÑ5Ô5ˆÝØS°4Ð3Q¸8Ô;QÐSÐSØ$Ð+Að
ñ 
ô 
ð 	
ð �mŠm‰oŒo€GØ@ð ð ˆØ˜ÐÐÝØ@¸Ð@Ð@Ø(Ð/Iðñ ô ð ð  ð
 ‡{‚{�7ÑÔ˜uÒ$Ð$ÝØ;Ø$Ð+;ð
ñ 
ô 
ð 	
ð €Nrc   rÊ  Únow_msc               ó.   — t          | ¦  «        |dz  k    S )zMTrue if ``expired_in`` is plausibly a unix-ms absolute time (vs TTL seconds).r2  )r  )rÊ  rÐ  s     rB   Ú&_minimax_expired_in_looks_like_unix_msrÒ  Ç   s   € åˆz‰?Œ?˜f¨™kÒ*Ð*rc   r7  r   c               óÞ   — t          | ¦  «        }t          |                     ¦   «         dz  ¦  «        }t          ||¬¦  «        r|dz  S |                     ¦   «         t          d|¦  «        z   S )zRReturn access-token expiry as unix seconds (MiniMax uses ms epoch or TTL seconds).r»  ©rÐ  rA  r"   )r  rA  rÒ  r  )rÊ  r7  r¶  rÐ  s       rB   Ú"_minimax_resolve_token_expiry_unixrÕ  Ì   sa   € å
ˆj‰/Œ/€CÝ�—’‘” 4Ñ'Ñ(Ô(€FÝ-¨c¸&ÐAÑAÔAð Ø�V‰|ÐØ�=Š=‰?Œ?�S  C™[œ[Ñ(Ð(rc   r¬  Úinterval_msc          	     óJ  ‡— dd l }t          |                      ¦   «         dz  ¦  «        }t          |¦  «        }	t          |	|¬¦  «        r|	dz  }
n%|                      ¦   «         t          d|	¦  «        z   }
t          d|pddz  ¦  «        }|                      ¦   «         |
k     �rpt	          | |› d�t
          |||d	œd
ddœ¬¦  «        }d}|j        dk    rt          |¦  «        }	 |rt          j	        |¦  «        ni Šn# t          $ r i ŠY nw xY w‰                     di ¦  «        pi                      d¦  «        p|}t          d|pd› �dd¬¦  «        ‚	 |j        r|                     ¦   «         ni Šn# t          $ r i ŠY nw xY w‰                     d¦  «        }|dk    rt          ddd¬¦  «        ‚|dk    r/t          ˆfd„dD ¦   «         ¦  «        st          ddd¬¦  «        ‚‰S |                     |¦  «         |                      ¦   «         |
k     �°pt          d dd!¬¦  «        ‚)"Nr   r»  rÔ  rA  r"   g       @iÐ  ú/oauth/token)rÆ  rT   r¬  r  rÂ  r/  rÃ  r   r7   r<  Ú	base_respÚ
status_msgzMiniMax OAuth error: r+   r—   r¡  r®  r˜  r‹  z8MiniMax OAuth reported an error. Please try again later.Úauthorization_deniedÚsuccessc              3  óB   •K  — | ]}‰                      |¦  «        V — Œd S r…  r  )râ   ÚkrÁ  s     €rB   rä   z&_minimax_poll_token.<locals>.<genexpr>!  s-   øè è € Ð_Ð_¨!�w—{’{ 1‘~”~Ð_Ð_Ð_Ð_Ð_Ð_rc   )r  rÀ  rÊ  z<MiniMax OAuth success payload missing required token fields.Útoken_incompletez7MiniMax OAuth timed out before authorization completed.r*  )r  r  rÒ  r  rÀ  ÚMINIMAX_OAUTH_GRANT_TYPEr@  r¹  r;  r)  r@   rg  r|  rB  Úallr  )rû  rR   rT   r¬  r  rÊ  rÖ  r¥  rÐ  r¶  r  r¯  rÓ  Ú
error_textr/  r˜  rÁ  s                   @rB   Ú_minimax_poll_tokenrã  Õ   sË  ø€ ð ÐÐÐÝ�—’‘” Ñ$Ñ%Ô%€FÝ
ˆj‰/Œ/€CÝ-¨c¸&ÐAÑAÔAð .Ø˜‘<ˆˆà—:’:‘<”<¥# a¨¡+¤+Ñ-ˆÝ�3˜Ð,¨°Ñ6Ñ7Ô7€Hà
�*Š*‰,Œ,˜Ò
!Ñ
!Ý%ØØÐ,Ð,Ð,å6Ø&Ø&Ø!.ð	ð ð !DØ,ðð ð
ñ 
ô 
ˆð ˆ
ØÔ 3Ò&Ð&Ý5°hÑ?Ô?ˆJðØ4>ÐF�$œ* ZÑ0Ô0Ð0ÀB��øÝð ð ð Ø���ðøøøà—;’;˜{¨BÑ/Ô/Ð5°2×:Ò:¸<ÑHÔHÐVÈJˆCÝØ:¨Ð(8¨yÐ:Ð:Ø(Ð/Fðñ ô ð ð	Ø)1¬Ð>�h—m’m‘o”o�o¸BˆGˆGøÝð 	ð 	ð 	ØˆGˆGˆGð	øøøð —’˜XÑ&Ô&ˆØ�WÒÐÝØJØ(Ð/Eðñ ô ð ð �YÒÐÝÐ_Ð_Ð_Ð_Ð/^Ð_Ñ_Ô_Ñ_Ô_ð ÝØRØ,Ð3Eðñ ô ð ð ˆNà�Š�HÑÔÐð] �*Š*‰,Œ,˜Ò
!Ñ
!õ` ØAØ  yðñ ô ð s$   Ã#C< Ã<DÄ
DÅE1 Å1F Å?F c                ó°   — t          ¦   «         5  t          ¦   «         }t          |d| ¦  «         t          |¦  «         ddd¦  «         dS # 1 swxY w Y   dS )zGPersist MiniMax OAuth state to Hermes auth store (~/.hermes/auth.json).r—   N)rl  re  re  rn  )rš  rp  s     rB   Ú_minimax_save_auth_staterå  !  s�   € å	Ñ	Ô	ð %ð %Ý%Ñ'Ô'ˆ
Ý˜Z¨¸*ÑEÔEÐEÝ˜Ñ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %ð %ð %s   �/AÁAÁA©rš   r–  ró  rš   c                ó~  — t           d         }| dk    r|j        d         }|j        d         }n|j        }|j        }t	          ¦   «         \  }}}t          ¦   «         rd}t          d| › d�¦  «         t          d|› �¦  «         t          j        t          j	        |¦  «        d	d
id¬¦  «        5 }	t          |	||j        ||¬¦  «        }
t          |
d         ¦  «        }t          |
d         ¦  «        }t          ¦   «          t          d¦  «         t          d|› �¦  «         t          d|› �¦  «         |rAt          ¦   «         r3t          j        |¦  «        rt          d¦  «         nt          d¦  «         |
                     d¦  «        }|�t#          |¦  «        nd}t          d¦  «         t%          |	||j        ||t#          |
d         ¦  «        |¬¦  «        }ddd¦  «         n# 1 swxY w Y   t'          j        t*          j        ¦  «        }t/          t#          |d         ¦  «        |¬¦  «        }t1          dt#          ||                     ¦   «         z
  ¦  «        ¦  «        }d| |||j        t4          |                     dd¦  «        |d         |d         |                     d ¦  «        |                     ¦   «         t'          j        |t*          j        ¬!¦  «                             ¦   «         |d"œ}t;          |¦  «         t          d#¦  «         |                     d$¦  «        x}rt          d%|› �¦  «         |S )&z?Run MiniMax OAuth flow, persist tokens, return auth state dict.r—   r'  r›   rœ   Fz#Starting Hermes login via MiniMax (z
) OAuth...úPortal: rÄ  r/  T)r*  r:  Úfollow_redirects)rR   rT   r%  rq  r­  r¬  rŽ  r�  r�  r‘  r’  r¯  NzWaiting for approval...rÊ  )rR   rT   r¬  r  rÊ  rÖ  ©r7  r   rÍ  rÎ  r  rÀ  rÏ  r’  )r~  rš   rR   rS   rT   rU   rÍ  r  rÀ  rÏ  r–  rw  rI  u#   âœ“ MiniMax OAuth login successful.Únotification_messagezNote from MiniMax: )rÖ   rX   rR   rS   rÇ  r†  rƒ  r>  r÷  rö  rÏ  rT   r3   r“  r‡  r  rg  r  rã  r   r7  r   r8  rÕ  r  rA  rÍ  r9  r”  rå  )rš   r–  ró  r	  rR   rS   rÅ  rÆ  rq  rû  Ú	code_datar–  r¬  Úinterval_rawrÖ  Ú
token_datar7  Úexpires_at_unixÚexpires_in_srš  r/  s                        rB   Ú_minimax_oauth_loginrñ  "!  s£  € õ
   Ô0€GØ�‚~€~Ø!œ-Ð(<Ô=ˆØ$œ]Ð+BÔCÐÐà!Ô1ˆØ$Ô7Ðå!3Ñ!5Ô!5Ñ€Hˆi˜åÑÔð Øˆå	Ð
B°Ð
BÐ
BÐ
BÑCÔCÐCÝ	Ð
&�_Ð
&Ð
&Ñ'Ô'Ð'å	Œ�eœm¨OÑ<Ô<Ø'Ð);Ð<Ø'+ð
-ñ 
-ô 
-ð 
à06Ý.Ø OØÔ'Ø$¨Eð
ñ 
ô 
ˆ	õ
 ˜yÐ);Ô<Ñ=Ô=ÐÝ˜	 +Ô.Ñ/Ô/ˆ	å‰ŒˆÝˆnÑÔÐÝÐ.Ð,Ð.Ð.Ñ/Ô/Ð/ÝÐ:¨yÐ:Ð:Ñ;Ô;Ð;Øð 	VÕ7Ñ9Ô9ð 	VÝŒÐ/Ñ0Ô0ð VÝÐ;Ñ<Ô<Ð<Ð<åÐTÑUÔUÐUà —}’} ZÑ0Ô0ˆØ+7Ð+C•c˜,Ñ'Ô'Ð'ÈˆÝÐ'Ñ(Ô(Ð(å(Ø OØÔ'Ø¨xÝ˜9 \Ô2Ñ3Ô3Ø#ð
ñ 
ô 
ˆ
ð3
ð 
ð 
ñ 
ô 
ð 
ð 
ð 
ð 
ð 
ð 
øøøð 
ð 
ð 
ð 
õB Œ,•x”|Ñ
$Ô
$€CÝ8ÝˆJ�|Ô$Ñ%Ô%¨3ðñ ô €Oõ �q�#˜o°·²±´Ñ?Ñ@Ô@ÑAÔA€Lð $ØØ*Ø0ØÔ&Ý$Ø —n’n \°8Ñ<Ô<Ø" >Ô2Ø# OÔ4Ø"Ÿš ~Ñ6Ô6Ø—}’}‘”ÝÔ,¨_ÅÄÐNÑNÔN×XÒXÑZÔZØ"ðð €Jõ  ˜ZÑ(Ô(Ð(Ý	Ð
2Ñ3Ô3Ð3Ø�nŠnÐ3Ñ4Ô4Ð4€sð +ÝÐ) CÐ)Ð)Ñ*Ô*Ð*ØÐs   Â/D-G(Ç(G,Ç/G,)ró  Úforcerò  c          	     óŒ  ‡— |                       d¦  «        st          dddd¬¦  «        ‚	 t          j        |                       dd¦  «        ¦  «                             ¦   «         }n# t
          $ r d	}Y nw xY wt          j        ¦   «         }|s||z
  t          k    r| S | d
         }t          j	        t          j
        |¦  «        d¬¦  «        5 }t          ||› d�d| d         | d         dœdddœ¬¦  «        }|j        dk    r[t          |¦  «        }|                     ¦   «         Št          ˆfd„dD ¦   «         ¦  «        }	t          d|p|j        › �dd|	¬¦  «        ‚	 ddd¦  «         n# 1 swxY w Y   |                     ¦   «         }
|
                      d¦  «        dk    rt          dddd¬¦  «        ‚t          j        t&          j        ¦  «        }t+          t-          |
d         ¦  «        |¬¦  «        }t/          dt-          ||                     ¦   «         z
  ¦  «        ¦  «        }t1          | ¦  «        }|                     |
d         |
                      d| d         ¦  «        |                     ¦   «         t          j        |t&          j        ¬ ¦  «                             ¦   «         |d!œ¦  «         t9          |¦  «         |S )"zBRefresh MiniMax OAuth access token if close to expiry (or forced).rÀ  z:MiniMax OAuth state has no refresh_token; please re-login.r—   Úno_refresh_tokenTr}  rw  r7   r“  rR   )r*  ré  rØ  rT   rw  rÂ  r/  rÃ  r   r<  c              3  ó    •K  — | ]}|‰v V — Œ	d S r…  rY   )râ   r  Ú
body_lowers     €rB   rä   z/_refresh_minimax_oauth_state.<locals>.<genexpr>ž!  s?   øè è € ð ^ð ^¨a˜!˜z˜/ð ^ð ^ð ^ð ^ð ^ð ^rc   )rî  rñ  Úinvalid_refresh_tokenzMiniMax OAuth refresh failed: rt  Nr˜  rÜ  z-MiniMax OAuth refresh did not return success.rÊ  rê  r   r  r’  )r  rÀ  r–  rw  rI  )rg  r|  r   r?  rA  r@   r  Ú"MINIMAX_OAUTH_REFRESH_SKEW_SECONDSr>  r÷  rö  rÀ  r@  r¹  r>   rB  rÎ  r;  r7  r   r8  rÕ  r  r  rb   r¿  r9  r”  rå  )rq  ró  rò  rw  r7  rR   rû  rÓ  rÔ  r  rÁ  Únow_dtrï  rð  Ú	new_staterö  s                  @rB   Ú_refresh_minimax_oauth_staterû  u!  sp  ø€ ð
 �9Š9�_Ñ%Ô%ð 
ÝØHØ$Ð+=ÐPTð
ñ 
ô 
ð 	
ðÝÔ+¨E¯IªI°lÀBÑ,GÔ,GÑHÔH×RÒRÑTÔTˆ
ˆ
øÝð ð ð Øˆ
ˆ
ˆ
ðøøøå
Œ)‰+Œ+€CØð �j 3Ñ&Õ*LÒLÐLØˆàÐ-Ô.€OÝ	Œ�eœm¨OÑ<Ô<Ø'+ð
-ñ 
-ô 
-ð Ø06Ý%ØØÐ,Ð,Ð,à-Ø" ;Ô/Ø!& Ô!7ðð ð !DØ,ðð ð
ñ 
ô 
ˆð" Ô 3Ò&Ð&Ý/°Ñ9Ô9ˆDØŸš™œˆJÝð ^ð ^ð ^ð ^Ø\ð^ñ ^ô ^ñ ^ô ^ˆGåØQ°Ð1O¸Ô9OÐQÐQØ(Ð/?Ø!(ðñ ô ð ð 'ð'ð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð: �mŠm‰oŒo€GØ‡{‚{�8ÑÔ 	Ò)Ð)ÝØ;Ø$Ð+;Ø!ð
ñ 
ô 
ð 	
õ
 Œ\�(œ,Ñ'Ô'€FÝ8ÝˆG�LÔ!Ñ"Ô"¨ðñ ô €Oõ �q�#˜o°×0@Ò0@Ñ0BÔ0BÑBÑCÔCÑDÔD€LÝ�U‘”€IØ×ÒØ Ô/Ø Ÿš _°e¸OÔ6LÑMÔMØ×'Ò'Ñ)Ô)ÝÔ,¨_ÅÄÐNÑNÔN×XÒXÑZÔZØ"ðð ñ ô ð õ ˜YÑ'Ô'Ð'ØÐs$   «:A& Á&A5Á4A5ÃBE*Å*E.Å1E.c                óš  — |j         r|                      d¦  «        sdS dD ]}|                      |d¦  «         Œd|j        pdt	          |¦  «        ddt          j        t          j        ¦  «         	                    ¦   «         dœ| d	<   	 t          | ¦  «         dS # t          $ r&}t                               d
|¦  «         Y d}~dS d}~ww xY w)a  Wipe dead tokens from auth.json after a terminal refresh failure.

    Shared by both the eager-resolve path and the lazy per-request token
    provider. Mirrors the Nous / xAI-OAuth / Codex-OAuth quarantine pattern
    so subsequent calls fail fast without a network retry.
    rÀ  Nrs  r—   rt  ru  Trv  rx  z6MiniMax OAuth: failed to persist quarantined state: %s)r€  rg  rÁ  r  r3   r   r7  r   r8  r9  rå  r@   r  rA  )rq  r  rz  r{  s       rB   Ú-_minimax_oauth_quarantine_on_terminal_refreshrý  ½!  sû   € ð Ô ð  U§Y¢Y¨Ñ%?Ô%?ð ØˆØZð ð ˆØ�	Š	�"�dÑÔÐÐà#Ø”Ð,Ð,Ý�s‘8”8Ø+Ø ÝŒl�8œ<Ñ(Ô(×2Ò2Ñ4Ô4ð ð  €EÐ
ÑðZÝ  Ñ'Ô'Ð'Ð'Ð'øÝð Zð Zð ZÝ�ŠÐMÈyÑYÔYÐYÐYÐYÐYÐYÐYÐYøøøøðZøøøs   Â	B Â
C
Â$CÃC
úCallable[[], str]c                 ó   — dd„} | S )uÍ  Return a zero-arg callable that yields a fresh MiniMax access token.

    The Anthropic SDK caches ``api_key`` as a static string at construction
    time, so a session that resolves credentials once at startup will keep
    sending the same bearer until MiniMax's server returns 401 â€” typically
    ~15 minutes in, because MiniMax issues short-lived access tokens.

    Returning a *callable* instead of a string lets us hook into the
    existing Entra-ID bearer infrastructure in
    :mod:`agent.anthropic_adapter`: ``build_anthropic_client`` detects a
    callable and routes through ``_build_anthropic_client_with_bearer_hook``,
    which mints a fresh ``Authorization`` header on every outbound request.
    Each invocation re-reads the persisted state from ``auth.json`` and
    calls :func:`_refresh_minimax_oauth_state` â€” that helper is a no-op
    when the token still has more than ``MINIMAX_OAUTH_REFRESH_SKEW_SECONDS``
    of life left, so the steady-state cost is one file read + one
    timestamp compare per request.

    Reading state fresh each time also means a refresh persisted by one
    process (CLI, gateway, cron) is immediately visible to every other
    process sharing the same ``auth.json``.
    r4   r3   c                 ó4  — t          d¦  «        } | r|                      d¦  «        st          dddd¬¦  «        ‚	 t          | ¦  «        } n## t          $ r}t	          | |¦  «         ‚ d }~ww xY w|                      d¦  «        }|st          dddd¬¦  «        ‚|S )	Nr—   r  úMNot logged into MiniMax OAuth. Run `hermes model` and select MiniMax (OAuth).Únot_logged_inTr}  z6MiniMax OAuth state has no access_token after refresh.Úno_access_token)rÄ  rg  r|  rû  rý  )rq  r  r  s      rB   Ú_providez4build_minimax_oauth_token_provider.<locals>._provideí!  sÙ   € Ý'¨Ñ8Ô8ˆØð 	˜EŸIšI nÑ5Ô5ð 	Ýð#à(¨ÐQUðñ ô ð ð
	Ý0°Ñ7Ô7ˆEˆEøÝð 	ð 	ð 	Ý9¸%ÀÑEÔEÐEØøøøøð	øøøð —	’	˜.Ñ)Ô)ˆØð 	ÝØHØ(Ð/@ÐSWðñ ô ð ð ˆó   »A Á
A+ÁA&Á&A+©r4   r3   rY   )r  s    rB   Ú"build_minimax_oauth_token_providerr  Ö!  s   € ð.ð ð ð ð* €Orc   )Úmin_token_ttl_secondsÚas_token_providerr  r	  c                óN  — t          d¦  «        }|r|                     d¦  «        st          dddd¬¦  «        ‚	 t          |¦  «        }n## t          $ r}t	          ||¦  «         ‚ d}~ww xY w|rt          ¦   «         }n|d         }d||d                              d	¦  «        d
dœS )u¬  Return {provider, api_key, base_url, source} for minimax-oauth.

    When ``as_token_provider`` is True, ``api_key`` is a zero-arg callable
    that mints a fresh access token per call (proactively refreshing if
    the cached token is within ``MINIMAX_OAUTH_REFRESH_SKEW_SECONDS`` of
    expiry). This is what the runtime provider path uses so that long
    sessions survive MiniMax's short access-token lifetime â€” see
    :func:`build_minimax_oauth_token_provider` for the rationale.

    The default (string ``api_key``) preserves the historical contract for
    diagnostic call sites like ``hermes status`` that just want to know
    whether a valid token exists right now.
    r—   r  r  r  Tr}  NrS   rE   rƒ  rÛ  )rÄ  rg  r|  rû  rý  r  r?   )r  r	  rq  r  rh   s        rB   Ú)resolve_minimax_oauth_runtime_credentialsr  "  så   € õ" $ OÑ4Ô4€EØð 
˜Ÿ	š	 .Ñ1Ô1ð 
Ýðà$¨?ÈTð
ñ 
ô 
ð 	
ð
Ý,¨UÑ3Ô3ˆˆøÝð ð ð Ý5°e¸SÑAÔAÐAØøøøøðøøøð ð (Ý9Ñ;Ô;ˆˆà˜Ô'ˆà#ØØÐ.Ô/×6Ò6°sÑ;Ô;Øð	ð ð r  c                 óÄ  — t          d¦  «        } | r|                      d¦  «        sdddœS 	 t          j        |                      dd¦  «        ¦  «                             ¦   «         }|t          j        ¦   «         z
  dk    }n2# t          $ r% t          |                      d¦  «        ¦  «        }Y nw xY w|d|                      dd	¦  «        |                      d¦  «        d
œS )z3Return auth status dict for MiniMax OAuth provider.r—   r  FrÇ  rw  r7   r   rš   r™   )r"  r~  rš   rw  )rÄ  rg  r   r?  rA  r  r@   r5   )rq  rw  Útoken_valids      rB   rÈ  rÈ  ."  sï   € å# OÑ4Ô4€EØð A˜Ÿ	š	 .Ñ1Ô1ð AØ"°Ð@Ð@Ð@ð6ÝÔ+¨E¯IªI°lÀBÑ,GÔ,GÑHÔH×RÒRÑTÔTˆ
Ø!¥D¤I¡K¤KÑ/°1Ò4ˆˆøÝð 6ð 6ð 6Ý˜5Ÿ9š9 ^Ñ4Ô4Ñ5Ô5ˆˆˆð6øøøð !Ø#Ø—)’)˜H hÑ/Ô/Ø—i’i Ñ-Ô-ð	ð ð s   ­AB Â,B1Â0B1c                ó  — t          | dd¦  «        pd}t          | dd¦  «         }t          | dd¦  «        pd}	 t          |||¬¦  «         dS # t          $ r0}t          t	          |¦  «        ¦  «         t          d	¦  «        ‚d}~ww xY w)
z"CLI entry for MiniMax OAuth login.rš   Nr™   rŽ  Fr*  r#   ræ  r"   )r  rñ  r|  rƒ  rŸ  r‹  )rA  r	  rš   r–  r*  r  s         rB   Ú_login_minimax_oauthr  @"  s³   € å�T˜8 TÑ*Ô*Ð6¨h€FÝ˜t \°5Ñ9Ô9Ð9€LÝ�d˜I tÑ,Ô,Ð4°€GðÝØ¨Àgð	
ñ 	
ô 	
ð 	
ð 	
ð 	
øõ ð ð ð ÝÕ Ñ$Ô$Ñ%Ô%Ð%Ý˜‰mŒmÐøøøøðøøøs   ºA Á
BÁ+BÂB)	rR   rS   rT   rU   r–  ró  r˜  r™  Úon_verificationr  ú$Optional[Callable[[str, str], None]]c        	   
     ó¨	  — t           d         }	| p.t          j        d¦  «        pt          j        d¦  «        p|	j                             d¦  «        } |pt          j        d¦  «        p|	j                             d¦  «        }
|p|	j        }|p|	j        }t          j	        |¦  «        }|rdn|r|nd}t          ¦   «         rd}t          d|	j        › d	�¦  «         t          d
| › �¦  «         |rt          d¦  «         n|rt          d|› d�¦  «         t          j        |ddi|¬¦  «        5 }t          || ||¬¦  «        }t          |d         ¦  «        }t          |d         ¦  «        }t!          |d         ¦  «        }t!          |d         ¦  «        }t          ¦   «          t          d¦  «         t          d|› �¦  «         t          d|› �¦  «         |r5t#          j        |¦  «        }|rt          d¦  «         nt          d¦  «         |�	  |||¦  «         n# t&          $ r Y nw xY wt)          dt+          |t,          ¦  «        ¦  «        }t          d|› d�¦  «         t/          || |t          |d         ¦  «        ||¬ ¦  «        }ddd¦  «         n# 1 swxY w Y   t1          j        t4          j        ¦  «        }t9          |                     dd!¦  «        ¦  «        }|                     ¦   «         |z   }t?          |                     d"¦  «        ¦  «        p|
}||
k    rt          d#|› �¦  «         i d$| “d"|“d%|“d&|                     d&¦  «        p|“d'|                     d'd(¦  «        “d)|d)         “d*|                     d*¦  «        “d+|                      ¦   «         “d,t1          j!        |t4          j        ¬-¦  «                              ¦   «         “d|“d.|du tE          |t          ¦  «        r|ndd/œ“d0d“d1d“d2d“d3d“d4d“d5d“}	 tG          ||d¬6¦  «        S # tH          $ rª}|j%        d7k    r™|                     d$tL          ¦  «                             d¦  «        }tO          |¦  «        }t          ¦   «          t          |¦  «         t          d8|› d9�¦  «         t          ¦   «          t          d:¦  «         tQ          d¦  «        ‚‚ d}~ww xY w);zMRun the Nous device-code flow and return full OAuth state without persisting.rd   r`  ra  rE   r\  FTzStarting Hermes login via z...rè  z'TLS verification: disabled (--insecure)z$TLS verification: custom CA bundle (r@  rÄ  r/  r  )rû  rR   rT   rU   r®  r¬  rI  r¯  rŽ  r�  r�  r‘  u=     Could not open browser automatically â€” use the URL above.Nr"   r“  r”  r%   )rû  rR   rT   r%   rI  rP  r   rS   z%Using portal-provided inference URL: rR   rT   rU   rÍ  rÎ  r  rÀ  r–  rw  r’  rœ  r  r™  rš  r›  rœ  r�  r˜  )ró  rÛ  r—  z  Subscribe here: z/billingz<After subscribing, run `hermes model` again to finish setup.))rÖ   r´  rµ  rR   r?   rS   rT   rU   r>  rö  r†  rƒ  rP   r÷  rµ  r3   r  r‡  r  r@   r  rb  rÀ  rÅ  r   r7  r   r8  rL  rg  rA  rO  r9  r”  r  r  r|  r  rT  rŸ  r‹  )rR   rS   rT   rU   r–  ró  r˜  r™  r  r	  Úrequested_inference_urlr*  r  rû  r•  r–  r¬  rI  r¯  r™  Úeffective_intervalrî  r7  Útoken_expires_inrw  Úresolved_inference_urlrš  r  rS  r�  s                                 rB   Ú_nous_device_code_loginr  N"  s  € õ   Ô'€Gàð 	#ÝŒ9Ð-Ñ.Ô.ð	#åŒ9Ð+Ñ,Ô,ð	#ð Ô"ß‚fˆS�k„kð ð 	ð 	&ÝŒ9Ð.Ñ/Ô/ð	&àÔ%ß‚fˆS�k„kð	 ð
 Ð.˜WÔ.€IØÐ"�W”]€EÝŒm˜OÑ,Ô,€GØ"*ÐR˜˜¸iÐ1Q°°ÈT€FåÑÔð Øˆå	Ð
8 w¤|Ð
8Ð
8Ð
8Ñ9Ô9Ð9Ý	Ð
&�_Ð
&Ð
&Ñ'Ô'Ð'Øð CÝÐ7Ñ8Ô8Ð8Ð8Ø	ð CÝÐA°YÐAÐAÐAÑBÔBÐBå	Œ˜g°Ð:LÐ/MÐV\Ð	]Ñ	]Ô	]ð -
ÐagÝ*ØØ+ØØð	
ñ 
ô 
ˆõ ˜{Ð+FÔGÑHÔHÐÝ˜ KÔ0Ñ1Ô1ˆ	Ý˜ \Ô2Ñ3Ô3ˆ
Ý�{ :Ô.Ñ/Ô/ˆå‰ŒˆÝˆnÑÔÐÝÐ.Ð,Ð.Ð.Ñ/Ô/Ð/ÝÐ:¨yÐ:Ð:Ñ;Ô;Ð;àð 	WÝ”_Ð%5Ñ6Ô6ˆFØð WÝÐ;Ñ<Ô<Ð<Ð<åÐUÑVÔVÐVð Ð&ðØ�Ð 0°)Ñ<Ô<Ð<Ð<øÝð ð ð Ø�ðøøøõ ! ¥C¨Õ2WÑ$XÔ$XÑYÔYÐÝÐNÐ5GÐNÐNÐNÑOÔOÐOå$ØØ+ØÝ˜K¨Ô6Ñ7Ô7Ø!Ø"ð
ñ 
ô 
ˆ
ðM-
ð -
ð -
ñ -
ô -
ð -
ð -
ð -
ð -
ð -
ð -
øøøð -
ð -
ð -
ð -
õ^ Œ,•x”|Ñ
$Ô
$€CÝ*¨:¯>ª>¸,ÈÑ+JÔ+JÑKÔKÐØ—’‘”Ð#3Ñ3€Jå˜:Ÿ>š>Ð*>Ñ?Ô?Ñ@Ô@ð 	#Ø"ð ð Ð!8Ò8Ð8ÝÐNÐ6LÐNÐNÑOÔOÐOðØ˜?ðàÐ4ðð 	�Yðð 	�—’ Ñ(Ô(Ð1¨Eð	ð
 	�j—n’n \°8Ñ<Ô<ðð 	˜
 >Ô2ðð 	˜Ÿš¨Ñ8Ô8ðð 	�s—}’}‘”ðð 	•hÔ,¨Z½H¼LÐIÑIÔI×SÒSÑUÔUðð 	Ð&ðð 	Ø %˜Ý#-¨fµcÑ#:Ô#:ÐD˜˜Àð
ð 
ðð 	�Tðð  	˜ð!ð" 	 ð#ð$ 	 ð%ð& 	˜Dð'ð( 	  ð)€Jð,Ý,ØØ+Øð
ñ 
ô 
ð 	
øõ
 ð ð ð ØŒ8Ð.Ò.Ð.Ø#ŸšØ!Õ#:ñô çŠf�S‰kŒkð õ (¨Ñ,Ô,ˆGÝ‰GŒGˆGÝ�'‰NŒNˆNÝÐ; zÐ;Ð;Ð;Ñ<Ô<Ð<Ý‰GŒGˆGÝÐPÑQÔQÐQÝ˜Q‘-”-ÐØøøøøðøøøsQ   Ä,C"JÈHÈJÈ
H)È&JÈ(H)È)A!JÊJÊJÐP Ð
SÐ'B%SÓSc                 óØ   — 	 t          d¦  «        pi } n# t          $ r Y dS w xY w|                      d¦  «        }t          |t          ¦  «        sdS t
          |                     ¦   «         v S )a•  Return True if the currently-held Nous token carries ``billing:manage``.

    Reads the persisted ``scope`` string saved at login (``_save_provider_state``
    stores ``token_data.get("scope") or scope``). A space-delimited match. Used by
    the lazy step-up: if False, the first billing call will 403 ``insufficient_scope``
    anyway, but checking up front lets a surface skip a doomed round-trip.
    rd   FrU   )rÄ  r@   rg  r  r3   ÚNOUS_BILLING_MANAGE_SCOPErÙ  )rq  rU   s     rB   Únous_token_has_billing_scoper  Ú"  sx   € ðÝ'¨Ñ/Ô/Ð5°2ˆˆøÝð ð ð Øˆuˆuðøøøà�IŠI�gÑÔ€EÝ�e�SÑ!Ô!ð ØˆuÝ$¨¯ª©¬Ð5Ð5s   ‚ ”
"¡")r–  ró  r  c           	     óì  — t          d¦  «        pi }t          d         }|                     d¦  «        }t          |t          ¦  «        r|nd}g }|                     ¦   «         pt          dgD ]}|r||vr|                     |¦  «         Œt          |vr|                     t          ¦  «         d 	                    |¦  «        }	t          |                     d¦  «        pd|                     d¦  «        pd|                     d	¦  «        p|j        |	| ||¬
¦  «        }
t          ¦   «         5  t          ¦   «         }t          |d|
¦  «         t          |¦  «         ddd¦  «         n# 1 swxY w Y   	 t!          |
¦  «         n# t"          $ r Y nw xY w	 t%          ¦   «          n# t"          $ r Y nw xY w|
                     d¦  «        }t          |t          ¦  «        ot          |                     ¦   «         v S )u™  Re-run the device flow requesting ``billing:manage`` and persist the result.

    The lazy step-up (plan D-A): triggered when a billing endpoint returns
    ``403 insufficient_scope``. Runs a fresh device-connect with
    ``inference:invoke tool:invoke billing:manage`` on the scope. The user must be
    an ADMIN/OWNER and select "Allow Remote Spending" in the portal for the minted
    token to actually carry the scope; otherwise the server silently downscopes and this
    returns False.

    Reuses the held credential's portal/inference URLs + client_id so the step-up
    targets the same deployment (incl. a preview via ``HERMES_PORTAL_BASE_URL`` set
    at the original login). Persists to the auth store + shared store + pool, exactly
    like ``_login_nous`` â€” but WITHOUT the model picker (this is a scope upgrade, not
    a fresh login).

    Returns True iff the new token carries ``billing:manage``.
    rd   rU   r7   ztool:invoker-   rR   NrS   rT   )rR   rS   rT   rU   r–  ró  r  )rÄ  rÖ   rg  r  r3   rÙ  r€  r°  r  rð  r  rT   rl  re  re  rn  rã  r@   rO  )r–  ró  r  Úpriorr	  Ú
_raw_scopeÚprior_scoperù  ÚtokrU   rš  rp  Úgranteds                rB   Ústep_up_nous_billing_scoper!  ì"  s]  € õ. $ FÑ+Ô+Ð1¨r€EÝ Ô'€Gð —’˜7Ñ#Ô#€JÝ *¨:µsÑ ;Ô ;ÐC�*�*À€KØ€IØ×!Ò!Ñ#Ô#ÐSÕ(CÀ]Ð'Sð "ð "ˆØð 	"�3˜iÐ'Ð'Ø×Ò˜SÑ!Ô!Ð!øÝ ¨	Ð1Ð1Ø×ÒÕ2Ñ3Ô3Ð3Ø�HŠH�YÑÔ€Eå(ØŸ	š	Ð"3Ñ4Ô4Ð<¸Ø Ÿ9š9Ð%9Ñ:Ô:ÐB¸dØ—)’)˜KÑ(Ô(Ð=¨GÔ,=ØØ!Ø'Ø'ðñ ô €Jõ 
Ñ	Ô	ð %ð %Ý%Ñ'Ô'ˆ
Ý˜Z¨°Ñ<Ô<Ð<Ý˜Ñ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %ðÝ  Ñ,Ô,Ð,Ð,øÝð ð ð ØˆðøøøðÝ'Ñ)Ô)Ð)Ð)øÝð ð ð Øˆðøøøð �nŠn˜WÑ%Ô%€GÝ�g�sÑ#Ô#ÐTÕ(AÀWÇ]Â]Á_Ä_Ð(TÐTs6   Ä*/E%Å%E)Å,E)Å1F Æ
FÆFÆF! Æ!
F.Æ-F.c                ó  — t          | dd¦  «        pd}t          t          | dd¦  «        ¦  «        }t          | dd¦  «        p't          j        d¦  «        pt          j        d¦  «        }	 d}t	          ¦   «         }|rÖ	 t          ¦   «         }n# t          $ r d}Y nw xY wt          ¦   «          |rt          d	|› �¦  «         nt          d
¦  «         	 t          d¦  «         	                    ¦   «          
                    ¦   «         }n# t          t          f$ r d}Y nw xY w|dv r0t          d¦  «         t          |¬¦  «        }|€t          d¦  «         |€jt          t          | dd¦  «        t          | dd¦  «        t          | dd¦  «        p|j        t          | dd¦  «        t          | dd¦  «         |||¬¦  «        }|d         }	t!          ¦   «         5  t#          ¦   «         }
|
                     d¦  «        }ddd¦  «         n# 1 swxY w Y   t!          ¦   «         5  t#          ¦   «         }t'          |d|¦  «         t)          |¦  «        }ddd¦  «         n# 1 swxY w Y   t+          |¦  «         t-          ¦   «          t          ¦   «          t          d¦  «         t          d|› �¦  «         d}	 |                     d¦  «        p|                     d¦  «        }t/          |t0          ¦  «        r|st3          ddd¬ ¦  «        ‚d!d"lm}m}m}m}m}m }  |¦   «         }t          ¦   «          g }d#}|r˜ |d¦  «        } |d$¬%¦  «        }|                     d&d#¦  «        }|rY	 d!d'l!m"}m#}  |d$¬%¦  «        } ||d(¬)¦  «        pd#}n# tH          $ r d#}Y nw xY w ||||¦  «        \  }} |||d$¬*¦  «        \  }}n ||||¦  «        \  }}|                     d&d#¦  «        }|r8t          d+tK          |¦  «        › d,�¦  «         tM          |||||d|	|¬-¦  «        }nR|rA|ptN           (                    d.¦  «        } t          d/¦  «         t          |pd0| › d1�¦  «         nt          d2¦  «         nj# tH          $ r]}!t/          |!t2          ¦  «        rtS          |!¦  «        nt1          |!¦  «        }"t          ¦   «          t          d3|"› �¦  «         Y d}!~!nd}!~!ww xY w|s�t!          ¦   «         5  t#          ¦   «         }|r||d<   n| *                    dd¦  «         t)          |¦  «         ddd¦  «         n# 1 swxY w Y   t          ¦   «          t          d4¦  «         t          d5¦  «         dS tW          d|	|¬6¦  «        }#|r!tY          |¦  «         t          d7|› �¦  «         t          d8|#› d9�¦  «         dS # t          $ r t          d:¦  «         t[          d;¦  «        ‚tH          $ r&}!t          d<|!› �¦  «         t[          d=¦  «        ‚d}!~!ww xY w)>z&Nous Portal device authorization flow.r*  Nr#   r˜  Fr™  rŸ  r   z)Found existing Nous OAuth credentials at z,Found existing shared Nous OAuth credentialsz!Import these credentials? [Y/n]: rû  >   r7   rû  r²  z3Rehydrating Nous session from shared credentials...rH  uK   Could not refresh shared credentials â€” falling back to device-code login.rS  Úinference_urlrT   rU   rŽ  )rR   rS   rT   rU   r–  ró  r˜  r™  rS   r'  rd   rr  r‘  r™  r  z,No runtime API key available to fetch modelsrï  r®  r   )Úget_curated_nous_model_idsÚget_pricing_for_providerÚcheck_nous_free_tierÚpartition_nous_models_by_tierÚ&union_with_portal_free_recommendationsÚ&union_with_portal_paid_recommendationsr7   Tr¤  rR   r¡  zpaid Nous modelsr¦  )Ú	free_tierzShowing u=    curated models â€” use "Enter custom model name" for others.)rþ  r   rS  r  r  r  r  rE   z#No free models currently available.r7  z to access paid models.z,No curated models available for Nous Portal.z?Login succeeded, but could not fetch available models. Reason: z:No provider change. Nous credentials saved for future use.z4  Run `hermes model` again to switch to Nous Portal.)rå  zDefault model set to: rs  z (model.provider=nous)r�  rž  zLogin failed: r"   ).r  r5   r´  rµ  rÓ  rÎ  rÌ  rƒ  rˆ  rG   r>   r‰  rŠ  r  r  rT   rl  re  rg  re  rn  rã  rO  r  r3   r|  rA  r$  r%  r&  r'  r(  r)  r¨  r¢  r£  r@   r  ri  rT  r?   rŸ  rÁ  rí  rl  r‹  )$rA  r	  ró  r˜  r™  rš  rÈ  Úshared_pathrz  rS   Ú_prior_storeÚprior_active_providerrp  rœ  Úselected_modelr‡  r$  r%  r&  r'  r(  r)  r+  r   r  rþ  r*  Ú_portal_for_recsr¢  r£  Ú_account_infoÚ_portalÚ_urlr  r�  ré  s$                                       rB   Ú_login_nousr3  /#  sÉ  € å˜d I¨tÑ4Ô4Ð<¸€OÝ•G˜D *¨eÑ4Ô4Ñ5Ô5€Hå��k 4Ñ(Ô(ð 	&ÝŒ9Ð'Ñ(Ô(ð	&åŒ9�_Ñ%Ô%ð ðØˆ
õ
 )Ñ*Ô*ˆØð 	ið#Ý5Ñ7Ô7��øÝð #ð #ð #Ø"���ð#øøøå‰GŒGˆGØð FÝÐOÀ+ÐOÐOÑPÔPÐPÐPåÐDÑEÔEÐEð Ý!Ð"EÑFÔF×LÒLÑNÔN×TÒTÑVÔV�	�	øÝÕ/Ð0ð  ð  ð  Ø�	�	�	ð øøøàÐ,Ð,Ð,ÝÐKÑLÔLÐLÝ:Ø$3ðñ ô �
ð Ð%ÝÐgÑhÔhÐhàÐÝ0Ý '¨¨l¸DÑ AÔ AÝ#*¨4°À$Ñ#GÔ#GÝ! $¨°TÑ:Ô:ÐO¸gÔ>OÝ˜d G¨TÑ2Ô2Ý!(¨¨|¸UÑ!CÔ!CÐCØ /Ø!Ø#ð	ñ 	ô 	ˆJð (Ð(<Ô=Ðõ ÑÔð 	Hð 	HÝ+Ñ-Ô-ˆLØ$0×$4Ò$4Ð5FÑ$GÔ$GÐ!ð	Hð 	Hð 	Hñ 	Hô 	Hð 	Hð 	Hð 	Hð 	Hð 	Hð 	Høøøð 	Hð 	Hð 	Hð 	Hõ ÑÔð 	4ð 	4Ý)Ñ+Ô+ˆJÝ  ¨V°ZÑ@Ô@Ð@Ý'¨
Ñ3Ô3ˆHð	4ð 	4ð 	4ñ 	4ô 	4ð 	4ð 	4ð 	4ð 	4ð 	4ð 	4øøøð 	4ð 	4ð 	4ð 	4õ 	! Ñ,Ô,Ð,Ý'Ñ)Ô)Ð)å‰ŒˆÝÐ!Ñ"Ô"Ð"ÝÐ)˜xÐ)Ð)Ñ*Ô*Ð*ð ˆðS	_Ø$Ÿ.š.¨Ñ5Ô5ÐW¸¿ºÈÑ9WÔ9WˆKÝ˜k­3Ñ/Ô/ð °{ð ÝØBØ#Ø(ðñ ô ð ðð ð ð ð ð ð ð ð ð ð ð ð ð ð ð ð 3Ð2Ñ4Ô4ˆIå‰GŒGˆGØ')ÐØ"$ÐØð )Ø2Ð2°6Ñ:Ô:�ð 1Ð0¸TÐBÑBÔB�	Ø#-§>¢>Ð2CÀRÑ#HÔ#HÐ Øð #ð1ðð ð ð ð ð ð ð ð
 )EÐ(DÐQUÐ(VÑ(VÔ(V˜àBÐBØ -Ø+=ðñ ô ð "ð  "ð ,Ð+øõ %ð 1ð 1ð 1Ø.0Ð+Ð+Ð+ð1øøøð *PÐ)OØ! 7Ð,<ñ*ô *Ñ&�I˜wð 5RÐ4QØ! 7°dð5ñ 5ô 5Ñ1�IÐ1Ð1ð *PÐ)OØ! 7Ð,<ñ*ô *Ñ&�I˜wð !—n’nÐ%6¸Ñ;Ô;ˆGØð FÝÐp¥ Y¡¤ÐpÐpÐpÑqÔqÐqÝ!8Ø wØ'9Ø&Ø(;Ø%+Ø%7Ø$/ð"ñ "ô "��ð $ð FØÐ:Õ#:×BÒBÀ3ÑGÔG�ÝÐ;Ñ<Ô<Ð<ÝÐ)ÐXÐ-X¸4Ð-XÐ-XÐ-XÑYÔYÐYÐYåÐDÑEÔEÐEøøÝð 	_ð 	_ð 	_Ý0:¸3Å	Ñ0JÔ0JÐXÕ'¨Ñ,Ô,Ð,ÕPSÐTWÑPXÔPXˆGÝ‰GŒGˆGÝÐ]ÐT[Ð]Ð]Ñ^Ô^Ð^Ð^Ð^Ð^Ð^Ð^øøøøð	_øøøð ð 	õ "Ñ#Ô#ð -ð -Ý-Ñ/Ô/�
Ø(ð <Ø4I�JÐ0Ñ1Ð1à—N’NÐ#4°dÑ;Ô;Ð;Ý  Ñ,Ô,Ð,ð-ð -ð -ñ -ô -ð -ð -ð -ð -ð -ð -øøøð -ð -ð -ð -õ ‰GŒGˆGÝÐNÑOÔOÐOÝÐHÑIÔIÐIØˆFå1ØÐ&°nð
ñ 
ô 
ˆð ð 	=Ý˜~Ñ.Ô.Ð.ÝÐ;¨>Ð;Ð;Ñ<Ô<Ð<ÝÐF ;ÐFÐFÐFÑGÔGÐGÐGÐGøåð ð ð ÝÐ"Ñ#Ô#Ð#Ý˜‰oŒoÐÝð ð ð ÝÐ$˜sÐ$Ð$Ñ%Ô%Ð%Ý˜‰mŒmÐøøøøðøøøs&  Á,V5 Á?B ÂV5 ÂBÂV5 ÂBÂ5V5 Ã3D ÄV5 ÄDÄV5 ÄDÄB9V5 Ç$HÇ:V5 ÈH
È
V5 ÈH
ÈV5 È/IÉV5 ÉIÉV5 É!IÉ"AV5 Ê4B0Q0 Í%#N	 ÎQ0 Î	NÎQ0 ÎNÎCQ0 Ñ/V5 Ñ0
SÑ:ASÓV5 ÓSÓV5 Ó*<T2Ô&V5 Ô2T6Ô6V5 Ô9T6Ô:/V5 Õ+AV5 Ö51X×&!XØXc                óR  — t          | dd¦  «        }|r0t          |¦  «        s!t          d|› �¦  «         t          d¦  «        ‚t	          ¦   «         }|p|pt          ¦   «         }|st          d¦  «         dS t          |¦  «        }t          |¦  «        }t          |¦  «        s|rn|rt          ¦   «          t          d|› d�¦  «         |r%t          j        d¦  «        rt          d	¦  «         dS |rt          d
¦  «         dS t          d¦  «         dS t          d|› d�¦  «         dS )z Clear auth state for a provider.r~  NzUnknown provider: r"   z#No provider is currently logged in.zLogged out of r8   r!  z)Hermes will use OpenRouter for inference.z9Run `hermes model` or configure an API key to use Hermes.z+Model provider configuration was unchanged.zNo auth state found for )r  rs  rƒ  r‹  rÇ  rõ  ró  ru  rå  r÷  r´  rµ  )rA  r  rÚ  rã  Úshould_reset_configrè  s         rB   Úlogout_commandr6  û#  sp  € å˜$ 
¨DÑ1Ô1€Kàð Õ1°+Ñ>Ô>ð ÝÐ0 ;Ð0Ð0Ñ1Ô1Ð1Ý˜‰mŒmÐå Ñ"Ô"€FØÐL˜FÐLÕ&JÑ&LÔ&L€Fàð ÝÐ3Ñ4Ô4Ð4ØˆåAÀ&ÑIÔIÐÝ2°6Ñ:Ô:€Må˜6Ñ"Ô"ð ;Ð&9ð ;Øð 	%Ý"Ñ$Ô$Ð$ÝÐ/˜}Ð/Ð/Ð/Ñ0Ô0Ð0Øð 	A¥2¤9Ð-AÑ#BÔ#Bð 	AÝÐ=Ñ>Ô>Ð>Ð>Ð>Ø ð 	AÝÐMÑNÔNÐNÐNÐNåÐ?Ñ@Ô@Ð@Ð@Ð@åÐ9¨Ð9Ð9Ð9Ñ:Ô:Ð:Ð:Ð:rc   )r2   r3   r4   r5   )r2   r3   r4   r3   r  )rh   r3   rí   r3   rî   r3   r4   r3   )rë   r   r   r  r4   r5   )r  r3   r	  rN   r4   r
  )rh   r3   r)  rZ   r*  r+  r4   r,  )rF  )rh   r3   r*  r+  r4   r,  )r‹  r@   r4   r5   )r:  r   r4   r�  )r‹  r@   r4   r3   )r‹  r|  r4   r3   )r  r   r4   r‚  )r4   r5   )r¹  r3   r¸  r‚  rº  r   r4   rƒ  )r4   r   )r4   rÐ  )r4   rW   )rä  r   rå  r   r4   r5   )ré  r   r4   rê  )rñ  r   rò  rê  ró  r+  rô  r3   )ró  r+  ré  rÐ  r…  )r  rÐ  r4   rW   )rp  rW   ré  rÐ  r4   r   )rp  rW   r  r3   r4   rP  )r  r3   )rp  rW   r  r3   r4   r_  )rp  rW   r  r3   rq  rW   r4   rƒ  )
rp  rW   r  r3   rq  rW   rX  rÐ  r4   rƒ  )
rp  rW   r  r3   rq  rW   rd  r5   r4   rƒ  )
r  r3   rq  rW   ré  r   rd  r5   r4   r   )r  r3   r4   rƒ  )r  r3   r4   r5   )r  r3   r4   r3   )r  r‚  r4   rW   )r#  rW   rŒ  r_  r  r3   r4   rW   )r  r3   r   r¡  rŸ  r¢  r4   r   )r  r3   r  r3   r4   rƒ  )r  r3   r  r3   r4   r5   )r  r3   r4   r_  )r4   r‚  )r  r‚  r4   r5   rD  )rè  r3   r4   r3   )rù  r‚  r÷  r‚  rø  r‚  r4   r3   rD  )rD  r   rE  r  r4   r5   )rI  r   r4   r  )rë   r   r4   r‚  )r   rW   r4   rƒ  )rJ   r‚  r4   r‚  )r  r   r4   rW   )rk  r   r4   rl  )
r  r   rU   r   rw  r   rx  r  r4   r‚  )
r  r   rU   r   rw  r   rx  r  r4   r5   )rq  rW   r  r   r4   rƒ  )r  r   r¸  r‚  r4   rƒ  )r  r   r�  r   r4   r‚  )rq  rW   r–  r‚  r4   rƒ  )rq  rW   r  r   r¸  r‚  r4   rƒ  )rq  rW   r4   rW   )r  r   rE  r  r4   r5   )r´  rW   r4   r   )r¹  r   rE  r  r4   r5   )r¾  )r´  rW   ró  r+  r4   rW   )rØ  rW   r4   rƒ  )rÛ  r5   rÜ  r5   rÝ  r  r4   rW   )rk  r‚  r4   rç  )rk  r‚  r4   r3   rR  )rñ  r‚  rq  r_  r4   r3   )rq  r_  r4   r3   )r  )r  r  r4   r3   )r  r3   r4   r3   )rT   r3   rÿ  r3   rU   r3   rq  r3   r%  r3   r
  r3   r4   r3   )rÿ  r3   r4   r,  )r2  r3   r4   r3  )rÿ  r3   ró  r+  r4   rI  )r_  rW   rT   r3   rÿ  r3   r`  r3   r
  r3   r  r3   r^  r_  r4   rW   )rT   r3   r  r3   rÿ  r3   r  r3   r
  r3   ró  r+  r4   rW   )rq  rW   ró  r+  r4   rW   )r€  r3   r4   r3   )rÿ  r3   r�  rÆ  r4   rƒ  )rË  r5   r4   rW   )
rp  rW   r´  r0   rÓ  r‚  r×  r,  r4   rƒ  )r´  r0   rÓ  r3   r=  r3   r4   rƒ  )r‰  r3   r4   r,  )r  r3   rÀ  r3   ró  r+  r4   rW   )r´  r0   ró  r+  r4   r0   )r4   r,  )r  r   r‰  r   r�  r   r4   r5   )r2   r‚  r4   r3   )r  r   r2   r‚  r0  r+  r4   r1  )r  r‚  r4   r  )r4   r_  )rp  rW   r4   r_  )rq  r_  r4   r5   )rp  rW   r4   r5   )rq  rW   r4   rƒ  )r´  rW   rR  r_  rÿ  r3   rÓ  r‚  rÞ  r3   rd  r5   r4   rƒ  rL  )r  r3   rE  r  r4   r5   )r  r3   r4   r  )rJ   r3   r   r3   r4   r3   )rë   r3   ri  r3   r4   r3   )r#   )ró  r+  r4   r0   )
r  r3   rÀ  r3   rq  r3   ró  r+  r4   rW   )
r´  rW   rq  r3   rÿ  r3   ró  r+  r4   rW   )rÛ  r5   rÜ  r5   rÝ  r�  r4   rW   )r4   r�  )r˜  r1  r™  r‚  rš  r_  r4   r�  )
rû  r¨  rR   r3   rT   r3   rU   r‚  r4   rW   )rR   r3   r4   r3   )rû  r¨  rR   r3   rT   r3   r%   r3   rI  r  rP  r  r4   rW   )ró  r+  )rq  rW   r4   r5   rp  )r  r@   r4   r5   )rq  rW   r‹  r|  r‰  r3   r4   rƒ  )rp  rW   r‹  r|  r‰  r3   r4   r5   )ró  r+  r4   r_  )
rû  r¨  rR   r3   rT   r3   rÀ  r3   r4   rW   )
rS   r3   rh   r3   ró  r+  r  r  r4   rç  )rq  rW   rx  r  r4   r5   )
ró  r+  r˜  r1  r™  r‚  rÝ  r  r4   r3   )"r  r3   rÀ  r3   rT   r3   rR   r3   rS   r3   rÍ  r3   rU   r3   r–  r‚  rw  r‚  r™  r‚  r›  r‚  ró  r+  r˜  r1  r™  r‚  rÛ  r5   r  rA  r4   rW   )
rq  rW   ró  r+  rÛ  r5   r  rA  r4   rW   )rØ  rW   r=  r‚  )
ró  r+  r˜  r1  r™  r‚  rÛ  r5   r4   rW   )r4   rŒ  )r  r3   r4   rW   )r  r3   rS   r3   rå  r‚  r4   r   )
r,  r3   r~  r3   r2   r3   rh   r3   r4   r5   )r7   NNr7   r7   r7   r7   r7   )r+  rç  rë  r3   rþ  rÿ  r   r  rS  r3   r  r3   r  r3   r  r3   r  r3   r4   r‚  )r,  r3   r4   rƒ  )r	  rN   ro  r5   r4   rƒ  )rû  r¨  rU   r3   r4   rW   )rû  r¨  rq  r3   r%   r3   rI  r  rP  r  r4   rW   )ró  r+  r–  r5   r4   rW   )rÓ  r°  r¯  r  r4   r3   )
rû  r¨  rJ   r3   r²  rW   r:  r0   r4   r°  )r4   rZ   )rû  r¨  rR   r3   rT   r3   r%  r3   rq  r3   r4   rW   )rÊ  r  rÐ  r  r4   r5   )rÊ  r  r7  r   r4   r+  )rû  r¨  rR   r3   rT   r3   r¬  r3   r  r3   rÊ  r  rÖ  r�  r4   rW   )rš  rW   r4   rƒ  )rš   r3   r–  r5   ró  r+  r4   rW   )rq  rW   ró  r+  rò  r5   r4   rW   )rq  rW   r  r|  r4   rƒ  )r4   rþ  )r  r  r	  r5   r4   rW   )r	  rN   r4   rƒ  )rR   r‚  rS   r‚  rT   r‚  rU   r‚  r–  r5   ró  r+  r˜  r5   r™  r‚  r  r  r4   rW   )r–  r5   ró  r+  r  r  r4   r5   (  r`   Ú
__future__r   r;  Úloggingr´  r+  rÂ  r“  r  r¸  rf  rh  rG  rî  r  r<  r‡  Ú
contextlibr   Údataclassesr   r   r   r   Úhttp.serverr	   r
   Úpathlibr   Útypingr   r   r   r   r   r   r   r   Úurllib.parser   r   r   r>  ré   r   r   r   r   rÔ  r   r   Úagent.credential_persistencer   Úutilsr   r   r    r!   Ú	getLoggerr]   r  rÿ  r@   r   r(  r  rT  rá  rà  r€  r  rß  r  rq  Ú!ACCESS_TOKEN_REFRESH_SKEW_SECONDSÚNOUS_INVOKE_JWT_MIN_TTL_SECONDSrÀ  r  r‡  ÚMINIMAX_OAUTH_CLIENT_IDrÍ  rà  ÚMINIMAX_OAUTH_GLOBAL_BASEÚMINIMAX_OAUTH_CN_BASEÚMINIMAX_OAUTH_GLOBAL_INFERENCEÚMINIMAX_OAUTH_CN_INFERENCErø  râ  ÚDEFAULT_GITHUB_MODELS_BASE_URLÚDEFAULT_COPILOT_ACP_BASE_URLÚDEFAULT_OLLAMA_CLOUD_BASE_URLrH   ÚDEFAULT_ACTUAL_LOCAL_BASE_URLÚSTEPFUN_STEP_PLAN_INTL_BASE_URLÚSTEPFUN_STEP_PLAN_CN_BASE_URLrú  rù  Ú
hermes_clir*   Ú_HERMES_CLI_VERSIONrø  Ú'CODEX_ACCESS_TOKEN_REFRESH_SKEW_SECONDSÚXAI_OAUTH_ISSUERrs  r~  ÚXAI_OAUTH_SCOPEr…  ra  rÒ  rÑ  Ú&QWEN_ACCESS_TOKEN_REFRESH_SKEW_SECONDSr  r  r   r„  r…  Ú)SPOTIFY_ACCESS_TOKEN_REFRESH_SKEW_SECONDSrÈ  rð  rê  r1   ra   rÜ  rÝ  rC   rL   rN   rÖ   r   rØ   Ú_list_providers_for_registryr,  rP   rQ   Úenv_varsrZ   Ú_api_key_varsrL  Ú_base_url_varÚdisplay_namer2   r&  r-  rì   rñ   rò   r  r  r%  rT  rE  r]  ru  ry  r�  rÌ  r|  r�  r•  rŸ  rž  r­  r·  rÂ  rÏ  r×  rÞ  râ  rã  ÚLockrì  rè  rð  r  rl  re  rn  rV  r^  rf  re  ri  rm  rg  rn  rs  ru  rz  r…  r•  rž  r¶  r¼  r¾  rÂ  rÄ  rÇ  rá  rå  rç  rö  ry  rC  rH  rL  rO  rq  rP  rR  r-  rV  rZ  r^  rb  rj  rr  r‚  r„  rŠ  r�  r•  r   r¢  r¥  r§  r©  r«  r³  r¸  r½  r×  rÚ  rä  ræ  rî  rð  rû  r  r  r  r  r  r"  r$  r+  r1  rF  r]  rd  rk  rp  r|  r  rŒ  r�  r†  r®  r“  rÅ  r’  rÕ  rÛ  rß  rã  r  r
  rá  r#  r,  Ú&CODEX_QUOTA_PROBE_MIN_INTERVAL_SECONDSr-  r8  r/  r  r  r  r  rJ  rL  rS  rU  rW  r[  r_  rd  rh  rk  rt  r  r�  rŒ  r–  r§  rµ  r¸  rÅ  rÌ  rï  rÐ  rÊ  rÎ  rÑ  rÚ  rã  rÓ  ré  rí  r†  rð  rÿ  r  r  r  r-  r/  r6  r0  r7  r?  rH  r  rM  rO  rv  r{  rŠ  r’  r‹  r�  rú  r™  r“  r¢  r§  r¦  r¥  r¨  r®  r°  r¸  rÅ  r'  rÉ  rà  rä  rí  rï  rñ  ró  rõ  r÷  rý  ri  rl  rn  r|  r€  r‡  rŒ  r  rw  Ú_MINIMAX_OAUTH_ERROR_BODY_LIMITr¹  rÀ  rÇ  rÏ  rÒ  rÕ  rã  rå  rñ  rû  rý  r  r  rÈ  r  r  r  r!  r3  r6  rY   rc   rB   ú<module>r^     s&  ððð ð ð$ #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø €€€Ø €€€Ø 
€
€
€
Ø €€€Ø 
€
€
€
Ø €€€Ø €€€Ø Ð Ð Ð Ø Ð Ð Ð Ø €€€Ø €€€Ø Ð Ð Ð Ø %Ð %Ð %Ð %Ð %Ð %Ø (Ð (Ð (Ð (Ð (Ð (Ð (Ð (Ø 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ø :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ø Ð Ð Ð Ð Ð Ø RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RÐ RØ 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6Ð 6à €€€ðð ð ð ð ð ð ð ð ð ð ð ð DÐ CÐ CÐ CÐ CÐ CÐ CÐ CØ MÐ MÐ MÐ MÐ MÐ MØ OÐ OÐ OÐ OÐ OÐ OÐ OÐ OÐ OÐ OÐ OÐ Oà	ˆÔ	˜8Ñ	$Ô	$€ðØ€L€L€L€LøØð ð ð Ø€E€E€EðøøøðØ€M€M€M€MøØð ð ð Ø€F€F€Fðøøøð Ð Ø Ð ð <Ð ØHÐ Ø%Ð Ø0Ð Ø,Ð Ø0Ð Ø'Ð Ø(Ð Ø$'Ð !Ø"CÐ Ø()Ð %Ø@Ð Ø2Ð Ø@Ð Ø9Ð ØGÐ Ø4Ð Ø2Ð Ø!CÐ ØAÐ Ø%'Ð "Ø3Ð Ø!@Ð Ø.Ð Ø 7Ð Ø5Ð Ø :Ð Ø"GÐ Ø FÐ Ø6Ð Ø=Ð ð$Ø=Ð=Ð=Ð=Ð=Ð=Ð=øØð $ð $ð $Ø#ÐÐÐð$øøøà<Ð':Ð<Ð<Ð Ø*-Ð 'Ø&Ð Ø-ÐPÐPÐPÐ Ø<Ð ØR€Ø/ÐDÐDÐDÐ ð )-Ð %Ø9Ð ØAÐ Ø),Ð &Ø$BÐ !Ø;Ð ØHÐ Ø[Ð ØAÐ Ø,/Ð )à\Ð ØŸšð "ñ ô Ð ð ˆyð*Ð ð ð ð ñ ð 1Ð Ø">Ð ñ@ð @ð @ð @ñð ð ð ð6 ðð ð ð ð ñ ô ñ „ðð h0Ø
ˆNˆNØØØ%Ø/Ø5Ø(Ø ðñ ô ðh0ð �N�NØØØ"Ø1ð	ñ ô ðh0ð  �.�.ØØØØ6Ø,Ø*ðñ ô ð!h0ð0 ��ØØ4Ø"Ø5ð	ñ ô ð1h0ð< �.�.ØØØ"Ø0ð	ñ ô ð=h0ðH ��ØØØØ5Ø(Ø&ðñ ô ðIh0ðX ˆ~ˆ~ØØØØ9ØMØ/ðñ ô ðYh0ðh �>�>ØØ!Ø$Ø7Ø/ðñ ô ðih0ðv ˆnˆnØØØØMØ=Ø*ðñ ô ðwh0ðF 
ˆ>ˆ>ØØØØ9ØGØ'ðñ ô ðGh0ðV �>�>ØØØð 8Ø@Ø(ð
ñ 
ô 
ðWh0ðl �n�nØØ&ØØ7Ø-ðñ ô ðmh0ðz ˆ~ˆ~ØØ ØØ:Ø-Ø+ðñ ô ð{h0ðJ ˆ^ˆ^ØØØØ8Ø-Ø)ðñ ô ðKh0ðZ 
ˆ>ˆ>ØØØØ;Ø)Ø'ðñ ô ð[h0ðj ˆnˆnØØØØ2Ø,Ø*ðñ ô ðkh0ðz ˆ~ˆ~ØØØØ=Ø-Ø+ðñ ô ð{h0ð h0ðJ �^�^ØØ0Ø!Ø1Ø9Ø)Ø!Ø!Ð9NØ(BðDð Dð
ñ 
ô 
ðKh0ð` ��ØØØØ6Ø\Ø-ðñ ô ðah0ðp ˆ~ˆ~ØØØØSØ/Ø-ðñ ô ðqh0ð@ ˜>˜>Ø Ø*ØØJØMØ7ðñ ô ðAh0ðP �.�.ØØØØ?Ø0Ø.ðñ ô ðQh0ð` ��ØØØØ8Ø.Ø,ðñ ô ðah0ðp 
ˆ>ˆ>ØØØØ0Ø)Ø'ðñ ô ðqh0ð@ ˆnˆnØØØØ@Ø,Ø*ðñ ô ðAh0ðP �.�.ØØ ØØ<Ø0Ø.ðñ ô ðQh0ð` �N�NØØØØ7Ø2Ø0ðñ ô ðah0ðp �>�>ØØØð ;Ø1Ø/ðñ ô ðqh0ðJ ��ØØØØ<Ø.Ø,ðñ ô ðKh0ðZ �>�>ØØØØ=Ø&Ø&ðñ ô ð[h0ðj ˆnˆnØØØØ:Ø,Ø*ðñ ô ðkh0ðz ˜˜ØØØØ@Ø.Ø,ðñ ô ð{h0ðJ �N�NØØØØ8Ø,Ø*ðñ ô ðKh0ðZ ˆ~ˆ~ØØØØLØØ+ðñ ô ð[h0ð h0ðj ˆnØØØð ØØð
ñ 
ô 
ð $�^ØØØØØ3Ø1ðñ ô ðA	h0ð h0ð h0Ð ð hð hð hñ hðZ		ØHÐHÐHÐHÐHÐHØ+Ð+Ñ-Ô-ð Hð HˆØŒ8Ð(Ð(Ð(ØØŒ=˜IÒ%Ð%¨S¬\Ð%Øð Œ8ÐbÐbÐbØØ˜ÐpÐp¨¬ÐpÑpÔpÑpÔpˆØ˜ÐgÐg¨¬ÐgÑgÔgÐimÑnÔnˆØ&4 nØŒxØÔ!Ð- S¤XØØ"œ|Ø*Ð:¨c¬lØ*Ð0¨bð'
ñ '
ô '
Ð˜#œ(Ñ#ð ”kð 	Hð 	HˆFØÐ.Ð.Ð.Ø,=¸c¼hÔ,GÐ! &Ñ)øð	Hð/Høð4 ð 	ð 	ð 	Ø€Dð	øøøñð ð ð ðD 3Ð ñð ð ð ð"ñ ð Ð ñ  89ñ 	ð 	ñ 	ñ 	ð 	ð 	ñ)ñ )ð )ð )ðr Ð4¹g¸YÉ(ÐSÙ	Ñ<¹w¸iÉ7ÐSÙÑ;Ð>oÑ>oÐ>oñ  rHð  IÙÑCÐEvÑEvÐEvñ  yNð  Oð€ñ%ñ %ð %ð %ñP/"ñ /"ñ /"ð /"ð /"ñd=ñ =ð =ð =ñ@5ñ 5ð 5ð 5ñ. /Ð ð1ð 1ñ 1ð 1ñ 1�ñ 1ô 1ð 1ñ"ñ ð ð ñ
5ñ 
5ð 
5ð 
5ññ ð ð ñBKñ Kð Kð Kñ&Dñ Dð Dð Dñ-ñ -ð -ð -ð
 >Bñ [ð [ñ [ñ [ð [ð [ññ ð ð ñ,%ñ %ð %ð %ñ>!ñ !ð !ð !ñH2ñ 2ð 2ð 2ð 9;Ð Ñ :Ð :Ñ :Ñ :Ø"0 )¤.Ñ"2Ô"2Ð ññ ð ð ñLñ Lð Lð Lð ñDñ Dð Dñ „ðDðN à6ðð #'ñð ñ ñ ð ñ „ðñ8B<ñ B<ñ B<ð B<ð B<ñJ3ñ 3ñ 3ð 3ð 3ñlñ ð ð ð< ñ8ñ 8ð 8ñ „ð8ñ<ñ ð ð ñ0ñ 0ð 0ð 0ññ ð ð ñ@ ñ4ð 4ñ 4ñ 4ð 4ð 4ñ* ñEð Eñ Eñ Eð Eð Eñ&)ñ )ð )ð )ñ$Sñ Sð Sð Sñ
?ñ ?ð ?ð ?ññ ð ð ñ*,Lñ ,Lñ ,Lð ,Lð ,Lñ^Ð ñ6ñ 6ð 6ð 6ðz ,0ñ	@,ð @,ñ @,ñ @,ð @,ð @,ñF%ñ %ð %ð %ññ ð ð ññ ð ð ñ,9ñ 9ð 9ð 9ñ"-ñ -ð -ð -ñpñ pð pð pñf%ñ %ñ %ð %ð %ñP	%ñ 	%ð 	%ð 	%ñ"ñ ð ð ð4  $ñJð '+Ø'+ñ	Jð Jñ Jñ Jð Jð Jñbñ ð ð ñ"9ñ 9ð 9ð 9ññ ð ð ñ(ñ (ð (ð (ð ,5¨9Ùð6ñ ,ô ,Ð ñ ð ñ ñ ð .7¨Yð 8ñ 8ð 8ñ .ô .Ð ñ ð ñ ñ ñ>ñ >ð >ð >ð. 1:°	Ù$ð;ñ 1ô 1Ð ñ ð ñ ñ ñ
,ñ ,ð ,ð ,ñ^
Dñ 
Dð 
Dð 
Dññ ð ð ñ,
6ñ 
6ð 
6ð 
6ññ ð ð ð& ØØ:ñð ñ ñ ð ð ð@ ØØ:ñð ñ ñ ð ð ð* ñð ñ ñ ð ð ð2 "&ñ
ð 
ñ 
ñ 
ð 
ð 
ñQñ Qñ Qð Qð Qð "&ñ#;ð #;ñ #;ñ #;ð #;ð #;ðR Ø!%ñ	ð ñ ñ ð ð ð &/ Yñ Ùð0ñ &ô &Ð "ññ ð ð ñCñ Cð Cð Cñ6ñ 6ð 6ð 6ññ ð ð ñ2ñ ð ð ð> Msð Iñ Iñ Ið Ið IñEñ Eñ Eð Eð EñP%ñ %ð %ð %ñ*  Ù $Ø Fñ	ð ñ ñ ð ð ñ@
ñ 
ð 
ð 
ñ6	ñ 	ñ 	ð 	ð 	ñ4ñ 4ñ 4ð 4ð 4ð
 #Ø&*ññ ñ ð ð ð0 #Ø&*ñ(ñ (ñ (ð (ð (ñ((ñ (ñ (ð (ð (ñ-ñ -ñ -ð -ð -ñ!ñ !ñ !ð !ð !ñ
Hñ Hð Hð Hñ
!ñ !ñ !ð !ð !ñ
Hñ Hð Hð Hñ
4ñ 4ð 4ð 4ñ*1ñ 1ð 1ð 1ñ0#+ñ #+ð #+ð #+ñR #ñ$ð $ñ $ñ $ð $ð $ð^ 04ñ!ð !ñ !ñ !ð !ð !ñV "ñ,ð ,ñ ,ñ ,ð ,ð ,ñd "ñ=ð =ñ =ñ =ð =ð =ñD  Ù $Ø Iñ	Cð Cñ Cñ Cð Cð CñLñ ð ð ñ&:ñ :ð :ð :ñz\)ñ \)ð \)ð \)ñDñ ð ñ ðJ *3¨ðñ ð ñ
*ô 
*Ñ ñ 
ð 
ñ 
ñ 
ñ6ñ 6ð 6ñ 6ñr ñ  ð  ñ  ð KOñ 'ð 'ñ 'ñ 'ð 'ñ 'ñd )-ñ .ð .ñ .ñ .ð .ñ .ðj ;?ñ	b,ñ b,ñ b,ð b,ñ b,ñJ%ñ %ñ %ð %ñ %ñ8ñ ð ñ ñ( "ñ	Cð Cñ Cñ Cð Cñ CñL)ñ )ð )ñ )ñXñ ð ñ ñH  Ù $Ø Gñ	Mð Mñ Mñ Mð Mñ Mñ`ñ ð ñ ñ, *-Ñ &ØDFÑ Ñ FÐ FÑ FÑ FØ(˜)œ.Ñ*Ô*Ñ ññ ð ñ ð0 #Ù"Hñ	Rð Rñ Rñ Rð Rñ Rñj0ñ 0ñ 0ð 0ñ 0ñfHñ Hð Hñ HñV%ñ %ð %ñ %ñX#6ñ #6ð #6ñ #6ñLñ ð ñ ñ -1ñ /ð /ñ /ñ /ð /ñ /ñdXñ Xð Xñ Xñ(Pñ (Pð (Pñ (Pð\ +/ØØ"&Ø(Ùñ<)ð <)ñ <)ñ <)ð <)ñ <)ñ~ñ ñ ð ñ ñ$ñ ð ñ ñD&ñ &ð &ñ &ñR5ñ 5ð 5ñ 5ñp.ñ .ñ .ð .ñ .ðj Ù!ñ_ð _ñ _ñ _ð _ñ _ðL ñ	(ð (ñ (ñ (ð (ñ (ñZ  Ù $Ø*.ñ	\ð \ñ \ñ \ð \ñ \ñFñ ð ñ ð(  $Ø#Ø+/ñ	 ð  ñ  ñ  ð  ñ  ñNñ ð ñ ñ6ñ ð ñ ñ&1Kñ 1Kð 1Kñ 1KñV .Ñ Ø*˜9�?Ñ,Ô,Ñ ñ0ñ 0ð 0ñ 0ñ(ñ ð ñ ð2 Ø5Nð ñ ñ ð ñ „ññ6 ñ  ð  ñ  ñF@Hñ @Hð @Hñ @HñFñ ð ñ ñ<Hñ Hð Hñ Hññ ð ñ ññ ð ñ ñ"ñ ð ñ ñ.R(ñ R(ð R(ñ R(ñjñ ð ñ ðF "ñDð Dñ Dñ Dð Dñ DñN7Wñ 7Wð 7Wñ 7Wð| "Ùñ6*ð 6*ñ 6*ñ 6*ð 6*ñ 6*ñr	ñ 	ð 	ñ 	ð& +˜IœNÑ,Ô,Ñ Ø37Ñ Ñ 7Ð 7Ñ 7Ñ 7Ù Ñ ð
 "Ø#Ø#Ø AñNð Nñ Nñ Nð Nñ Nñp Ø#Ø!%Ø $Ø#Ø*.Ø!Ø#Ø#ÙØGKñ#dð dñ dñ dð dñ dðT "ÙØGKñð ñ ñ ð ñ ð@  ñ8ð 8ñ 8ñ 8ð 8ñ 8ñvUñ Uð Uñ Uð "Ø#Ø#ÙñCð Cñ Cñ Cð Cñ CñT

ñ 
ð 
ñ 
ñ8)ñ 8)ð 8)ñ 8)ðH #Ñ ØX\Ñ Ñ \Ð \Ñ \Ñ \ñ#ñ #ð #ñ #ñ	#ñ 	#ð 	#ñ 	#ññ ð ñ ñB1(ñ 1(ð 1(ñ 1(ñh<ñ <ð <ñ <ñF Ñ Ù"Ñ Ø Ñ ñ6 ñ 6 ð 6 ñ 6 ñr>
ñ >
ð >
ñ >
ñB*
ñ *
ð *
ñ *
ñZ%ñ %ð %ñ %ñPñ ð ñ ñ<  ñ   ñ   ð   ñ   ñFJñ Jð Jñ JñZNñ Nð Nñ Nñb%ñ %ð %ñ %ð^ $(ñ<ñ <ñ <ð <ñ <ñ~ñ ð ñ ñ$Añ Að Añ AñTñ Tð Tñ Tññ ð ñ ññ ð ñ ð. ØØñ$ð $ñ $ñ $ð $ñ $ðH Ø37Ø.2ØØ!ØØØñ]ñ ]ñ ]ð ]ñ ]ñ@	ñ ð ñ ñ"ñ ð ñ ñ "ñ	GLð GLñ GLñ GLð GLñ GLñ\ "ñ	AIð AIñ AIñ AIð AIñ AIðN !ñ'ð 'ñ 'ñ 'ð 'ñ 'ñTFñ Fð Fñ FñV "ÙñCð Cñ Cñ Cð Cñ CñLDñ Dð Dñ DñR #,Ñ ñ 1ñ%ð %ñ %ñ %ð %ñ %ñPñ ð ñ ñ&&ñ &ð &ñ &ñ'ñ 'ð 'ñ 'ñT+ñ +ð +ñ +ñ
)ñ )ð )ñ )ñBñ Bð Bñ BñJ%ñ %ð %ñ %ð ±DØ!ñPð Pñ Pñ Pð Pñ Pðh 8<ÙñEð Eñ Eñ Eð Eñ EñPZñ Zð Zñ Zñ2,ñ ,ð ,ñ ,ð` %GÙ#ñ&ð &ñ &ñ &ð &ñ &ñRñ ð ñ ñ$ñ ð ñ ð  &*Ø(,Ø#ØÙØ!ÙØ#Ø<@ñIð Iñ Iñ Ið Iñ IñX6ñ 6ð 6ñ 6ñ( Ø!Ø<@ñ	@Uð @Uñ @Uñ @Uð @Uñ @UñFIñ Ið Iñ IñX;ñ ;ð ;ñ ;ð ;ð ;sI   ÃC ÃCÃCÃC ÃC%Ã$C%Ä+D2 Ä2D<Ä;D<Ð=CT ÔTÔ
T