Ë
    âß²j1 ã            	       óº  — U 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Zddl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 daeed<    e«       Z e
d	e¬
«      Ze
eez     ed	<   dZeedf   ed<   dZeed<   deez  dz  defd„Zdeddfd„Zdedz  fd„Zdedefd„Z defd„Z!dedz  fd„Z"dÆd„Z#defd„Z$i Z%e&eef   ed<   dÇdeez  dz  defd„Z'dÆd„Z(defd„Z) e*h d£«      Z+e*e   ed <   da,d!ed"<   defd#„Z-d$Z.d%Z/d&edefd'„Z0deez  dedz  fd(„Z1deez  dz  dedz  fd)„Z2d*edefd+„Z3d*eez  defd,„Z4d-Z5 ejl                  d.«      Z7d*eez  defd/„Z8d*eez  defd0„Z9d*eez  defd1„Z:d*eez  ddfd2„Z;d*eez  ddfd3„Z<deez  ddfd4„Z=deez  defd5„Z>d6ed7edz  d8edefd9„Z?dÇd7edz  defd:„Z@dÇd7edz  defd;„ZAdÇd7edz  defd<„ZBdd=œd>ed?ed@edz  defdA„ZCdÇd@edz  deDe   fdB„ZEg dC¢g dD¢dEdFgdGœZFdHedeDe   fdI„ZGdÇdJeDe   d@edz  fdK„ZHdJeDe   deedz  ef   fdL„ZIdMeDe   fdN„ZJdedefdO„ZK eLejš                  j�                  dPdQ«      «      ZOdaP eeQ«      j¥                  «       j¦                  dRz  dSz  dTz  ZT eeQ«      j¥                  «       j¦                  ZUdedefdU„ZVdedz  defdV„ZWdÇd@edz  defdW„ZXdedXeDe   defdY„ZYdÇd@edz  defdZ„ZZda[dÆd[„Z\d\ed]eLde]dz  fd^„Z^d@ed_ededz  fd`„Z_daedbededz  fdc„Z`dÇd@edz  dedz  fdd„Zadeed]eLdfedefdg„Zbdedz  fdh„Zcdefdi„ZddÇd@edz  defdj„ZedHededz  fdk„ZfdHededz  fdl„ZgdHededz  fdm„ZhdÇdne&eef   dz  de&eef   fdo„Zidedz  defdp„Zjdedefdq„ZkdÇd@edz  defdr„Zldefds„Zmdeddfdt„Zndedz  defdu„ZodÇdne&eef   dz  dedz  fdv„Zpdwedz  d*edz  defdx„ZqdÈdne&eef   dyed7edefdz„ZrdÇdne&eef   dz  deDe   fd{„ZsdÇdne&eef   dz  defd|„Ztd}d}d}d~d~d~d~dœZudÇdne&eef   dz  dedz  fd€„Zvdneeef   ddfd�„Zwd‚ZxdƒZyd„Zzd…Z{d†Z|da}d‡Z~defdˆ„Zd‰Z€dŠZ� e*d‹dŒh«      Z‚ e*h d�£«      ZƒdÇd@eez  dz  dedz  fdŽ„Z„defd�„Z…deeLdz  eLdz  f   fd�„Z†dÆd‘„Z‡dd=œd@eez  dz  ddfd’„ZˆdÇd“d”œd@eez  dz  d•edefd–„Z‰dezfd—edz  d˜eŠdeLfd™„Z‹d—eddfdš„ZŒdÇd—edz  deLfd›„Z�dneeef   defdœ„ZŽdefd�„Z�džZ�de&dz  fdŸ„Z‘d edeDe   fd¡„Z’d ed¢e&dz  de&dz  fd£„Z“d ed¤e&dz  de&fd¥„Z”dÈd¦e&dz  d ede&dz  fd§„Z•dededz  fd¨„Z–dededz  fd©„Z—dªedefd«„Z˜defd¬„Z™defd­„Zšdefd®„Z›dÉd¯eddfd°„Zœd±Z�d²Zžd³ZŸeŸ› d´�Z  e*h dµ£«      Z¡e*e   ed¶<   d·ededz  fd¸„Z¢d¹Z£ddºœd»edz  defd¼„Z¤dedz  fd½„Z¥ddºœd»edz  defd¾„Z¦ e*h d¿£«      Z§dÀedz  defdÁ„Z¨dÂe©deDe   fdÃ„ZªddÄœdÂe©defdÅ„Z«y)Êux   Shared constants for Hermes Agent.

Import-safe, stdlib-only â€” importable from anywhere without circular-import risk.
é    N)ÚMutableMapping)Ú
ContextVarÚToken)ÚPath)Ú_detect_containerÚis_containerÚ	is_termuxÚis_wslFÚ_profile_fallback_warnedÚ_HERMES_HOME_OVERRIDE©Údefault)ÚasciiÚemojiÚkaomojiÚunicode.ÚINDICATOR_STYLESr   ÚDEFAULT_INDICATOR_STYLEÚpathÚreturnc                 óR   — | €t         n
t        | «      }t        j                  |«      S )z£Set a context-local Hermes home override and return its reset token.

    Deliberately does not mutate ``os.environ`` (shared by every thread in the process).
    )Ú_UNSETÚstrr   Úset)r   Úvalues     ú5/home/ubuntu/.hermes/hermes-agent/hermes_constants.pyÚset_hermes_home_overrider      s$   € ð
 %) L�&´c¸$³i€EÜ ×$Ñ$ UÓ+Ð+ó    Útokenc                 ó.   — t         j                  | «       y)z8Restore the previous context-local Hermes home override.N)r   Úreset)r   s    r   Úreset_hermes_home_overrider"   %   s   € ä×Ñ Õ&r   c                  óX   — t         j                  «       } | t        ur| rt        | «      S dS )z=Return the active context-local Hermes home override, if any.N)r   Úgetr   r   ©Úoverrides    r   Úget_hermes_home_overrider'   *   s(   € ä$×(Ñ(Ó*€HØ$¬FÑ2±xŒ3ˆx‹=ÐIÀTÐIr   c                 óŒ   — t        t        j                  j                  t        j                  j	                  | «      «      «      S )z>Expand environment and user-home syntax in a Hermes home path.)r   Úosr   Ú
expanduserÚ
expandvars©r   s    r   Ú_expand_hermes_homer-   0   s+   € ä”—‘×"Ñ"¤2§7¡7×#5Ñ#5°dÓ#;Ó<Ó=Ð=r   c                  ó
  — t         j                  dk(  rZt        j                  j	                  dd«      j                  «       } | rt        | «      nt        j                  «       dz  dz  }|dz  S t        j                  «       dz  S )z4Return the platform-native default Hermes home path.Úwin32ÚLOCALAPPDATAÚ ÚAppDataÚLocalÚhermesú.hermes)ÚsysÚplatformr)   Úenvironr$   Ústripr   Úhome)Úlocal_appdataÚbases     r   Ú!_get_platform_default_hermes_homer=   5   se   € ä
‡|�|�wÒÜŸ
™
Ÿ™ ~°rÓ:×@Ñ@ÓBˆÙ&3Œt�MÔ"¼¿¹»ÀyÑ9PÐSZÑ9ZˆØ�h‰ÐÜ�9‰9‹;˜Ñ"Ð"r   c                  ó4  — t        t        d«      rt        j                  «       dk7  ryt        j                  j	                  dd«      j                  «       } | r| dk(  ryddl}	 t        |j                  | «      j                  «      dz  S # t        $ r Y yw xY w)a  The invoking user's native ``~/.hermes`` when this process is root under ``sudo``, else None.

    sudo strips HERMES_HOME and sets HOME=/root, so the process's own default is root's; the profile
    store and the system service being operated on belong to SUDO_USER.
    Úgeteuidr   NÚ	SUDO_USERr1   Úrootr5   )Úhasattrr)   r?   r8   r$   r9   Úpwdr   ÚgetpwnamÚpw_dirÚKeyError)Ú	sudo_userrC   s     r   Úsudo_invoker_default_homerH   >   s�   € ô ”2�yÔ!¤R§Z¡Z£\°QÒ%6ØÜ—
‘
—‘˜{¨BÓ/×5Ñ5Ó7€IÙ˜	 VÒ+ØÛðÜ�C—L‘L Ó+×2Ñ2Ó3°iÑ?Ð?øÜò Ùðús   Á$&B Â	BÂBc                  óÎ  — t         ry	 t        «       } | dz  }|j                  «       r |j                  d¬«      j	                  «       nd}|rw|dk7  rqda d|›d	 › d
|›d�}t        j                  t        «      5  t        j                  j                  |dz   «       t        j                  j                  «        ddd«       yyy# t
        t        f$ r d}Y Œ�w xY w# 1 sw Y   yxY w)z`Warn once when HERMES_HOME is unset but a non-default profile is sticky-active (wrong fallback).NÚactive_profileúutf-8©Úencodingr1   r   TzB[HERMES_HOME fallback] HERMES_HOME is unset but active profile is z. Falling back to u'   , which is the DEFAULT profile â€” not zŒ. Any data this process writes will land in the wrong profile. The subprocess spawner should pass HERMES_HOME explicitly (see issue #18594).ú
)r   r=   ÚexistsÚ	read_textr9   ÚUnicodeDecodeErrorÚOSErrorÚ
contextlibÚsuppressÚ	Exceptionr6   ÚstderrÚwriteÚflush)Úfallback_homeÚactive_pathÚactiveÚmsgs       r   Ú_warn_profile_fallback_oncer]   Q   sû   € õ  ØðÜ9Ó;ˆØ#Ð&6Ñ6ˆØDO×DVÑDVÔDX�×&Ñ&°Ð&Ó8×>Ñ>Ô@Ð^`ˆñ �&˜IÒ%Ø#'Ð ðØ ˜Ð#5°m°_ð E.Ø.4¨Zð 8"ð#ð 	ô × Ñ ¤Ó+ñ 	Ü�J‰J×Ñ˜S 4™ZÔ(Ü�J‰J×ÑÔ÷	ð 	ð &€vøô ¤Ð(ò ØŠðú÷	ð 	ús   ‰AC Á8ACÃCÃCÃC$c                  ó´   — t        «       } | rt        | «      S t        j                  j	                  dd«      j                  «       s
t        «        t        «       S )uU   Hermes home: context-local override â†’ ``HERMES_HOME`` env var â†’ platform default.ÚHERMES_HOMEr1   )r'   r-   r)   r8   r$   r9   r]   Úget_process_hermes_homer%   s    r   Úget_hermes_homera   m   sB   € ä'Ó)€HÙÜ" 8Ó,Ð,Ü�:‰:�>‰>˜-¨Ó,×2Ñ2Ô4Ü#Ô%Ü"Ó$Ð$r   Ú_HOME_KEY_CACHEc                 ó²  — | �t        | «      n	t        «       }t        |«      }t        j	                  |«      }|�|S |j                  «       }	 |j                  d¬«      }t        j                  j                  t        |«      «      }|t        |<   |S # t        $ r; t        j                  j                  t        |j                  d¬«      «      «      cY S w xY w)az  Stable registry key for a Hermes home/profile dir.

    ``strict=False`` so profiles whose directories don't exist yet still get a key.

    The resolved value is remembered per input path. A directory that does
    not exist yet is resolved without touching the cache, because the answer
    can change once it is created (e.g. part of the path turns out to be a symlink).
    T©ÚstrictF)r   ra   r   rb   r$   r*   ÚresolverR   r)   r   Únormcase)r   Ú	candidateÚrawÚcachedÚexpandedÚresolvedÚkeys          r   Úhermes_home_keyrn      sÈ   € ð #Ð.”�T”
´OÓ4E€IÜ
ˆi‹.€CÜ× Ñ  Ó%€FØÐØˆØ×#Ñ#Ó%€HðEØ×#Ñ#¨4Ð#Ó0ˆô
 �'‰'×
Ñ
œ3˜x›=Ó
)€CØ„O�CÑØ€Jøô ò Eô �w‰w×Ñ¤ H×$4Ñ$4¸EÐ$4Ó$BÓ CÓDÒDðEús   ÁB ÂACÃCc                  ó,   — t         j                  «        y)zJForget every remembered home key (for tests that move a home dir on disk).N)rb   Úclear© r   r   Úreset_hermes_home_key_cacherr   ™   s   € ä×ÑÕr   c                  óŒ   — t         j                  j                  dd«      j                  «       } | rt	        | «      S t        «       S )a  Hermes home of the running process, ignoring task overrides.

    For process-level assets (theme YAML, dashboard plugin manifests) that must stay visible while a
    request is scoped to another profile (e.g. embedded ``/chat`` under ``--open-profile``).
    r_   r1   )r)   r8   r$   r9   r-   r=   )Úvals    r   r`   r`   ž   s8   € ô �*‰*�.‰.˜¨Ó
