+
    lHàj(  ã                   ó  € R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIH	t	H
t
 ]P                  ! R4      t]R]R]P                  /R R ll4       t]R	3R
 R lltR R ltR4t]P(                  ! R4      tR R ltR R ltR R ltR R ltR R lt]! 0 R5m4      t]0 R6m,          tR R ltR7R R lltR R lt R R  lt!R! R" lt"R# R$ lt#]
R% R& l4       t$]
R' R( l4       t$R) R* lt$R+ R, lt%R-R/R. R/ llt&R8R0 R1 llt'R2 R3 lt(R# )9aƒ  Terminal backend configuration: scope-aware TERMINAL_* reads, env-var parsing,
container-cwd sanity checks, plugin-backend classification, and the ``_quiet``
best-effort block shared by the terminal_tool_* modules.

Split out of ``tools/terminal_tool.py``; every public/patched name is re-imported there,
so ``tools.terminal_tool.<name>`` keeps resolving (and monkeypatching) as before.
N)Úcontextmanager)ÚAnyÚoverloadztools.terminal_toolÚexcÚlevelc                ó0   € V ^8„  d   QhR\         R\        /# )é   Úlabelr   )ÚstrÚint)Úformats   "Ú?/home/ubuntu/.hermes/hermes-agent/tools/terminal_tool_config.pyÚ__annotate__r      s   € ÷ 7ñ 7”#ð 7´Cñ 7ó    c             '  óh   "  €  Rx € R#   T d    \         P                  ! Y .TO5RR/   R# i ; i5i)z±Best-effort block: swallow *exc*, log *label* (``%``-formatted with *args*)
at *level* with the traceback. For janitor/advisory work that must never
take the terminal tool down.NÚexc_infoT)ÚloggerÚlog)r	   r   r   Úargss   &$$*r   Ú_quietr      s1   é € ð
7ÝøØô 7Ü�
Š
�5Ð6 $Ò6°Õ6ð7üs   ‚2„
 ˆ2Š!/«2®/¯2Úintegerc                óH   € V ^8„  d   QhR\         R\         R\        R\         /# )r   ÚnameÚdefaultÚ	converterÚ
type_label)r
   r   )r   s   "r   r   r       s(   € ÷ 
ñ 
œð 
¤sð 
´sð 
Ìcñ 
r   c           
     óî   € V P                  R4      '       d   \        W4      M\        P                  ! W4      p V! V4      #   \        \
        P                  3 d    \	        RT  RT: RT R24      hi ; i)z»Parse an env var with *converter*, raising a clear ValueError on bad
