§
    ‰eîiU$  ã                   óì  — d 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 ddlZ ej        e¦  «        Z eh d£¦  «        Zd,de	d	ed
efd„Zd-ded	ed
efd„Zded
dfd„Zdeddd
dfd„Zddœde
eef         de	dede	d
df
d„Zddddœde
eef         de	dedededz  d
dfd„Zd.ded	e	d
e	fd „Zd/d!ed	ed
efd"„Zd,d!ed	ed
efd#„Zd$Zd%edz  d
edz  fd&„Z d0d'„Z!d(ed
efd)„Z"d(ed*ed
efd+„Z#dS )1z*Shared utility functions for hermes-agent.é    N)ÚPath)ÚAnyÚUnion)Úurlparse>   Ú1ÚonÚyesÚtrueFÚvalueÚdefaultÚreturnc                 óÚ   — | €|S t          | t          ¦  «        r| S t          | t          ¦  «        r-|                      ¦   «                              ¦   «         t
          v S t          | ¦  «        S )zDCoerce bool-ish values using the project's shared truthy string set.)Ú
isinstanceÚboolÚstrÚstripÚlowerÚTRUTHY_STRINGS)r   r   s     ú'/home/div/.hermes/hermes-agent/utils.pyÚis_truthy_valuer      s`   € à€}ØˆÝ�%�ÑÔð ØˆÝ�%�ÑÔð 7Ø�{Š{‰}Œ}×"Ò"Ñ$Ô$­Ð6Ð6Ý�‰;Œ;Ðó    Ú Únamec                 óJ   — t          t          j        | |¦  «        d¬¦  «        S )zBReturn True when an environment variable is set to a truthy value.F©r   ©r   ÚosÚgetenv)r   r   s     r   Úenv_var_enabledr      s!   € å�2œ9 T¨7Ñ3Ô3¸UÐCÑCÔCÐCr   Úpathz
int | Nonec                 ó¨   — 	 |                       ¦   «         r+t          j        |                      ¦   «         j        ¦  «        ndS # t          $ r Y dS w xY w)zBCapture the permission bits of *path* if it exists, else ``None``.N)ÚexistsÚstatÚS_IMODEÚst_modeÚOSError)r    s    r   Ú_preserve_file_moder'   $   sV   € ðØ48·K²K±M´MÐK�tŒ|˜DŸIšI™KœKÔ/Ñ0Ô0Ð0ÀtÐKøÝð ð ð Øˆtˆtðøøøs   ‚A A Á
AÁAÚmodec                 ó\   — |€dS 	 t          j        | |¦  «         dS # t          $ r Y dS w xY w)a’  Re-apply *mode* to *path* after an atomic replace.

    ``tempfile.mkstemp`` creates files with 0o600 (owner-only).  After
    ``os.replace`` swaps the temp file into place the target inherits
    those restrictive permissions, breaking Docker / NAS volume mounts
    that rely on broader permissions set by the user.  Calling this
    right after ``os.replace`` restores the original permissions.
    N)r   Úchmodr&   )r    r(   s     r   Ú_restore_file_moder+   ,   sM   € ð €|ØˆðÝ
Œ��tÑÔÐÐÐøÝð ð ð Øˆˆðøøøs   † �
+ª+é   )ÚindentÚdatar-   Údump_kwargsc                ó˜  — t          | ¦  «        } | j                             dd¬¦  «         t          | ¦  «        }t	          j        t          | j        ¦  «        d| j        › d�d¬¦  «        \  }}	 t          j	        |dd¬	¦  «        5 }t          j        ||f|d
dœ|¤Ž |                     ¦   «          t          j        |                     ¦   «         ¦  «         ddd¦  «         n# 1 swxY w Y   t          j        || ¦  «         t!          | |¦  «         dS # t"          $ r( 	 t          j        |¦  «         n# t&          $ r Y nw xY w‚ w xY w)a  Write JSON data to a file atomically.

    Uses temp file + fsync + os.replace to ensure the target file is never
    left in a partially-written state. If the process crashes mid-write,
    the previous version of the file remains intact.

    Args:
        path: Target file path (will be created or overwritten).
        data: JSON-serializable data to write.
        indent: JSON indentation (default 2).
        **dump_kwargs: Additional keyword args forwarded to json.dump(), such
            as default=str for non-native types.
    T©ÚparentsÚexist_okú.Ú_ú.tmp©ÚdirÚprefixÚsuffixÚwúutf-8©ÚencodingF)r-   Úensure_asciiN)r   ÚparentÚmkdirr'   ÚtempfileÚmkstempr   Ústemr   ÚfdopenÚjsonÚdumpÚflushÚfsyncÚfilenoÚreplacer+   ÚBaseExceptionÚunlinkr&   )r    r.   r-   r/   Úoriginal_modeÚfdÚtmp_pathÚfs           r   Úatomic_json_writerR   =   s½  € õ( �‰:Œ:€DØ„K×Ò˜d¨TÐÑ2Ô2Ð2å'¨Ñ-Ô-€MåÔ#Ý�”ÑÔØ�4”9ÐÐÐØðñ ô �L€Bˆð