+×
1Ñ
1Ó
3€CÙ'*Ô˜sÓ#ÐSÔ0QÓ0SÐSr   >   ÚnodeÚmodelsÚruntimesÚLOCAL_RUNTIME_ROOT_DIRSztuple[str, str, Path] | NoneÚ_default_hermes_root_memoc                  óä  — t        «       } t        j                  j                  dd«      j	                  «       }|rt        |«      nd}t        | «      |�t        |«      ndf}t        }|�|dd |k(  r|d   S | }|�.	 |j                  «       j                  | j                  «       «       g |¢|‘­a|S # t        $ r4 |j                  j                  dk(  r|j                  j                  n|}Y ŒEw xY w)z^Root Hermes dir for profile-level ops: ``<root>`` when ``HERMES_HOME=<root>/profiles/<name>``.r_   r1   Né   Úprofiles)r=   r)   r8   r$   r9   r-   r   ry   rf   Úrelative_toÚ
ValueErrorÚparentÚname)Únative_homeÚenv_homeÚenv_pathÚmemo_keyÚmemoÚresults         r   Úget_default_hermes_rootr‡   ³   sñ   € ô 4Ó5€KÜ�z‰z�~‰~˜m¨RÓ0×6Ñ6Ó8€HÙ08Ô" 8Ô,¸d€HÜ�KÓ °8Ð3G¤# h¤-ÈRÐP€HÜ$€DØÐ˜D  !˜H¨Ò0Ø�A‰wˆØ€FØÐð	`Ø×ÑÓ×*Ñ*¨;×+>Ñ+>Ó+@ÔAð !4 (Ð 3¨FÑ 3ÐØ€Møô ò 	`Ø/7¯©×/CÑ/CÀzÒ/Q�X—_‘_×+Ò+ÐW_ŠFð	`ús   Á<-B2 Â2:C/Ã.C/z.deleted)úconfig.yamlú.envústate.dbÚprofiles_dirc                 ó8  ‡— | j                   Š‰j                  dk(  ry	 | t        z  j                  «       st	        ˆfd„t
        D «       «      ry	 	 ‰j                  d¬«      t        «       j                  d¬«      k(  S # t        $ r Y Œ9w xY w# t        $ r Y yw xY w)a  True when *profiles_dir* is provably ``<hermes-home>/profiles``.

    Accepts the classic ``~/.hermes`` layout, a root carrying Hermes-home marker files, a
    ``profiles/.deleted`` tombstone dir (only ``profile delete`` creates it), or the default root.
    r5   Tc              3   óD   •K  — | ]  }‰|z  j                  «       –— Œ y ­w©N)rO   )Ú.0ÚmarkerrA   s     €r   ú	<genexpr>z+_is_hermes_profiles_root.<locals>.<genexpr>×   s%   øè ø€ ò B
Ø)/ˆT�F‰]×"Ñ"×$ñB
ùs   ƒ Frd   )	r   r€   Ú_DELETED_PROFILES_DIRÚis_dirÚanyÚ_HERMES_HOME_MARKERSrR   rf   r‡   )r‹   rA   s    @r   Ú_is_hermes_profiles_rootr–   Í   s«   ø€ ð ×Ñ€DØ‡y�y�IÒØðØÔ0Ñ0×8Ñ8Ô:¼có B
Ü3GôB
ô ?
ð ð?
ðØ�|‰| 5ˆ|Ó)Ô-DÓ-F×-NÑ-NÐV[Ð-NÓ-\Ñ\Ð\øô ò Ùðûô ò Ùðús#   Ÿ/A> Á,B Á>	B
Â	B
Â	BÂBc                 ó   — t        | «      }|g|j                  ¢­D ]`  }|j                  j                  dk(  r4|j                  j	                  d«      st        |j                  «      r|c S |j                  dk(  sŒ` y y)a  Return ``<root>/profiles/<name>`` when *path* is that home or under it.

    Requires ``<name>`` not to start with ``.`` and the ``profiles`` parent to be a real Hermes home;
    a default home whose path merely contains a ``profiles`` segment is not a named profile.
    r|   ú.r5   N)r   Úparentsr   r€   Ú
startswithr–   )r   Úcurrentrh   s      r   Únamed_profile_homerœ   ã   sv   € ô �4‹j€GØÐ0 §¡Ñ0ò ˆ	Ø×Ñ×!Ñ! ZÒ/¸	¿¹×8QÑ8QÐRUÔ8VÜ,¨Y×-=Ñ-=Ô>ØÒØ�>‰>˜YÓ&Ùðð r   c                 óà  — | �t        | «      j                  «       syt        | «      j                  «       }	 t	        «       }||j                  d¬«      fD ]|  }||k(  s||j                  d¬«      k(  r yt        |«      }|�|j                  c S |j                  j                  dk(  sŒT|j                  j                  d«      rŒp|j                  c S  	 y# t        t        t        f$ r Y yw xY w)a  Return the canonical profile id owning *path*, or ``None`` when it is not a profile home.

    The default home is the Hermes root itself, so its basename is an installation detail (``.hermes``
    on POSIX and commonly ``hermes`` on Windows), not the profile id ``default``.
    NFrd   r   r|   r˜   )r   r9   r   r*   r‡   rf   rœ   r€   r   rš   rR   ÚRuntimeErrorr~   )r   r›   Údefault_rootrh   Únameds        r   Úprofile_name_for_homer¡   ó   sä   € ð €|œ3˜t›9Ÿ?™?Ô,ØÜ�4‹j×#Ñ#Ó%€GðÜ.Ó0ˆØ! 7§?¡?¸% ?Ó#@ÐAò 		&ˆIØ˜LÒ(¨I¸×9MÑ9MÐUZÐ9MÓ9[Ò,[Ù Ü& yÓ1ˆEØÐ Ø—z‘zÒ!ð ×Ñ×$Ñ$¨
Ó2¸9¿>¹>×;TÑ;TÐUXÕ;YØ —~‘~Ò%ñ		&ð øô ”\¤:Ð.ò Ùðús/   ·<C Á4C ÂC Â)C ÃC ÃC ÃC-Ã,C-Úprofile_homec                 óB   — | j                   t        z  | j                  z  S rŽ   )r   r’   r€   ©r¢   s    r   Úprofile_tombstone_pathr¥     s   € Ø×ÑÔ!6Ñ6¸×9JÑ9JÑJÐJr   c                 óF   — t        t        | «      «      j                  «       S rŽ   )r¥   r   rO   r¤   s    r   Únamed_profile_is_deletedr§     s   € Ü!¤$ |Ó"4Ó5×<Ñ<Ó>Ð>r   )rˆ   r‰   zSOUL.mdzprofile.yamlz	auth.jsonrŠ   z^[a-z0-9][a-z0-9_-]{0,63}$c                 óJ   ‡— t        | «      Št        ˆfd„t        D «       «      S )Nc              3   ón   •K  — | ],  }‰|z  j                  «       xs ‰|z  j                  «       –— Œ. y ­wrŽ   )Úis_fileÚ
is_symlink)r�   r�   r:   s     €r   r‘   z-named_profile_has_identity.<locals>.<genexpr>"  s3   øè ø€ ÒqÈV��v‘×&Ñ&Ó(ÒH¨T°F©]×,FÑ,FÓ,HÓHÑqùs   ƒ25)r   r”   Ú_PROFILE_IDENTITY_MARKERS©r¢   r:   s    @r   Únamed_profile_has_identityr®     s!   ø€ ô �Ó€DÜÓqÔWpÔqÓqÐqr   c                 óæ   — t        | «      }t        D ]N  }||z  }|j                  «       r y	 |j                  «       r$|dk7  s|j	                  «       j
                  dkD  r yŒP y# t        $ r Y Œ]w xY w)uê  Stricter than :func:`named_profile_has_identity`: is this dir a profile a host should change
    its own posture for?

    An EMPTY ``.env`` is all a crashed ``hermes profile create`` leaves behind, and it is enough for
    ``named_profile_has_identity``. Listing such a shell is harmless; counting it as a second tenant
    is not â€” it flips the whole host's credential reads fail-closed at the next boot. Every other
    marker, and a non-empty or symlinked ``.env``, still counts.
    Tr‰   r   F)r   r¬   r«   rª   ÚstatÚst_sizerR   )r¢   r:   r�   r   s       r   Ú#named_profile_has_servable_identityr²   %  sx   € ô �Ó€DÜ+ò ˆØ�f‰}ˆØ�?‰?ÔÙð	Ø�|‰|Œ~ 6¨VÒ#3°t·y±y³{×7JÑ7JÈQÒ7NÙøðð øô ò 	Ùð	ús   ­2A$Á$	A0Á/A0c                 ón   — t        | «      }|j                  «       xr t        |«      xr t        |«       S )a  A resolvable named profile: an existing dir with identity that has not been deleted.
    ``-p``/``--profile`` resolution and ``profile_exists`` share this so a stale ghost shell can
    never be started as a backend (whose ``ensure_hermes_home`` would rebuild the full tree).)r   r“   r®   r§   r­   s     r   Únamed_profile_is_liver´   ;  s4   € ô �Ó€DØ�;‰;‹=ÒdÔ7¸Ó=ÒdÔF^Ð_cÓFdÐBdÐdr   c                 óŒ   — t        t        | «      «      }|j                  j                  dd¬«       |j	                  dd¬«       y )NT©r™   Úexist_okzdeleted
rK   rL   )r¥   r   r   ÚmkdirÚ
write_text)r¢   r�   s     r   Úmark_named_profile_deletedrº   C  s;   € Ü#¤D¨Ó$6Ó7€FØ
‡M�M×Ñ ¨tÐÔ4Ø
×Ñ�k¨GÐÕ4r   c                 óL   — t        t        | «      «      j                  d¬«       y )NT)Ú
missing_ok)r¥   r   Úunlinkr¤   s    r   Úclear_named_profile_deletedr¾   I  s   € Üœ4 Ó-Ó.×5Ñ5ÀÐ5ÕFr   c                 ót   — t        | «      }|�+t        |«      s|j                  «       st        d|› d�«      ‚yy)z1Refuse missing or tombstoned named profile homes.Nz#Named profile home does not exist: z0. Create the profile explicitly before using it.)rœ   r§   rO   ÚFileNotFoundError)r   r:   s     r   Úassert_named_profile_home_liverÁ   M  sJ   € ä˜dÓ#€DØÐÔ5°dÔ;À4Ç;Á;Ä=ÜØ1°$°ð 8=ð =ó
ð 	
ð DQÐr   c                 óX   — t        | «      }t        |«       |j                  dd¬«       |S )zECreate *path*, but never materialize a deleted/missing named profile.Tr¶   )r   rÁ   r¸   )r   Útargets     r   Úmkdir_under_hermes_homerÄ   W  s(   € ä�$‹Z€FÜ" 6Ô*Ø
‡L�L˜¨€LÔ-Ø€Mr   Úenv_varr   Úsubdirc                 ó†   — t        j                  | d«      j                  «       }|rt        |«      S |�|S t	        «       |z  S )uº   Resolve a package-manager-relocatable directory.

    Order: *env_var* (Nix wrapper / explicit override) â†’ caller ``default`` (source checkout) â†’
    ``<HERMES_HOME>/<subdir>``.
    r1   )r)   Úgetenvr9   r   ra   )rÅ   r   rÆ   r&   s       r   Ú_packaged_dirrÉ   _  sA   € ô �y‰y˜ "Ó%×+Ñ+Ó-€HÙ%Œ4�‹>Ði°gÐ6I¨7ÐiÌÓO`ÐciÑOiÐir   c                 ó   — t        d| d«      S )zHReturn the optional-skills directory, honoring package-manager wrappers.ÚHERMES_OPTIONAL_SKILLSzoptional-skills©rÉ   r   s    r   Úget_optional_skills_dirrÍ   i  s   € äÐ1°7Ð<MÓNÐNr   c                 ó   — t        d| d«      S )zaReturn the optional-mcps directory, honoring package-manager wrappers (``HERMES_OPTIONAL_MCPS``).ÚHERMES_OPTIONAL_MCPSzoptional-mcpsrÌ   r   s    r   Úget_optional_mcps_dirrÐ   n  s   € äÐ/°¸/ÓJÐJr   c                 ó   — t        d| d«      S )zcReturn the bundled skills directory, honoring package-manager wrappers (``HERMES_BUNDLED_SKILLS``).ÚHERMES_BUNDLED_SKILLSÚskillsrÌ   r   s    r   Úget_bundled_skills_dirrÔ   s  s   € äÐ0°'¸8ÓDÐDr   ©r:   Únew_subpathÚold_namer:   c                óL   — |xs
 t        «       }||z  }t        |«      r|S || z  S )uy  Resolve a Hermes subdirectory, honouring a populated legacy ``<old_name>/`` (no migration).

    An empty legacy dir does NOT count (install scaffolds, manual mkdir) so it cannot shadow the new path.

    A bare empty ``<old_name>/`` directory does **not** count as "the legacy install is in use" â€” install
    scaffolds, manual ``mkdir`` work, and cleared-then-abandoned locations all create empty stubs that would
    otherwise silently shadow real data populated at ``<new_subpath>/``. See #27602 for the pairing-store
    regression where a dormant empty ``pairing/`` orphaned approved-user data in ``platforms/pairing/``.
    )ra   Ú_legacy_path_has_content)rÖ   r×   r:   Úold_paths       r   Úget_hermes_dirrÛ   x  s1   € ð Ò$”?Ó$€DØ�h‰€HÜ/°Ô9ˆ8ÐQ¸tÀkÑ?QÐQr   c                 óf   — | xs
 t        «       dz  }t        j                  dk(  r||dz  gS |dz  |gS )zÆHermes-managed Node dirs in lookup order; both Windows and POSIX shapes so migrated installs work.

    Keep in sync with hermesManagedNodePathEntries() in apps/desktop/electron/backend-env.ts.
    ru   r/   Úbin)ra   r6   r7   )r:   Únode_dirs     r   Úiter_hermes_node_dirsrß   ‡  sB   € ð
 Ò)œÓ)¨VÑ3€HÜ+.¯<©<¸7Ò+BˆH�h Ñ&Ð'ÐdÈÐTYÑIYÐ[cÐHdÐdr   )znpm.cmdznpm.exeÚnpm)znpx.cmdznpx.exeÚnpxúnode.exeru   )rà   rá   ru   Úcommandc                 óº   — t        | «      j                  }t        j                  dk7  sd|v r|gS t        j                  |j                  «       |› d�|› d�|g«      S )Nr/   r˜   z.cmdz.exe)r   r€   r6   r7   Ú_WINDOWS_NODE_SHIMSr$   Úlower)rã   r<   s     r   Ú_candidate_node_command_namesrç   •  sW   € Ü�‹=×Ñ€DÜ