values (e.g. TERMINAL_TIMEOUT=5m) instead of an opaque crash. TERMINAL_*
names are read scope-aware via :func:`_tenv`.Ú	TERMINAL_zInvalid value for z: z (expected z1). Check ~/.hermes/.env or environment variables.)Ú
startswithÚ_tenvÚosÚgetenvÚ
ValueErrorÚjsonÚJSONDecodeError)r   r   r   r   Úraws   &&&& r   Ú_parse_env_varr&       s{   € ð #'§/¡/°+×">Ò">Œ%�Ô
ÄBÇIÂIÈdÓD\€Cð
Ù˜‹~ÐøÜœ×,Ñ,Ð-ô 
ÜØ    b¨©¨{¸:¸,ð G=ð >ó
ð 	
ð
ús   ºA Á2A4c                ó$   € V ^8„  d   QhR\         /# )r   Úreturn©r
   )r   s   "r   r   r   .   s   € ÷ @ñ @”cñ @r   c                 óÀ   €  \         P                  ! 4       #   \        \        3 d6    \	        R4      ;'       g     \         P
                  P                  R4      u # i ; i)z»``os.getcwd()`` tolerant of a deleted cwd (FileNotFoundError) or a macOS
TCC-protected one without Full Disk Access (PermissionError); falls back
to TERMINAL_CWD, then the home directory.ÚTERMINAL_CWDÚ~)r    ÚgetcwdÚFileNotFoundErrorÚPermissionErrorr   ÚpathÚ
expanduser© r   r   Ú_safe_getcwdr3   .   sL   € ð@Ü�yŠy‹{ÐøÜœÐ/ô @Ü�^Ó$×?Ð?¬¯©×(:Ñ(:¸3Ó(?Ò?ð@ús   ‚ —"Aº AÁAz^[A-Za-z]:[\\/]c                ó0   € V ^8„  d   QhR\         R\        /# ©r   r0   r(   ©r
   Úbool)r   s   "r   r   r   >   s   € ÷ Vñ V”sð Vœtñ Vr   c                 óx   € V P                  \        4      ;'       g    \        \        P	                  V 4      4      # ©N)r   Ú_HOST_CWD_PREFIXESr7   Ú_WINDOWS_DRIVE_REÚmatch©r0   s   &r   Ú_is_host_cwdr>   >   s+   € Ø�?‰?Ô-Ó.×UÐU´$Ô7H×7NÑ7NÈtÓ7TÓ2UÐUr   c                ó0   € V ^8„  d   QhR\         R\        /# r5   r6   )r   s   "r   r   r   B   s   € ÷ >ñ >¤ð >¬ñ >r   c                ód   € \        V 4      ;'       d    \        \        P                  V 4      4      # )z@True for any ``D:\...`` / ``e:/...`` path. Not a username check.)r7   r;   r<   r=   s   &r   Ú_is_windows_drive_pathrA   B   s%   € ä�‹:×=Ð=œ$Ô0×6Ñ6°tÓ<Ó=Ð=r   c                ó0   € V ^8„  d   QhR\         R\         /# r5   r)   )r   s   "r   r   r   G   s   € ÷ ñ œð ¤ñ r   c                ó  € T ;'       g    RP                  RR4      p\        V4      ^8¼  d4   V^,          R8X  d&   V^ ,          P                  4       VR,          ,           p\        V4      ^8”  d   VP                  R4      pV# )zåCompare host paths without caring about slash style or drive-letter case.

A trailing slash is not significant, except we never collapse a drive root
(``C:/``) into a bare ``C:`` that would prefix-match every path on that drive.
Ú Ú\Ú/Ú::é   NN)ÚreplaceÚlenÚlowerÚrstrip)r0   Útexts   & r   Ú_host_path_keyrN   G   sg   € ð �JˆJ�B×Ñ  cÓ*€DÜ
ˆ4ƒy�A„~˜$˜q�' Sœ.Ø�A�w�}‰}‹  b¥Õ)ˆÜ
ˆ4ƒy�1„}Ø�{‰{˜3ÓˆØ€Kr   c          	      óV   € V ^8„  d   QhR\         R\         R\         R\         R,          /# )r   r0   Ú	host_rootÚcontainer_rootr(   Nr)   )r   s   "r   r   r   U   s/   € ÷ *ñ *¤cð *´cð *Ì3ð *ÔSVÐY]ÕS]ñ *r   c                óð  € \        V \        4      '       d-   \        V\        4      '       d   \        V\        4      '       g   R# V '       d   V'       d	   V'       g   R# \        V 4      p\        V4      pV'       d	   V'       g   R# VP                  R4      ;'       g    RpW48X  d   V# VP	                  R4      '       d   TMVR,           pVP                  V4      '       g   R# V RV\        V4      R  2# )zøMap *path* onto *container_root* when it is *host_root* or a child of it.

Returns None when *path* is not under that host directory. Slash style and
drive-letter case do not matter; a sibling directory (``proj`` vs ``proj-other``)
is not a child.
NrF   )Ú
isinstancer
   rN   rL   Úendswithr   rJ   )r0   rP   rQ   ÚkeyÚrootÚmountÚprefixs   &&&    r   Útranslate_mounted_host_pathrY   U   s¾   € ô �dœC× Ò ¬
°9¼c×(BÒ(BÌ*ÐUcÔeh×JiÒJiÙß—y¯ÙÜ
˜Ó
€CÜ˜)Ó$€Dß—dÙØ×!Ñ! #Ó&×-Ð-¨#€EØ
„{ØˆØ—]‘] 3×'Ò'‰T¨T°C­Z€FØ�>‰>˜&×!Ò!ÙØˆW�A�cœ#˜f›+˜,Ð'Ð(Ð)Ð)r   c                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   ÚcwdrW   r(   r6   )r   s   "r   r   r   m   s!   € ÷ 	9ñ 	9¤ð 	9¬Cð 	9´Dñ 	9r   c                ó|   € V'       d   V '       d   W8X  d   R# \        V 4      '       d   R# V R8H  ;'       d    VR8g  # )zœTrue when *cwd* was the host workspace (or the assumed ``/workspace`` view of it).

