+
    iHàjÝ*  ã                  óØ  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RI	H
t
 ^ RIHt ]P                  ! R4      t]! 0 R%m4      t]! 0 R&m4      t]P                  ! R]P$                  4      t]P                  ! R4      t]P                  ! R	4      tR
 R ltR R lt]! ^R7      R R l4       tR R ltR R ltR R ltRR/R R lltR R ltR R ltR R  ltR! R" lt R# R$ lt!R# )'uÀ  The running Hermes runtime's own interpreter/venv is not agent-deletable.

Deleting the Python interpreter the current process boots from â€” or the base
interpreter its venv depends on â€” bricks the install: the next boot fails with
``uv trampoline failed to spawn Python child process`` and no amount of agent
work can repair it, because the agent itself no longer starts (#58748). The
same applies to overwriting the interpreter through the file tools.

Two questions, one coordinate system:

* :func:`command_deletes_runtime` â€” would a shell command delete a protected
  path? Wired into the approval floor (``tools.approval._floor_block``), so it
  cannot be bypassed by yolo / approvals.mode=off / cron approve mode.
* :func:`is_protected_path` â€” is a filesystem path protected? Wired into the
  file-safety write classifier, covering write/patch/move/delete.

Protected set (all resolved through the same normalizer so shell spellings â€”
native, git-bash ``/c/...``, WSL ``/mnt/c/...``, ``$HOME`` â€” compare equal):

* ``sys.executable`` and ``sys.prefix`` (the runtime's own venv),
* the base interpreter from ``pyvenv.cfg``'s ``home =`` / ``sys._base_executable``,
* the uv-managed install directory holding that base (matched by version for
  ``uv python uninstall``).

Deliberately NOT protected: any other venv or interpreter on the machine â€” the
agent may freely manage project environments. Only the runtime it is itself
running from is off-limits.
)ÚannotationsN)Ú	lru_cache)ÚPath)ÚOptionalz\n|&&|\|\||[;|]z(?:^|\s)-(?:delete|exec\s+rm\b)zk(?i)(?P<root>.*[/\\](?:uv[/\\])?python[/\\]cpython-(?P<version>\d+(?:\.\d+)*)(?:[-_][^/\\]*)?)(?:[/\\].*)?$z^/(?:(mnt)/)?([a-zA-Z])/(.+)$c               ó    € V ^8„  d   QhRRRR/# )é   ÚrawÚstrÚreturn© )Úformats   "ÚB/home/ubuntu/.hermes/hermes-agent/agent/runtime_self_protection.pyÚ__annotate__r   C   s   € ÷ 8ñ 8˜ð 8 ñ 8ó    c                óì  € \        T ;'       g    R4      P                  4       pV'       g   R# \        V4      ^8¼  d)   V^ ,          VR,          8X  d   V^ ,          R9   d   V^R p \        P                  P                  \        P                  P                  V4      4      p\        P                  R8X  dU   \        P                  T4      pT'       d&   TP                  ^4       RTP                  ^4       2pTP                  RR4      p \        P                  P                  \        P                  P                  \        P                  P                  T4      4      4      #   \         d6     \        P                  P                  T4      p Lð  \         d      Lþi ; ii ; i  \         d@    \        P                  P                  \        P                  P                  T4      4      u # i ; i)af  One canonical form for both shell spellings and runtime paths.