‡|�|�wÒ #¨¡+Øˆvˆä×"Ñ" 4§:¡:£<°T°F¸$°-ÀDÀ6ÈÀÐPTÐ1UÓVÐVr   Únamesc              #   óÞ   K  — t        |«      D ][  }| D ]T  }||z  }|j                  «       sŒt        j                  dk(  s%t	        j
                  |t        j                  «      sŒQ|–— ŒV Œ] y­w)zFYield existing (and on POSIX, executable) ``<node-dir>/<name>`` files.r/   N)rß   rª   r6   r7   r)   ÚaccessÚX_OK)rè   r:   Ú	directoryr€   rh   s        r   Ú_iter_managed_node_candidatesrí   �  sc   è ø€ ä*¨4Ó0ò  ˆ	Øò 	 ˆDØ! DÑ(ˆIØ× Ñ Õ"¬¯©¸Ò(?Ä2Ç9Á9ÈYÔXZ×X_ÑX_ÕC`Ø“ñ	 ñ ùs   ‚)A-¬7A-Á$	A-c                 óp   — d}t        t        t        | «      «      D ]  }t        |«      r||fc S d}Œ d|fS )z8Return ``(first runnable candidate, saw a broken one)``.FTN)Úmapr   rí   Únode_tool_runnable)rè   Úbrokenrh   s      r   Ú_first_runnable_managedrò   ¦  sG   € à€FÜœÔ;¸EÓBÓCò ˆ	Ü˜iÔ(Ø˜fÐ$Ò$Ø‰ðð �ˆ<Ðr   Úargvc                 ó�   — ddl }	 ddlm}  |j                  | fdd |«       dœ|¤ŽS # t        |j
                  t        f$ r Y yw xY w)z>Run a hidden ``--version`` probe; ``None`` when it cannot run.r   N)Úwindows_hide_flagsTé
   )Úcapture_outputÚtimeoutÚcreationflags)Ú
subprocessÚhermes_cli._subprocess_compatrõ   ÚrunrR   ÚTimeoutExpiredr~   )ró   Úkwargsrú   rõ   s       r   Ú_run_version_proberÿ   °  s\   € ãðÝDØˆz�~‰~Øð
Ø!%¨rÑASÓAUñ
ØY_ñ
ð 	
øô �Z×.Ñ.´
Ð;ò Ùðús   †!( ¨AÁAc                 óZ   — t        | dgt        «       ¬«      }|duxr |j                  dk(  S )zJTrue when ``<path> --version`` exits 0 under the Hermes-managed Node PATH.ú	--version)ÚenvNr   )rÿ   Úwith_hermes_node_pathÚ
returncode)r   r†   s     r   Ú_version_probe_okr  ¼  s2   € ä  {Ð 3Ô9NÓ9PÔQ€FØ˜ÐÒ8 &×"3Ñ"3°qÑ"8Ð8r   ÚHERMES_NODE_TARGET_MAJORÚ22ÚscriptsÚlibznode-bootstrap.shc                 óŒ   — t         j                  j                  | «      xr$ t        j                  | t         j                  «      S )zG``exists()`` follows symlinks, so a dangling link never spawns a probe.)r)   r   rO   rê   rë   r,   s    r   Ú_is_executable_filer  Ì  s)   € ä�7‰7�>‰>˜$ÓÒ<¤B§I¡I¨d´B·G±GÓ$<Ð<r   c                 ó”   — | syt         j                  dk(  rt        | «      j                  «       n
t	        | «      }|xr t        | «      S )zXTrue only when *path* is a Node/npm/npx binary that actually runs (``--version`` probe).Fr/   )r6   r7   r   rª   r  r  )r   Úpresents     r   rð   rð   Ñ  s?   € áØÜ&)§l¡l°gÒ&=Œd�4‹j× Ñ Ô"ÔCVÐW[ÓC\€GØÒ.Ô(¨Ó.Ð.r   c                 ó€   — dD ��cg c]  }t        |«      D ]  }|‘Œ Œ }}}t        t        || «      d«      duS c c}}w )zEReturn True when any Hermes-managed node/npm/npx shim exists on disk.)ru   rà   rá   N)rç   Únextrí   )r:   ÚcÚnrè   s       r   Ú hermes_managed_node_tree_presentr  Ù  sH   € à.×Y�1Ô8UÐVWÓ8XÒY°1ŠQÐYˆQÐY€EÑYÜÔ-¨e°TÓ:¸DÓAÈÐMÐMùó Zs   †:Úrootsc                 ón  — t         j                  j                  t         j                  j                  | «      «      }|D ]e  }t         j                  j                  t         j                  j                  |«      «      }	 t         j                  j	                  ||g«      |k(  r yŒg y# t
        $ r Y Œtw xY w)zŸTrue when *path* sits inside one of *roots* (same drive).

    Compared via ``normcase``: psutil and env vars can disagree on Windows drive-letter casing.
    TF)r)   r   rg   ÚnormpathÚ
commonpathr~   )r   r  Ú	path_normrA   Ú	root_norms        r   Ú_path_under_anyr  ß  sœ   € ô
 —‘× Ñ ¤§¡×!1Ñ!1°$Ó!7Ó8€IØò ˆÜ—G‘G×$Ñ$¤R§W¡W×%5Ñ%5°dÓ%;Ó<ˆ	ð	Ü�w‰w×!Ñ! 9¨iÐ"8Ó9¸YÒFÙð Gðð øô ò 	Ùð	ús   Á?$B(Â(	B4Â3B4c           
      ó®  ‡— t         j                  dk7  ry	 ddl}g Št	        | «      D ]4  }	 ‰j                  t        t        |«      j                  «       «      «       Œ6 ‰sy	 |j                  ddg«      }|D ]  }	 |j                  }|j                  d«      }|r#	 t        t        |«      j                  «       «      }t        ˆfd„|r|gng t        |j                  d«      xs g «      z   D «       «      sŒ y y# t        $ r Y yw xY w# t        $ r Y Œíw xY w# t        $ r Y yw xY w# t        $ r Y Œ»w xY w# t        t        f$ r t        |«      }Y Œ•w xY w)	aW  True when a running process executes from the managed Node tree.

    Windows locks running executables against delete/overwrite, so the updater must not rewrite
    ``%HERMES_HOME%\node`` while the desktop app holds it (``[WinError 5]`` on ``npm.cmd``).

    Always ``False`` on POSIX, which has no equivalent lock semantics. See #80926.
    r/   Fr   NÚexeÚcmdlinec              3   ó6   •K  — | ]  }t        |‰«      –— Œ y ­wrŽ   )r  )r�   ÚpÚdirss     €r   r‘   z+managed_node_tree_in_use.<locals>.<genexpr>  s   øè ø€ Òj¨AŒ˜q $×'Ñjùs   ƒT)r6   r7   ÚpsutilrU   rß   Úappendr   r   rf   rR   Úprocess_iterÚinfor$   r~   r”   Úlist)r:   r   rì   ÚprocsÚprocr#  r  r  s          @r   Úmanaged_node_tree_in_user'  ï  sl  ø€ ô ‡|�|�wÒØðÛð €DÜ*¨4Ó0ò ˆ	ð	Ø�K‰KœœD ›O×3Ñ3Ó5Ó6Õ7ðñ
 ØðØ×#Ñ# U¨IÐ$6Ó7ˆð ò ˆð	Ø—9‘9ˆDð �h‰h�u‹oˆÙðÜœ$˜s›)×+Ñ+Ó-Ó.�ô Ój¹3°3±%ÀBÌ$ÈtÏxÉxÐXaÓObÒOhÐfhÓJiÑ1iÔjÕjÙðð øô7 ò Ùðûô ò 	Ùð	ûô ò Ùðûô
 ò 	Ùð	ûô œZÐ(ò Ü˜#“h’ðúsX   —C; ¬1D
Á#D Á<D(Â"D7Ã;	DÄDÄ
	DÄDÄ	D%Ä$D%Ä(	D4Ä3D4Ä7EÅEc                  ó0   — t         ryda t        dd¬«       y)z8Print the managed-Node deferral notice once per process.NTu‰   â†’ Hermes-managed Node.js is in use by a running app; deferring its upgrade until the app is closed (re-run `hermes update` afterwards).)rX   )Ú#_managed_node_in_use_notice_printedÚprintrq   r   r   Ú!_print_managed_node_in_use_noticer+    s!   € õ +ØØ*.Ð'Ü	ð	OØVZör   Úurlrø   c                 ó°   — dd l }	 |j                  j                  | |¬«      5 }|j                  «       cd d d «       S # 1 sw Y   y xY w# t        $ r Y y w xY w)Nr   ©rø   )Úurllib.requestÚrequestÚurlopenÚreadrR   )r,  rø   ÚurllibÚresponses       r   Ú
_fetch_urlr5  (  sR   € ÛðØ�^‰^×#Ñ# C°Ð#Ó9ð 	#¸XØ—=‘=“?÷	#÷ 	#ò 	#ûäò Ùðús+   †A	 £=³	A	 ½AÁA	 ÁA	 Á		AÁAÚ	node_archc                 óR  — ddl }ddl}ddl}dt        › d�}t	        |d«      }|€ydt        › d|› d�}t        j                  ||j                  d	d
¬«      «      }|sy|j                  d«      }	t	        |› |	› �d«      }
|
€y| d|j                  «       j                  dd › �z  }	 |j                  «       5 }t        |«      }||	z  j                  |
«       |dz  }|j                  «        |j                  ||	z  «      5 }|j!                  |«       ddd«       t#        |j%                  d«      d«      }|�|j'                  «       s
	 ddd«       yt)        j*                  t-        |«      t-        |«      «       ddd«       |S # 1 sw Y   ŒrxY w# 1 sw Y   |S xY w# t.        $ r Y yw xY w)z¦Download the target-major portable Node zip into a sibling ``node.new-*`` dir.

    A sibling makes the later swap a same-volume rename. ``None`` on any failure.
    r   Nz https://nodejs.org/dist/latest-vz.x/é<   znode-vz\.\d+\.\d+-win-z\.ziprK   Úreplace)Úerrorsé,  ú	node.new-é   Úextractznode-v*)ÚtempfileÚuuidÚzipfileÚ_HERMES_NODE_TARGET_MAJORr5  ÚreÚsearchÚdecodeÚgroupÚuuid4ÚhexÚTemporaryDirectoryr   Úwrite_bytesr¸   ÚZipFileÚ
extractallr  Úglobr“   ÚshutilÚmover   rR   )r:   r6  r?  r@  rA  Ú	index_urlÚindex_bytesÚpatternÚmatchÚzip_nameÚ	zip_bytesÚstagedÚtmp_dirÚtmp_pathÚextract_dirÚarchiveÚ	extracteds                    r   Ú_stage_windows_node_zipr\  2  s·  € ó
 ÛÛà2Ô3LÐ2MÈSÐQ€IÜ˜Y¨Ó+€KØÐØØÔ1Ð2°/À)ÀÈEÐR€GÜ�I‰I�g˜{×1Ñ1°'À)Ð1ÓLÓM€EÙØØ�{‰{˜1‹~€HÜ˜i˜[¨¨
Ð3°SÓ9€IØÐØØ�i §
¡
£× 0Ñ 0°°!Ð 4Ð5Ð6Ñ6€FðØ×(Ñ(Ó*ð 
	5¨gÜ˜G“}ˆHØ˜Ñ ×-Ñ-¨iÔ8Ø" YÑ.ˆKØ×ÑÔØ—‘ ¨HÑ!4Ó5ð 0¸Ø×"Ñ" ;Ô/÷0ä˜[×-Ñ-¨iÓ8¸$Ó?ˆIØÐ ¨	×(8Ñ(8Ô(:Ø÷
	5ð 
	5ô �K‰Kœ˜I›¬¨F«Ô4÷
	5ð €M÷0ð 0ú÷
	5ð €Mûô ò ÙðúsU   Â%F Â5A	FÃ>FÄ6FÅF Å(FÅ7F ÆF
	ÆFÆFÆF ÆF Æ	F&Æ%F&rÃ   rV  c                 ó:  — | j                   d|j                  j                  d«      › �z  }| j                  «       }|ra	 t	        j
                  t        | «      t        |«      «       t        j                  t        «      5  t	        j                  |d«       ddd«       	 t	        j
                  t        |«      t        | «      «       |rt        j                  |d¬«       y# t        $ r$ t        «        t        j                  |d¬«       Y yw xY w# 1 sw Y   Œ|xY w# t        $ rs |rWt        j                  t        «      5  t	        j
                  t        |«      t        | «      «       ddd«       n# 1 sw Y   nxY wt        j                  |d¬«       Y yw xY w)zøRename the live tree aside (``node.old-*``) and *staged* into place.

    ``None`` when the OS refuses to move the live tree (in use; untouched, retried next time),
    ``False`` when the staged tree cannot be moved in (live tree rolled back).
    z	node.old-r<  T©Úignore_errorsNF)r   r€   ÚremoveprefixrO   r)   r9  r   rR   r+  rN  ÚrmtreerS   rT   Úutime)rÃ   rV  ÚbackupÚhad_lives       r   Ú_swap_node_treere  Y  s;  € ð �]‰]˜y¨¯©×)AÑ)AÀ+Ó)NÐ(OÐPÑP€FØ�}‰}‹€HÙð	Ü�J‰J”s˜6“{¤C¨£KÔ0ô × Ñ ¤Ó)ñ 	#Ü�H‰H�V˜TÔ"÷	#ðÜ