An explicit in-container path other than that assumption is left alone.
FTz
/workspace)Ú_is_unusable_container_cwd)r[   rW   s   &&r   Úcwd_follows_host_mountr^   m   s6   € ÷
 Ÿ˜sœ|ÙÜ! #×&Ò&ÙØ�,Ñ×8Ð8 5¨LÑ#8Ð8r   c                ó0   € V ^8„  d   QhR\         R\         /# )r   Úenv_typeÚfn_namer)   )r   s   "r   r   r   |   s   € ÷ ñ ¤cð ´Cñ r   c                ó†   € V '       d   V \         9   d   V#  ^ RIHp \        WA4      ! V .VO5!  #   \         d    Tu # i ; i)u  Call ``agent.terminal_env_registry.<fn_name>(env_type, *args)`` for a
plugin backend. Fail-soft: *default* for built-in/empty backends, when the
registry is unavailable, or when the provider raises â€” a misbehaving plugin
must never take the terminal tool down.N)Ú_BUILTIN_BACKENDSÚagent.terminal_env_registryÚterminal_env_registryÚgetattrÚ	Exception)r`   ra   r   r   Úregs   &&&* r   Ú_plugin_registry_lookupri   |   sE   € ÷
 �xÔ#4Ô4ØˆðÝ1ä�sÔ$ XÐ5°Ó5Ð5øÜô ØŠðús   —0 °A ¿A c                ó0   € V ^8„  d   QhR\         R\         /# )r   r`   Úattrr)   )r   s   "r   r   r   ‹   s   € ÷ Vñ Vœsð V¬#ñ Vr   c                ó   € \        V RW!V4      # )zJClassification flag of a plugin-registered backend (fail-soft, see above).Úprovider_flag©ri   )r`   rk   r   s   &&&r   Ú_plugin_env_flagro   ‹   s   € ä" 8¨_¸gÈWÓUÐUr   c                ó0   € V ^8„  d   QhR\         R\        /# )r   r`   r(   r6   )r   s   "r   r   r   �   s   € ÷ Yñ Y¤Cð Y¬Dñ Yr   c                ó<   € V \         9   ;'       g    \        V R4      # )zLTrue for built-in container backends and plugins declaring ``is_container``.Úis_container)Ú_CONTAINER_BACKENDSro   ©r`   s   &r   Ú_is_container_backendru   �   s   € àÔ*Ñ*×XÐXÔ.>¸xÈÓ.XÐXr   c                ó$   € V ^8„  d   QhR\         /# )r   r`   r)   )r   s   "r   r   r   •   s   € ÷ Cñ C¤sñ Cr   c                ó   € \        V RR4      # )z>Return the registered plugin provider for *env_type*, or None.Úget_providerNrn   rt   s   &r   Ú_get_plugin_env_providerry   •   s   € ä" 8¨^¸TÓBÐBr   c                ó>   € V ^8„  d   QhR\         R\        R,          /# )r   Úenvr(   N)r   r
   )r   s   "r   r   r   š   s"   € ÷ ]ñ ]œSð ]¤S¨4¥Zñ ]r   c                ó–   € \        V RR4      p\        V\        4      '       d&   \        P                  ! V4      '       d
   VR8w  d   V# R# )z”The home a plugin environment started in (``_build_plugin_env`` stamps it per environment, so two