Expands ``~``/``$HOME``, maps git-bash (``/c/...``) and WSL (``/mnt/c/...``)
drive forms to native Windows paths, then ``realpath``s so symlink mirrors
(macOS ``/private``) and relocated installs compare equal. Missing tails are
fine: POSIX ``realpath`` resolves the existing prefix lexically.
Ú z"'Úntz:\Ú/Ú\éÿÿÿÿ)r	   ÚstripÚlenÚosÚpathÚ
expandvarsÚ
expanduserÚ	ExceptionÚnameÚ_WIN_DRIVE_FROM_POSIX_REÚmatchÚgroupÚreplaceÚnormcaseÚrealpathÚnormpath)r   r   Úms   &  r   Ú_normalize_pathr&   C   sr  € ô ˆs�yˆy�b‹>×ÑÓ!€DßÙÜ
ˆ4ƒy�A„~˜$˜q�' T¨"¥XÔ-°$°qµ'¸UÔ2BØ�A�bˆzˆðÜ�w‰w×!Ñ!¤"§'¡'×"4Ñ"4°TÓ":Ó;ˆô 
‡w�w�$„Ü$×*Ñ*¨4Ó0ˆßØ—g‘g˜a“j�\  Q§W¡W¨Q£Z LÐ1ˆDØ�|‰|˜C Ó&ˆð8Ü�w‰w×Ñ¤§¡× 0Ñ 0´·±×1AÑ1AÀ$Ó1GÓ HÓIÐIøô ô ð	Ü—7‘7×%Ñ% dÓ+ŠDøÜô 	Úð	úðûô ô 8Ü�w‰w×Ñ¤§¡× 0Ñ 0°Ó 6Ó7Ò7ð8ús>   Á'<E& ÄAF) Å&F&Å2FÆF"ÆF&Æ!F"Æ"F&Æ)AG3Ç2G3c               ó    € V ^8„  d   QhRRRR/# )r   Úprefixr	   r
   r   )r   s   "r   r   r   b   s   € ÷ ñ ˜ð  ñ r   c                óD  €  \        V 4      R,          P                  RRR7      P                  4       pT FU  pRT9  d   K  TP	                  R^4      w  r4TP                  4       P                  4       R8X  g   KE  TP                  4       u # 	  R#   \         d     R# i ; i)zGThe ``home =`` base-interpreter directory from ``<prefix>/pyvenv.cfg``.z
pyvenv.cfgz	utf-8-sigr!   )ÚencodingÚerrorsr   Ú=Úhome)r   Ú	read_textÚ
splitlinesr   Úsplitr   Úlower)r(   ÚlinesÚlineÚkeyÚvalues   &    r   Ú_pyvenv_homer6   b   s“   € ðÜ�f“ Õ,×7Ñ7ÀÐU^Ð7Ó_×jÑjÓlˆó ˆØ�dŒ?ÙØ—Z‘Z  QÓ'‰
ˆØ�9‰9‹;×ÑÓ &Ö(Ø—;‘;“=Ò ñ ñ øô ô Úðús   ‚1B ÂBÂB)Úmaxsizec               ó$   € V ^8„  d   QhRRRRRR/# )r   Ú
executabler	   r(   r
   útuple[tuple[str, str], ...]r   )r   s   "r   r   r   r   s'   € ÷ Añ A Cð A°ð AÐ9Tñ Ar   c                ó¢  € . p\        V 4      pV'       d   VP                  VR34       \        V4      pV'       d   WC8w  d   VP                  VR34       \        \        V4      4      ;'       g%    \        \        \        RR4      ;'       g    R4      pV'       d‰   VP                  VR34       \
        P                  VP                  RR4      4      pV'       dI   \        VP                  R4      4      pV'       d'   VP                  VR	VP                  R
4       R234       \        ;QJ d    . R V 4       F  NK  	  5# ! R V 4       4      # )uà   Resolved ``(path, description)`` pairs for the runtime's own interpreter.

Cached per (executable, prefix) â€” the pair cannot change while a process
runs, and keying on the inputs lets tests swap ``sys`` attributes freely.
z:the Python interpreter this Hermes runtime is running fromz$this Hermes runtime's own virtualenvÚ_base_executabler   z0the base interpreter this Hermes venv depends onr   r   Úrootz;the uv-managed Python install this Hermes venv depends on (ÚversionÚ)c              3  ó@   "  € T F  w  rV'       g   K  W3x € K  	  R # 5i©Nr   )Ú.0r   Údescs   &  r   Ú	<genexpr>Ú&_protected_snapshot.<locals>.<genexpr>‹   s   é € Ð@±¡* $¼4”�$•³ùs   ‚“)
r&   Úappendr6   ÚgetattrÚsysÚ_UV_INSTALL_DIR_REr   r!   r    Útuple)r9   r(   ÚentriesÚexeÚvenvÚbase_dirr%   Úuv_roots   &&      r   Ú_protected_snapshotrP   q   s  € ð &(€Gä
˜*Ó
%€Cß
Ø�‰˜ÐYÐZÔ[ä˜6Ó"€Dß�”Ø�‰˜ÐDÐEÔFäœ|¨FÓ3Ó4×sÐs¼ÌÔPSÐUgÐikÓHl×HrÐHrÐprÓ8s€HßØ�‰˜Ð"TÐUÔVÜ×$Ñ$ X×%5Ñ%5°d¸CÓ%@ÓAˆßÜ% a§g¡g¨f£oÓ6ˆGßØ—‘ Ð+fÐgh×gnÑgnÐoxÓgyÐfzÐz{Ð)|Ð}Ô~çŒ5Ñ@±Ó@�5Ð@ˆ5Ñ@±Ó@Ó@Ð@r   c               ó   € V ^8„  d   QhRR/# )r   r
   r:   r   )r   s   "r   r   r   Ž   s   € ÷ gñ gÐ/ñ gr   c                 ó~   € \        \        \        R R4      ;'       g    R\        \        RR4      ;'       g    R4      # )r9   r   r(   )rP   rG   rH   r   r   r   Ú
_protectedrS   Ž   s4   € Üœw¤s¨L¸"Ó=×CÐCÀÄWÌSÐRZÐ\^ÓE_×EeÐEeÐceÓfÐfr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úar	   Úbr
   Úboolr   )r   s   "r   r   r   ’   s&   € ÷ Dñ D�ð D˜ð D ñ Dr   c                óÊ   € V '       d	   V'       g   R# \         P                  pW8H  ;'       g7    V P                  W,           4      ;'       g    VP                  W,           4      # )zOTrue when ``a`` and ``b`` are the same path or one is an ancestor of the other.F)r   ÚsepÚ