ÝŒY�r˜3¨Ð1Ñ1Ô1ð 		!°QÝŒIØØðð Ø"ð	ð ð
 ðð ð ð �GŠG‰IŒIˆIÝŒH�Q—X’X‘Z”ZÑ Ô Ð ð		!ð 		!ð 		!ñ 		!ô 		!ð 		!ð 		!ð 		!ð 		!ð 		!ð 		!øøøð 		!ð 		!ð 		!ð 		!õ 	Œ
�8˜TÑ"Ô"Ð"Ý˜4 Ñ/Ô/Ð/Ð/Ð/øÝð ð ð ð	ÝŒI�hÑÔÐÐøÝð 	ð 	ð 	ØˆDð	øøøàðøøøsU   Á1D ÂAC%ÃD Ã%C)Ã)D Ã,C)Ã-(D Ä
E	Ä"D7Ä6E	Ä7
EÅE	ÅEÅE	)Údefault_flow_styleÚ	sort_keysÚextra_contentrS   rT   rU   c                óÊ  — t          | ¦  «        } | j                             dd¬¦  «         t          | ¦  «        }t	          j        t          | j        ¦  «        d| j        › d�d¬¦  «        \  }}	 t          j	        |dd¬	¦  «        5 }t          j        ||||¬
¦  «         |r|                     |¦  «         |                     ¦   «          t          j        |                     ¦   «         ¦  «         ddd¦  «         n# 1 swxY w Y   t          j        || ¦  «         t#          | |¦  «         dS # t$          $ r( 	 t          j        |¦  «         n# t(          $ r Y nw xY w‚ w xY w)an  Write YAML data to a file atomically.

    Uses temp file + fsync + os.replace to ensure the target file is never
    left in a partially-written state.  If the process crashes mid-write,
    the previous version of the file remains intact.

    Args:
        path: Target file path (will be created or overwritten).
        data: YAML-serializable data to write.
        default_flow_style: YAML flow style (default False).
        sort_keys: Whether to sort dict keys (default False).
        extra_content: Optional string to append after the YAML dump
            (e.g. commented-out sections for user reference).
    Tr1   r4   r5   r6   r7   r;   r<   r=   )rS   rT   N)r   r@   rA   r'   rB   rC   r   rD   r   rE   ÚyamlrG   ÚwriterH   rI   rJ   rK   r+   rL   rM   r&   )	r    r.   rS   rT   rU   rN   rO   rP   rQ   s	            r   Úatomic_yaml_writerY   r   sº  € õ, �‰:Œ:€DØ„K×Ò˜d¨TÐÑ2Ô2Ð2å'¨Ñ-Ô-€MåÔ#Ý�”ÑÔØ�4”9ÐÐÐØðñ ô �L€Bˆð