sandboxes of one backend never share it), or None.Ú_hermes_sandbox_homeNrF   )rf   rS   r
   Ú	posixpathÚisabs)r{   Úhomes   & r   Úplugin_sandbox_homer�   š   s?   € ô �3Ð.°Ó5€DÜ˜d¤C×(Ò(¬Y¯_ª_¸T×-BÒ-BÀtÈsÄ{ˆ4Ð\ÐX\Ð\r   c                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   r[   r{   r(   )r   r7   )r   s   "r   r   r   ¡   s!   € ÷ 5ñ 5œ#ð 5¤Cð 5¬Dñ 5r   c                ó.  € \        V4      pV'       d3   \        V \        4      '       d   \        P                  ! V 4      '       g   R# \        P
                  ! V4      \        P
                  ! V 4      rW8H  ;'       g    V P                  VR,           4      # )z‘True for *cwd* at or under *env*'s sandbox home: a ``cd`` inside that sandbox, not a host workspace,
even when it looks like one (``/home/...``).FrF   )r�   rS   r
   r~   r   Únormpathr   )r[   r{   r€   s   && r   Ú_in_sandbox_homer…   ¡   sh   € ô ˜sÓ#€Dß”z #¤s×+Ò+´9·?²?À3×3GÒ3GÙÜ×"Ò" 4Ó(¬)×*<Ò*<¸SÓ*Aˆ#Ø‰;×4Ð4˜#Ÿ.™.¨°­Ó4Ð4r   c                óJ   € V ^8„  d   QhR\         R\         R,          R\         /# )r   r[   r`   Nr(   r)   )r   s   "r   r   r   ¬   s   € × EÑ EœsÐ E¬c°D­jÐ E¼SÑ Er   c                 ó   € R # r9   r2   ©r[   r`   s   &&r   Úcoerce_ssh_remote_cwdr‰   «   s   € ÙBEr   c                ó:   € V ^8„  d   QhRRR\         R,          RR/# ©r   r[   Nr`   r(   r)   )r   s   "r   r   r   ®   s   € × GÑ G˜tÐ G¬s°T­zÐ G¸dÑ Gr   c                 ó   € R # r9   r2   rˆ   s   &&r   r‰   r‰   ­   s   € ÙDGr   c                óf   € V ^8„  d   QhR\         R,          R\         R,          R\         R,          /# r‹   r)   )r   s   "r   r   r   ¯   s2   € ÷ Hñ Hœs T�zð H´S¸4µZð HÄCÈ$ÅJñ Hr   c                ó®  € \        V \        4      '       d.   T;'       g    RP                  4       P                  4       R8w  d   V # V P                  4       pV'       d   VP	                  R4      '       d   T;'       g    R# ^ RIHpHp V! 4       pV'       dQ   \        P                  ! V4      '       d5   \        P                  ! V4      \        P                  ! V! 4       4      8X  d   V# \        P                  ! \        P                  ! V4      \        P                  ! V4      4      pVR8X  d   R# VR8X  g   VP	                  R4      '       d   V# RV 2# )	aÿ  Cwd to send to an SSH backend.

``~``-prefixed paths stay literal so the remote shell expands them to the
SSH user's home. The Hermes process's subprocess home (``/opt/data/home``
in the official Docker image) is a directory on the machine running
Hermes: it and anything under it are rewritten onto the remote ``~``, since
``cd`` into the host path exits 126 on the target. A subprocess home that is
the OS user's real home is left alone: a remote path may legitimately match
it. Other backends are unchanged.
rD   Ússhr,   )Úget_real_homeÚget_subprocess_homeÚ.z..z../z~/)rS   r
   ÚstriprK   r   Úhermes_constantsr�   r‘   r~   r   r„   Úrelpath)r[   r`   rM   r�   r‘   r€   Úrels   &&     r   r‰   r‰   ¯   sö   € ô �cœ3×Ò H§N N°×#9Ñ#9Ó#;×#AÑ#AÓ#CÀuÔ#LØˆ
Ø�9‰9‹;€Dß�4—?‘? 3×'Ò'Ø�{ˆ{�sÐßCáÓ €Dß”y—’ t×,Ò,´	×0BÒ0BÀ4Ó0HÌI×L^ÒL^Ñ_lÓ_nÓLoÔ0oØˆÜ
×
Ò
œI×.Ò.¨tÓ4´i×6HÒ6HÈÓ6NÓ
O€CØ
ˆc„zÙØ˜$”; #§.¡.°×"7Ò"7ˆ4ÐG¸rÀ#À¸ZÐGr   c                óJ   € V ^8„  d   QhR\         R\         R,          R\        /# ©r   r[   Úmounted_hostNr(   r6   )r   s   "r   r   r   Ê   s%   € ÷ ñ œcð ´°tµð Äñ r   c                óð  € V '       d   \        V\        4      '       d	   V'       g   R#  \        P                  P	                  \        P                  P                  \        P                  P                  V 4      4      4      p\        P                  P	                  \        P                  P                  \        P                  P                  V4      4      4      pW#8H  #   \        \        3 d     R# i ; i)a  True when *cwd* is the host directory mounted at ``/workspace``.

Checked before the ``/Users`` / ``/home`` / drive-letter heuristic: a WSL
checkout under ``/mnt/...`` or an absolute path under ``/srv/...`` is
``os.path.isabs`` and would otherwise look like a valid container workdir.
F)	rS   r
   r    r0   r„   Úabspathr1   ÚOSErrorr"   )r[   r™   ÚleftÚrights   &&  r   Ú_is_mounted_host_cwdrŸ   Ê   s    € ÷ ”j ¬s×3Ò3¿<ÙðÜ�w‰w×Ñ¤§¡§¡´·±×0BÑ0BÀ3Ó0GÓ HÓIˆÜ—‘× Ñ ¤§¡§¡´·±×1CÑ1CÀLÓ1QÓ!RÓSˆð ‰=Ðøô ”ZÐ ô Úðús   ªB2C  Ã C5Ã4C5r™   c                óJ   € V ^8„  d   QhR\         R\         R,          R\        /# r˜   r6   )r   s   "r   r   r   Û   s&   € ÷ 7ñ 7¤Cð 7¼#À½*ð 7ÔPTñ 7r   c               óª   € V '       g   R# \        W4      '       d   R# \        V 4      ;'       g%    \        P                  P	                  V 4      '       * # )aä  True if *cwd* is a host or relative path that can't be a container
workdir: ``docker run -w`` needs an absolute in-sandbox path, otherwise the
container fails to start (exit 125). Windows drive paths aren't ``isabs``
on POSIX, so they're caught by the prefix check.

The directory mounted at ``/workspace`` is unusable inside the container
even when it matches none of those prefixes. That equality check runs
first so ``/mnt/...`` and ``/srv/...`` are not wrapped as ``cd`` targets.
FT)rŸ   r>   r    r0   r   )r[   r™   s   &$r   r]   r]   Û   s;   € ÷ ÙÜ˜C×.Ò.ÙÜ˜Ó×6Ð6¤B§G¡G§M¡M°#Ó$6Ô 6Ð6r   c                ó<   € V ^8„  d   QhR\         R\         R\         /# ©r   r   r   r(   r)   )r   s   "r   r   r   ì   s!   € ÷ 'ñ '”ð 'œcð '¬3ñ 'r   c                ó   € ^ RI Hp V! W4      # )a  Scope-aware read of a ``TERMINAL_*`` variable. Every terminal setting
must go through this: under gateway multiplexing the active profile's
config arrives via a per-turn scope, and a raw ``os.getenv`` would read
whatever a previous turn pinned into the process env (cross-profile leak).)Úterminal_env)Útools.terminal_scoper¥   )r   r   r¥   s   && r   r   r   ì   s   € õ
 2á˜Ó&Ð&r   c                ó<   € V ^8„  d   QhR\         R\         R\        /# r£   r6   )r   s   "r   r   r   ö   s&   € ÷ @ñ @”Sð @¤3ð @¬4ñ @r   c                ó:   € \        W4      P                  4       R9   # )zGScope-aware boolean ``TERMINAL_*`` read: true/1/yes (case-insensitive).>   Ú1ÚyesÚtrue)r   rK   )r   r   s   &&r   Ú
_tenv_boolr¬   ö   s   € ä�Ó×%Ñ%Ó'Ð+?Ñ?Ð?r   )z/Users/z/home/>   ÚmodalÚdockerÚdaytonaÚvercel_sandbox>   r�   ÚlocalÚmanaged_modal)F)rD   ))Ú__doc__Úloggingr#   r    r~   ÚreÚ
contextlibr   Útypingr   r   Ú	getLoggerr   rg   ÚDEBUGr   r   r&   r3   r:   Úcompiler;   r>   rA   rN   rY   r^   Ú	frozensetrs   rc   ri   ro   ru   ry   r�   r…   r‰   rŸ   r]   r   r¬   r2   r   r   Ú<module>r¼      s  ðñó Û Û 	Û Û 	Ý %ß  ð 
×	Ò	Ð0Ó	1€ð ð7 )ð 7¸'¿-¹-ö 7ó ð7ð >AÐT]÷ 
õ@ð +Ð Ø—J’JÐ1Ó2Ð õVõ>õ
õ*õ0	9ñ  Ò PÓQÐ Ø'Ò*KÕKÐ õ÷Võ
Yõ
Cõ
]õ5ð 
Ü Eó 
Ø EØ	Ü Gó 
Ø GõHõ6ð"7Àt÷ 7÷"'÷@r   