startswith)rU   rV   rY   s   && r   Ú	_overlapsr[   ’   sA   € ç—AÙÜ
�&‰&€CØ‰6×CÐC�Q—\‘\ !¥'Ó*×CÐC¨a¯l©l¸1½7Ó.CÐCr   c               ó    € V ^8„  d   QhRRRR/# )r   r   r	   r
   ztuple[str, str]r   )r   s   "r   r   r   š   s   € ÷ 	ñ 	�cð 	˜oñ 	r   c                óf  € \         P                  P                  V 4      w  r\         P                  P                  YP	                  \         P
                  \         P                  ;'       g    R,           4      ;'       g
    VR,          ,           4      w  r4VR8X  d   V'       d   \        V4      # W43# )a$  ``os.path.split`` for a directory entry, trailing separators and ``.`` components
dropped first: an empty or ``.`` leaf (``dir/link/``, ``dir/link/.``) would make entry
checks degenerate to the link's target, while pathlib/rm still act on ``link``.
A bare root (``/``, ``C:\``) is kept as is.r   :Né   NÚ.)r   r   Ú
splitdriver0   ÚrstriprY   ÚaltsepÚsplit_entry)r   ÚdriveÚtailÚparentÚleafs   &    r   rc   rc   š   sx   € ô
 —'‘'×$Ñ$ TÓ*�K€EÜ—7‘7—=‘= ¯+©+´b·f±fÄÇ	Á	ÇÀÈRÕ6PÓ*Q×*]Ð*]ÐUYÐZ\ÕU]Õ!^Ó_�L€FØˆs„{—vÜ˜6Ó"Ð"Øˆ<Ðr   ÚfollowTc               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r	   rh   rW   r
   úOptional[str]r   )r   s   "r   r   r   ¦   s!   € ÷ ñ ˜Cð ¨Dð ¸Mñ r   c               ób  € V'       d   \        V 4      pMh\        V 4      w  r4\        T;'       g    R4      pT;'       d=    \        P                  P	                  \        P                  P                  W$4      4      pV'       g   R# \        4        F  w  rV\        W%4      '       g   K  Vu # 	  R# )zÒDescription of the protected runtime path ``path`` touches, else ``None``.

``follow=False`` keeps the final component unresolved (the entry itself, for
ops that unlink/rename a symlink rather than its target).r_   N)r&   rc   r   r   r"   ÚjoinrS   r[   )r   rh   Úresolvedrf   rg   Ú	protectedÚdescriptions   &$     r   Úis_protected_pathrp   ¦   s�   € ÷
 Ü" 4Ó(‰ä" 4Ó(‰ˆÜ" 6§= =¨SÓ1ˆØ×NÐN¤§¡× 0Ñ 0´·±·±¸hÓ1MÓ NˆßÙÜ",¦,Ñˆ	Ü�X×)Ô)ØÒñ #/ñ r   c               ó    € V ^8„  d   QhRRRR/# )r   Úsegmentr	   r
   ú	list[str]r   )r   s   "r   r   r   ¹   s   € ÷ ñ ˜#ð  )ñ r   c                ór   €  \         P                  ! V 4      #   \         d    T P                  4       u # i ; irA   )Úshlexr0   Ú