�
‰
”3�v“;¤ F£Ô,ñ ä�‰�f¨DÕ1Øøô' ò 	Ü-Ô/Ü�M‰M˜&°Õ5Ùð	ú÷	#ð 	#ûô ò ÙÜ×$Ñ$¤WÓ-ñ 5Ü—
‘
œ3˜v›;¬¨F«Ô4÷5÷ 5ñ 5úä�‰�f¨DÕ1ÙðúsG   ¿(C" Â DÂ (D Ã"*DÄDÄDÄ$FÅ)E4Å+	FÅ4E=	Å9FÆFc                 ó  — ddl }ddlm} ddddœj                  |j	                  «       «      }|€y| xs
 t        «       } | d	z  }t        | «      rt        «        y|j                  «       d
z
  }g | j                  d«      ¢| j                  d«      ¢­D ]7  }	 |j                  «       j                  |k  rt        j                  |d¬«       Œ9 t        | |«      }|€yt        ||«      xr t!        t#        |dz  «      «      S # t        $ r Y Œyw xY w)u¡  Redownload the portable Node zip into ``%HERMES_HOME%\node`` on Windows.

    ``True`` on success, ``False`` on genuine failure (offline, bad archive), ``None`` when the
    tree is in use and the heal is deferred â€” callers must not record the once-per-process attempt
    for ``None``. Staging-first (extract to ``node.new-*``, rename live aside, rename staged in) so
    an interrupted heal cannot gut the install; a refused rename *is* the in-use signal.

    The replacement is staging-first: the new tree is fully downloaded and extracted to a sibling
    ``node.new-*`` directory, then the live tree is renamed aside (``node.old-*``) and the staged tree
    renamed into place. The live tree is never deleted before its replacement is ready, so an interrupted
    heal cannot gut the running installation. Windows allows renaming a tree whose executables are running
    (images are mapped with ``FILE_SHARE_DELETE`` â€” the same mechanism as the hermes.exe quarantine); when
    the OS refuses the rename, that refusal *is* the in-use signal and the heal defers instead of forcing
    the write and crashing with ``PermissionError: [WinError 5]`` on ``npm.cmd`` (#80926).
    r   N)ÚfactsÚx64Úarm64Úx86)Úamd64ri  rj  Fru   éX  z
node.old-*z
node.new-*Tr^  râ   )ÚtimeÚhermes_platform.hostrg  r$   Únative_archra   r'  r+  rM  r°   Úst_mtimerN  ra  rR   r\  re  rð   r   )r:   rm  rg  r6  rÃ   ÚcutoffÚstalerV  s           r   Ú_heal_managed_node_windowsrs  z  s	  € ó  å*à¨'¸%Ñ@×DÑDÀU×EVÑEVÓEXÓY€IØÐØØÒ$”?Ó$€DØ�F‰]€Fä Ô%Ü)Ô+Øà�Y‰Y‹[˜3Ñ€FØE�4—9‘9˜\Ó*ÐE¨T¯Y©Y°|Ó-DÑEò ˆð	Ø�z‰z‹|×$Ñ$ vÒ-Ü—‘˜e°4Õ8øðô % T¨9Ó5€FØ€~ØÜ˜6 6Ó*Ò[Ô/AÄ#ÀfÈzÑFYÓBZÓ/[Ð[øô ò 	Ùð	ús   Â4D Ä 	DÄDÚfuncÚ	extra_envc          	      ó>  — t         j                  «       syddl}	 ddlm} |j                   |«       ddt         › d| › �gi t        j                  ¥dt        t        «       «      i¥|¥d	|d¬
«      }|j                  dk(  S # t        t        |j                  f$ r Y yw xY w)zGSource ``scripts/lib/node-bootstrap.sh`` and run shell function *func*.Fr   N)Ú
_find_bashz-czsource "z" && r_   T)r  r÷   rø   Úcheck)Ú_NODE_BOOTSTRAP_SCRIPTrª   rú   Útools.environments.localrw  rü   r)   r8   r   ra   rR   rž   ÚSubprocessErrorr  )rt  rø   ru  rú   rw  r†   s         r   Ú_run_node_bootstrapr|  ¥  s¥   € ä!×)Ñ)Ô+ØÛð	å7Ø—‘Ù‹\˜4 8Ô,BÐ+CÀ5ÈÈÐ!OÐPØR”2—:‘:ÐR˜}¬c´/Ó2CÓ.DÑRÈ	ÐRØ¨¸ð  ó 
ˆð ×Ñ Ñ!Ð!øô ”\ :×#=Ñ#=Ð>ò Ùðús   ›AA? Á?BÂBc                  ó¬   — t        d«      } | r| S t        j                  dk(  rt        «       }nt	        ddd¬«      }|syt        t        d«      «      d   S )	z¿Install a Hermes-managed Node tree under ``$HERMES_HOME/node`` and return its npm path.

    Hermes never modifies a user-owned toolchain (system, nvm, brew, Nix) that fails ``engines``.
    rà   r/   Ú_nb_install_bundled_noderl  Ú1)rø   ÚHERMES_NODE_SKIP_LINKSNr   )Úfind_hermes_node_executabler6   r7   rs  r|  rò   rç   )ÚexistingÚoks     r   Úbootstrap_hermes_managed_noder„  ·  sX   € ô
 +¨5Ó1€HÙØˆÜ
‡|�|�wÒÜ'Ó)‰ô !Ð!;ÀSÐadÔeˆÙØÜ"Ô#@ÀÓ#GÓHÈÑKÐKr   c                  óš   — t         s
t        «       syt        j                  dk(  rt	        «       } nt        dd¬«      } | €yda t        | «      S )a{  Redownload Hermes-managed Node when the tree exists but is broken; at most once per process.

    A Windows in-use deferral does NOT record the attempt so a later call can heal once free.

    POSIX installs shell out to ``heal_managed_node`` in ``scripts/lib/node-bootstrap.sh``; Windows
    downloads the portable zip directly (same source as ``install.ps1``). See #80926.
    Fr/   Úheal_managed_noder;  r.  T)Ú_managed_node_heal_attemptedr  r6   r7   rs  r|  Úbool)r†   s    r   Úheal_hermes_managed_noder‰  É  sI   € õ $Ô+KÔ+MØÜ
‡|�|�wÒÜ+Ó-‰ä$Ð%8À#ÔFˆØ€~ØØ#'Ð Ü�‹<Ðr   c                 ób  — t        t        d«      | «      D ]�  }t        t        |«      dg«      }|€ y	 |j                  j                  «       j                  «       j                  d«      }t        |j                  d«      d   «      }d|v r y|t        k  c S  y# t        t        f$ r Y  yw xY w)	zYTrue when the managed node runs but is below the target major (heals like a broken tree).ru   r  FÚvr˜   r   ú-T)rí   rç   rÿ   r   ÚstdoutrE  r9   ÚlstripÚintÚsplitr~   Ú
IndexErrorrB  )r:   rh   r†   ÚversionÚmajors        r   Ú_managed_node_tree_outdatedr”  Þ  s´   € ä2Ô3PÐQWÓ3XÐZ^Ó_ò 1ˆ	Ü#¤S¨£^°[Ð$AÓBˆØˆ>Ùð	Ø—m‘m×*Ñ*Ó,×2Ñ2Ó4×;Ñ;¸CÓ@ˆGÜ˜Ÿ™ cÓ*¨1Ñ-Ó.ˆEð
 �'‰>ÙØÔ0Ñ0Ò0ð1ð øô œJÐ'ò 	Úð	ús   ´ABÂB.Â-B.c                 óœ   — t        | «      }t        |«      \  }}|xs |duxr
 t        «       }|rt        «       rt        |«      \  }}|r|S |S )zaHermes-managed Node/npm path, healing broken/outdated trees; heal failure still returns old Node.N)rç   rò   r”  r‰  )rã   rè   rl   Úbroken_presentÚ
needs_healÚhealedÚ_s          r   r�  r�  ñ  sW   € ä)¨'Ó2€EÜ6°uÓ=Ñ€HˆnØÒ[ H°DÐ$8Ò$ZÔ=XÓ=Z€JÙÔ.Ô0Ü+¨EÓ2‰	ˆ�ÙØˆMØ€Or   c                 óN  ‡— t         j                  dk7  rt        j                  | «      S t	        | «      Št        ˆfd„t        j                  t        j                  ddfD «       «      rt        ‰«      j                  «       r‰S dS t        j                  j                  dd«      j                  t        j                  «      D �cg c]  }|sŒ|‘Œ	 }}t        ‰«      D ]@  }|D ]9  }t        |«      |z  j                  «       sŒ t	        t        |«      |z  «      c c S  ŒB yc c}w )zaNode/npm from PATH; on Windows prefer ``.cmd``/``.exe`` (CreateProcess cannot run the bare shim).r/   c              3   ó.   •K  — | ]  }|xr |‰v –— Œ y ­wrŽ   rq   )r�   ÚsepÚcommand_strs     €r   r‘   z/find_node_executable_on_path.<locals>.<genexpr>  s   øè ø€ Ò
P¨#ˆ3Ò%�3˜+Ð%Ó%Ñ
Pùs   ƒú/ú\NÚPATHr1   )r6   r7   rN  Úwhichr   r”   r)   rœ  Úaltsepr   rª   r8   r$   r�  Úpathseprç   )rã   ÚdÚdirectoriesr€   rì   r�  s        @r   Úfind_node_executable_on_pathr¦  ý  së   ø€ ä
‡|�|�wÒÜ�|‰|˜GÓ$Ð$Ü�g“,€KÜ
Ó
P´"·&±&¼"¿)¹)ÀSÈ$Ð1OÔ
PÔPÜ" ;Ó/×7Ñ7Ô9ˆ{ÐC¸tÐCÜ Ÿj™jŸn™n¨V°RÓ8×>Ñ>¼r¿z¹zÓJÖP˜Êa’1ÐP€KÐPÜ-¨kÓ:ò 3ˆØ$ò 	3ˆIÜ�Y“ $Ñ&×/Ñ/Õ1Üœ4 	›?¨TÑ1Ó2Ô2ñ	3ð3ð ùò Qs   ÃD"ÃD"c                 óL   — t        | «      }|r|S t        «       ryt        | «      S )z Resolve a Node command, preferring a healthy managed install.

    A managed tree that exists but cannot be healed yields ``None`` rather than system Node.
    N)r�  r  r¦  )rã   Úmanageds     r   Úfind_node_executabler©    s*   € ô
 *¨'Ó2€GÙØˆÜ'Ô)ØÜ'¨Ó0Ð0r   r  c                 óÄ  — t        | €t        j                  n| «      }|j                  dd«      j	                  t        j
                  «      D �cg c]  }|sŒ|‘Œ	 }}t        t        «       D �cg c]  }|j                  «       sŒt        |«      ‘Œ  c}«      D ]  }||vsŒ|j                  d|«       Œ t        j
                  j                  |«      |d<   |S c c}w c c}w )zDReturn *env* with Hermes-managed Node directories prepended to PATH.r   r1   r   )Údictr)   r8   r$   r�  r£  Úreversedrß   r“   r   ÚinsertÚjoin)r  Úmergedr  Úpartsr   Úentrys         r   r  r    s°   € ä  ”"—*’*°Ó5€FØŸ
™
 6¨2Ó.×4Ñ4´R·Z±ZÓ@ÖF�1ÂAŠQÐF€EÐFÜÔ1FÓ1HÖZ¨ÈDÏKÉKÍMœ3˜t�9ÒZÓ[ò #ˆØ˜ÒØ�L‰L˜˜EÕ"ð#ô —Z‘Z—_‘_ UÓ+€Fˆ6�NØ€Mùò GùÚZs   ÁCÁCÁ.CÂCc                 ó†   — | syd| v r#| j                  «       d   j                  d«      ryt        | «      xr t        | «      S )u¬  True when *path* is an agent-browser CLI that runs (``--version`` exits 0) or the npx fallback.

    Dead/wrong-arch/hung binaries are rejected so callers try the next candidate.

    A bare presence check (``shutil.which`` / ``Path.exists``) is not enough: agent-browser's npm
    ``postinstall`` re-points a *global* install symlink (e.g. ``/opt/homebrew/bin/agent-browser``) at our
    local ``node_modules/agent-browser/bin/...`` binary, which then disappears on the next ``hermes update``
    â€” leaving a **dangling symlink** that ``which`` still reports but exec fails on with exit 127 (issue
    #48521). Callers that trust such a path silently break every browser tool.
    Fú r   rá   T)r�  Úendswithr  r  r,   s    r   Úagent_browser_runnablerµ  $  sA   € ñ Øà
ˆd�{�t—z‘z“| A‘×/Ñ/°Ô6ØÜ˜tÓ$Ò@Ô):¸4Ó)@Ð@r   c                 ó\  — 	 | j                  «       }t        j                  |j                  «      r| j                  «       }t        j                  |j                  «      sy	 t        | j                  «       «       y# t        $ r Y yt
        $ r Y yw xY w# t        $ r Y yt
        $ r Y yw xY w)záTrue iff *path* is a non-directory file or a populated directory.

    Non-not-found ``OSError`` means "assume occupied" (never orphan legacy data). Symlinks are
    judged on their target; a dangling one does NOT count.
    FT)
Úlstatr°   ÚS_ISLNKÚst_moderÀ   rR   ÚS_ISDIRr  ÚiterdirÚStopIteration)r   Ústs     r   rÙ   rÙ   7  sš   € ðØ�Z‰Z‹\ˆÜ�<‰<˜Ÿ
™
Ô#Ø—‘“ˆBô
 �<‰<˜Ÿ
™
Ô#ØðÜˆT�\‰\‹^Ôð
 øô ò ÙÜò Ùðûô ò ÙÜò ØØðús/   ‚?A< Á"B Á<	BÂBÂBÂ	B+Â B+Â*B+c                 ó¸   — | €