ÝŒY�r˜3¨Ð1Ñ1Ô1ð 	!°QÝŒI�d˜AÐ2DÐPYÐZÑZÔZÐZØð 'Ø—’˜Ñ&Ô&Ð&Ø�GŠG‰IŒIˆIÝŒH�Q—X’X‘Z”ZÑ Ô Ð ð	!ð 	!ð 	!ñ 	!ô 	!ð 	!ð 	!ð 	!ð 	!ð 	!ð 	!øøøð 	!ð 	!ð 	!ð 	!õ 	Œ
�8˜TÑ"Ô"Ð"Ý˜4 Ñ/Ô/Ð/Ð/Ð/øÝð ð ð ð	ÝŒI�hÑÔÐÐøÝð 	ð 	ð 	ØˆDð	øøøàðøøøsU   Á1D0 ÂA*C>Ã2D0 Ã>DÄD0 ÄDÄ(D0 Ä0
E"Ä;EÅE"Å
EÅE"ÅEÅE"Útextc                 ót   — 	 t          j        | ¦  «        S # t           j        t          t          f$ r |cY S w xY w)zêParse JSON, returning *default* on any parse error.

    Replaces the ``try: json.loads(x) except (JSONDecodeError, TypeError)``
    pattern duplicated across display.py, anthropic_adapter.py,
    auxiliary_client.py, and others.
    )rF   ÚloadsÚJSONDecodeErrorÚ	TypeErrorÚ