ValueError)rr   s   &r   Ú_split_wordsrw   ¹   s1   € ðÜ�{Š{˜7Ó#Ð#øÜô Ø�}‰}‹Òðús   ‚ ˜6µ6c               ó    € V ^8„  d   QhRRRR/# )r   Úwordsrs   r
   r   )r   s   "r   r   r   À   s   € ÷ ñ ˜9ð ¨ñ r   c                óü   € \        V 4      pV'       di   V^ ,          pV\        9   d   VR,          pK'  RV9   d@   VP                  R4      '       g)   \        P                  ! RV4      '       d   VR,          pKm   V# V# )é    ºr^   NNr,   z^[A-Za-z_][A-Za-z0-9_]*=)Ú-r   )ÚlistÚ_COMMAND_PREFIXESrZ   Úrer   )ry   ÚoutÚfirsts   &  r   Ú_strip_prefixesrƒ   À   sm   € Ü
ˆu‹+€Cß
Ø�A•ˆØÔ%Ô%Ø�b•'ˆCÙØ�%Œ< × 0Ñ 0°× <Ò <ÄÇÂÐJeÐgl×AmÒAmØ�b•'ˆCÙØØ€Jˆ3€Jr   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Úspecr	   r>   Úuv_root_namer
   rW   r   )r   s   "r   r   r   Î   s.   € ÷ eñ e ð e¨cð eÀð eÈñ er   c                óp  € V P                  4       P                  4       p V '       g   R# V R9   d   R# V P                  R4      '       d   R# VP                  4       P                  V 4      '       d   R# W8H  ;'       g;    VP                  V 4      ;'       d"    V\        V 4      \        V 4      ^,            R8H  # )zD``uv python uninstall`` spec against the running base's version/dir.FTr}   r_   )z--allz-aÚall)r   r1   rZ   r   )r…   r>   r†   s   &&&r   Ú_version_spec_matchesr‰   Î   s•   € à�:‰:‹<×ÑÓ€DßÙØÐ%Ô%ÙØ‡��s×ÒÙØ×ÑÓ×&Ñ& t×,Ò,ÙØ‰?×dÐd˜w×1Ñ1°$Ó7×cÐc¸GÄCÈÃIÌcÐRVËiÐZ[ÍmÐ<\Ð`cÑ<cÐdr   c               ó    € V ^8„  d   QhRRRR/# )r   ry   rs   r
   rj   r   )r   s   "r   r   r   Ü   s   € ÷ ñ  	ð ¨mñ r   c                óÒ  aa€ \        4       pV UUu. uF!  w  r#VP                  R4      '       g   K  W#3NK#  	  pppV'       g   R# V  Uu. uF  qUP                  4       NK  	  pp VP                  R4      pVP                  RV^,           4      pY^,           R p	T Fª  w  r*\
        P                  TP                  RR4      4      pT'       d   TP                  R4      MRo\        P                  P                  T4      o\        ;QJ d     TT3R	 lT	 4       F  '       g   K   R