t        «       } 	 d| j                  t        j                  «       «      j	                  «       z   S # t
        $ r t        | «      cY S w xY w)a  User-facing ``~/`` display string for HERMES_HOME (``~/.hermes/profiles/coder``).

    ``home`` overrides the lookup for callers that run before the CLI has applied the sticky
    ``active_profile`` (``get_hermes_home()`` would emit the wrong-profile fallback warning there).
    z~/)ra   r}   r   r:   Úas_posixr~   r   rÕ   s    r   Údisplay_hermes_homerÀ  P  sT   € ð €|ÜÓ ˆðØ�d×&Ñ&¤t§y¡y£{Ó3×<Ñ<Ó>Ñ>Ð>øÜò Ü�4‹yÒðús   Ž3A ÁAÁAc                  óF   — t        t        «       «      } | r| dk7  rd| › d�S dS )a^  ``-p <name> `` (trailing space) pinning copy-pasteable ``hermes ...`` guidance to the
    active NAMED profile, else ``""``: a bare ``hermes`` follows the sticky ``active_profile``
    file, which can name a different database than the one that failed (#105887). A custom
    home outside the profile tree has no selector (only HERMES_HOME names it).r   z-p r³  r1   )r¡   ra   ©r€   s    r   Úprofile_cli_selectorrÃ  ^  s-   € ô
 !¤Ó!2Ó3€DÙ  T¨YÒ%6ˆS���aˆ=Ð>¸BÐ>r   c                 ó¢  — | j                   j                  «       }|t        d«      k(  st        |j                  «      dk  ry|t
        k(  st
        |j                  v r/ddl}|j                  t        «      j                  d|t
        «       yt        j                  t        «      5  t        j                  |d«       ddd«       y# 1 sw Y   yxY w)z`Chmod ``0o700`` on *path*'s parent, refusing ``/`` and top-level dirs (misresolved HERMES_HOME).rž  é   Nr   z¦Not restricting permissions on %s: it is inside the hermes-agent install directory (%s). Credential files are normally stored under the hermes home directory instead.éÀ  )r   rf   r   Úlenr°  Ú_INSTALL_ROOTr™   ÚloggingÚ	getLoggerÚ__name__ÚwarningrS   rT   rR   r)   Úchmod)r   r   rÉ  s      r   Úsecure_parent_dirrÎ  g  s¦   € à�[‰[× Ñ Ó"€FØ”�c“Òœc &§,¡,Ó/°!Ò3Øð ”Ò¤-°6·>±>Ñ"AÛà×Ñœ(Ó#×+Ñ+ðGàHNÔP]ô	
ð
 	Ü	×	Ñ	œWÓ	%ñ  Ü
�‰�˜Ô÷ ÷  ñ  ús   Â%CÃCc                 ó@  — | xs dj                  «       }|sy	 t        j                  j                  t        j                  j	                  t        j                  j                  |«      «      «      S # t        $ r" t        j                  j                  |«      cY S w xY w)zDReturn a comparable absolute path string, or ``""`` for empty input.r1   )r9   r)   r   rg   Úabspathr*   rU   )r   ri   s     r   Ú_norm_home_pathrÑ  |  st   € àŠ:�2×
Ñ
Ó
€CÙØð%Ü�w‰w×Ñ¤§¡§¡´·±×0BÑ0BÀ3Ó0GÓ HÓIÐIøÜò %Ü�w‰w×Ñ Ó$Ò$ð%ús   ™AA2 Á2(BÂBc                 óì   — t        «       xs, | xs i j                  d«      xs t        j                  d«      }|syt	        t        |«      dz  «      }t        j                  j                  |«      r|S dS )zEReturn ``{HERMES_HOME}/home`` when the profile-home directory exists.r_   Nr:   )r'   r$   r)   rÈ   r   r-   r   Úisdir)r  Úhermes_homer¢   s      r   Ú_profile_home_pathrÕ  ‡  sc   € ä*Ó,Òj°²¸·±ÀÓ0NÒjÔRT×R[ÑR[Ð\iÓRj€KÙØÜÔ*¨;Ó7¸&Ñ@ÓA€LÜŸ7™7Ÿ=™=¨Ô6ˆ<Ð@¸DÐ@r   rh   c                 óR   — t        | xr |xr t        | «      t        |«      k(  «      S rŽ   )rˆ  rÑ  )rh   r¢   s     r   Ú_is_profile_homer×  �  s'   € Ü�	Òj˜lÒj¬¸yÓ/IÌ_Ð]iÓMjÑ/jÓkÐkr   rm   c                 ó‚   — t        | j                  |«      xs t        j                  ||«      «      j	                  «       S )zCStripped *key* from *env*, falling back to the process environment.)r   r$   r)   rÈ   r9   )r  rm   r   s      r   Ú_env_getrÙ  ”  s.   € äˆs�w‰w�s‹|Ò6œrŸy™y¨¨gÓ6Ó7×=Ñ=Ó?Ð?r   c                 óÊ  — | xs i } t        | d«      t        | d«      g}t        j                  t        «      5  ddl}|j                  |j                  t        j                  «       «      j                  j                  «       «       ddd«       |j                  t        | d«      «       t        | d«      t        | d«      }}|rH|rF|j                  |j                  d«      r|› |› �nt        j                  j                  ||«      «       t        j                  j                  d	«      }|d	k7  r|j                  |«       |D �cg c]  }|sŒ|‘Œ	 c}S # 1 sw Y   ŒÎxY wc c}w )
z5Return likely OS-user home candidates in trust order.ÚHERMES_REAL_HOMEÚHOMEr   NÚUSERPROFILEÚ	HOMEDRIVEÚHOMEPATH)rŸ  rž  ú~)rÙ  rS   rT   rU   rC   r!  Úgetpwuidr)   ÚgetuidrE   r9   rš   r   r®  r*   )r  Ú
candidatesrC   Údriver   rk   r  s          r   Ú_iter_real_home_candidatesrå  ™  s'  € à
Š)�€CÜ˜3Ð 2Ó3´X¸cÀ6Ó5JÐK€JÜ	×	Ñ	œYÓ	'ñ DÛØ×Ñ˜#Ÿ,™,¤r§y¡y£{Ó3×:Ñ:×@Ñ@ÓBÔC÷Dð ×Ñ”h˜s MÓ2Ô3Ü˜3 Ó,¬h°s¸JÓ.Gˆ4€EÙ‘Ø×Ñ¨d¯o©o¸kÔ.J˜U˜G D 6Ñ*ÔPR×PWÑPW×P\ÑP\Ð]bÐdhÓPiÔjÜ�w‰w×!Ñ! #Ó&€HØ�3‚Ø×Ñ˜(Ô#Ø!Ö'�!¢QŠAÒ'Ð'÷Dð Düò (s   ¸AEÅE ÅE ÅEc                 ó  — t        | «      }t        «       }t        | «      D ]5  }t        |«      }|r||v rŒ|j	                  |«       t        ||«      rŒ3|c S  ddl}	 |j                  «       S # t        t        f$ r Y yw xY w)zøThe OS user's real home, avoiding the Hermes profile HOME.

    ``HOME`` belongs to the OS account and external CLIs keeping credentials under ``~``; a parent
    already running with ``HOME={HERMES_HOME}/home`` is repaired back when possible.
    r   Nú/tmp)
rÕ  r   rå  rÑ  Úaddr×  r?  Ú
gettempdirrž   rR   )r  r¢   Úseenrh   rm   r?  s         r   Úget_real_homerë  ª  sŠ   € ô & cÓ*€LÜ“U€DÜ/°Ó4ò ˆ	Ü˜iÓ(ˆÙ�c˜T‘kØØ�‰�ŒÜ 	¨<Õ8ØÒðó ðØ×"Ñ"Ó$Ð$øÜœ'Ð"ò áðús   ÁA. Á.B Á?B ÚprofileÚreal)Úisolatedr¢   zprofile-homeÚhostÚuserÚ	real_homez	real-homec                 óL  — | xs i } t        | «      }t        | dd«      j                  «       xs d}t        j	                  ||«      }|dk(  r|S t        | «      }t        | d«      }t        |«      t        |«      k7  r|nd}|dk(  r|S |rt        «       r|S |rt        ||«      r|S y)zãSubprocess ``HOME`` override, or ``None``.

    ``auto``: hosts keep real HOME (repairing a profile-home parent), containers use
    ``{HERMES_HOME}/home``; ``real``: always real HOME; ``profile``: always the profile home.
    ÚTERMINAL_HOME_MODEÚautorì  rÜ  Nrí  )	rÕ  rÙ  ræ   Ú_HOME_MODE_ALIASESr$   rë  rÑ  r   r×  )r  r¢   Úmoderñ  Úcurrent_homeÚrepaireds         r   Úget_subprocess_homerù  Å  s±   € ð Š)�€CÜ% cÓ*€LÜ�CÐ-¨vÓ6×<Ñ<Ó>ÒHÀ&€DÜ×!Ñ! $¨Ó-€DàˆyÒØÐÜ˜cÓ"€IÜ˜C Ó(€LÜ+¨IÓ6¼/È,Ó:WÒW‰yÐ]a€HØˆv‚~ØˆáœœØÐÙÔ+¨L¸,ÔGØˆØr   c                 ób   — t        | «      }|r|| d<   t        | «      }|r|| d<   t        | «       y)z´Apply Hermes' subprocess HOME contract to *env* in-place: ``HOME``/``HERMES_REAL_HOME``
    per the home mode, and the temp vars re-pointed at ``env["HERMES_HOME"]``'s scratch dir.rÛ  rÜ  N)rë  rù  Úapply_scratch_tmp_env)r  rñ  r:   s      r   Úapply_subprocess_home_envrü  ß  s:   € ô ˜cÓ"€IÙØ"+ˆÐÑÜ˜sÓ#€DÙØˆˆF‰Ü˜#Õr   )ÚTMPDIRÚTMPÚTEMPÚHERMES_SCRATCH_DIRé   z.last_prunei  é2   c                  óº   — ddl } t        j                  dk(  ry| j                  «       }t	        |«      t
        k  st        j                  j                  d«      s|S y)zõTemp root short enough for AF_UNIX sockets. The scratch dir usually fits; macOS
    ``TMPDIR`` never does and a deep profile home may not, so those fall back to the OS
    default root for sockets only (everything else stays in the scratch dir).r   NÚdarwinrç  )	r?  r6   r7   ré  rÇ  ÚSOCKET_TMPDIR_MAX_LENr)   r   rÓ  )r?  rh   s     r   Úsocket_safe_tmpdirr    sI   € ó Ü
‡|�|�xÒØØ×#Ñ#Ó%€IÜ
ˆ9ƒ~Ô.Ò.´b·g±g·m±mÀFÔ6KØÐØr   )Útruer  ÚyesÚnixosÚbrewÚhomebrew>   Ú0ÚnoÚoffÚfalsec                 ó˜  — t        j                  dd«      j                  «       j                  «       xs d}| �t	        | «      n	t        «       dz  }|€@|j                  «       r0	 |j                  dd¬«      j                  «       j                  «       }|�|t        v s|t        v ry|dk(  s|t        v rt        S |S # t        $ r d}Y Œ5w xY w)u  Return the package manager owning this install, if any.
    Signals: HERMES_MANAGED env var (systemd service) or a ``.managed`` marker file in
    HERMES_HOME (NixOS activation script â€” interactive shells don't see the service env).
    An unreadable or empty marker still counts as managed (the legacy NixOS shape).

    ``home`` names the home whose marker file is read, for callers that already resolved it
    (:func:`get_scratch_dir` at boot, before ``--profile`` re-homes the process).
    Defaults to the effective home.ÚHERMES_MANAGEDr1   Nz.managedrK   r9  )rM   r:  )r)   rÈ   r9   ræ   r   ra   rO   rP   rR   Ú_IGNORED_MANAGED_VALUESÚ_MANAGED_FALSE_VALUESÚ_MANAGED_TRUE_VALUESÚ_LEGACY_MANAGED_SYSTEM)r:   r�   Úmanaged_markers      r   Úget_managed_systemr    sÊ   € ô �Y‰YÐ'¨Ó,×2Ñ2Ó4×:Ñ:Ó<ÒDÀ€FØ$(Ð$4”d˜4”j¼/Ó:KÈzÑY€NØ€~˜.×/Ñ/Ô1ð	Ø#×-Ñ-°wÀyÐ-ÓQ×WÑWÓY×_Ñ_ÓaˆFð €~˜Ô#:Ñ:¸fÔH]Ñ>]ØØ�‚|�vÔ!5Ñ5Ü%Ð%Ø€Møô ò 	ØŠFð	ús   Á$/B; Â;C	ÃC	c                  ó”   — t         j                  j                  d«      st         j                  j                  d«      ryt        «       S )uZ  Container/chmod-skip detection: the ``HERMES_CONTAINER``/``HERMES_SKIP_CHMOD`` operator
    overrides on top of the canonical :func:`_detect_container` signals (same breadth as
    :func:`is_container` â€” Docker/Podman/LXC/Kubernetes, cgroup and root-mountinfo). The cached
    :func:`is_container` itself is deliberately avoided: it ignores these env overrides and is
    computed only once per process, so tests could not flip it. Volume-mounted config is not
    forced to owner-only in containers: gateway and dashboard may run as different UIDs, or
    the mount itself needs broader permissions.ÚHERMES_CONTAINERÚHERMES_SKIP_CHMODT)r)   r8   r$   r   rq   r   r   Ú_container_or_chmod_skippedr  5  s1   € ô 