ValueError)rZ   r   s     r   Úsafe_json_loadsr`   ¨   sE   € ðÝŒz˜$ÑÔÐøÝÔ ¥)­ZÐ8ð ð ð Øˆˆˆðøøøs   ‚ –7¶7Úkeyc                 óª   — t          j        | d¦  «                             ¦   «         }|s|S 	 t          |¦  «        S # t          t
          f$ r |cY S w xY w)z:Read an environment variable as an integer, with fallback.r   )r   r   r   Úintr_   r^   )ra   r   Úraws      r   Úenv_intre   ¸   se   € å
Œ)�C˜Ñ
Ô
×
"Ò
"Ñ
$Ô
$€CØð ØˆðÝ�3‰xŒxˆøÝ�	Ð"ð ð ð Øˆˆˆðøøøs   ­< ¼AÁAc                 óJ   — t          t          j        | d¦  «        |¬¦  «        S )z*Read an environment variable as a boolean.r   r   r   )ra   r   s     r   Úenv_boolrg   Ã   s!   € å�2œ9 S¨"Ñ-Ô-°wÐ?Ñ?Ô?Ð?r   )ÚHTTPS_PROXYÚ
HTTP_PROXYÚ	ALL_PROXYÚhttps_proxyÚ
http_proxyÚ	all_proxyÚ	proxy_urlc                 óÖ   — t          | pd¦  «                             ¦   «         }|sdS |                     ¦   «                              d¦  «        rd|t	          d¦  «        d…         › �S |S )zîNormalize proxy URLs for httpx/aiohttp compatibility.

    WSL/Clash-style environments often export SOCKS proxies as
    ``socks://127.0.0.1:PORT``. httpx rejects that alias and expects the
    explicit ``socks5://`` scheme instead.
    r   Nzsocks://z	socks5://)r   r   r   Ú
startswithÚlen)rn   Ú	candidates     r   Únormalize_proxy_urlrs   Ñ   ss   € õ �I�O Ñ$Ô$×*Ò*Ñ,Ô,€IØð ØˆtØ‡‚ÑÔ×#Ò# JÑ/Ô/ð 9Ø8˜9¥S¨¡_¤_Ð%5Ð%5Ô6Ð8Ð8Ð8ØÐr   c                  ó�   — t           D ]=} t          j        | d¦  «        }t          |¦  «        }|r||k    r|t          j        | <   Œ>dS )zARewrite supported proxy env vars to canonical URL forms in-place.r   N)Ú_PROXY_ENV_KEYSr   r   rs   Úenviron)ra   r   Ú
normalizeds      r   Únormalize_proxy_env_varsrx   à   sW   € åð )ð )ˆÝ”	˜#˜rÑ"Ô"ˆÝ(¨Ñ/Ô/ˆ
Øð 	)˜*¨Ò-Ð-Ø(�BŒJ�s‰Oøð	)ð )r   Úbase_urlc                 óÂ   — | pd                      ¦   «         }|sdS t          d|v r|nd|› �¦  «        }|j        pd                     ¦   «                              d¦  «        S )aß  Return the lowercased hostname for a base URL, or ``""`` if absent.

    Use exact-hostname comparisons against known provider hosts
    (``api.openai.com``, ``api.x.ai``, ``api.anthropic.com``) instead of
    substring matches on the raw URL. Substring checks treat attacker- or
    proxy-controlled paths/hosts like ``https://api.openai.com.example/v1``
    or ``https://proxy.test/api.openai.com/v1`` as native endpoints, which
    leads to wrong api_mode / auth routing.
    r   z://z//r4   )r   r   Úhostnamer   Úrstrip)ry   rd   Úparseds      r   Úbase_url_hostnamer~   ì   sl   € ð ˆ>�r×
 Ò
 Ñ
"Ô
"€CØð ØˆrÝ˜U c˜\˜\�c�c¨z°C¨z¨zÑ:Ô:€FØŒOÐ!˜r×(Ò(Ñ*Ô*×1Ò1°#Ñ6Ô6Ð6r   Údomainc                 óâ   — t          | ¦  «        }|sdS |pd                     ¦   «                              ¦   «                              d¦  «        }|sdS ||k    p|                     d|z   ¦  «        S )ac  Return True when the base URL's hostname is ``domain`` or a subdomain.

    Safer counterpart to ``domain in base_url``, which is the substring
    false-positive class documented on ``base_url_hostname``. Accepts bare
    hosts, full URLs, and URLs with paths.

        base_url_host_matches("https://api.moonshot.ai/v1", "moonshot.ai") == True
        base_url_host_matches("https://moonshot.ai", "moonshot.ai")        == True
        base_url_host_matches("https://evil.com/moonshot.ai/v1", "moonshot.ai") == False
        base_url_host_matches("https://moonshot.ai.evil/v1", "moonshot.ai")     == False
    Fr   r4   )r~   r   r   r|   Úendswith)ry   r   r{   s      r   Úbase_url_host_matchesr‚   ý   s|   € õ ! Ñ*Ô*€HØð ØˆuØˆl˜×!Ò!Ñ#Ô#×)Ò)Ñ+Ô+×2Ò2°3Ñ7Ô7€FØð ØˆuØ�vÒÐ@ ×!2Ò!2°3¸±<Ñ!@Ô!@Ð@r   )F)r   )N)r   )r   N)$Ú__doc__rF   Úloggingr   r#   rB   Úpathlibr   Útypingr   r   Úurllib.parser   rW   Ú	getLoggerÚ__name__ÚloggerÚ	frozensetr   r   r   r   r   r'   r+   rc   rR   rY   r`   re   rg   ru   rs   rx   r~   r‚   © r   r   ú<module>r�      sU  ðØ 0Ð 0à €€€Ø €€€Ø 	€	€	€	Ø €€€Ø €€€Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð Ð Ð Ø !Ð !Ð !Ð !Ð !Ð !à €€€à	ˆÔ	˜8Ñ	$Ô	$€ð �Ð5Ð5Ð5Ñ6Ô6€ðð ˜3ð ¨ð ¸$ð ð ð ð ðDð D˜#ð D¨ð D°Tð Dð Dð Dð Dð
˜dð  |ð ð ð ð ð˜Tð ¨ð ¸$ð ð ð ð ð* ð	2ð 2ð 2Ø
��T�	Ô
ð2à
ð2ð ð	2ð
 ð2ð 
ð2ð 2ð 2ð 2ðr  %ØØ $ð0ð 0ð 0Ø
��T�	Ô
ð0à
ð0ð ð	0ð
 ð0ð ˜‘:ð0ð 
ð0ð 0ð 0ð 0ðl
ð 
˜#ð 
¨ð 
°sð 
ð 
ð 
ð 
ð ð �ð ˜sð ¨3ð ð ð ð ð@ð @�#ð @ ð @°ð @ð @ð @ð @ð€ð 3¨¡:ð °#¸±*ð ð ð ð ð)ð )ð )ð )ð7 ð 7¨ð 7ð 7ð 7ð 7ð"A Cð A°ð A¸ð Að Að Að Að Að Ar   