M	  RM! TT3R	 lT	 4       4      '       g   K¨  T
u # 	  R# u uppi u upi   \         d     R# i ; i)zGDescription when ``uv python uninstall`` would remove the running base.zthe uv-managed Python installNÚpythonÚ	uninstallr   r   r>   r   c              3  ó>   <"  € T F  p\        VSS4      x € K  	  R # 5irA   )r‰   )rB   r…   Ú	root_namer>   s   & €€r   rD   Ú'_uv_uninstall_target.<locals>.<genexpr>ð   s   øé € ÐQÉ5À4Ô$ T¨7°I×>Ð>Ë5ùs   ƒTF)rS   rZ   r1   Úindexrv   rI   r   r!   r    r   r   ÚbasenameÚany)ry   rn   r=   rC   Ú
uv_entriesÚwÚloweredÚ	python_atÚuninstall_atÚspecsro   r%   r�   r>   s   &           @@r   Ú_uv_uninstall_targetrš   Ü   s-  ù€ ä“€Iá'0ôÙ'0™˜Ø�?‰?Ð:×;ô 	ˆ‹¡yð ñ ÷ ÙÙ"'Ó(¡%˜Q�w‰wŽy¡%€GÐ(ðØ—M‘M (Ó+ˆ	Ø—}‘} [°)¸aµ-Ó@ˆð  Õ"Ð#Ð$€EÛ'ÑˆÜ×$Ñ$ T§\¡\°$¸Ó%<Ó=ˆß()�!—'‘'˜)Ô$¨rˆÜ—G‘G×$Ñ$ TÓ*ˆ	ß‹3ÕQÉ5ÓQ�3�3Š3ÕQÉ5ÓQ×QÔQØÒñ (ñ ùó'ùò )øô ô Úðús"   ’E²EÁ
EÁ%*E ÅE&Å%E&c               ó    € V ^8„  d   QhRRRR/# )r   Úcommandr	   r
   rj   r   )r   s   "r   r   r   õ   s   € ÷ -ñ - Sð -¨]ñ -r   c                óø  € V '       d   V P                  4       '       g   R# \        4       pV'       g   R# \        P                  V 4       EF+  p\	        \        V4      4      pV'       g   K"  \        P                  P                  V^ ,          4      P                  4       pVR8X  d   \        V4      pV'       d   Vu # Kv  VR8X  d`   \        P                  V4      '       dE   VR,           F5  pVP                  R4      '       d   K  \        V4      pV'       g   K1  Vu u # 	  KÜ  V\        9  d   Ké  VR,           F5  pVP                  R4      '       d   K  \        V4      pV'       g   K1  Vu u # 	  EK.  	  R# )uµ  Description of the runtime path ``command`` would delete, else ``None``.

Covers ``rm``/``rmdir``/``rd``/``del``/``erase``/``Remove-Item`` (any flags â€”
the interpreter is a file, so no recursion is needed to kill it), the
``find <roots> -delete`` form, and ``uv python uninstall``. Known limits:
paths assembled by ``xargs``/command substitution are invisible here, and
``shutil.rmtree`` inside executed *code* is a different sandbox.
NÚuvÚfindr|   r}   )r   rS   Ú_SEGMENT_SPLIT_REr0   rƒ   rw   r   r   r’   r1   rš   Ú_FIND_DELETE_REÚsearchrZ   rp   Ú_DELETING_COMMANDS)rœ   rn   rr   ry   r   ÚtargetÚwordÚhits   &       r   Úcommand_deletes_runtimer§   õ   s  € ÷ ˜'Ÿ-™-Ÿ/š/ÙÜ“€IßÙä$×*Ñ*¨7×3ˆÜ¤¨WÓ 5Ó6ˆßÙÜ�w‰w×Ñ  a¥Ó)×/Ñ/Ó1ˆà�4Œ<Ü)¨%Ó0ˆFßØ’Ùà�6Œ>œo×4Ñ4°W×=Ò=Ø˜bŸ	˜	�Ø—‘ s×+Ô+Ü+¨DÓ1�Cß‘sØ"œ
ñ	 "ñ
 àÔ)Ô)Ùà˜"—I�IˆDØ�‰˜s×#Ò#ÙÜ# DÓ)ˆCß‰sØ”
ô ñ/ 4ñ< r   >   ÚenvÚexecÚniceÚsudoÚtimeÚnohuprœ   >   ÚrdÚriÚrmÚdelÚeraseÚrmdirúremove-item)"Ú__doc__Ú
__future__r   r   r€   ru   rH   Ú	functoolsr   Úpathlibr   Útypingr   Úcompiler    Ú	frozensetr   r£   Ú
IGNORECASEr¡   rI   r   r&   r6   rP   rS   r[   rc   rp   rw   rƒ   r‰   rš   r§   r   r   r   Ú<module>r½      sï   ðñõ: #ã 	Û 	Û Û 
Ý Ý Ý ð
 —J’JÐ1Ó2Ð ñ ÒYÓZÐ ñ
 ò  ó Ð ð
 —*’*Ð?ÀÇÁÓO€ð —Z’ZØróÐ ð Ÿ:š:Ð&FÓGÐ õ8õ>ñ �1ÔôAó ðAõ8gõDõ	ð°4÷ õ&õõeõ÷2-r   