‡z�z‡~�~Ð(Ô)¬R¯Z©Z¯^©^Ð<OÔ-PØÜÓÐr   c                  óp   — t         j                  dk(  rydt        dt        dz  fd„}  | d«       | d«      fS )	aÎ  Read HERMES_UID / HERMES_GID (set by Docker deployments); (None, None) if unset/invalid/Windows.
    The entrypoint chowns HERMES_HOME once, but subdirs created at runtime (``profiles/<name>/``)
    need the same chown or they land root:root and block later uid-mapped workers.

    Docker containers running Hermes commonly set these to map the in-container user to a host user so
    volume-mounted state files end up with the right ownership. See #34107.
    r/   )NNr€   r   Nc                 ó¤   — 	 t        t        j                  j                  | d«      j	                  «       xs d «      S # t
        t        f$ r Y y w xY w)Nr1   )r�  r)   r8   r$   r9   Ú	TypeErrorr~   rÂ  s    r   Ú_env_intz)_resolve_hermes_uid_gid.<locals>._env_intM  sF   € ð	Ü”r—z‘z—~‘~ d¨BÓ/×5Ñ5Ó7Ò?¸4Ó@Ð@øÜœ:Ð&ò 	Ùð	ús   ‚:= ½AÁAÚ
HERMES_UIDÚ
HERMES_GID)r6   r7   r   r�  )r  s    r   Ú_resolve_hermes_uid_gidr"  B  sA   € ô ‡|�|�wÒØð”sð œs T™zó ñ �LÓ!¡8¨LÓ#9Ð9Ð9r   c                 ó¦   — t        «       \  }}|€|€y	 t        j                  | |�|nd|�|«       yd«       y# t        t        t
        f$ r Y yw xY w)aL  Chown ``path`` to ``HERMES_UID:HERMES_GID`` when set; EPERM/ENOENT are non-fatal (the
    entrypoint's startup chown -R fixes ownership on the next restart).

    Used by :func:`apply_secure_dir_policy` to keep ownership consistent across all directories
    created by ``ensure_hermes_home`` on Docker deployments. See #34107.
    Néÿÿÿÿ)r"  r)   ÚchownrR   ÚAttributeErrorÚNotImplementedError)r   ÚuidÚgids      r   Ú_chown_to_hermes_uidr*  V  s[   € ô 'Ó(�H€CˆØ
€{�s�{ØðÜ
�‰�˜c˜o‘s°2¸c¸o°sÕVÐSUÕVøÜ”^Ô%8Ð9ò Ùðús   ”9 ²9 ¹AÁAc                óZ  — t        |«      �yt        j                  j                  dd«      j	                  «       }t        «       r|st        | «       y	 t        |xs dd«      }	 t        j                  | |«       t        | «       y# t        $ r d}Y Œ0w xY w# t        t        f$ r Y Œ.w xY w)uæ  Apply the canonical Hermes home-directory permission policy to *path*.

    Owner-only ``0700`` by default, but the operator's explicit and managed sharing choices
    win (#117347): managed installs are left exactly as the package manager / activation
    script set them (#77579); in a container only an explicit ``HERMES_HOME_MODE`` is applied
    (a bind-mounted data dir is often shared with sibling containers, #10757); elsewhere
    ``HERMES_HOME_MODE`` (e.g. ``0701``, ``2770``) overrides the mode. ``HERMES_UID`` /
    ``HERMES_GID`` ownership is applied when those env vars are set (#34107).

    ``home`` (keyword-only: both arguments are path-likes) names the home whose managed-mode
    marker is read, for callers that already resolved it; without it the effective home is
    consulted.

    Import-safe twin of ``hermes_cli.config._secure_dir`` (which delegates here), so callers
    outside the CLI package â€” like :func:`get_scratch_dir` â€” share one policy implementation.
    NÚHERMES_HOME_MODEr1   Ú700r=  rÆ  )r  r)   r8   r$   r9   r  r*  r�  r~   rÍ  rR   r'  )r   r:   Úexplicit_moderö  s       r   Úapply_secure_dir_policyr/  f  s¥   € ô" ˜$ÓÐ+ØÜ—J‘J—N‘NÐ#5°rÓ:×@Ñ@ÓB€MÜ"Ô$©]Ü˜TÔ"ØðÜ�=Ò) E¨1Ó-ˆðÜ
�‰��tÔô ˜Õøô ò ØŠðûô Ô(Ð)ò Ùðús$   ÁB Á%B ÂBÂBÂB*Â)B*T©Úpruner1  c                óä   — | �t        | «      n	t        «       }|dz  dz  }	 |j                  dd¬«       t        j                  dk7  rt        ||¬«       |rt        |«       |S # t        $ r Y Œw xY w)a  ``<home>/cache/scratch`` (created, owner-only); *home* defaults to the active Hermes home.

    Every Hermes process and child gets ``TMPDIR``/``TMP``/``TEMP`` pointed here at boot (see
    :func:`export_scratch_tmp_env`), so ``tempfile`` defaults land here without call sites
    knowing. Entries idle for ``SCRATCH_MAX_IDLE_HOURS`` are pruned at most once per process
    and once per hour across processes (stamp file), so a fan-out of children stays cheap.

    Permissions follow :func:`apply_secure_dir_policy`, so an explicit ``HERMES_HOME_MODE`` or
    a managed/shared home is honored instead of a blanket ``0700`` (#117347).
    ÚcacheÚscratchTr¶   r/   rÕ   )r   ra   r¸   r6   r7   r/  rR   Ú_prune_scratch_dir_once)r:   r1  r<   r4  s       r   Úget_scratch_dirr6  ˆ  sx   € ð Ð)Œ4�Œ:¬Ó/@€DØ�W‰n˜yÑ(€GðØ�‰˜d¨TˆÔ2Ü�<‰<˜7Ò"ô $ G°$Õ7ñ Ü Ô(Ø€Nøô	 ò Ùðús   ¡3A# Á#	A/Á.A/r4  Úmax_idle_hoursc                 ó^   — ddl m} | �| nt        d¬«      } |||t        t        h«      «      S )zæDelete top-level scratch entries with no write anywhere in their subtree for
    *max_idle_hours*, reaping processes and git worktree registrations rooted in them
    first (``hermes_constants_scratch``); return the count removed.r   )Úprune_idle_entriesFr0  )Úhermes_constants_scratchr9  r6  Ú	frozensetÚ_SCRATCH_PRUNE_STAMP)r4  r7  r9  rA   s       r   Úprune_scratch_dirr=  ¢  s0   € õ <àÐ)‰7¬ÀUÔ/K€DÙ˜d N´IÔ?SÐ>TÓ4UÓVÐVr   c                 óJ  — t         ry da dd l}| t        z  }	 |j                  «       |j                  «       j                  z
  t
        k  ry 	 t        j                  t        «      5  |j                  «        t        | «       d d d «       y # t        $ r Y ŒIw xY w# 1 sw Y   y xY w)NTr   )Ú_scratch_pruned_oncerm  r<  r°   rp  Ú_SCRATCH_PRUNE_INTERVAL_SECONDSrR   rS   rT   rU   Útouchr=  )r4  rm  Ústamps      r   r5  r5  ¬  s™   € åØØÐÛØÔ*Ñ*€EðØ�9‰9‹;˜Ÿ™›×.Ñ.Ñ.Ô1PÒPØð Qô 
×	Ñ	œYÓ	'ñ #Ø�‰ŒÜ˜'Ô"÷#ð #øô ò Ùðú÷#ð #ús   ˜2B
 Á%BÂ
	BÂBÂB"c           
      óV  — | �| nt        d¬«      }d}t        j                  |d„ ¬«      D ]o  \  }}}|D ]d  }t        j                  t
        «      5  |t        j                  t        j                  j                  ||«      «      j                  z  }ddd«       Œf Œq |S # 1 sw Y   ŒtxY w)zMTotal bytes under the scratch dir (for ``hermes doctor``); 0 when unreadable.NFr0  r   c                  ó   — y rŽ   rq   )Ú_es    r   ú<lambda>z)scratch_dir_usage_bytes.<locals>.<lambda>Á  s   � r   )Úonerror)
r6  r)   ÚwalkrS   rT   rR   r·  r   r®  r±   )r4  rA   ÚtotalÚdirpathÚ	_dirnamesÚ	filenamesr€   s          r   Úscratch_dir_usage_bytesrM  ½  s¨   € àÐ)‰7¬ÀUÔ/K€DØ€EÜ)+¯©°¹Ô)Oò GÑ%ˆ�˜IØò 	GˆDÜ×$Ñ$¤WÓ-ñ GØœŸ™¤"§'¡'§,¡,¨w¸Ó"=Ó>×FÑFÑF�÷Gð Gñ	GðGð €L÷Gð Gús   ÁABÂB(c                 óŠ  — | j                  t        d«      }t        D ],  }| j                  |d«      j                  «       }|sŒ&||k7  sŒ, y | j                  dd«      j                  «       }	 t	        t        |rt        |«      n	t        «       «      «      }t        D ]  }|| |<   Œ	 || t        <   y# t        t        f$ r Y yw xY w)uì  Point ``TMPDIR``/``TMP``/``TEMP`` in *env* at the scratch dir of ``env["HERMES_HOME"]``.

    A temp var the user (or the OS: macOS ``/var/folders``, Windows ``%TEMP%``) set is
    respected and nothing changes. A value Hermes itself exported earlier â€” recognisable
    because it equals ``HERMES_SCRATCH_DIR`` â€” is re-derived, so a child running under another
    profile's home gets that home's scratch dir rather than its parent's. Returns True when
    the vars were (re)written.
    r1   Fr_   T)
r$   ÚSCRATCH_DIR_MARKER_ENVÚSCRATCH_TMP_ENV_VARSr9   r   r6  r-   r`   rž   rR   )r  Úoursrm   r   r:   r4  s         r   rû  rû  È  sÉ   € ð �7‰7Ô)¨2Ó.€DÜ#ò ˆØ—‘˜˜RÓ ×&Ñ&Ó(ˆÚ�U˜d“]Ùðð �7‰7�= "Ó%×+Ñ+Ó-€DðÜ”oÁ4Ô&9¸$Ô&?ÔMdÓMfÓgÓhˆô
 $ò ˆØˆˆCŠðà")€CÔÑØøô œ'Ð"ò ñ ðús   Á-)B0 Â0CÃCc                  óR   — t        t        j                  «      } | rddl}d|_        | S )a  Boot hook: apply :func:`apply_scratch_tmp_env` to this process and reset ``tempfile``'s
    cached default so ``tempfile.gettempdir()`` follows. Call again after anything that
    re-homes the process (``--profile`` resolution); a user-set temp var is never overridden.r   N)rû  r)   r8   r?  Útempdir)Úchangedr?  s     r   Úexport_scratch_tmp_envrU  ã  s%   € ô $¤B§J¡JÓ/€GÙÛØˆÔØ€Nr   )ÚminimalÚlowÚmediumÚhighÚxhighÚmaxÚultrac                 óD  — | �| du ryt        | t        «      rM| j                  dd«      du rddiS t        | j                  d«      xs d«      j	                  «       }|rd|dœS dS t        | «      j	                  «       j                  «       } | dv rddiS | t        v rd| dœS y)	up  Parse a reasoning effort level into a config dict.

    ``None`` for empty/unrecognized input (caller uses the default); ``{"enabled": False}`` for
    "none"/"false"/"disabled"/YAML False â€” ``reasoning_effort: false`` must mean disabled.

    The dict form ``{"enabled": true, "effort": "<level>"}`` passes ``effort`` through verbatim so
    providers with bespoke thinking tiers (``fast``/``thinking`` relays) can be asked for their real
    level; bare strings stay strict so a typo like ``hgih`` never reaches the wire. The wire layer
    already tolerates unknown names (``agent.reasoning_effort.clamp_effort``).
    NTÚenabledFÚeffortr1   )r^  r_  >   Únoner  Údisabled)Ú
isinstancer«  r$   r   r9   ræ   ÚVALID_REASONING_EFFORTS)r_  Úlevels     r   Úparse_reasoning_effortre  ñ  s³   € ð €~˜ 4™ØÜ�&œ$ÔØ�:‰:�i Ó&¨%Ñ/Ø˜uÐ%Ð%ä�F—J‘J˜xÓ(Ò.¨BÓ/×5Ñ5Ó7ˆÙ5:˜4¨5Ñ1ÐDÀÐDÜ�‹[×ÑÓ ×&Ñ&Ó(€FØÐ.Ñ.Ø˜5Ð!Ð!ØÔ(Ñ(Ø¨6Ñ2Ð2Ør   Úmodelc                 óà  ‡‡‡‡‡	‡
— d„ Šd„ Št        «       Š	g Š
ˆ	ˆ
fd„Šˆˆˆfd„} || «       | j                  d«      }t        |«      dk\  r ||d   «       t        |«      dk\  r |dj                  |d	d
 «      «       d}‰
D �cg c]	  }d|vsŒ|‘Œ c}D ]  Š ‰ˆfd„|D «       Ž  Œ d}‰
D �cg c]  }|j	                  d«      d	k(  sŒ|‘Œ c}D ]  Š ‰ˆfd„|D «       Ž  Œ ‰
S c c}w c c}w )zÀSpelling variants for tolerant override matching, exact first, deduped in order.

    Dot/dash recovery runs on EACH base form so ``x-4.5``, ``x-4-5`` and ``x.4.5`` share one variant set.
    c                 ó0   — t        j                  dd| «      S )Nz	(\d)-(\d)z\1.\2©rC  Úsub©Úss    r   rF  z+_canonical_model_variants.<locals>.<lambda>  s   € œRŸV™V L°(¸AÓ>€ r   c                 ó0   — t        j                  dd| «      S )Nz
(\d)\.(\d)z\1-\2ri  rk  s    r   rF  z+_canonical_model_variants.<locals>.<lambda>  s   € œRŸV™V M°8¸QÓ?€ r   c                  óh   •— | D ],  }|sŒ|‰vsŒ‰j                  |«       ‰j                  |«       Œ. y rŽ   )rè  r!  )Úvaluesr‹  rê  Úvariantss     €€r   Ú_addz'_canonical_model_variants.<locals>._add  s2   ø€ Øò 	#ˆAÚ�Q˜d’]Ø—‘˜”Ø—‘ Õ"ñ	#r   c                 óš   •— | j                  dd«      | j                  dd«      }} ‰| || ‰| «       ‰| «       ‰|«       ‰|«      «       y )Nr˜   rŒ  )r9  )rl  ÚdashedÚdottedrq  Ú_dash_to_dotÚ_dot_to_dashs      €€€r   Ú_add_with_derivativesz8_canonical_model_variants.<locals>._add_with_derivatives  sJ   ø€ ØŸ™ 3¨Ó,¨a¯i©i¸¸SÓ.A�ˆÙˆQ�˜¡¨Q£±¸a³Á,ÈvÓBVÑXdÐekÓXlÕmr   rž  r{   r$  rÅ  é   N)Ú	anthropicÚopenaiÚgoogleÚ
openrouterÚgroqÚmistralÚxaiÚcohereÚ
perplexityÚtogetherÚ	fireworksÚdeepseekc              3   ó,   •K  — | ]  }|› d ‰› �–— Œ y­w©rž  Nrq   )r�   Úproviderr‹  s     €r   r‘   z,_canonical_model_variants.<locals>.<genexpr>*  s   øè ø€ ÒA X�(�˜1˜Q˜CÔ ÑAùó   ƒ)r|  Úopencoderƒ  r}  r‚  c              3   ó,   •K  — | ]  }|› d ‰› �–— Œ y­wr†  rq   )r�   Úaggr‹  s     €r   r‘   z,_canonical_model_variants.<locals>.<genexpr>-  s   øè ø€ Ò9 �#��a˜�sŒ|Ñ9ùrˆ  )r   r�  rÇ  r®  Úcount)rf  rw  r°  Úknown_providersr‹  Úknown_aggregatorsrq  ru  rv  rê  rp  s       ` @@@@@r   Ú_canonical_model_variantsr�    sý   ý€ ñ
 ?€LÙ?€LÜ“U€DØ€Hõ#önñ ˜%Ô Ø�K‰K˜Ó€EÜ
ˆ5ƒz�Q‚Ù˜e B™iÔ(Ü
ˆ5ƒz�Q‚Ù˜cŸh™h u¨Q¨R yÓ1Ô2ð€Oð "Ö2�A S°¢\ŠaÒ2ò CˆÙÓA°ÔAÒBðCàSÐØ!Ö7�A Q§W¡W¨S£\°QÓ%6ŠaÒ7ò ;ˆÙÓ9Ð'8Ô9Ò:ð;à€Oùò 3ùò 8s   Â	C&ÂC&Â0C+Ã
C+Ú	overridesc           	      óÜ  ‡	— |rt        |t        «      r| syt        | «      }|D ]  }||v sŒt        ||   «      }|€Œ|c S  t	        |«      Š	|j                  «       D ]�  \  }}t        |t        «      rd|vrŒ|j                  d«      }t        |d   «      }t        |«      dk\  r |t        dj                  |dd «      «      z  }t        ˆ	fd„|D «       «      sŒ}t        |«      }|€Œ‹|c S  y)uÒ  Per-model reasoning_effort override with spelling tolerance; first non-None parse wins.

    Order: exact â†’ dotsâ†”dashes â†’ provider stripped â†’ aggregator stripped â†’ known prefixes added â†’
    reverse lookup of prefixed keys whose stripped forms match (custom provider slugs are not
    enumerable, so a key like ``ollama-local/qwen3.6:27b`` must still match the bare
    ``qwen3.6:27b`` model string a fallback swap feeds after stripping the prefix).
    Nrž  r$  rÅ  rx  c              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­wrŽ   rq   )r�   ÚformÚvariant_sets     €r   r‘   z5resolve_per_model_reasoning_effort.<locals>.<genexpr>M  s   øè ø€ Ò9 tˆt�{Ô"Ñ9ùs   ƒ)rb  r«  r�  re  r   Úitemsr   r�  rÇ  r®  r”   )
rf  r�  rp  Úvariantr†   rm   ri   r°  Ú	key_formsr”  s
            @r   Ú"resolve_per_model_reasoning_effortr˜  1  sö   ø€ ñ œJ y´$Ô7¹uØÜ(¨Ó/€HØò ˆØ�iÒÜ+¨I°gÑ,>Ó?ˆFØÑ!Ø’ð	ô �h“-€KØ—O‘OÓ%ò 
‰ˆˆSÜ˜#œsÔ# s°#¡~ØØ—	‘	˜#“ˆÜ-¨e°B©iÓ8ˆ	Üˆu‹:˜Š?ØÔ2°3·8±8¸EÀ!À"¸IÓ3FÓGÑGˆIÜÓ9¨yÔ9Õ9Ü+¨CÓ0ˆFØÑ!Ø’ð
ð r   rv   c                 ó˜   — | rt        |t        «      si S t        | «      D ]'  }|j                  |«      }t        |t        «      sŒ%|c S  i S )zú``provider_routing.models.<id>`` entry for *model*, spelling-tolerant like
    ``reasoning_overrides``; ``{}`` when none matches. Only the keys a user sets per model
    are returned so unset ones fall through to the flat ``provider_routing`` values.)rb  r«  r�  r$   )rf  rv   r–  r±  s       r   Ú"resolve_per_model_provider_routingrš  T  sM   € ñ œ
 6¬4Ô0Øˆ	Ü,¨UÓ3ò ˆØ—
‘
˜7Ó#ˆÜ�eœTÕ"ØŠLðð €Ir   Úcfgc                 óx  — t        | t        «      r| ni } t        | j                  d«      t        «      r| j                  d«      ni }|sk| j                  d«      }t        |t        «      r(|j                  d«      xs |j                  d«      xs d}t        |t        «      r|j	                  «       nd}t        ||j                  d«      xs i «      }|�|S |j                  dd«      }t        |«      }|rDt        |«      j	                  «       r+|€)ddl}|j                  t        «      j                  d	|«       |S )
zÍEffective reasoning config for *model*: per-model override, then global ``agent.reasoning_effort``.

    Single chokepoint for every surface (CLI, gateway, TUI, cron, ``/model``, fallback activation).
    Úagentrf  r   r1   Úreasoning_overridesNÚreasoning_effortr   z5Unknown reasoning_effort '%s', using default (medium))rb  r«  r$   r   r9   r˜  re  rÉ  rÊ  rË  rÌ  )r›  rf  Ú	agent_cfgÚ	model_cfgÚ	per_modelr_  r†   rÉ  s           r   Úresolve_reasoning_configr£  a  s	  € ô
 ˜C¤Ô&‰#¨B€CÜ$.¨s¯w©w°wÓ/?ÄÔ$F�—‘˜Ô ÈB€IáØ—G‘G˜GÓ$ˆ	Ü�i¤Ô&Ø!Ÿ™ iÓ0ÒP°I·M±MÀ'Ó4JÒPÈbˆIÜ%/°	¼3Ô%?�	—‘Ô!ÀRˆÜ2°5¸)¿-¹-ÐH]Ó:^Ò:dÐbdÓe€IØÐØÐð �]‰]Ð-¨rÓ2€FÜ# FÓ+€FÙ”#�f“+×#Ñ#Ô%¨&¨.ÛØ×Ñœ(Ó#×+Ñ+Ð,cÐekÔlØ€Mr   c                 ó  — t        j                  dt        | xs d«      j                  «       «      }|rMd|j	                  d«      j                  «       › d|j	                  d«      j                  t        d«      d«      › �S dS )	zKConvert a Windows drive path (``C:\...``) to its ``/mnt/<drive>/...`` form.z^([A-Za-z]):[\\/](.*)$r1   z/mnt/rx  rž  r{   é\   N)rC  rS  r   r9   rF  ræ   r9  Úchr)r   rS  s     r   Úwindows_path_to_wslr§  {  sk   € ä�H‰HÐ.´°D²J¸B³×0EÑ0EÓ0GÓH€EÙV[ˆU�5—;‘;˜q“>×'Ñ'Ó)Ð*¨!¨E¯K©K¸«N×,BÑ,BÄ3ÀrÃ7ÈCÓ,PÐ+QÐRÐeÐaeÐer   c                 óö   — t        | xs d«      j                  «       j                  dd«      }t        j                  d|t        j
                  «      }|r$d|j                  d«      j                  dd«      z   S dS )zTConvert a ``\\wsl.localhost\<distro>\...`` (or legacy ``\\wsl$``) UNC path to POSIX.r1   rž  rŸ  z)^\\\\wsl(?:\.localhost|\$)\\[^\\]+\\(.*)$rx  N)r   r9   r9  rC  rS  Ú
IGNORECASErF  )r   Ú
normalizedrS  s      r   Úwsl_unc_path_to_posixr«  �  sc   € ä�T’Z˜R“×&Ñ&Ó(×0Ñ0°°dÓ;€JÜ�H‰HÐAÀ:ÌrÏ}É}Ó]€EÙ6;ˆ3�—‘˜Q“×'Ñ'¨¨cÓ2Ñ2ÐEÀÐEr   Úcwdc                 ó\   — t        «       s| S t        t        fD ]  } || «      }|€Œ|c S  | S )z–Map a Windows-host cwd (drive path or ``\\wsl.localhost\`` UNC) to POSIX when Hermes runs in WSL.

    No-op off WSL and for paths already POSIX.
    )r
   r«  r§  )r¬  Ú
translatorÚ
translateds      r   Útranslate_cwd_for_wsl_backendr°  ˆ  s?   € ô
 Œ8Øˆ
Ü,Ô.AÐBò ˆ
Ù “_ˆ
ØÑ!ØÒðð €Jr   c                  ó   — t        «       dz  S )z5Return the path to ``config.yaml`` under HERMES_HOME.rˆ   ©ra   rq   r   r   Úget_config_pathr³  –  s   € äÓ˜}Ñ,Ð,r   c                  ó   — t        «       dz  S )z:Return the path to the skills directory under HERMES_HOME.rÓ   r²  rq   r   r   Úget_skills_dirrµ  ›  s   € äÓ˜xÑ'Ð'r   c                  ó   — t        «       dz  S )z7Return the path to the ``.env`` file under HERMES_HOME.r‰   r²  rq   r   r   Úget_env_pathr·     s   € äÓ˜vÑ%Ð%r   Úforcec                 óˆ   ‡‡— | syddl Št        ‰j                  dd«      ry‰j                  Šdˆˆfd„	}d|_        |‰_        y)a  Monkey-patch ``socket.getaddrinfo`` to prefer IPv4 when *force* is True.

    Broken-IPv6 hosts hang on AAAA for the full TCP timeout; ``AF_UNSPEC`` resolves as ``AF_INET``,
    falling back to full resolution when no A record exists (pure-IPv6 hosts still work).
    Nr   Ú_hermes_ipv4_patchedFc           	      óœ   •— |dk(  r	  ‰| |‰j                   |||«      S  ‰| |||||«      S # ‰j                  $ r  ‰| |||||«      cY S w xY w)Nr   )ÚAF_INETÚgaierror)rï  ÚportÚfamilyÚtypeÚprotoÚflagsÚ_original_getaddrinfoÚsockets         €€r   Ú_ipv4_getaddrinfoz0apply_ipv4_preference.<locals>._ipv4_getaddrinfo´  sm   ø€ Ø�QŠ;ðUÙ,¨T°4¸¿¹ÈÈuÐV[Ó\Ð\ñ % T¨4°¸¸uÀeÓLÐLøð —?‘?ò UÙ,¨T°4¸ÀÀuÈeÓTÒTðUús   ˆ, ¬AÁ
AT)r   r   r   r   )rÄ  ÚgetattrÚgetaddrinforº  )r¸  rÅ  rÃ  rÄ  s     @@r   Úapply_ipv4_preferencerÈ  ¥  sI   ù€ ñ Øãäˆv×!Ñ!Ð#9¸5ÔAØØ"×.Ñ.ÐöMð .2ÐÔ*Ø*€FÕr   zpartial-stream-stubÚlengthzhttps://openrouter.ai/api/v1z/models>   ÚfloorÚnitroÚexactoÚonlineÚOPENROUTER_VARIANT_SUFFIXESÚmodel_idc                 óp   — | xs dj                  d«      \  }}}|r|sy|j                  «       t        v r|S y)uM  Return the base model id when ``model_id`` carries a recognized
    OpenRouter routing-variant suffix (e.g. ``x-ai/grok-4:nitro`` â†’
    ``x-ai/grok-4``), else ``None``.

    Lives here rather than in ``hermes_cli.models`` so the metadata layer
    (``agent.model_metadata``) can share one definition without importing the
    CLI â€” this module is dependency-free by contract.

    >>> openrouter_variant_base("x-ai/grok-4:nitro")
    'x-ai/grok-4'
    >>> openrouter_variant_base("x-ai/grok-4:free") is None
    True
    >>> openrouter_variant_base("x-ai/grok-4") is None
    True
    r1   ú:N)Ú
rpartitionræ   rÎ  )rÏ  r<   rœ  Úsuffixs       r   Úopenrouter_variant_baserÔ  Ô  s>   € ð  "š R×3Ñ3°CÓ8Ñ€Dˆ#ˆvÙ‘dØØ‡|�|ƒ~Ô4Ñ4ØˆØr   zhttps://ai-gateway.vercel.sh/v1©ÚwindowsrÖ  c                óX   — |€t         j                  dk(  n|}t        | «      |rdz  S dz  S )uì  Venv executable dir (``Scripts``/``bin``); *windows* lets tests exercise Windows paths on Linux.

    Returned unconditionally â€” callers differ on whether a missing venv is an error.

    Canonical helper for venv layout. This was open-coded in seven places across four ``hermes_cli`` modules
    using three different Windows predicates (``platform.system()``, ``is_windows()``, ``_is_windows()``);
    each new call site had to re-derive it, and #76091 shipped an eighth copy because the correct behaviour
    lived 2400 lines away in another function. A few sites outside ``hermes_cli``
    (``tools/code_execution_tool.py``, ``agent/lsp/install.py``, ``agent/lsp/servers.py``) still hand-roll
    it â€” convert them as they are touched.
    r/   ÚScriptsrÝ   )r6   r7   r   )Úvenv_dirrÖ  s     r   Úvenv_bin_dirrÚ  ï  s1   € ð *1¨Œc�l‰l˜gÒ%¸g€GÜ�‹>©'˜YÑ=Ð=°uÑ=Ð=r   c                 óh  ‡— t        | «      Št        ˆfd„dD «       d«      }|�|S t        t        j                  «      }t        t        «      j                  «       j                  ‰j                  «       k(  r<t        j                  t        j                  k7  rt        |«      j                  «       r|S y)uN  The project's ``venv`` or ``.venv`` dir when one exists (``uv venv`` defaults to ``.venv``);
    for an install whose interpreter lives outside the checkout, the running interpreter's venv.

    ``uv venv`` defaults to ``.venv`` while our installers create ``venv``, so both layouts are in the wild.
    Call sites that only knew about ``venv`` silently no-oped on a ``.venv`` install â€” that is how the
    Windows shim-lock preflight skipped itself entirely (#79542). ``venv`` wins when both exist, matching
    what the installers write.

    Installers that keep the interpreter out of the checkout (``$HERMES_HOME/venvs/<name>``, the layout the
    shipped Windows launchers assume) have neither, and the ``project_venv_dir(root) or root / "venv"``
    idiom those call sites share then handed ``uv`` a ``VIRTUAL_ENV`` that does not exist: that one invented
    path skipped the import probe, reclassified every ``hermes tools`` dependency as missing and failed the
    reinstall with interpreter errors (#116148). The interpreter running this module is the only truthful
    answer to "which venv is live", so fall back to it â€” but only for the checkout it was loaded from. A
    foreign root (test temp dir, another clone) still resolves to ``None``: handing it someone else's venv
    would point the callers' writes at the wrong environment.
    c              3   óP   •K  — | ]  }‰|z  j                  «       sŒ‰|z  –— Œ y ­wrŽ   )r“   )r�   r  rA   s     €r   r‘   z#project_venv_dir.<locals>.<genexpr>  s$   øè ø€ ÒO ¸DÀ1¹H×;LÑ;LÕ;N�D˜1•HÑOùs   ƒ&œ
&)Úvenvz.venvN)
r   r  r6   ÚprefixÚ__file__rf   r   Úbase_prefixÚvenv_python_pathrª   )Úproject_rootÚin_treeÚrunningrA   s      @r   Úproject_venv_dirrå  ÿ  sˆ   ø€ ô$ �Ó€DÜÓOÐ&7ÔOÐQUÓV€GØÐØˆô ”3—:‘:Ó€GÜŒX‹×ÑÓ ×'Ñ'¨4¯<©<«>Ò9Ü—
‘
œcŸo™oÒ-Ü  Ó)×1Ñ1Ô3ØˆØr   c                óL   — t        | |¬«      }||j                  dk(  rdz  S dz  S )zAPath to the Python interpreter inside *venv_dir* (may not exist).rÕ  rØ  z
python.exeÚpython)rÚ  r€   )rÙ  rÖ  Úbin_dirs      r   rá  rá    s,   € ä˜8¨WÔ5€GØ g§l¡l°iÒ&?�lÑNÐNÀXÑNÐNr   >   ÚcliÚcronr�  ÚtoolsÚutilsÚgatewayÚpluginsÚtoolsetsÚ	providersÚ	run_agentÚacp_adapterÚmodel_toolsÚtui_gatewayr€   c                 ó”   — | rt        | «      j                  d«      d   nd}t        |«      xr |t        v xs |j	                  d«      S )zbTrue when *name* ships with Hermes (exact first segment; ``startswith`` would claim ``agentops``).r˜   r   r1   Úhermes_)r   r�  rˆ  ÚFIRST_PARTY_MODULE_ROOTSrš   )r€   rA   s     r   Úis_first_party_modulerø  -  s@   € á&*Œ3ˆt‹9�?‰?˜3Ó Ò"°€DÜ�‹:ÒZ˜4Ô#;Ð;ÒY¸t¿¹ÈyÓ?YÐZr   Úexcc                 óz   — t        | t        «      r&t        | t        «      st        t	        | dd«      «      sg S g d¢S )zORecovery guidance lines when *exc* looks like a half-updated tree, else ``[]``.r€   N)r1   z`This looks like a partially-updated install: one module was refreshed and a related one was not.z>Re-run the update to bring the whole tree to the same version:z    hermes updatezDIf that also fails, reinstall: https://hermes-agent.nousresearch.com)rb  ÚImportErrorÚModuleNotFoundErrorrø  rÆ  )rù  s    r   Úpartial_update_hintrý  3  s8   € ô �sœKÔ(¬J°sÔ<OÔ,PÜ(¬°°f¸dÓ)CÔDØˆ	òð r   ©Úfilec                óz   — t        | «      }|syd| › �g|¢­D ]!  }t        ||€t        j                  n|¬«       Œ# y)z0Print recovery guidance for a half-updated tree.FzError: rþ  T)rý  r*  r6   rV   )rù  rÿ  ÚlinesÚlines       r   Úemit_partial_update_hintr  C  sF   € ä Ó$€EÙØØ˜3˜%�Ð) 5Ñ)ò ?ˆÜˆd t |œŸš¸Ö>ð?àr   )r   NrŽ   )r1   )F)¬Ú__doc__rS   r)   rC  rN  r°   r6   Úcollections.abcr   Úcontextvarsr   r   Úpathlibr   Úhermes_platform.host.runtimer   r   r	   r
   r   rˆ  Ú__annotations__Úobjectr   r   r   r   Útupler   r   r"   r'   r-   r=   rH   r]   ra   rb   r«  rn   rr   r`   r;  rx   ry   r‡   r’   r•   r–   rœ   r¡   r¥   r§   r¬   ÚcompileÚPROFILE_ID_REr®   r²   r´   rº   r¾   rÁ   rÄ   rÉ   rÍ   rÐ   rÔ   rÛ   r$  rß   rå   rç   rí   rò   rÿ   r  r�  r8   r$   rB  r‡  rß  rf   r   ry  rÈ  r  rð   r  r  r'  r)  r+  Úbytesr5  r\  re  rs  r|  r„  r‰  r”  r�  r¦  r©  r  rµ  rÙ   rÀ  rÃ  rÎ  rÑ  rÕ  r×  rÙ  rå  rë  rõ  rù  rü  rP  rO  ÚSCRATCH_MAX_IDLE_HOURSr<  r@  r?  r  r  r  r  r  r  r  r  r"  r*  r/  r6  Úfloatr=  r5  rM  rû  rU  rc  re  r�  r˜  rš  r£  r§  r«  r°  r³  rµ  r·  rÈ  ÚPARTIAL_STREAM_STUB_IDÚFINISH_REASON_LENGTHÚOPENROUTER_BASE_URLÚOPENROUTER_MODELS_URLrÎ  rÔ  ÚAI_GATEWAY_BASE_URLrÚ  rå  rá  r÷  rø  ÚBaseExceptionrý  r  rq   r   r   ú<module>r     sw  ðòó
 Û 	Û 	Û Û Û 
Ý *ß )Ý ç [Ó [à!&Ð ˜$Ó &Ù	‹€Ù2<Ð=TÐ^dÔ2eÐ �z #¨¡,Ñ/Ó eð %MÐ �%˜˜S˜‘/Ó LØ(Ð ˜Ó (ð, 3¨¡:°Ñ#4ð ,¸ó ,ð' eð '°ó 'ð
J #¨¡*ó Jð>˜cð > dó >ð
#¨4ó #ð 4¨$¡;ó ó&ð8%˜ó %ð #%€��c˜3�h‘Ó $ñ˜# ™* tÑ+ð °só ó4ð
T ó Tñ +4Ò4RÓ*SÐ ˜ 3™Ó Sð =AÐ Ð9Ó @ð ó ð* #Ð à:Ð ð¨4ð °Dó ð,˜S 4™Zð ¨D°4©Kó ð   d¡
¨TÑ 1ð °c¸D±jó ð4K¨ð K°$ó Kð?¨3°©:ð ?¸$ó ?ð hÐ à�—
‘
Ð8Ó9€ðr¨S°4©Zð r¸Dó rð°c¸D±jð ÀTó ð,e¨¨d©
ð e°tó eð5¨S°4©Zð 5¸Dó 5ðG¨c°D©jð G¸Tó Gð
¨¨t©ð 
¸ó 
ð #¨¡*ð °ó ðj˜3ð j¨°©ð j¸cð jÀdó jñO T¨D¡[ð O¸Dó Oñ
K 4¨$¡;ð K¸$ó Kñ
E D¨4¡Kð E¸4ó Eð
 LPò R ð R¨sð R¸TÀD¹[ð RÐTXó Rñe  t¡ð e°t¸D±zó eò )Ò1NÐYcÐekÐXlñÐ ð
W¨3ð W°4¸±9ó Wñ ¨¨c©ð  ¸$À¹+ó  ð 4¨¡9ð °°s¸T±zÀ4Ð7GÑ1Hó ð	˜T #™Yó 	ð9˜Cð 9 Dó 9ñ   §
¡
§¡Ð/IÈ4Ó PÓQÐ Ø$Ð Ù˜h›×/Ñ/Ó1×8Ñ8¸9ÑDÀuÑLÐObÑbÐ ñ
 �X“×&Ñ&Ó(×/Ñ/€ð=˜cð = dó =ð
/˜S 4™Zð /¨Dó /ñN¨4°$©;ð NÀ$ó Nð˜#ð  d¨3¡ið °Dó ñ ' 4¨$¡;ð '¸$ó 'ðT ',Ð #ó	ð�Cð  #ð ¨%°$©,ó ð$ $ð $°3ð $¸4À$¹;ó $ðN˜Dð ¨$ð °4¸$±;ó ñB(\ T¨D¡[ð (\¸DÀ4¹Kó (\ðV"˜cð "¨sð "Àð "Èó "ð$L s¨T¡zó Lð$ $ó ñ* d¨T¡kð ¸Tó ð&	¨ð 	°°t±ó 	ð¨#ð °#¸±*ó ð
1 #ð 
1¨#°©*ó 
1ñ˜t C¨ H™~°Ñ4ð ÀÀSÈ#ÀXÁó ðA  t¡ð A°ó Að& 4ð ¨Dó ñ2˜d T™kð °Só ð?˜có ?ð ˜Dð   Tó  ð*%˜# ™*ð %¨ó %ñA˜D  c ™N¨TÑ1ð A¸SÀ4¹Zó Aðl  d¡
ð l¸#À¹*ð lÈó lñ@�$�s˜C�x‘.ð @ sð @°Sð @À#ó @ñ
( D¨¨c¨¡N°TÑ$9ð (ÀTÈ#ÁYó (ñ"�t˜C ˜H‘~¨Ñ,ð ¸ó ð. #,¸YÐXaØ$¨fÀ6ÐX^ñ`Ð ñ˜T # s (™^¨dÑ2ð ¸cÀD¹jó ð4	 >°#°s°(Ñ#;ð 	Àó 	ð* 1Ð Ø-Ð ØÐ Ø$Ð Ø"&Ð ØÐ ð Ð ð
˜Có 
ð" ,Ð à Ð ñ $ V¨ZÐ$8Ó9Ð ñ "Ò"=Ó>Ð ñ˜S 4™Z¨$Ñ.ð ¸#À¹*ó ð.
 Tó 
ð:  s¨T¡z°3¸±:Ð'=Ñ!>ó :ó(ð  @Dò ¨3°©:¸Ñ+<ð Èó ðDÀTò ˜# ™* tÑ+ð ¸dð Èdó ð4 .2ÐKañ W˜t d™{ð WÀ5ð WÐfió Wð# Tð #¨dó #ñ" T¨D¡[ð ¸Có ð˜~¨c°3¨hÑ7ð ¸Dó ð6 ó ð XÐ ð d¨T¡kó ð6" Sð "¨T°#©Yó "ðJ ¨cð  ¸dÀT¹kð  ÈdÐUYÉkó  ðF
¨cð 
¸4À$¹;ð 
È4ó 
ñ $¨¡+ð °cð À4È$Á;ó ð4f˜cð f c¨D¡jó fðF ð F¨¨d©
ó Fð sð ¨só ð-˜ó -ð
(˜ó (ð
&�dó &ñ
+ ð +°$ó +ð4 /Ð ØÐ Ø4Ð Ø.Ð/¨wÐ7Ð ñ /8Ú*ó/Ð ˜Y s™^ó ð
 cð ¨c°D©jó ð0 8Ð ð 6:ò > t¨d¡{ð >¸dó >ð  d¨T¡kó ð@ :>ò O¨4°$©;ð OÀ$ó Oñ %ò &ó Ð ð[  d¡
ð [¨tó [ð˜]ð ¨t°C©yó ð  :>ò  -ð À$ô r   