§
    øžyj%” ã                   ó  — 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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mZmZ ddlmZ  ej        e¦  «        Zdedefd„Zdd	lmZmZ dd
l m!Z! ddl"m#Z# ddl$m%Z%m&Z&m'Z'm(Z(m)Z) dededefd„Z* e*dde+d¦  «        Z, e*dde-d¦  «        Z.dZ/dZ0dede1fd„Z2de3eef         de1fd„Z4dddœZ5e3e6d <   d!Z7d"„ Z8i Z9e3eef         e6d#<    ej:        ¦   «         Z; ej<        ¦   «         Z=d$„ Z>d%„ Z?d&„ Z@d'„ ZAdefd(„ZBdefd)„ZCd*eddfd+„ZDdþd,„ZEdd-lFmGZH d.ede1fd/„ZIdeeef         de1fd0„ZJ	 dÿd1ed2ed3e1de3fd4„ZK eLd5¦  «        ZMd6ede1fd7„ZNd8ededz  fd9„ZOd:ed2edefd;„ZPd<ZQd:ede1fd=„ZRd1edz  d:ede1fd>„ZS�d d@e+defdA„ZT�dd1edCe+defdD„ZUdEede1fdF„ZVd1edGe+deWee+f         fdH„ZXd1edeWee+f         fdI„ZYd1ede+fdJ„ZZde1fdK„Z[d1edefdL„Z\d1edz  deWedz  edz  f         fdM„Z]ddNl^m_Z_ ddOl`maZb ddPl"mcZd ddQlemfZg ddRlhmiZj ddSlkmlZm ddTlnmoZp ddUlqmrZr ddlsZsdVZti Zueeef         e6dW<   i Zveee-f         e6dX<    ej:        ¦   «         Zwi Zxeeej:        f         e6dY<    ej:        ¦   «         Zydazda{da| ej:        ¦   «         Z}dZeeef         ddfd[„Z~i Zeeeeef         f         e6d\<   i Z€eeef         e6d]<    ej:        ¦   «         Z�d^ee         d_ee         ddfd`„Z‚d^ee         dee         fda„Zƒd^eddfdb„Z„dceddeeef         fde„Z…dcefdf„Z†i Z‡eeef         e6dg<    ej:        ¦   «         Zˆdhediee         ddfdj„Z‰dcedefdk„ZŠde1fdl„Z‹ eLh dm£¦  «        ZŒdcee         de1fdn„Z�dcee         defdo„ZŽdcee         deeef         fdp„Z�deeef         dcee         dee         fdq„Z�e+dfdededredefds„Z‘defdt„Z’duZ“ eLh dv£¦  «        Z”d_ede1fdw„Z•da–dþdx„Z—deeef         fdy„Z˜dze™dz  deeef         fd{„Zšdeeef         de3fd|„Z›deeef         de3fd}„Zœ	 	 	 	 �dd2ed~ed_ede+d€e3dZe3d�e3dced‚ee         fdƒ„Z��dd…e+fd†„Zžd‡„ ZŸdˆ„ Z d‰„ Z¡dcefdŠ„Z¢�ddcee         fd‹„Z£dcede1fdŒ„Z¤d�„ Z¥ddŽœdced�e1fd�„Z¦d‘„ Z§ ej¨        e§¦  «         d1ed’e+dedz  fd“„Z©d1ede1fd”„Zª ej«        d•ej¬        ej­        z  ¦  «        Z® ej«        d–¦  «        Z¯ ej«        d—¦  «        Z°d1edefd˜„Z± ej«        d™ej¬        ¦  «         ej«        dšej¬        ¦  «         ej«        d›ej¬        ¦  «         ej«        dœej¬        ¦  «         ej«        d�ej¬        ¦  «         ej«        džej¬        ¦  «         ej«        dŸej¬        ¦  «         ej«        d ej¬        ¦  «        fZ²d1ede1fd¡„Z³d1ededz  fd¢„Z´d£e1d¤e1deWfd¥„Zµddd¦œd8ee         d§ed^ee         d2ee         def
d¨„Z¶	 	 	 	 	 	 	 	 	 �dd1ed¤e1dee+         dcee         d©ee         dªe1d8ee         d«e1d£e1d¬eee                  defd­„Z·dcee         ddfd®„Z¸de1fd¯„Z¹ed°k    �r\ eºd±¦  «          eºd²¦  «          e˜¦   «         Z» eºd³¦  «          eºd´e»d2         › �¦  «          eºdµe»d¶         › �¦  «          eºd·e»d¸         › �¦  «          eºd¹e»d_         › �¦  «          eºdºe»d         › d»�¦  «          eºd¼e»d…         › d»�¦  «          e¹¦   «         s eºd½¦  «          esj¼        d¾¦  «          eºd¿¦  «          eºdÀ¦  «          eºdÁ¦  «          eºdÂ¦  «          eºdÃ¦  «          eºdÄ¦  «          eºdÅ¦  «          eºdÆ¦  «          eºdÇ¦  «          eºdÈ¦  «         dÉZ½ eºdÊ ej¾        dËdÌ¦  «        › dÍ�¦  «          eºdÎ ej¾        dÏe½¦  «        › �¦  «          eºdÐ ej¾        dÑdÒe½› �¦  «        › �¦  «          eºdÓ ej¾        dÔe½¦  «        › �¦  «          eºdÕ ej¾        dÖe½¦  «        › �¦  «          eºd× ej¾        dØ e’¦   «         ¦  «        › �¦  «         ddÙl¿mÀZÁ  eºdÚ ej¾        dÛ eÁ¦   «         › dÜ�¦  «        › �¦  «          eºdÝ ej¾        dÞdß¦  «        › �¦  «          eºdà ej¾        dádâ¦  «        › �¦  «         ddãl mÂZÂ däetdådædçdèœdédêddëœddìe,› díe,› dî�d¾dïœdædðdèœdédñddëœdédòddëœdódôdæidõdöœd÷œd1gdøœdùœZÃdú„ ZÄ eÂj¨        dädäeÃeÄe¹dûdü¬ý¦  «         dS (  a¼  
Terminal Tool Module

A terminal tool that executes commands in local, Docker, Modal, SSH,
Singularity, Daytona, and Vercel Sandbox environments. Supports local
execution, containerized backends, and cloud sandboxes, including managed
Modal mode.

Environment Selection (via TERMINAL_ENV environment variable):
- "local": Execute directly on the host machine (default, fastest)
- "docker": Execute in Docker containers (isolated, requires Docker)
- "modal": Execute in Modal cloud sandboxes (direct Modal or managed gateway)
- "vercel_sandbox": Execute in Vercel Sandbox cloud sandboxes

Features:
- Multiple execution backends (local, docker, modal, vercel_sandbox)
- Background task support
- VM/container lifecycle management
- Automatic cleanup after inactivity

Cloud sandbox note:
- Persistent filesystems preserve working state across sandbox recreation
- Persistent filesystems do NOT guarantee the same live sandbox or long-running processes survive cleanup, idle reaping, or Hermes exit

Usage:
    from terminal_tool import terminal_tool

    # Execute a simple command
    result = terminal_tool("ls -la")

    # Execute in background
    result = terminal_tool("python server.py", background=True)
é    N)ÚPath)ÚOptionalÚDictÚAnyÚList)Úenv_var_enabledÚvalueÚreturnc                 óJ   — ddl m}  || €dnt          | ¦  «        d¬¦  «        S )z?Force-redact text before serializing a terminal error envelope.r   )Úredact_sensitive_textNÚ T)Úforce)Úagent.redactr   Ústr)r	   r   s     ú9/home/ragecks/.hermes/hermes-agent/tools/terminal_tool.pyÚ_redact_terminal_error_textr   9   s8   € à2Ð2Ð2Ð2Ð2Ð2à Ð  u }  ½#¸e¹*¼*ÈDÐQÑQÔQÐQó    )Úis_interruptedÚ_interrupt_event)Ú
tool_error)Ú_get_scratch_dir)Úcoerce_modal_modeÚhas_direct_modal_credentialsÚmanaged_nous_tools_enabledÚ%nous_tool_gateway_unavailable_messageÚresolve_modal_backend_stateÚnameÚdefaultÚ
type_labelc                 óÄ   — t          j        | ¦  «        }|�|dk    r|S 	  ||¦  «        S # t          t          f$ r# t                               d| |||¦  «         |cY S w xY w)záParse module-level numeric env vars without breaking import.

    Terminal tool is imported by CLI, ACP, tests, and tool discovery. A single
    malformed env var must not make the whole module unloadable at import time.
    Nr   z;Invalid value for %s: %r (expected %s). Falling back to %r.)ÚosÚgetenvÚ	TypeErrorÚ
ValueErrorÚloggerÚwarning©r   r   Ú	converterr   Úraws        r   Ú_safe_parse_import_envr*   [   s†   € õ Œ)�D‰/Œ/€CØ
€{�c˜R’i�iØˆð
Øˆy˜‰~Œ~ÐøÝ•zÐ"ð ð ð Ý�ŠØIØØØØñ	
ô 	
ð 	
ð ˆˆˆðøøøs    
+ «1AÁAÚTERMINAL_MAX_FOREGROUND_TIMEOUTiX  ÚintegerÚTERMINAL_DISK_WARNING_GBg     @@Únumberz/vercel/sandbox)Únode24Únode22z
python3.13Úruntimec                 ó   — |  p| t           v S ©N)Ú_SUPPORTED_VERCEL_RUNTIMES)r1   s    r   Ú_is_supported_vercel_runtimer5   ‰   s   € Øˆ;Ð?˜'Õ%?Ð?Ð?r   Úconfigc                 ó&  — |                       d¦  «        pd                     ¦   «         }t          |¦  «        s8d                     t          ¦  «        }t
                               d||¦  «         dS |                       dd¦  «        }|dvrt
                               d	|¦  «         dS t          j         	                    d
¦  «        €t
                               d¦  «         dS ddl
m} t           |d¦  «        ¦  «        }t           |d¦  «        ¦  «        }t           |d¦  «        ¦  «        }t           |d¦  «        ¦  «        }|rdS |s|s|r$|r|r|rdS t
                               d¦  «         dS t
                               d¦  «         dS )z6Validate Vercel Sandbox terminal backend requirements.Úvercel_runtimer   z, zVVercel Sandbox runtime %r is not supported. Set TERMINAL_VERCEL_RUNTIME to one of: %s.FÚcontainer_diské È  >   r   r:   zmVercel Sandbox does not support custom TERMINAL_CONTAINER_DISK=%s. Use the default shared setting (51200 MB).ÚvercelNzNvercel is required for the Vercel Sandbox terminal backend: pip install vercelr   ©Ú
get_secretÚVERCEL_OIDC_TOKENÚVERCEL_TOKENÚVERCEL_PROJECT_IDÚVERCEL_TEAM_IDTzÅVercel Sandbox backend selected with token auth, but VERCEL_TOKEN, VERCEL_PROJECT_ID, and VERCEL_TEAM_ID must all be set together. VERCEL_OIDC_TOKEN is supported for one-off local development only.zÙVercel Sandbox backend selected but no supported auth configuration was found. Set VERCEL_TOKEN, VERCEL_PROJECT_ID, and VERCEL_TEAM_ID for normal use. VERCEL_OIDC_TOKEN is supported for one-off local development only.)ÚgetÚstripr5   Újoinr4   r%   ÚerrorÚ	importlibÚutilÚ	find_specÚagent.secret_scoper=   Úbool)	r6   r1   Ú	supportedÚdiskr=   Úhas_oidcÚ	has_tokenÚhas_projectÚhas_teams	            r   Ú"_check_vercel_sandbox_requirementsrQ   �   sÜ  € à�zŠzÐ*Ñ+Ô+Ð1¨r×8Ò8Ñ:Ô:€GÝ'¨Ñ0Ô0ð Ø—I’IÕ8Ñ9Ô9ˆ	Ý�Šð9àØñ		
ô 	
ð 	
ð ˆuà�:Š:Ð&¨Ñ.Ô.€DØ�:ÐÐÝ�Šð9àñ	
ô 	
ð 	
ð
 ˆuå„~×Ò Ñ)Ô)Ð1Ý�ŠØ\ñ	
ô 	
ð 	
ð ˆuà-Ð-Ð-Ð-Ð-Ð-å�J�JÐ2Ñ3Ô3Ñ4Ô4€HÝ�Z�Z Ñ/Ô/Ñ0Ô0€IÝ�z�zÐ"5Ñ6Ô6Ñ7Ô7€KÝ�J�JÐ/Ñ0Ô0Ñ1Ô1€Hàð Øˆtàð 	�Kð 	 8ð 	Øð 	˜ð 	¨ð 	Ø�4Ý�Šð&ñ	
ô 	
ð 	
ð ˆuå
‡L‚Lð	ñô ð ð ˆ5r   g        F)Ú	timestampÚresultÚ_disk_usage_cacheg     Àr@c                  ó,  — ddl } |                      ¦   «         }|t          d         z
  t          k     rt          d         S 	 t	          ¦   «         }d}ddl}|                     t          |dz  ¦  «        ¦  «        D ]Œ}t          |¦  «                             d¦  «        D ]g}| 	                    ¦   «         rQ	 || 
                    ¦   «         j        z  }Œ4# t          $ r&}t                               d||¦  «         Y d}~Œ_d}~ww xY wŒhŒ�|dz  }|t          k    }	|	r!t                               d	|t          ¦  «         |                      ¦   «         t          d<   |	t          d<   |	S # t"          $ r(}t                               d
|d¬¦  «         Y d}~dS d}~ww xY w)a   Check if total disk usage exceeds warning threshold.

    Result is cached for :data:`_DISK_USAGE_CACHE_TTL` seconds (default:
    5 minutes) to avoid an expensive recursive filesystem scan on every
    terminal command.  The check is advisory-only so a stale result is
    harmless.
    r   NrR   rS   úhermes-*Ú*zCould not stat file %s: %si   @z\Disk usage (%.1fGB) exceeds threshold (%.0fGB). Consider running cleanup_all_environments().z#Disk usage warning check failed: %sT©Úexc_infoF)ÚtimeÚ	monotonicrT   Ú_DISK_USAGE_CACHE_TTLr   Úglobr   r   ÚrglobÚis_fileÚstatÚst_sizeÚOSErrorr%   ÚdebugÚDISK_USAGE_WARNING_THRESHOLD_GBr&   Ú	Exception)
Ú	_time_modÚnowÚscratch_dirÚtotal_bytesr]   ÚpathÚfÚeÚtotal_gbÚexceededs
             r   Ú_check_disk_usage_warningro   Í   sã  € ð ÐÐÐØ
×
Ò
Ñ
Ô
€CØ
Õ˜{Ô+Ñ+Õ.CÒCÐCÝ  Ô*Ð*ðÝ&Ñ(Ô(ˆð ˆØˆˆˆØ—I’I�c +°
Ñ":Ñ;Ô;Ñ<Ô<ð 	Ið 	IˆDÝ˜$‘Z”Z×%Ò% cÑ*Ô*ð Ið I�Ø—9’9‘;”;ð IðIØ# q§v¢v¡x¤xÔ'7Ñ7˜˜øÝ"ð Ið Ið IÝŸšÐ%AÀ1ÀaÑHÔHÐHÐHÐHÐHÐHÐHøøøøðIøøøðIðIð  )Ñ,ˆàÕ=Ò=ˆØð 	FÝ�NŠNÐyØ#Õ%DñFô Fð Fà)2×)<Ò)<Ñ)>Ô)>Õ˜+Ñ&Ø&.Õ˜(Ñ#ØˆøÝð ð ð Ý�ŠÐ:¸AÈˆÑMÔMÐMàˆuˆuˆuˆuˆuøøøøðøøøsD   Á A3E! Â4CÃE! Ã
DÃC<Ã7E! Ã<DÄAE! Å!
FÅ+FÆFÚ_sudo_password_cachec                  ó.   — t          t          dd ¦  «        S )NÚsudo_password©ÚgetattrÚ_callback_tls© r   r   Ú_get_sudo_password_callbackrw     s   € Ý•= /°4Ñ8Ô8Ð8r   c                  ó.   — t          t          dd ¦  «        S )NÚapprovalrs   rv   r   r   Ú_get_approval_callbackrz     s   € Ý•= *¨dÑ3Ô3Ð3r   c                 ó   — | t           _        dS )u½   Register a callback for sudo password prompts (used by CLI).

    Per-thread scope â€” ACP sessions that run concurrently in a
    ThreadPoolExecutor each have their own callback slot.
    N)ru   rr   ©Úcbs    r   Úset_sudo_password_callbackr~     s   € ð #%…MÔÐÐr   c                 ó   — | t           _        dS )uÙ   Register a callback for dangerous command approval prompts.

    Per-thread scope â€” ACP sessions that run concurrently in a
    ThreadPoolExecutor each have their own callback slot. See
    GHSA-qg5c-hvr5-hjgr.
    N)ru   ry   r|   s    r   Úset_approval_callbackr€     s   € ð  …MÔÐÐr   c                  ó‚  — 	 ddl m}   | dd¦  «        }n%# t          $ r t          j        dd¦  «        }Y nw xY w|rd|› �S t          ¦   «         }|�Zt          |dd¦  «        }t          |dd¦  «        }|�$|�"d	t          |¦  «        › d
t          |¦  «        › �S dt          |¦  «        › �S dt          j	        ¦   «         › �S )z6Return the cache scope for interactive sudo passwords.r   )Úget_session_envÚHERMES_SESSION_KEYr   zsession:NÚ__self__Ú__func__zcallback-owner:ú:z	callback:zthread:)
Úgateway.session_contextr‚   re   r!   r"   rw   rt   ÚidÚ	threadingÚ	get_ident)r‚   Úsession_keyÚcallbackÚownerÚfuncs        r   Ú_get_sudo_password_cache_scoper�   )  sÿ   € ð:Ø;Ð;Ð;Ð;Ð;Ð;à%�oÐ&:¸BÑ?Ô?ˆˆøÝð :ð :ð :Ý”iÐ 4°bÑ9Ô9ˆˆˆð:øøøàð (Ø'˜+Ð'Ð'Ð'å*Ñ,Ô,€HØÐÝ˜ *¨dÑ3Ô3ˆÝ�x ¨TÑ2Ô2ˆØÐ Ð!1Ø;¥R¨¡Y¤YÐ;Ð;µ°D±´Ð;Ð;Ð;Ø)�2˜h™<œ<Ð)Ð)Ð)à,•YÔ(Ñ*Ô*Ð,Ð,Ð,s   ‚ •7¶7c                  ó–   — t          ¦   «         } t          5  t                               | d¦  «        cddd¦  «         S # 1 swxY w Y   dS )z6Return the cached sudo password for the current scope.r   N)r�   Ú_sudo_password_cache_lockrp   rB   )Úscopes    r   Ú_get_cached_sudo_passwordr“   ?  sŠ   € å*Ñ,Ô,€EÝ	"ð 3ð 3Ý#×'Ò'¨¨rÑ2Ô2ð3ð 3ð 3ð 3ñ 3ô 3ð 3ð 3ð 3ð 3ð 3ð 3øøøð 3ð 3ð 3ð 3ð 3ð 3s   –>¾AÁAÚpasswordc                 ó²   — t          ¦   «         }t          5  | r| t          |<   nt                               |d¦  «         ddd¦  «         dS # 1 swxY w Y   dS )z.Persist a sudo password for the current scope.N)r�   r‘   rp   Úpop)r”   r’   s     r   Ú_set_cached_sudo_passwordr—   F  s£   € å*Ñ,Ô,€EÝ	"ð 2ð 2Øð 	2Ø*2Õ  Ñ'Ð'å ×$Ò$ U¨DÑ1Ô1Ð1ð	2ð 2ð 2ñ 2ô 2ð 2ð 2ð 2ð 2ð 2ð 2ð 2øøøð 2ð 2ð 2ð 2ð 2ð 2s   –)AÁAÁAc                  óx   — t           5  t                               ¦   «          ddd¦  «         dS # 1 swxY w Y   dS )z`Clear all cached sudo passwords.

    Internal helper for tests and process teardown paths.
    N)r‘   rp   Úclearrv   r   r   Ú_reset_cached_sudo_passwordsrš   P  s€   € õ
 
#ð %ð %Ý×"Ò"Ñ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %ð %ð %s   ˆ/¯3¶3)Úcheck_all_command_guardsÚvolume_specc                 óò   — t          | t          ¦  «        sdS |                      ¦   «         }t          |¦  «        o=|                     d¦  «        p(t          |¦  «        dk    o|d         dk    o	|d         dv S )z>Return True when a docker volume spec bind-mounts a host path.F)ú/Ú~z./z../é   é   r†   é   )rž   ú\)Ú
isinstancer   rC   rJ   Ú
startswithÚlen)rœ   Úvols     r   Ú_docker_volume_uses_host_pathr¨   b  s{   € å�k¥3Ñ'Ô'ð Øˆuà
×
Ò
Ñ
Ô
€CÝ�‰9Œ9ð Ø�ŠÐ.Ñ/Ô/ð 	DÝ	ˆS‰Œ�QŠÐ	B˜3˜qœ6 Sš=Ð	B¨S°¬V°{Ð-Bðr   c                 óê   — |                       d¦  «        dk    rdS |                       d¦  «        r|                       d¦  «        rdS t          d„ |                       dg ¦  «        D ¦   «         ¦  «        S )	zIReturn True when a Docker sandbox exposes host paths through bind mounts.Úenv_typeÚdockerFÚhost_cwdÚdocker_mount_cwd_to_workspaceTc              3   ó4   K  — | ]}t          |¦  «        V — Œd S r3   )r¨   )Ú.0r§   s     r   ú	<genexpr>z*_docker_has_host_access.<locals>.<genexpr>t  s+   è è € Ð^Ð^°cÕ,¨SÑ1Ô1Ð^Ð^Ð^Ð^Ð^Ð^r   Údocker_volumes)rB   Úany©r6   s    r   Ú_docker_has_host_accessr´   n  sx   € à‡z‚z�*ÑÔ Ò)Ð)ØˆuØ‡z‚z�*ÑÔð  &§*¢*Ð-LÑ"MÔ"Mð ØˆtÝÐ^Ð^¸V¿ZºZÐHXÐZ\Ñ=]Ô=]Ð^Ñ^Ô^Ñ^Ô^Ð^r   Úcommandrª   Úhas_host_accessc                 ó@   — t          | |t          ¦   «         |¬¦  «        S )zJDelegate to consolidated guard (tirith + dangerous cmd) with CLI callback.)Úapproval_callbackr¶   )Ú_check_all_guards_implrz   )rµ   rª   r¶   s      r   Ú_check_all_guardsrº   w  s/   € õ " '¨8Ý4JÑ4LÔ4LØ2AðCñ Cô Cð Cr   z/\:_-.~ +@=,Úchc                 ó”   — | sdS t          | ¦  «        dk     st          | ¦  «        dk    rdS |                      ¦   «         p| t          v S )NFé    é   )ÚordÚisalnumÚ_WORKDIR_SAFE_ASCII_CHARS)r»   s    r   Ú_is_safe_workdir_charrÂ   Š  sL   € Øð Øˆuõ ˆ2�w„w�‚|€|•s˜2‘w”w #’~�~ØˆuØ�:Š:‰<Œ<Ð:˜2Õ!:Ð:Ð:r   Úworkdirc                 ó`   — | sdS | D ]&}t          |¦  «        sdt          |¦  «        › d�c S Œ'dS )zÿReject workdir values that don't look like a filesystem path.

    Uses an allowlist of safe characters rather than a deny-list, so novel
    shell metacharacters can't slip through.

    Returns None if safe, or an error message string if dangerous.
    Nz/Blocked: workdir contains disallowed character z<. Use a simple filesystem path without shell metacharacters.)rÂ   Úrepr)rÃ   r»   s     r   Ú_validate_workdirrÆ   ”  sk   € ð ð ØˆtØð ð ˆÝ$ RÑ(Ô(ð 	ðMÅ$ÀrÁ(Ä(ð Mð Mð Mðð ð ð	ð
 ˆ4r   Úoutputc                 óx   — t          d¦  «        }|s| S g d¢}|D ]}|| v rddlm} | d |¦   «         › d�z   c S Œ | S )z¥
    Check for sudo failure and add helpful message for messaging contexts.
    
    Returns enhanced output if sudo failed in messaging context, else original.
    ÚHERMES_GATEWAY_SESSION)zsudo: a password is requiredzsudo: no tty presentzsudo: a terminal is requiredr   ©Údisplay_hermes_homeu@   

ðŸ’¡ Tip: To enable sudo over messaging, add SUDO_PASSWORD to z/.env on the agent machine.)r   Úhermes_constantsrË   )rÇ   rª   Ú
is_gatewayÚsudo_failuresÚfailureÚ_dhhs         r   Ú_handle_sudo_failurerÑ   §  s«   € õ !Ð!9Ñ:Ô:€Jàð Øˆðð ð €Mð !ð Eð EˆØ�fÐÐØDÐDÐDÐDÐDÐDØð  EÐaeÐaeÑagÔagð  Eð  Eð  Eñ  Eð  Eð  Eð  Eð ð €Mr   )zsudo: authentication failedz sudo: incorrect password attemptz1sudo: maximum 3 incorrect authentication attemptsz#sudo: 3 incorrect password attemptsc                 ót   ‡— | sdS |                       ¦   «         Št          ˆfd„t          D ¦   «         ¦  «        S )z0Return True when sudo rejected a piped password.Fc              3   ó    •K  — | ]}|‰v V — Œ	d S r3   rv   )r¯   ÚmarkerÚlowereds     €r   r°   z/_sudo_wrong_password_failure.<locals>.<genexpr>Ï  s(   øè è € ÐLÐL Vˆv˜Ð ÐLÐLÐLÐLÐLÐLr   )Úlowerr²   Ú_SUDO_WRONG_PASSWORD_MARKERS)rÇ   rÕ   s    @r   Ú_sudo_wrong_password_failurerØ   Ê  sA   ø€ àð ØˆuØ�lŠl‰nŒn€GÝÐLÐLÐLÐLÕ/KÐLÑLÔLÑLÔLÐLr   c                 ó´   — dt           j        v rdS t          |¦  «        sdS t          | pd¦  «        dk    rdS t	          ¦   «         sdS t          d¦  «         dS )uÀ   Drop a session-cached sudo password after sudo rejects it.

    Env-configured ``SUDO_PASSWORD`` is left alone â€” that is an explicit
    operator choice, not an interactive cache entry.
    ÚSUDO_PASSWORDFr   r   T)r!   ÚenvironrØ   Ú_count_real_sudo_invocationsr“   r—   )rµ   rÇ   s     r   Ú'_invalidate_cached_sudo_on_auth_failurerÝ   Ò  sm   € ð �"œ*Ð$Ð$ØˆuÝ'¨Ñ/Ô/ð ØˆuÝ# G M¨rÑ2Ô2°aÒ7Ð7ØˆuÝ$Ñ&Ô&ð ØˆuÝ˜bÑ!Ô!Ð!Øˆ4r   é-   Útimeout_secondsc                 óF  ‡— ddl }t          ¦   «         }|�	  |¦   «         pdS # t          $ r Y dS w xY wdddœŠˆfd„}	 dt          j        d<   t          j        d	¦  «         t          ¦   «          t          d
¦  «         t          d¦  «         t          d¦  «         t          d¦  «         t          d¦  «         t          d| › d�dz   dz   ¦  «         t          d¦  «         t          ¦   «          t          ddd¬¦  «         t          j	        |d¬¦  «        }| 
                    ¦   «          |                     | ¬¦  «         ‰d         r~‰d         pd}t          ¦   «          |rt          d¦  «         nt          d¦  «         t          ¦   «          |j                             ¦   «          |dt          j        v rt          j        d= S S t          d¦  «         t          d¦  «         t          ¦   «          |j                             ¦   «          	 dt          j        v rt          j        d= dS dS # t          t          f$ re t          ¦   «          t          d¦  «         t          ¦   «          |j                             ¦   «          Y dt          j        v rt          j        d= dS dS t          $ rT}t          d |› d!�¦  «         |j                             ¦   «          Y d}~dt          j        v rt          j        d= dS dS d}~ww xY w# dt          j        v rt          j        d= w xY w)"aà  
    Prompt user for sudo password with timeout.
    
    Returns the password if entered, or empty string if:
    - User presses Enter without input (skip)
    - Timeout expires (45s default)
    - Any error occurs
    
    Only works in interactive mode (HERMES_INTERACTIVE=1).
    If a _sudo_password_callback is registered (by the CLI), delegates to it
    so the prompt integrates with prompt_toolkit's UI.  Otherwise reads
    directly from /dev/tty with echo disabled.
    r   Nr   F)r”   Údonec                  óÂ  •— d} d}	 t          j        ¦   «         dk    r\ddl}g }	 |                     ¦   «         }|dv rn#|dk    rt          ‚|                     |¦  «         Œ<d                     |¦  «        ‰
d<   nßddl}t          j	        d	t          j
        ¦  «        } |                     | ¦  «        }|                     | ¦  «        }|d
         |j         z  |d
<   |                     | |j        |¦  «         g }	 t          j        | d¦  «        }|r|dv rn|                     |¦  «         Œ2d                     |¦  «                             dd¬¦  «        ‰
d<   n2# t"          t          t$          f$ r d‰
d<   Y nt&          $ r d‰
d<   Y nw xY w| �V|�T	 ddl}|                     | |j        |¦  «         n2# t&          $ r%}	t(                               d|	¦  «         Y d}	~	nd}	~	ww xY w| �H	 t          j        | ¦  «         n2# t&          $ r%}	t(                               d|	¦  «         Y d}	~	nd}	~	ww xY wd‰
d<   dS # | �V|�T	 ddl}|                     | |j        |¦  «         n2# t&          $ r%}	t(                               d|	¦  «         Y d}	~	nd}	~	ww xY w| �H	 t          j        | ¦  «         n2# t&          $ r%}	t(                               d|	¦  «         Y d}	~	nd}	~	ww xY wd‰
d<   w xY w)zKRead password with echo disabled. Uses msvcrt on Windows, /dev/tty on Unix.NÚWindowsr   T>   Ú
úúr   r”   z/dev/ttyr    r¡   >   ó   
ó   r   úutf-8Úreplace©Úerrorsz)Failed to restore terminal attributes: %szFailed to close tty fd: %srá   )ÚplatformÚsystemÚmsvcrtÚgetwchÚKeyboardInterruptÚappendrD   Útermiosr!   ÚopenÚO_RDONLYÚ	tcgetattrÚECHOÚ	tcsetattrÚ	TCSAFLUSHÚreadÚdecodeÚEOFErrorrb   re   r%   rc   Úclose)Útty_fdÚ	old_attrsrï   ÚcharsÚcró   Ú	new_attrsÚbÚ_termiosrl   rS   s             €r   Úread_password_threadz7_prompt_for_sudo_password.<locals>.read_password_thread   s¼  ø€ àˆØˆ	ð*	"ÝŒÑ Ô  IÒ-Ð-Ø���Ø�ð$ØŸš™œ�AØ˜LÐ(Ð(ØØ˜F’{�{Ý/Ð/Ø—L’L ‘O”O�Oð$ð &(§W¢W¨U¡^¤^��zÑ"Ð"à���Ýœ ­R¬[Ñ9Ô9�Ø#×-Ò-¨fÑ5Ô5�	Ø#×-Ò-¨fÑ5Ô5�	Ø(¨œ|¨w¬|¨mÑ;�	˜!‘Ø×!Ò! &¨'Ô*;¸YÑGÔGÐGØ�ð$Ýœ ¨Ñ*Ô*�AØð   ^Ð 3Ð 3ØØ—L’L ‘O”O�Oð	$ð
 &)§X¢X¨e¡_¤_×%;Ò%;¸GÈIÐ%;Ñ%VÔ%V��zÑ"øøÝÕ+­WÐ5ð 	$ð 	$ð 	$Ø!#ˆF�:ÑÐÐÝð 	$ð 	$ð 	$Ø!#ˆF�:ÑÐÐð	$øøøð Ð! iÐ&;ðQØ.Ð.Ð.Ð.Ø×&Ò& v¨xÔ/AÀ9ÑMÔMÐMÐMøÝ ð Qð Qð QÝ—L’LÐ!LÈaÑPÔPÐPÐPÐPÐPÐPÐPøøøøðQøøøàÐ!ðBÝ”H˜VÑ$Ô$Ð$Ð$øÝ ð Bð Bð BÝ—L’LÐ!=¸qÑAÔAÐAÐAÐAÐAÐAÐAøøøøðBøøøà!ˆF�6‰NˆNˆNøð Ð! iÐ&;ðQØ.Ð.Ð.Ð.Ø×&Ò& v¨xÔ/AÀ9ÑMÔMÐMÐMøÝ ð Qð Qð QÝ—L’LÐ!LÈaÑPÔPÐPÐPÐPÐPÐPÐPøøøøðQøøøàÐ!ðBÝ”H˜VÑ$Ô$Ð$Ð$øÝ ð Bð Bð BÝ—L’LÐ!=¸qÑAÔAÐAÐAÐAÐAÐAÐAøøøøðBøøøà!ˆF�6‰NÐ!Ð!Ð!Ð!sº   ‡EE ÅH5 ÅF	Å6H5 Å8F	ÆH5 ÆF	Æ	H5 Æ F2 Æ2
G!Æ<GÇG!Ç'G< Ç<
H+ÈH&È&H+È5KÈ; IÉKÉ
JÉ&JÊKÊJÊKÊJ&Ê%KÊ&
KÊ0KËKËKË	KÚ1ÚHERMES_SPINNER_PAUSEgš™™™™™É?u´   â”Œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”�uA   â”‚  ðŸ”� SUDO PASSWORD REQUIRED                              â”‚u´   â”œâ”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”¤u?   â”‚  Enter password below (input is hidden), or:            â”‚uA   â”‚    â€¢ Press Enter to skip (command fails gracefully)     â”‚u   â”‚    â€¢ Wait zs to auto-skipz                           u   â”‚u´   â””â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”˜z  Password (hidden): T)ÚendÚflush©ÚtargetÚdaemon©Útimeoutrá   r”   u1     âœ“ Password received (cached for this session)u'     â�­ Skipped - continuing without sudou(   
  â�± Timeout - continuing without sudoz    (Press Enter to dismiss)u)     â�­ Cancelled - continuing without sudoz
  [sudo prompt error: z] - continuing without sudo
)Úsysrw   re   r!   rÛ   rZ   ÚsleepÚprintr‰   ÚThreadÚstartrD   Ústdoutr	  rü   rñ   )rß   r  Ú_sudo_cbr  Úpassword_threadr”   rl   rS   s          @r   Ú_prompt_for_sudo_passwordr  æ  s�  ø€ ð €J€J€Jõ +Ñ,Ô,€HØÐð	Ø�8‘:”:Ð# Ð#øÝð 	ð 	ð 	Ø�2�2ð	øøøð ¨Ð.Ð.€Fð."ð ."ð ."ð ."ð ."ð`03Ø-0�Œ
Ð)Ñ*ÝŒ
�3‰Œˆå‰ŒˆÝÐ(Ñ)Ô)Ð)ÝÐCÑDÔDÐDÝÐ(Ñ)Ô)Ð)ÝÐOÑPÔPÐPÝÐQÑRÔRÐRÝÐ@ Ð@Ð@Ð@À8ÑKÈeÑSÑTÔTÐTÝÐ(Ñ)Ô)Ð)Ý‰ŒˆÝÐ%¨2°TÐ:Ñ:Ô:Ð:å#Ô*Ð2FÈtÐTÑTÔTˆØ×ÒÑÔÐØ×Ò _ÐÑ5Ô5Ð5à�&Œ>ð 	Ø˜jÔ)Ð/¨RˆHÝ‰GŒGˆGØð AÝÐIÑJÔJÐJÐJåÐ?Ñ@Ô@Ð@Ý‰GŒGˆGØŒJ×ÒÑÔÐØð& "¥R¤ZÐ/Ð/Ý”
Ð1Ð2Ð2ð 0õ# Ð=Ñ>Ô>Ð>ÝÐ0Ñ1Ô1Ð1Ý‰GŒGˆGØŒJ×ÒÑÔÐØð "¥R¤ZÐ/Ð/Ý”
Ð1Ð2Ð2Ð2ð 0Ð/øõ Õ'Ð(ð ð ð Ý‰ŒˆÝÐ9Ñ:Ô:Ð:Ý‰ŒˆØŒ
×ÒÑÔÐØð "¥R¤ZÐ/Ð/Ý”
Ð1Ð2Ð2Ð2ð 0Ð/õ ð ð ð ÝÐI¨ÐIÐIÐIÑJÔJÐJØŒ
×ÒÑÔÐØˆrˆrˆrà!¥R¤ZÐ/Ð/Ý”
Ð1Ð2Ð2Ð2ð 0Ð/øøøøðøøøøð
 "¥R¤ZÐ/Ð/Ý”
Ð1Ð2Ð2Ð2Ð2Ð2sJ   —# £
1°1¿E-H. Ç	AH. È.AL ÊL Ê#	L Ê,,K;ËL Ë;L Ì L ÌL éÈ   Úlimitc                 óÈ   — | €dS t          | t          ¦  «        r
| d|…         S 	 t          | ¦  «        d|…         S # t          $ r dt	          | ¦  «        j        › d�cY S w xY w)z>Return a log-safe preview for possibly-invalid command values.Nz<None>Ú<Ú>)r¤   r   rÅ   re   ÚtypeÚ__name__)rµ   r  s     r   Ú_safe_command_previewr  b  s�   € à€ØˆxÝ�'�3ÑÔð Ø�v˜�vŒÐð-Ý�G‰}Œ}˜V˜e˜VÔ$Ð$øÝð -ð -ð -Ø,•4˜‘=”=Ô)Ð,Ð,Ð,Ð,Ð,Ð,ð-øøøs   ¥< ¼"A!Á A!Útokenc                 ó®   — d| vs|                       d¦  «        rdS |                      dd¦  «        \  }}t          t          j        d|¦  «        ¦  «        S )zCReturn True when *token* is a leading shell environment assignment.Ú=Fr¡   z^[A-Za-z_][A-Za-z0-9_]*$)r¥   ÚsplitrJ   ÚreÚmatch)r   r   Ú_values      r   Ú_looks_like_env_assignmentr'  m  sW   € à
�%ÐÐ˜5×+Ò+¨CÑ0Ô0ÐØˆuØ—;’;˜s AÑ&Ô&�L€Dˆ&Ý•”Ð4°dÑ;Ô;Ñ<Ô<Ð<r   r  c                 óÖ  — |}t          | ¦  «        }||k     rÇ| |         }|                     ¦   «         s|dv rn¦|dk    r:|dz  }||k     r#| |         dk    r|dz  }||k     r| |         dk    °||k     r|dz  }Œg|dk    r@|dz  }||k     r4| |         }|dk    r|dz   |k     r|dz  }Œ#|dk    r|dz  }n|dz  }||k     °4Œ­|dk    r|dz   |k     r|dz  }ŒÂ|dz  }||k     °Ç| ||…         |fS )zERead one shell token, preserving quotes/escapes, starting at *start*.z;|&()ú'r¡   ú"r£   r¢   )r¦   Úisspace)rµ   r  ÚiÚnr»   Úinners         r   Ú_read_shell_tokenr/  u  s]  € à€AÝˆG‰Œ€Aà
ˆaŠ%ˆ%Ø�QŒZˆØ�:Š:‰<Œ<ð 	˜2 ˜=˜=ØØ�Š9ˆ9Ø�‰FˆAØ�a’%�%˜G AœJ¨#Ò-Ð-Ø�Q‘�ð �a’%�%˜G AœJ¨#Ò-Ð-à�1ŠuˆuØ�Q‘�ØØ�Š9ˆ9Ø�‰FˆAØ�a’%�%Ø œ
�Ø˜D’=�= Q¨¡U¨Q¢Y YØ˜‘F�AØØ˜C’<�<Ø˜‘F�AØØ�Q‘�ð �a’%�%ð Ø�Š:ˆ:˜!˜a™% !š)˜)Ø�‰FˆAØØ	ˆQ‰ˆð5 ˆaŠ%ˆ%ð8 �5˜�7Ô˜QÐÐr   c                 óæ  — g }d}t          | ¦  «        }d}d}||k     �r½| |         }|                     ¦   «         r#|                     |¦  «         |dk    rd}|dz  }ŒF|dk    r]|r[|                      d|¦  «        }|dk    r|                     | |d…         ¦  «         �n;|                     | ||…         ¦  «         |}Œ©|                      d|¦  «        s,|                      d	|¦  «        s|                      d
|¦  «        r)|                     | ||dz   …         ¦  «         |dz  }d}�Œ|dv r|                     |¦  «         |dz  }d}�Œ6|dk    r|                     |¦  «         |dz  }d}�ŒZt          | |¦  «        \  }}	|r!|dk    r|                     d¦  «         |dz  }n|                     |¦  «         |rt          |¦  «        rd}nd}|	}||k     �°½d                     |¦  «        |fS )z�Rewrite only real unquoted sudo command words, not plain text mentions.

    Returns the rewritten command and the number of sudo invocations rewritten.
    r   Trä   r¡   ú#éÿÿÿÿNú&&ú||ú;;r¢   ú;|&(ú)FÚsudozsudo -S -p ''r   )r¦   r+  rò   Úfindr¥   r/  r'  rD   )
rµ   Úoutr,  r-  Úcommand_startÚ
sudo_countr»   Úcomment_endr   Únext_is
             r   Ú_rewrite_real_sudo_invocationsr?  ™  sB  € ð
 €CØ	€AÝˆG‰Œ€AØ€MØ€Jà
ˆaŠ%‰%Ø�QŒZˆà�:Š:‰<Œ<ð 	Ø�JŠJ�r‰NŒNˆNØ�TŠzˆzØ $�Ø�‰FˆAØà�Š9ˆ9˜ˆ9Ø!Ÿ,š, t¨QÑ/Ô/ˆKØ˜bÒ Ð Ø—
’
˜7 1 2 2œ;Ñ'Ô'Ð'ÙØ�JŠJ�w˜q ˜}Ô-Ñ.Ô.Ð.ØˆAØà×Ò˜d AÑ&Ô&ð 	¨'×*<Ò*<¸TÀ1Ñ*EÔ*Eð 	È×I[ÒI[Ð\`ÐbcÑIdÔIdð 	Ø�JŠJ�w˜q  Q¡˜wÔ'Ñ(Ô(Ð(Ø�‰FˆAØ ˆMÙà�ˆ<ˆ<Ø�JŠJ�r‰NŒNˆNØ�‰FˆAØ ˆMÙà�Š9ˆ9Ø�JŠJ�r‰NŒNˆNØ�‰FˆAØ!ˆMÙå)¨'°1Ñ5Ô5‰ˆˆvØð 	˜U fš_˜_Ø�JŠJ�Ñ'Ô'Ð'Ø˜!‰OˆJˆJà�JŠJ�uÑÔÐàð 	"Õ7¸Ñ>Ô>ð 	"Ø ˆMˆMà!ˆMØˆða ˆaŠ%‰%ðd �7Š7�3‰<Œ<˜Ð#Ð#r   c                 ó$  — d}d}t          | ¦  «        }d}||k     rô| |         }|                     ¦   «         r|dk    rd}|dz  }Œ0|dk    r"|r |                      d|¦  «        }|dk    rn¥|}ŒX|                      d|¦  «        s,|                      d|¦  «        s|                      d	|¦  «        r|d
z  }d}Œ¢|dv r|dz  }d}Œ®|dk    r|dz  }d}Œ¼t	          | |¦  «        \  }}|r|dk    r|dz  }|rt          |¦  «        rd}nd}|}||k     °ô|S )zûReturn how many real sudo command words appear in *command*.

    Lightweight scan that reuses the same tokeniser as
    ``_rewrite_real_sudo_invocations`` but skips the string-building, so it
    is cheap to call from the result-processing path.
    r   Trä   r¡   r1  r2  r3  r4  r5  r¢   r6  r7  Fr8  )r¦   r+  r9  r¥   r/  r'  )	rµ   Úcountr,  r-  r;  r»   r=  r   r>  s	            r   rÜ   rÜ   Ù  s†  € ð €EØ	€AÝˆG‰Œ€AØ€Mà
ˆaŠ%ˆ%Ø�QŒZˆà�:Š:‰<Œ<ð 	Ø�TŠzˆzØ $�Ø�‰FˆAØà�Š9ˆ9˜ˆ9Ø!Ÿ,š, t¨QÑ/Ô/ˆKØ˜bÒ Ð ØØˆAØà×Ò˜d AÑ&Ô&ð 	¨'×*<Ò*<¸TÀ1Ñ*EÔ*Eð 	È×I[ÒI[Ð\`ÐbcÑIdÔIdð 	Ø�‰FˆAØ ˆMØà�ˆ<ˆ<Ø�‰FˆAØ ˆMØà�Š9ˆ9Ø�‰FˆAØ!ˆMØå)¨'°1Ñ5Ô5‰ˆˆvØð 	˜U fš_˜_Ø�Q‰JˆEàð 	"Õ7¸Ñ>Ô>ð 	"Ø ˆMˆMà!ˆMØˆðO ˆaŠ%ˆ%ðR €Lr   c                  ó6  — t          j        dd¦  «                             ¦   «                              ¦   «         pd} | dk    rdS 	 t	          j        g d¢t          j        t          j        t          j        dd¬¦  «        }|j        dk    S # t          $ r Y dS w xY w)aN  Return True when local sudo currently works without prompting.

    Only probes for the `local` terminal backend; Docker/SSH/Modal/etc. must
    not inherit the host's sudo state. Re-probes every call (no process-level
    cache) so an expired sudo timestamp cannot make a later command silently
    block waiting for a password.
    ÚTERMINAL_ENVÚlocalF)r8  z-nÚtruer    )Ústdinr  Ústderrr  Úcheckr   )	r!   r"   rC   rÖ   Ú
subprocessÚrunÚDEVNULLÚ
returncodere   )Úterminal_envÚprobes     r   Ú_sudo_nopasswd_worksrO    s°   € õ ”9˜^¨WÑ5Ô5×;Ò;Ñ=Ô=×CÒCÑEÔEÐPÈ€LØ�wÒÐØˆuðÝ”Ø"Ð"Ð"ÝÔ$ÝÔ%ÝÔ%ØØð
ñ 
ô 
ˆð Ô 1Ò$Ð$øÝð ð ð Øˆuˆuðøøøs   ÁAB
 Â

BÂBc                 óT  — t          | ¦  «        }d}d}d}d}g }||k     �rv| |         }|dk    r|dk    r|dk    rd}|dz  }Œ)|                     ¦   «         r|dz  }ŒC|dk    r!|                      d|¦  «        }|dk    r�n|}Œj|dk    r|dz   |k     r|dz  }Œ|dv r't          | |¦  «        \  }	}
t	          |
|dz   ¦  «        }Œª|d	k    r|dz  }|dz  }Œ»|d
k    rt	          d|dz
  ¦  «        }|dz  }ŒÚ|dk    rA|dz   |k     r8| |dz                                 ¦   «         s| |dz            dk    r|dz  }|dz  }�Œ!|dk    r|dk    r|dz  }d}|dz  }�Œ;|dk    s|dk    r|dz  }�ŒN|                      d|¦  «        s|                      d|¦  «        r|dz   }|dz  }�Œ†|dk    r	d}|dz  }�Œ•|dk    r	d}|dz  }�Œ¤|dk    r¦|dz   |k     r| |dz            dk    r|dz  }�ŒÉ|dz
  }|dk    r?| |                              ¦   «         r%|dz  }|dk    r| |                              ¦   «         °%|dk    r| |         dv r|dz  }�Œ*|dk    r|                     ||f¦  «         d}|dz  }�ŒPt          | |¦  «        \  }	}
t	          |
|dz   ¦  «        }||k     �°v|s| S | }t          |¦  «        D ]{\  }}|}||k     r?||                              ¦   «         r%|dz  }||k     r||                              ¦   «         °%|d|…         }|||…         }||dz   d…         }|dz   |z   dz   |z   }Œ||S )u¸  Wrap `A && B &` (or `A || B &`) to `A && { B & }` at depth 0.

    Bash parses ``A && B &`` with `&&` tighter than `&`, so it forks a
    subshell for the whole `A && B` compound and backgrounds it. Inside
    the subshell, `B` runs foreground, so the subshell waits for `B` to
    finish. When `B` is a long-running process (`python3 -m http.server`,
    `yes > /dev/null`, anything that doesn't naturally exit), the subshell
    never exits. It leaks as a process stuck in ``wait4`` forever â€” and
    on the way, its open stdout pipe can prevent the terminal tool from
    returning promptly.

    Rewriting the tail to `A && { B & }` preserves `&&`'s error semantics
    (skip B if A fails) while replacing the subshell with a brace group.
    The brace group runs in the current shell (no fork), backgrounds B as
    a simple command (bash doesn't wait for it in non-interactive mode),
    and exits immediately. B runs as a normal backgrounded child, orphaned
    when the parent shell exits.

    Handles redirects (``&>``, ``2>&1``) and skips content inside quoted
    strings and parenthesised subshells. Leaves simple ``cmd &`` alone â€”
    that construct doesn't have the subshell-wait bug.
    r   r2  rä   r¡   r1  r£   r¢   >   r*  r)  ú(r7  Ú{Ú}r3  r4  ú;Ú|ú&r  z<>Nz{ z& })r¦   r+  r9  r/  Úmaxr¥   rò   Úreversed)rµ   r-  r,  Úparen_depthÚbrace_depthÚlast_chain_op_endÚrewritesr»   ÚnlÚ_r>  ÚjrS   Ú	chain_endÚamp_posÚ
insert_posÚprefixÚmiddleÚsuffixs                      r   Ú_rewrite_compound_backgroundrf  +  sg  € õ. 	ˆG‰Œ€AØ	€AØ€KØ€Kð ÐØ&(€Hà
ˆaŠ%‰%Ø�QŒZˆð �Š:ˆ:˜+¨Ò*Ð*¨{¸aÒ/?Ð/?Ø "ÐØ�‰FˆAØà�:Š:‰<Œ<ð 	Ø�‰FˆAØð
 �Š9ˆ9Ø—’˜d AÑ&Ô&ˆBØ�RŠxˆxÙØˆAØà�Š:ˆ:˜!˜a™% !š)˜)Ø�‰FˆAØð �ÐÐÝ)¨'°1Ñ5Ô5‰IˆAˆvÝ�F˜A ™EÑ"Ô"ˆAØà�Š9ˆ9Ø˜1ÑˆKØ�‰FˆAØà�Š9ˆ9Ý˜a ¨q¡Ñ1Ô1ˆKØ�‰FˆAØð �Š9ˆ9˜˜Q™ š˜¨°°A±¬×(>Ò(>Ñ(@Ô(@˜ÀGÈAÐPQÉEÄNÐVZÒDZÐDZØ˜1ÑˆKØ�‰FˆAÙØ�Š9ˆ9˜ qš˜Ø˜1ÑˆKà "ÐØ�‰FˆAÙð
 ˜Š?ˆ?˜k¨Ašo˜oØ�‰FˆAÙð ×Ò˜d AÑ&Ô&ð 	¨'×*<Ò*<¸TÀ1Ñ*EÔ*Eð 	Ø ! A¡ÐØ�‰FˆAÙð �Š9ˆ9Ø "ÐØ�‰FˆAÙð �Š9ˆ9Ø "ÐØ�‰FˆAÙð �Š9ˆ9à�1‰u�qŠyˆy˜W Q¨¡Uœ^¨sÒ2Ð2à�Q‘�Ùà�A‘ˆAØ�q’&�&˜W QœZ×/Ò/Ñ1Ô1�&Ø�Q‘�ð �q’&�&˜W QœZ×/Ò/Ñ1Ô1�&à�AŠvˆv˜' !œ*¨Ð,Ð,Ø�Q‘�Ùà  AÒ%Ð%Ø—’Ð!2°AÐ 6Ñ7Ô7Ð7Ø "ÐØ�‰FˆAÙõ & g¨qÑ1Ô1‰	ˆˆ6Ý�˜˜A™ÑÔˆð] ˆaŠ%‰%ð` ð Øˆð €FÝ& xÑ0Ô0ð 9ð 9Ñˆ	�7ð ˆ
Ø˜7Ò"Ð" v¨jÔ'9×'AÒ'AÑ'CÔ'CÐ"Ø˜!‰OˆJð ˜7Ò"Ð" v¨jÔ'9×'AÒ'AÑ'CÔ'CÐ"à˜˜˜Ô$ˆØ˜
 7Ð*Ô+ˆØ˜ !™˜˜Ô&ˆð ˜$‘ Ñ'¨%Ñ/°&Ñ8ˆˆà€Mr   c                 ó2  — | €dS t          | ¦  «        \  }}|dk    r| dfS 	 ddlm}m} 	  |d¦  «        }n*# |$ r" t          j                             d¦  «        }Y nw xY wn/# t          $ r" t          j                             d¦  «        }Y nw xY w|du}|r|nt          ¦   «         }|s|st          ¦   «         r| dfS t          ¦   «         du}t          d¦  «        p|}	|s%|s#|	r!t          d¬¦  «        }|rt          |¦  «         |s|r|d	z   }
||
|z  fS | dfS )
a¥  
    Transform sudo commands to use -S flag if SUDO_PASSWORD is available.

    This is a shared helper used by all execution environments to provide
    consistent sudo handling across local, SSH, and container environments.

    Returns:
        (transformed_command, sudo_stdin) where:
        - transformed_command has every bare ``sudo`` replaced with
          ``sudo -S -p ''`` so sudo reads its password from stdin.
        - sudo_stdin is the password string with a trailing newline that the
          caller must prepend to the process's stdin stream.  sudo -S reads
          exactly one line (the password) and passes the rest of stdin to the
          child command, so prepending is safe even when the caller also has
          its own stdin_data to pipe.
        - If no password is available, sudo_stdin is None and the command is
          returned unchanged so it fails gracefully with
          "sudo: a password is required".

    Callers that drive a subprocess directly (local, ssh, docker, singularity)
    should prepend sudo_stdin to their stdin_data and pass the merged bytes to
    Popen's stdin pipe.

    Callers that cannot pipe subprocess stdin (modal, daytona,
    vercel_sandbox) must embed the password in the command string
    themselves; see their execute() methods for how they handle the
    non-None sudo_stdin case.

    If SUDO_PASSWORD is not set and an interactive UI is available
    (HERMES_INTERACTIVE=1 or a registered sudo password callback):
      Prompts user for password with 45s timeout, caches for session.

    If SUDO_PASSWORD is not set and NOT interactive:
      Command runs as-is (fails gracefully with "sudo: a password is required").
    N)NNr   )ÚUnscopedSecretErrorr=   rÚ   ÚHERMES_INTERACTIVErÞ   )rß   rä   )r?  rI   rh  r=   r!   rÛ   rB   re   r“   rO  rw   r   r  r—   )rµ   Útransformedr<  rh  r=   Ú_configured_passwordÚhas_configured_passwordrr   Úhas_sudo_prompt_callbackÚshould_prompt_for_sudoÚpassword_lines              r   Ú_transform_sudo_commandrp  Ð  sÇ  € ðH €ØˆzÝ<¸WÑEÔEÑ€K�Ø�Q‚€Ø˜ˆ}Ðð
?ØFÐFÐFÐFÐFÐFÐFÐFð	CØ#- :¨oÑ#>Ô#>Ð Ð øØ"ð 	Cð 	Cð 	CÝ#%¤:§>¢>°/Ñ#BÔ#BÐ Ð Ð ð	Cøøøøøåð ?ð ?ð ?Ý!œzŸ~š~¨oÑ>Ô>ÐÐÐð?øøøà2¸$Ð>Ðð #ð	)ÐÐå&Ñ(Ô(ð ð #ð ¨=ð Õ=QÑ=SÔ=Sð Ø˜ˆ}Ðå:Ñ<Ô<ÀDÐHÐåÐ,Ñ-Ô-ÐIÐ1Ið ð #ð 5¨=ð 5Ð=Sð 5Ý1À"ÐEÑEÔEˆØð 	5Ý% mÑ4Ô4Ð4àð 7 -ð 7ð &¨Ñ,ˆØ˜M¨JÑ6Ð6Ð6à�Dˆ=Ðs1   ¢A" «7 ¶A" ·$AÁA" ÁAÁA" Á")BÂB)ÚEnvironmentConnectionError)ÚLocalEnvironment)ÚSingularityEnvironment)ÚSSHEnvironment)ÚDockerEnvironment)ÚModalEnvironment)ÚManagedModalEnvironment)Úis_managed_tool_gateway_readyuf  Execute shell commands on a Linux environment. Filesystem, current working directory, and exported environment variables persist between calls.

Do NOT use cat/head/tail (use read_file), grep/rg/find/ls (use search_files), sed/awk (use patch), or echo/heredoc file creation (use write_file). Reserve terminal for: builds, installs, git, processes, scripts, network, package managers, and anything that needs a shell.
Environment state persists: activate a virtualenv or export variables once per session, not before every command.

Foreground (default): returns INSTANTLY when the command finishes, even with a high timeout â€” set timeout generously for long builds.
Background: set background=true (returns a session_id). Pair with notify_on_complete=true for bounded tasks; leave silent only for servers/daemons that never exit. Never use nohup/setsid/trailing '&' â€” use background=true so Hermes tracks the process. After starting a server, verify readiness with a health check, then act in a separate call; no blind sleep loops. Manage with process(action="poll"/"wait").
Working directory: use 'workdir' for per-command cwd. When a command changes the session cwd (cd, pushd), the result includes a "cwd" field â€” trust it instead of prefixing every command with 'cd'.
PTY: set pty=true for interactive CLIs (they hang without it). Pipe git output to cat if it might page.
Ú_active_environmentsÚ_last_activityÚ_creation_locksÚcontainer_configc                 ód  — |                       dd¦  «        sdS t          rdS t          5  t          r	 ddd¦  «         dS daddd¦  «         n# 1 swxY w Y   	 t          t	          j        dd¦  «        ¦  «        }n# t          t          f$ r d}Y nw xY wt          d|¦  «        }|dz  }	 d	d
l	m
}m} n# t          $ r Y dS w xY w	  |¦   «         } |||¬¦  «        }|rt                               d||¦  «         dS dS # t          $ r&}t                               d|¦  «         Y d}~dS d}~ww xY w)uo  Run the docker orphan reaper once per process, if enabled.

    Sweeps long-Exited containers labeled ``hermes-agent=1`` for the current
    profile that match the issue #20561 leak class â€” containers left behind
    by Hermes processes that exited without firing ``atexit`` (SIGKILL,
    OOM, terminal-window-close). The reaper is conservative by default:
    only Exited containers older than ``2 Ã— lifetime_seconds`` and scoped to
    the current profile.

    Gates:

    * ``terminal.docker_orphan_reaper: false`` disables it entirely (the
      operator opted out â€” usually because they're running multiple
      Hermes processes in the same profile and don't trust the
      conservative defaults).
    * ``_docker_orphan_reaper_ran`` flag â€” sweep runs once per Python
      interpreter, not on every subagent / RL-rollout / parallel
      ``terminal()`` call.
    Údocker_orphan_reaperTNÚTERMINAL_LIFETIME_SECONDSÚ300é,  é<   r¢   r   )Úreap_orphan_containersÚ_get_active_profile_name)Úmax_age_secondsÚprofile_filterzADocker orphan reaper removed %d stale container(s) for profile %szDocker orphan reaper raised: %s)rB   Ú_docker_orphan_reaper_ranÚ_docker_orphan_reaper_lockÚintr!   r"   r#   r$   rW  Útools.environments.dockerrƒ  r„  ÚImportErrorr%   Úinfore   rc   )r|  ÚlifetimeÚmax_agerƒ  r„  ÚprofileÚremovedrl   s           r   Ú_maybe_reap_docker_orphansr‘  P  s2  € ð* ×ÒÐ 6¸Ñ=Ô=ð Øˆõ !ð ØˆÝ	#ð )ð )Ý$ð 	Øð)ð )ð )ñ )ô )ð )ð )ð )ð %)Ð!ð)ð )ð )ñ )ô )ð )ð )ð )ð )ð )ð )øøøð )ð )ð )ð )ðÝ•r”yÐ!<¸eÑDÔDÑEÔEˆˆøÝ•zÐ"ð ð ð Øˆˆˆðøøøå�2�xÑ Ô €HØ˜‰l€Gðð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
ð 	
øõ ð ð ð Øˆˆðøøøð;Ø*Ð*Ñ,Ô,ˆØ(Ð(Ø#°Gð
ñ 
ô 
ˆð ð 	Ý�KŠKØSØ˜ñô ð ð ð ð	ð 	øõ
 ð ;ð ;ð ;å�ŠÐ6¸Ñ:Ô:Ð:Ð:Ð:Ð:Ð:Ð:Ð:øøøøð;øøøsR   ©	A¿AÁAÁAÁ"A< Á<BÂBÂ+B4 Â4
CÃCÃ5C? Ã?
D/Ä	D*Ä*D/Ú_task_env_overridesÚ_session_cwdr‹   Úcwdc                 ó  — t          |t          ¦  «        r|                     ¦   «         sdS t          | pd¦  «        }t          5  t                               |¦  «        |k    r
|t          |<   ddd¦  «         dS # 1 swxY w Y   dS )a�  Record *cwd* as the working directory of *session_key*.

    Called wherever a session's live cwd becomes known: after a terminal
    command completes (the env's post-command tracking has just parsed the
    resulting cwd) and when a surface registers a workspace cwd override.
    Empty/None session keys collapse to ``"default"`` (single-session CLI).
    Non-string / empty cwds are ignored.
    Nr   )r¤   r   rC   Ú_session_cwd_lockr“  rB   )r‹   r”  Úkeys      r   Úrecord_session_cwdr˜  ­  sÉ   € õ �c�3ÑÔð  s§y¢y¡{¤{ð ØˆÝ
ˆkÐ&˜YÑ
'Ô
'€CÝ	ð $ð $Ý×Ò˜CÑ Ô  CÒ'Ð'Ø #�L˜Ñð$ð $ð $ñ $ô $ð $ð $ð $ð $ð $ð $ð $øøøð $ð $ð $ð $ð $ð $s   Á)A:Á:A>ÂA>c                 óš   — t          | pd¦  «        }t          5  t                               |¦  «        cddd¦  «         S # 1 swxY w Y   dS )a  Return the recorded working directory for *session_key*, if any.

    No fallback chain here on purpose: callers decide what an absent record
    means (config default, TERMINAL_CWD seed, process cwd). ``None``/empty
    keys read the ``"default"`` record.
    r   N)r   r–  r“  rB   )r‹   r—  s     r   Úget_session_cwdrš  ¾  s‘   € õ ˆkÐ&˜YÑ
'Ô
'€CÝ	ð %ð %Ý×Ò Ñ$Ô$ð%ð %ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %ð %ð %s   ™A Á AÁAc                 ó|   — t           5  t                               | d¦  «         ddd¦  «         dS # 1 swxY w Y   dS )z/Drop a session's cwd record (session teardown).N)r–  r“  r–   )r‹   s    r   Úclear_session_cwdrœ  Ê  s‚   € å	ð ,ð ,Ý×Ò˜ dÑ+Ô+Ð+ð,ð ,ð ,ñ ,ô ,ð ,ð ,ð ,ð ,ð ,ð ,ð ,øøøð ,ð ,ð ,ð ,ð ,ð ,s   ˆ1±5¸5Útask_idÚ	overridesc                 ó¾  — |t           | <   |                     d¦  «        }t          |t          ¦  «        r¢|                     ¦   «         r�t          | |¦  «         t          | ¦  «        }t          5  t                               | ¦  «        pt                               |¦  «        }ddd¦  «         n# 1 swxY w Y   |�t          |dd¦  «        �||_
        dS dS dS dS dS )a#  
    Register environment overrides for a specific task/rollout.

    Called by Atropos environments before the agent loop to configure
    per-task sandbox settings (e.g., a custom Dockerfile for the Modal image).

    Supported override keys:
        - modal_image: str -- Path to Dockerfile or Docker Hub image name
        - docker_image: str -- Docker image name
        - cwd: str -- Working directory inside the sandbox

    Args:
        task_id: The rollout's unique task identifier
        overrides: Dict of config keys to override
    r”  N)r’  rB   r¤   r   rC   r˜  Ú_resolve_container_task_idÚ	_env_lockry  rt   r”  )r�  rž  Únew_cwdÚcontainer_idÚenvs        r   Úregister_task_env_overridesr¥  Ð  s:  € ð  $-Õ˜Ñ ð �mŠm˜EÑ"Ô"€GÝ�'�3ÑÔð  G§M¢M¡O¤Oð õ 	˜7 GÑ,Ô,Ð,õ 2°'Ñ:Ô:ˆÝð 	^ð 	^Ý&×*Ò*¨7Ñ3Ô3Ð]Õ7K×7OÒ7OÐP\Ñ7]Ô7]ˆCð	^ð 	^ð 	^ñ 	^ô 	^ð 	^ð 	^ð 	^ð 	^ð 	^ð 	^øøøð 	^ð 	^ð 	^ð 	^àˆ?�w s¨E°4Ñ8Ô8ÐDØˆCŒGˆGˆGðð ð ð ð ˆ?ÐDÐDs   Á/5B0Â0B4Â7B4c                 óÐ   — t                                | d¦  «         t          | ¦  «         t          5  t                               | d¦  «         ddd¦  «         dS # 1 swxY w Y   dS )z‰
    Clear environment overrides for a task after rollout completes.

    Called during cleanup to avoid stale entries accumulating.
    N)r’  r–   rœ  Ú_container_alias_lockÚ_container_aliases©r�  s    r   Úclear_task_env_overridesrª  ø  s¨   € õ ×Ò˜G TÑ*Ô*Ð*Ý�gÑÔÐÝ	ð .ð .Ý×Ò˜w¨Ñ-Ô-Ð-ð.ð .ð .ñ .ô .ð .ð .ð .ð .ð .ð .ð .øøøð .ð .ð .ð .ð .ð .s   ²AÁAÁ"Ar¨  Úchild_task_idÚparent_task_idc                 ó€   — | sdS t           5  t          |pd¦  «        t          | <   ddd¦  «         dS # 1 swxY w Y   dS )a&  Make *child_task_id* resolve to *parent_task_id*'s container.

    Called by ``delegate_task`` at child spawn so subagents share the parent
    session's sandbox under per-session container isolation. A missing/empty
    parent id aliases the child to ``"default"`` (top-level CLI parent).
    Nr   )r§  r   r¨  )r«  r¬  s     r   Úregister_container_aliasr®    s§   € ð ð ØˆÝ	ð Mð MÝ,/°Ð0KÀ)Ñ,LÔ,LÕ˜=Ñ)ðMð Mð Mñ Mô Mð Mð Mð Mð Mð Mð Mð Møøøð Mð Mð Mð Mð Mð Ms   Œ3³7º7c                 óÜ   — t          ¦   «         }| }t          5  |t          v r3||vr/|                     |¦  «         t          |         }|t          v r||v°/ddd¦  «         n# 1 swxY w Y   |S )uA   Follow the childâ†’parent alias chain (cycle-safe) for *task_id*.N)Úsetr§  r¨  Úadd)r�  Úseenr—  s      r   Ú_resolve_container_aliasr³    sµ   € å‰5Œ5€DØ
€CÝ	ð *ð *ØÕ'Ð'Ð'¨C°t¨O¨OØ�HŠH�S‰MŒMˆMÝ$ SÔ)ˆCð Õ'Ð'Ð'¨C°t¨O¨Oð*ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *ð €Js   ˜=A!Á!A%Á(A%c                  ó¦   — t          ¦   «          t          j        dd¦  «        dk    rdS t          j        dd¦  «                             ¦   «         dvS )aÈ  True when docker sessions get their OWN containers (issue: stale
    workspace mounts leaking between desktop sessions).

    Gated on ``terminal.backend: docker`` + ``container_persistent: false``:
    a non-persistent sandbox is a statement that state must not survive the
    session, so sharing one container across sessions contradicts it. With
    ``container_persistent: true`` the documented ONE-long-lived-container
    contract is unchanged.
    rC  rD  r«   FÚTERMINAL_CONTAINER_PERSISTENTrE  >   r  ÚyesrE  )Ú_ensure_terminal_env_bridgedr!   r"   rÖ   rv   r   r   Ú!_docker_session_isolation_enabledr¸  &  sQ   € õ !Ñ"Ô"Ð"Ý	„y� Ñ)Ô)¨XÒ5Ð5ØˆuÝŒ9Ð4°fÑ=Ô=×CÒCÑEÔEÐMaÐaÐar   >   rª   Úmodal_imageÚdocker_imageÚdaytona_imageÚsingularity_imagec                 óž   — | r	| t           vrdS t          t          t           |                               ¦   «         ¦  «        t          z  ¦  «        S )uû   True when *task_id* registered backend-image/env_type overrides.

    The single owner of the "is this an RL/benchmark-style isolated rollout"
    predicate â€” shared by container-key resolution and container creation so
    the two can't drift.
    F)r’  rJ   r°  ÚkeysÚ_ISOLATION_OVERRIDE_KEYSr©  s    r   Ú_has_isolation_overridesrÀ  <  sJ   € ð ð �gÕ%8Ð8Ð8ØˆuÝ•Õ'¨Ô0×5Ò5Ñ7Ô7Ñ8Ô8Õ;SÑSÑTÔTÐTr   c                 ój   — | rt          | ¦  «        r| S | rt          ¦   «         rt          | ¦  «        S dS )uE  
    Map a tool-call ``task_id`` to the container/sandbox key used by
    ``_active_environments``.

    The top-level agent passes ``task_id=None`` and lands on ``"default"``.
    ``delegate_task`` children pass their own subagent ID so that
    file-state tracking, the active-subagents registry, and TUI events stay
    distinct per child -- but we deliberately collapse that ID back to
    ``"default"`` here so subagents share the parent's long-lived container
    (one bash, one /workspace, one set of installed packages).

    Exception: RL / benchmark environments (TerminalBench2, HermesSweEnv, ...)
    call ``register_task_env_overrides(task_id, {...})`` to request a
    per-task Docker/Modal image. When an override is registered for a
    task_id, we honour it by returning the task_id unchanged -- those
    rollouts need their own isolated sandbox, which is the whole point of
    the override.

    CWD-only overrides (registered by the ACP adapter for workspace
    tracking) are *not* isolation signals â€” they should not cause each
    session to spin up its own container.  Only overrides containing
    backend-specific image keys or ``env_type`` trigger isolation.

    Per-session container isolation (docker + ``container_persistent:
    false``): each session's task_id is its own container key, so a fresh
    chat gets a fresh sandbox with only ITS mounts â€” a previous session's
    workspace can no longer appear in a new session's container.
    ``delegate_task`` children keep sharing the parent's container via the
    alias registry (``register_container_alias``).
    r   )rÀ  r¸  r³  r©  s    r   r   r   H  sJ   € ð> ð Õ+¨GÑ4Ô4ð ØˆØð 1Õ4Ñ6Ô6ð 1Ý'¨Ñ0Ô0Ð0Øˆ9r   c                 ó�   — | pd}t                                |¦  «        p(t                                t          |¦  «        ¦  «        pi S )a·  Return the env overrides for *task_id*, raw key first then collapsed.

    ``register_task_env_overrides`` writes under the *raw* task/session id, but
    a CWD-only override collapses (:func:`_resolve_container_task_id`) to the
    shared ``"default"`` container so per-session surfaces (ACP/gateway/
    dashboard) don't each spin up their own sandbox. Callers that need the
    override (terminal command setup, file-tool cwd resolution) must therefore
    read the raw id FIRST and only fall back to the collapsed container id, or
    the originating session's override is silently dropped. This is the single
    source of that lookup so the terminal and file layers can't drift apart.
    r   )r’  rB   r   )r�  r)   s     r   Úresolve_task_overridesrÃ  n  sK   € ð Ð
�Y€Cå×Ò Ñ$Ô$ð 	Ý×"Ò"Õ#=¸cÑ#BÔ#BÑCÔCð	àðr   c                 ó¼  — |                       d¦  «        dk    rdS |                       d¦  «        sdS t          ¦   «         s|                       d¦  «        S t          |¦  «        dk    r|                       d¦  «        S t          |¦  «        }|                      d¦  «        dk    rdS |                      d	¦  «        }t	          |t
          ¦  «        r|                     ¦   «         sdS t          j         	                    t          j         
                    |¦  «        ¦  «        }t          j                             |¦  «        sdS |                     d
¦  «        rdS |S )u“  Host directory to bind-mount at ``/workspace`` for *task_id*'s container.

    The single owner of the cwd-mount policy, shared by every environment
    creation site (terminal tool, file tools, execute_code, lazy bring-up):

    * Shared-container mode (the default): the process-global
      ``TERMINAL_CWD``-derived ``config["host_cwd"]`` â€” unchanged legacy
      behavior, ONE container whose mount tracks the configured workspace.
    * Per-session isolation mode (docker + ``container_persistent: false``):
      only the SESSION's own registered workspace may mount.  The process
      env var is a launch artifact â€” the TUI/desktop workspace picker writes
      ``os.environ["TERMINAL_CWD"]`` and it outlives the session that set it,
      so deriving a fresh session's mount from it leaks the previous
      session's directory into a chat that never attached one.  Overrides
      tagged ``cwd_source: "process"`` (gateway fallback to the global env
      var) are likewise refused as mount sources; only a workspace the user
      actually attached to THIS session (``cwd_source: "session"`` or an
      untagged override from ACP/RL surfaces) mounts.
    rª   r«   Nr­   r¬   r   Ú
cwd_sourceÚprocessr”  ©ú
/workspaceú/root)rB   r¸  r   rÃ  r¤   r   rC   r!   rj   ÚabspathÚ
expanduserÚisdirr¥   )r6   r�  rž  Ú	candidates       r   Ú_resolve_task_host_cwdrÎ  ‚  sA  € ð( ‡z‚z�*ÑÔ Ò)Ð)ØˆtØ�:Š:Ð5Ñ6Ô6ð ØˆtÝ,Ñ.Ô.ð &Ø�zŠz˜*Ñ%Ô%Ð%Ý! 'Ñ*Ô*¨iÒ7Ð7à�zŠz˜*Ñ%Ô%Ð%Ý& wÑ/Ô/€IØ‡}‚}�\Ñ"Ô" iÒ/Ð/ØˆtØ—’˜eÑ$Ô$€IÝ�i¥Ñ%Ô%ð ¨Y¯_ª_Ñ->Ô->ð ØˆtÝ”—’¥¤× 2Ò 2°9Ñ =Ô =Ñ>Ô>€IÝŒ7�=Š=˜Ñ#Ô#ð ØˆtØ×ÒÐ3Ñ4Ô4ð àˆtØÐr   r(   c           
      óª   — t          j        | |¦  «        }	  ||¦  «        S # t          t          j        f$ r t          d| › d|›d|› d�¦  «        ‚w xY w)zðParse an environment variable with *converter*, raising a clear error on bad values.

    Without this wrapper, a single malformed env var (e.g. TERMINAL_TIMEOUT=5m)
    causes an unhandled ValueError that kills every terminal command.
    zInvalid value for ú: z (expected z1). Check ~/.hermes/.env or environment variables.)r!   r"   r$   ÚjsonÚJSONDecodeErrorr'   s        r   Ú_parse_env_varrÓ  °  s‹   € õ Œ)�D˜'Ñ
"Ô
"€Cð
Øˆy˜‰~Œ~ÐøÝ�Ô,Ð-ð 
ð 
ð 
Ýð> ð >ð >¨ð >ð >¸:ð >ð >ð >ñ
ô 
ð 	
ð
øøøs	   —
" ¢0Ac                  ó°   — 	 t          j        ¦   «         S # t          $ r6 t          j        d¦  «        pt           j                             d¦  «        cY S w xY w)am  Return the current working directory, tolerating a deleted CWD.

    ``os.getcwd()`` raises FileNotFoundError when the process's working
    directory has been removed out from under it (e.g. a scratch workspace
    that was cleaned up mid-session). Fall back to TERMINAL_CWD, then the
    user's home directory, so terminal setup never crashes on a stale CWD.
    ÚTERMINAL_CWDrŸ   )r!   ÚgetcwdÚFileNotFoundErrorr"   rj   rË  rv   r   r   Ú_safe_getcwdrØ  À  s^   € ðDÝŒy‰{Œ{ÐøÝð Dð Dð DÝŒy˜Ñ(Ô(ÐC­B¬G×,>Ò,>¸sÑ,CÔ,CÐCÐCÐCðDøøøs   ‚ •=AÁA)z/Users/z/home/zC:\zC:/>   Úmodalr«   ÚdaytonaÚsingularityÚvercel_sandboxc                 ó–   ‡ — ‰ sdS t          ˆ fd„t          D ¦   «         ¦  «        rdS t          j                             ‰ ¦  «        sdS dS )a¤  Return True if *cwd* is a host/relative path that won't work as the
    working directory inside a container sandbox.

    A container's cwd must be an absolute path that exists *inside* the
    sandbox (e.g. ``/workspace`` or ``/root``). A host path (``/home/user``,
    ``C:\Users\me``) or a relative path (``.``, ``src/``) is meaningless to
    ``docker run -w`` and makes the container fail to start (exit 125).
    Fc              3   óB   •K  — | ]}‰                      |¦  «        V — Œd S r3   ©r¥   )r¯   Úpr”  s     €r   r°   z-_is_unusable_container_cwd.<locals>.<genexpr>â  s/   øè è € Ð
9Ð
9 ˆ3�>Š>˜!ÑÔÐ
9Ð
9Ð
9Ð
9Ð
9Ð
9r   T)r²   Ú_HOST_CWD_PREFIXESr!   rj   Úisabs)r”  s   `r   Ú_is_unusable_container_cwdrã  ×  s_   ø€ ð ð ØˆuÝ
Ð
9Ð
9Ð
9Ð
9Õ&8Ð
9Ñ
9Ô
9Ñ9Ô9ð Øˆtõ Œ7�=Š=˜ÑÔð ØˆtØˆ5r   c                  óH  — t           rdS da 	 ddlm} m}  |¦   «         }t	          |                     d¦  «        t          ¦  «        }|r | dd¬¦  «         dS dt          j        vr | dd¬¦  «         dS dS # t          $ r  t                               d	d¬
¦  «         Y dS w xY w)u-  Backfill TERMINAL_* env vars from config.yaml when no launcher did.

    terminal_tool reads ALL terminal settings from os.environ (TERMINAL_*).
    The CLI (cli.py ``env_mappings``), the gateway (gateway/run.py
    ``_terminal_env_map``), and TUI/dashboard PTY launches
    (``apply_terminal_config_to_env``) bridge ``terminal.*`` config into env
    vars at startup â€” but processes that skip all of those paths (``hermes
    serve`` / the Desktop app backend's in-process agents, the desktop cron
    ticker, ACP) used to silently fall back to the local backend even when
    config.yaml selects ``terminal.backend: docker``, running commands on the
    host the user intended to sandbox (#63141, #54449, #61115, #65696).

    Explicit terminal config keys win: when config.yaml has a ``terminal``
    section, each key present there overrides its matching env value (which may
    be stale from ``hermes setup``). Environment values for omitted terminal
    keys are preserved. When no terminal section exists, exported/.env values
    keep working unchanged.
    NTr   )Úapply_terminal_config_to_envÚread_raw_configÚterminal)r¤  ÚoverriderC  Fu.   terminal config â†’ env fallback bridge failedrX   )Ú!_terminal_config_bridge_attemptedÚhermes_cli.configrå  ræ  r¤   rB   Údictr!   rÛ   re   r%   rc   )rå  ræ  Ú
raw_configÚhas_terminal_sections       r   r·  r·  ó  sü   € õ( )ð ØˆØ(,Ð%ðVØSÐSÐSÐSÐSÐSÐSÐSð %�_Ñ&Ô&ˆ
Ý)¨*¯.ª.¸Ñ*DÔ*DÅdÑKÔKÐàð 	Cà(Ð(¨T¸DÐAÑAÔAÐAÐAÐAØ¥2¤:Ð-Ð-ð )Ð(¨T¸EÐBÑBÔBÐBÐBÐBð .Ð-øõ ð Vð Vð Võ 	�ŠÐEÐPTˆÑUÔUÐUÐUÐUÐUðVøøøs   �A	A7 ÁA7 Á7&B!Â B!c                  óD
  ‡— d} t          ¦   «          t          j        dd¦  «        }t          j        dd¦  «                             ¦   «         dv }|dv }|dk    }|r8t	          d	d
t
          d¦  «        }t	          dd¦  «        }t	          dd¦  «        }nd}d}d}|r†t	          ddt          j        d¦  «        }t	          ddt          j        d¦  «        }	t	          ddt          j        d¦  «        }
t	          ddt          j        d¦  «        }t          j        dd¦  «        }n
g }g }	i }
g }d}|dk    rt          ¦   «         }n|dk    rd}n|dk    rt          }nd}t          j        d |¦  «        }d!d"l
m} |r+ |||¦  «        st          j                             |¦  «        }d#}|dk    rØ|rÖt          j        d ¦  «        pt          ¦   «         }t          j                             t          j                             |¦  «        ¦  «        Št          ˆfd$„t           D ¦   «         ¦  «        sSt          j                             ‰¦  «        r8t          j                             ‰¦  «        r‰                     d%¦  «        s‰}d&}n?|t(          v r6|r4t+          |¦  «        r%||k    rt,                               d'|||¦  «         |}i d(|“d)t1          t          j        d*d+¦  «        ¦  «        “d,t          j        d-| ¦  «        “d.|“d/t          j        d0d1| › �¦  «        “d2t          j        d3| ¦  «        “d4t          j        d5| ¦  «        “d6t          j        d7d8¦  «                             ¦   «         “d9|“d:|“d;|“d<t	          d=d>¦  «        “d?t	          d@dA¦  «        “dBt          j        dCd8¦  «        “dDt          j        dEd8¦  «        “dFt	          dGdH¦  «        “dIt          j        dJd8¦  «        “t          j        dKt          j        dLdM¦  «        ¦  «                             ¦   «         dv t          j        dNd¦  «                             ¦   «         dv |||t          j        dOdM¦  «                             ¦   «         dv |	|
t          j        dPd¦  «                             ¦   «         dv t          j        dQdM¦  «                             ¦   «         dv ||t          j        dRdM¦  «                             ¦   «         dv t          j        dSdM¦  «                             ¦   «         dv dTœ¥S )UzBGet terminal environment configuration from environment variables.ú*nikolaik/python-nodejs:python3.11-nodejs20rC  rD  Ú&TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACEÚfalse>   r  r¶  rE  >   rÙ  r«   rÚ  rÛ  rÜ  r«   ÚTERMINAL_CONTAINER_CPUr  r.   ÚTERMINAL_CONTAINER_MEMORYÚ5120ÚTERMINAL_CONTAINER_DISKÚ51200g      ð?é   r:   ÚTERMINAL_DOCKER_FORWARD_ENVz[]z
valid JSONÚTERMINAL_DOCKER_VOLUMESÚTERMINAL_DOCKER_ENVz{}ÚTERMINAL_DOCKER_EXTRA_ARGSÚTERMINAL_DOCKER_SHM_SIZEÚ1gÚsshrŸ   rÜ  rÉ  rÕ  r   )Ú_is_ssh_remote_tilde_cwdNc              3   óB   •K  — | ]}‰                      |¦  «        V — Œd S r3   rß  )r¯   rà  rÍ  s     €r   r°   z"_get_env_config.<locals>.<genexpr>`  s1   øè è € ÐDÐD¨A�	×$Ò$ QÑ'Ô'ÐDÐDÐDÐDÐDÐDr   rÇ  rÈ  zeIgnoring TERMINAL_CWD=%r for %s backend (host/relative path won't work in sandbox). Using %r instead.rª   Ú
modal_modeÚTERMINAL_MODAL_MODEÚautorº  ÚTERMINAL_DOCKER_IMAGEÚdocker_forward_envr¼  ÚTERMINAL_SINGULARITY_IMAGEú	docker://r¹  ÚTERMINAL_MODAL_IMAGEr»  ÚTERMINAL_DAYTONA_IMAGEr8   ÚTERMINAL_VERCEL_RUNTIMEr   r”  r¬   r­   r  ÚTERMINAL_TIMEOUTÚ180Úlifetime_secondsr  r€  Ússh_hostÚTERMINAL_SSH_HOSTÚssh_userÚTERMINAL_SSH_USERÚssh_portÚTERMINAL_SSH_PORTÚ22Ússh_keyÚTERMINAL_SSH_KEYÚTERMINAL_SSH_PERSISTENTÚTERMINAL_PERSISTENT_SHELLrE  ÚTERMINAL_LOCAL_PERSISTENTrµ  Ú TERMINAL_DOCKER_RUN_AS_HOST_USERÚTERMINAL_DOCKER_NETWORKÚ(TERMINAL_DOCKER_PERSIST_ACROSS_PROCESSESÚTERMINAL_DOCKER_ORPHAN_REAPER)Ússh_persistentÚlocal_persistentÚcontainer_cpuÚcontainer_memoryr9   Úcontainer_persistentr±   Ú
docker_envÚdocker_run_as_host_userÚdocker_networkÚdocker_extra_argsÚdocker_shm_sizeÚdocker_persist_across_processesr~  )r·  r!   r"   rÖ   rÓ  ÚfloatrÑ  ÚloadsrØ  Ú_VERCEL_SANDBOX_DEFAULT_CWDrê  rÿ  rj   rË  rÊ  r²   rá  râ  rÌ  r¥   Ú_CONTAINER_BACKENDSrã  r%   rŒ  r   rC   )Údefault_imagerª   Úmount_docker_cwdÚcontainer_backendÚdocker_backendr   r!  r9   r  r±   r#  r&  r'  Údefault_cwdr”  rÿ  r¬   Údocker_cwd_sourcerÍ  s                     @r   Ú_get_env_configr3  "  sÁ  ø€ ð A€MÝ Ñ"Ô"Ð"ÝŒy˜¨Ñ1Ô1€Hå”yÐ!IÈ7ÑSÔS×YÒYÑ[Ô[Ð_sÐsÐØ Ð$cÐcÐØ Ò)€Nð ð Ý&Ð'?ÀÅeÈXÑVÔVˆÝ)Ð*EÀvÑNÔNÐÝ'Ð(AÀ7ÑKÔKˆˆàˆØÐØˆàð Ý+Ð,IÈ4ÕQUÔQ[Ð]iÑjÔjÐÝ'Ð(AÀ4ÍÌÐUaÑbÔbˆÝ#Ð$9¸4ÅÄÈ\ÑZÔZˆ
Ý*Ð+GÈÍtÌzÐ[gÑhÔhÐÝœ)Ð$>ÀÑEÔEˆˆàÐØˆØˆ
ØÐØˆð
 �7ÒÐÝ"‘n”nˆˆØ	�UÒ	Ð	ØˆˆØ	Ð%Ò	%Ð	%Ý1ˆˆàˆõ Œ)�N KÑ
0Ô
0€CØ:Ð:Ð:Ð:Ð:Ð:Ø
ð &Ð+Ð+¨H°cÑ:Ô:ð &ÝŒg× Ò  Ñ%Ô%ˆØ€HØ�8ÒÐÐ 0ÐÝœI nÑ5Ô5ÐG½¹¼ÐÝ”G—O’O¥B¤G×$6Ò$6Ð7HÑ$IÔ$IÑJÔJˆ	åÐDÐDÐDÐDÕ1CÐDÑDÔDÑDÔDð	å”—’˜iÑ(Ô(ð	å-/¬W¯]ª]¸9Ñ-EÔ-Eð	àNW×NbÒNbÐczÑN{ÔN{ð	ð !ˆHØˆCøØ	Õ(Ð	(Ð	(¨SÐ	(å% cÑ*Ô*ð 	¨s°kÒ/AÐ/AÝ�KŠKð Xà˜X {ñ4ô 4ð 4ð ˆCð7Ø�Hð7àÕ'­¬	Ð2GÈÑ(PÔ(PÑQÔQð7ð 	�œ	Ð"9¸=ÑIÔIð7ð 	Ð0ð	7ð
 	�RœYÐ'CÐE`ÐQ^ÐE`ÐE`ÑaÔað7ð 	•r”yÐ!7¸ÑGÔGð7ð 	�œÐ#;¸]ÑKÔKð7ð 	�"œ)Ð$=¸rÑBÔB×HÒHÑJÔJð7ð 	ˆsð7ð 	�Hð7ð 	(Ð)9ð7ð 	•>Ð"4°eÑ<Ô<ð7ð 	�NÐ+FÈÑNÔNð7ð 	•B”IÐ1°2Ñ6Ô6ð7ð  	•B”IÐ1°2Ñ6Ô6ð!7ð" 	•NÐ#6¸Ñ=Ô=ð#7ð$ 	•2”9Ð/°Ñ4Ô4ð%7õ, œ)Ø%ÝŒIÐ1°6Ñ:Ô:ñ
ô 
÷ Š%‰'Œ'Ð)ð*õ œIÐ&AÀ7ÑKÔK×QÒQÑSÔSÐWkÐkð 'Ø,Ø(Ý "¤	Ð*IÈ6Ñ RÔ R× XÒ XÑ ZÔ ZÐ^rÐ rØ(Ø Ý#%¤9Ð-OÐQXÑ#YÔ#Y×#_Ò#_Ñ#aÔ#aÐeyÐ#yÝœ)Ð$=¸vÑFÔF×LÒLÑNÔNÐRfÐfØ.Ø*õ ,.¬9Ø6¸ñ,
ô ,
ç
Š%‰'Œ'Ð)ð,*õ !#¤	Ø+¨Vñ!
ô !
ç
Š%‰'Œ'Ð)ð!*ði7ð 7ð 7ð 7r   r  c                 óX   — t          | t          ¦   «         t          d¦  «        ¬¦  «        S )z2Resolve direct vs managed Modal backend selection.rÙ  )Ú
has_directÚmanaged_ready)r   r   rx  )r  s    r   Ú_get_modal_backend_stater7  §  s0   € å&ØÝ/Ñ1Ô1Ý3°GÑ<Ô<ðñ ô ð r   c                 óÚ   — |                       dd¦  «        |                       dd¦  «        |                       dd¦  «        |                       dd¦  «        |                       dd¦  «        d	œS )
a  Build the ``ssh_config`` dict passed to :func:`_create_environment`.

    Shared by the terminal tool's own get-or-create path and the lazy
    :func:`ensure_task_env` bring-up so both derive SSH connection settings
    from the resolved config identically.
    r  r   r  r  é   r  r  F)ÚhostÚuserÚportr—  Ú
persistent©rB   r³   s    r   Ú_ssh_config_from_configr?  °  si   € ð —
’
˜: rÑ*Ô*Ø—
’
˜: rÑ*Ô*Ø—
’
˜: rÑ*Ô*Ø�zŠz˜) RÑ(Ô(Ø—j’jÐ!1°5Ñ9Ô9ðð ð r   c                 óæ  — i d|                       dd¦  «        “d|                       dd¦  «        “d|                       dd¦  «        “d|                       dd¦  «        “d	|                       d	d
¦  «        “d|                       dd¦  «        “d|                       dg ¦  «        “d|                       dd¦  «        “d|                       dg ¦  «        “d|                       di ¦  «        “d|                       dd¦  «        “d|                       dg ¦  «        “d|                       dd¦  «        “d|                       dd¦  «        “d|                       dd¦  «        “d|                       dd¦  «        “S )zâBuild the ``container_config`` dict passed to :func:`_create_environment`.

    Shared by the terminal tool's own get-or-create path and the lazy
    :func:`ensure_task_env` bring-up (see :func:`_ssh_config_from_config`).
    r   r¡   r!  r÷  r9   r:   r"  Tr  r  r8   r   r±   r­   Fr  r#  r$  r&  r'  rý  r%  r(  r~  r>  r³   s    r   Ú_container_config_from_configrA  À  s·  € ðØ˜Ÿš O°QÑ7Ô7ðà˜FŸJšJÐ'9¸4Ñ@Ô@ðð 	˜&Ÿ*š*Ð%5°uÑ=Ô=ðð 	 §
¢
Ð+AÀ4Ñ HÔ Hð	ð
 	�f—j’j ¨vÑ6Ô6ðð 	˜&Ÿ*š*Ð%5°rÑ:Ô:ðð 	˜&Ÿ*š*Ð%5°rÑ:Ô:ðð 	(¨¯ªÐ4SÐUZÑ)[Ô)[ðð 	˜fŸjšjÐ)=¸rÑBÔBðð 	�f—j’j ¨rÑ2Ô2ðð 	" 6§:¢:Ð.GÈÑ#OÔ#Oðð 	˜VŸZšZÐ(;¸RÑ@Ô@ðð 	˜6Ÿ:š:Ð&7¸Ñ>Ô>ðð 	˜&Ÿ*š*Ð%5°tÑ<Ô<ðð 	*¨6¯:ª:Ð6WÐY]Ñ+^Ô+^ðð  	 §
¢
Ð+AÀ4Ñ HÔ Hð!ð r   Úimager  Ú
ssh_configÚlocal_configr¬   c	           
      óŠ  — |pi }	|	                      dd¦  «        }
|	                      dd¦  «        }|	                      dd¦  «        }|	                      dd¦  «        }|	                      d	g ¦  «        }|	                      d
g ¦  «        }|	                      di ¦  «        }|	                      dg ¦  «        }|	                      dd¦  «        }| dk    rt          ||¬¦  «        S | dk    rät          |	¦  «         t          ¦   «         o|dk    ot	          |¦  «         }t          dOi d|“d|“d|“d|
“d|“d|“d|“d|“d|“d|“d|	                      dd¦  «        “d|“d |“d!|	                      d"d¦  «        “d#|“d$|“d%|rdn|	                      d&d¦  «        “d'|	                      d(d)¦  «        “Ž}|r	 d|_        n# t          $ r Y nw xY w|S | d*k    rt          ||||
||||¬+¦  «        S | d,k    �rXi }|
d-k    r|
|d<   |d-k    r||d<   |d-k    rE	 d-d.l	}d-d.l
}d/|                     |j        j        ¦  «        j        v r||d/<   n# t          $ r Y nw xY wt!          |	                      d0¦  «        ¦  «        }|d1         d2k    rt#          ||||||¬3¦  «        S |d1         d4k    r‘|d5         r"t%          d6t'          d7¦  «        z   d8z   ¦  «        ‚|d9         d2k    rt%          d:t'          d7¦  «        z   ¦  «        ‚|d9         d4k    rt%          d;¦  «        ‚d<}t)          ¦   «         rd=}t%          |¦  «        ‚t+          ||||||¬3¦  «        S | d>k    r&d-d?lm}  ||||t1          |
¦  «        ||||¬+¦  «        S | d@k    r.d-dAlm}  ||	                      dB¦  «        pd.|||
||||¬C¦  «        S | dDk    r„|r*|                      dE¦  «        r|                      dF¦  «        st%          dG¦  «        ‚t7          |dE         |dF         |                      dHdI¦  «        |                      dJdK¦  «        ||¬L¦  «        S t%          dM| › dN�¦  «        ‚)Paø  
    Create an execution environment for sandboxed command execution.
    
    Args:
        env_type: One of "local", "docker", "singularity", "modal",
            "daytona", "vercel_sandbox", "ssh"
        image: Docker/Singularity/Modal image name (ignored for local/ssh/vercel)
        cwd: Working directory
        timeout: Default command timeout
        ssh_config: SSH connection config (for env_type="ssh")
        container_config: Resource config for container backends (cpu, memory, disk, persistent)
        task_id: Task identifier for environment reuse and snapshot keying
        host_cwd: Optional host working directory to bind into Docker when explicitly enabled
        
    Returns:
        Environment instance with execute() method
    r   r¡   r!  r÷  r9   r:   r"  Tr±   r  r#  r&  r%  rD  )r”  r  r«   r   rB  r”  r  ÚcpuÚmemoryrL   Úpersistent_filesystemr�  Úvolumesr¬   Úauto_mount_cwdr­   FÚforward_envr¤  Úrun_as_host_userr$  ÚnetworkÚ
extra_argsÚpersist_across_processesr(  Úshm_sizer'  rý  rÛ  )rB  r”  r  rF  rG  rL   rH  r�  rÙ  r   NÚephemeral_diskr  Úselected_backendÚmanaged)rB  r”  r  Úmodal_sandbox_kwargsrH  r�  ÚdirectÚmanaged_mode_blockedz™Modal backend is configured for managed mode, but Nous Tool Gateway access is not currently available and no direct Modal credentials/config were found. úmanaged Modal executionzH Choose TERMINAL_MODAL_MODE=direct/auto to use direct Modal credentials.Úmodez[Modal backend is configured for managed mode, but the managed tool gateway is unavailable. z_Modal backend is configured for direct mode, but no direct Modal credentials/config were found.zHModal backend selected but no direct Modal credentials/config was found.z`Modal backend selected but no direct Modal credentials/config or managed tool gateway was found.rÚ  )ÚDaytonaEnvironmentrÜ  )ÚVercelSandboxEnvironmentr8   )r1   r”  r  rF  rG  rL   rH  r�  rþ  r:  r;  z?SSH environment requires ssh_host and ssh_user to be configuredr<  r9  r—  r   )r:  r;  r<  Úkey_pathr”  r  zUnknown environment type: zV. Use 'local', 'docker', 'singularity', 'modal', 'daytona', 'vercel_sandbox', or 'ssh'rv   )rB   Ú_LocalEnvironmentr‘  r¸  rÀ  Ú_DockerEnvironmentÚ_session_scopedÚAttributeErrorÚ_SingularityEnvironmentÚinspectrÙ  Ú	signatureÚSandboxÚcreateÚ
parametersre   r7  Ú_ManagedModalEnvironmentr$   r   r   Ú_ModalEnvironmentÚtools.environments.daytonarY  r‰  Ú!tools.environments.vercel_sandboxrZ  Ú_SSHEnvironment)rª   rB  r”  r  rC  r|  rD  r�  r¬   ÚccrF  rG  rL   r=  rI  r  r#  r&  r%  Úsession_scopedÚdocker_env_objÚsandbox_kwargsra  rÙ  Úmodal_stateÚmessageÚ_DaytonaEnvironmentÚ_VercelSandboxEnvironments                               r   Ú_create_environmentrs  Ú  sl  € ð, 
Ð	˜R€BØ
�&Š&� !Ñ
$Ô
$€CØ�VŠVÐ&¨Ñ-Ô-€FØ�6Š6Ð" EÑ*Ô*€DØ—’Ð.°Ñ5Ô5€JØ�fŠfÐ% rÑ*Ô*€GØŸšÐ 4°bÑ9Ô9ÐØ—’˜ bÑ)Ô)€JØŸšÐ2°BÑ7Ô7ÐØ—V’VÐ,¨dÑ3Ô3€Nà�7ÒÐÝ  S°'Ð:Ñ:Ô:Ð:à	�XÒ	Ð	õ 	# 2Ñ&Ô&Ð&õ .Ñ/Ô/ð 6Ø˜9Ò$ð6å,¨WÑ5Ô5Ð5ð 	õ
 ,ð 
ð 
ð 
Ø�%ð
Ø ˜Sð
Ø*1¨'ð
à�ð
à"˜Fð
à)-¨ð
ð #- *ð
ð 7>°gð
ð �Gð	
ð
 �Xð
ð Ÿ6š6Ð"AÀ5ÑIÔIÐIð
ð +Ð*ð
ð �
ð
ð  ŸVšVÐ$=¸uÑEÔEÐEð
ð #�Nð
ð )Ð(ð
ð (ð E��Ø—V’VÐ=¸tÑDÔDøð
ð  —V’VÐ-¨tÑ4Ô4Ð4ð!
ˆð, ð 	ðØ15�Ô.Ð.øÝ!ð ð ð Ø�ðøøøàÐà	�]Ò	"Ð	"Ý&Ø˜S¨'Ø˜F¨Ø",°gð
ñ 
ô 
ð 	
ð 
�WÒ	Ñ	ØˆØ�Š7ˆ7Ø$'ˆN˜5Ñ!Ø�AŠ:ˆ:Ø'-ˆN˜8Ñ$Ø�!Š8ˆ8ðØ%Ð%Ð%Ð%Ð%Ð%Ð%Ð%Ø# w×'8Ò'8¸¼Ô9MÑ'NÔ'NÔ'YÐYÐYØ7;�NÐ#3Ñ4øøÝð ð ð Ø�ðøøøõ /¨r¯vªv°lÑ/CÔ/CÑDÔDˆàÐ)Ô*¨iÒ7Ð7Ý+Ø ¨gØ%3Ø&0¸'ðñ ô ð ð Ð)Ô*¨hÒ6Ð6ØÐ1Ô2ð 	Ý ð<õ <Ø1ñô ñð añañô ð ð ˜6Ô" iÒ/Ð/Ý ØqÝ;Ø1ñô ññô ð ð ˜6Ô" hÒ.Ð.Ý Øuñô ð ð aˆGÝ)Ñ+Ô+ð àvð õ ˜WÑ%Ô%Ð%å Ø˜S¨'Ø!/Ø",°gð
ñ 
ô 
ð 	
ð 
�YÒ	Ð	àXÐXÐXÐXÐXÐXØ"Ð"Ø˜S¨'Ý�C‘” ¨dØ",°gð
ñ 
ô 
ð 	
ð 
Ð%Ò	%Ð	%ð	
ð 	
ð 	
ð 	
ð 	
ð 	
ð )Ð(Ø—F’FÐ+Ñ,Ô,Ð4°ØØØØØØ",Øð	
ñ 	
ô 	
ð 		
ð 
�UÒ	Ð	Øð 	` §¢°Ñ!7Ô!7ð 	`¸z¿~º~ÈfÑ?UÔ?Uð 	`ÝÐ^Ñ_Ô_Ð_ÝØ˜FÔ#Ø˜FÔ#Ø—’ ¨Ñ+Ô+Ø—^’^ E¨2Ñ.Ô.ØØð
ñ 
ô 
ð 	
õ ðM¨ð Mð Mð Mñ
ô 
ð 	
s$   Æ2F: Æ:
GÇGÈ3I É
IÉIr�  r  c                 ó  — t          j         ¦   «         }	 ddlm} t          t                               ¦   «         ¦  «        D ]!}|                     |¦  «        r
|t          |<   Œ"n# t          $ r Y nw xY wg }t          5  t          t           	                    ¦   «         ¦  «        D ]]\  }}||z
  | k    rOt                               |d¦  «        }t                               |d¦  «         |�|                     ||f¦  «         Œ^t          5  |D ] \  }}t                               |d¦  «         Œ!	 ddd¦  «         n# 1 swxY w Y   ddd¦  «         n# 1 swxY w Y   |D �]+\  }}	 ddlm}  ||¦  «         n# t          $ r Y nw xY w	 t#          |d¦  «        r|                     ¦   «          nIt#          |d¦  «        r|                     ¦   «          n$t#          |d¦  «        r|                     ¦   «          t*                               d|¦  «         Œ´# t.          $ rl}	t1          |	¦  «        }
d	|
v sd
|
                     ¦   «         v rt*                               d|¦  «         nt*                               d||	¦  «         Y d}	~	�Œ%d}	~	ww xY wdS )zOClean up environments that have been inactive for longer than lifetime_seconds.r   ©Úprocess_registryN©Úclear_file_ops_cacheÚcleanupÚstopÚ	terminatez,Cleaned up inactive environment for task: %sÚ404ú	not foundú*Environment for task %s already cleaned upú-Error cleaning up environment for task %s: %s)rZ   Útools.process_registryrv  Úlistrz  r¾  Úhas_active_processesr‹  r¡  Úitemsry  r–   rò   Ú_creation_locks_lockr{  Útools.file_toolsrx  Úhasattrry  rz  r{  r%   rŒ  re   r   rÖ   r&   )r  Úcurrent_timerv  r�  Úenvs_to_stopÚ	last_timer¤  r^  rx  rl   Ú	error_strs              r   Ú_cleanup_inactive_envsr‹  š  sq  € å”9‘;”;€LðØ;Ð;Ð;Ð;Ð;Ð;Ý�N×/Ò/Ñ1Ô1Ñ2Ô2ð 	7ð 	7ˆGØ×4Ò4°WÑ=Ô=ð 7Ø*6•˜wÑ'øð	7øõ ð ð ð Øˆðøøøð €Lå	ð 3ð 3Ý"&¥~×';Ò';Ñ'=Ô'=Ñ">Ô">ð 	8ð 	8ÑˆG�YØ˜iÑ'Ð*:Ò:Ð:Ý*×.Ò.¨w¸Ñ=Ô=�Ý×"Ò" 7¨DÑ1Ô1Ð1Ø�?Ø ×'Ò'¨°#¨Ñ7Ô7Ð7øõ "ð 	3ð 	3Ø*ð 3ð 3‘
�˜Ý×#Ò# G¨TÑ2Ô2Ð2Ð2ð3ð	3ð 	3ð 	3ñ 	3ô 	3ð 	3ð 	3ð 	3ð 	3ð 	3ð 	3øøøð 	3ð 	3ð 	3ð 	3ð3ð 3ð 3ñ 3ô 3ð 3ð 3ð 3ð 3ð 3ð 3øøøð 3ð 3ð 3ð 3ð %ð \ñ \‰ˆ�ð	Ø=Ð=Ð=Ð=Ð=Ð=Ø Ð  Ñ)Ô)Ð)Ð)øÝð 	ð 	ð 	ØˆDð	øøøð	\Ý�s˜IÑ&Ô&ð  Ø—’‘”��Ý˜˜fÑ%Ô%ð  Ø—’‘
”
�
�
Ý˜˜kÑ*Ô*ð  Ø—’‘”�å�KŠKÐFÈÑPÔPÐPÐPøåð 	\ð 	\ð 	\Ý˜A™œˆIØ˜	Ð!Ð! [°I·O²OÑ4EÔ4EÐ%EÐ%EÝ—’ÐHÈ'ÑRÔRÐRÐRå—’ÐNÐPWÐYZÑ[Ô[Ð[øøøøùøøøøð	\øøøð'\ð \su   •AA$ Á$
A1Á0A1Á=BEÄ	$D:Ä.EÄ:D>	Ä>EÅD>	ÅEÅEÅEÅ%E7Å7
FÆFÆB	HÈ
JÈA!JÊJc                  ó6  — t           r‘	 t          ¦   «         } t          | d         ¦  «         n4# t          $ r'}t                               d|d¬¦  «         Y d}~nd}~ww xY wt          d¦  «        D ]}t           s nt          j        d¦  «         Œ t           °�dS dS )zKBackground thread worker that periodically cleans up inactive environments.r  zError in cleanup thread: %sTrX   Nr‚  r¡   )	Ú_cleanup_runningr3  r‹  re   r%   r&   ÚrangerZ   r  )r6   rl   r^  s      r   Ú_cleanup_thread_workerr�  Ø  sÎ   € å
ð 
ð	LÝ$Ñ&Ô&ˆFÝ" 6Ð*<Ô#=Ñ>Ô>Ð>Ð>øÝð 	Lð 	Lð 	LÝ�NŠNÐ8¸!ÀdˆNÑKÔKÐKÐKÐKÐKÐKÐKøøøøð	Løøøõ �r‘”ð 	ð 	ˆAÝ#ð Ø�ÝŒJ�q‰MŒMˆMˆMõ ð 
ð 
ð 
ð 
ð 
s   ‰#- ­
A·AÁAc                  óò   — t           5  t          �t                               ¦   «         s6dat	          j        t          d¬¦  «        at                               ¦   «          ddd¦  «         dS # 1 swxY w Y   dS )z;Start the background cleanup thread if not already running.NTr
  )r¡  Ú_cleanup_threadÚis_aliver�  r‰   r  r�  r  rv   r   r   Ú_start_cleanup_threadr“  ç  s´   € õ 
ð $ð $ÝÐ"­/×*BÒ*BÑ*DÔ*DÐ"Ø#ÐÝ'Ô.Õ6LÐUYÐZÑZÔZˆOÝ×!Ò!Ñ#Ô#Ð#ð	$ð $ð $ñ $ô $ð $ð $ð $ð $ð $ð $ð $øøøð $ð $ð $ð $ð $ð $s   ˆAA,Á,A0Á3A0c                  ó„   — da t          �6	 t                               d¬¦  «         dS # t          t          f$ r Y dS w xY wdS )z#Stop the background cleanup thread.FNé   r  )r�  r‘  rD   Ú
SystemExitrñ   rv   r   r   Ú_stop_cleanup_threadr—  ò  sb   € ð ÐÝÐ"ð	Ý× Ò ¨Ð Ñ+Ô+Ð+Ð+Ð+øÝÕ-Ð.ð 	ð 	ð 	ØˆDˆDð	øøøð #Ð"s   ‹( ¨=¼=c                 óÊ   — t          | ¦  «        }t          5  t                               |¦  «        pt                               | ¦  «        cddd¦  «         S # 1 swxY w Y   dS )z9Return the active BaseEnvironment for *task_id*, or None.N)r   r¡  ry  rB   )r�  Úlookups     r   Úget_active_envrš  ý  s²   € å'¨Ñ0Ô0€FÝ	ð Uð UÝ#×'Ò'¨Ñ/Ô/ÐTÕ3G×3KÒ3KÈGÑ3TÔ3TðUð Uð Uð Uñ Uô Uð Uð Uð Uð Uð Uð Uøøøð Uð Uð Uð Uð Uð Us   —4AÁAÁAc                 ó†  — t          ¦   «         }|d         }|dk    rdS t          | ¦  «        }t          |¦  «        }|�<t          5  t	          j        ¦   «         t
          |<   ddd¦  «         n# 1 swxY w Y   |S t          | ¦  «        }|dk    r|                     d¦  «        p|d         }nn|dk    r|                     d¦  «        p|d         }nJ|dk    r|                     d	¦  «        p|d	         }n&|d
k    r|                     d¦  «        p|d         }nd}t          ¦   «          t          5  t                               |t          j        ¦   «         ¦  «        }ddd¦  «         n# 1 swxY w Y   |5  t          |¦  «        }|�|cddd¦  «         S 	 t          |||d         |d         |dk    rt          |¦  «        nd|t           v rt#          |¦  «        ndd|t%          || ¦  «        ¬¦	  «	        }nH# t&          $ r;}	t(                               d||dd…         |	¦  «         Y d}	~	ddd¦  «         dS d}	~	ww xY wt          5  |t,          |<   t	          j        ¦   «         t
          |<   ddd¦  «         n# 1 swxY w Y   t(                               d||dd…         ¦  «         |cddd¦  «         S # 1 swxY w Y   dS )u3  Lazily create and cache the sandbox env for *task_id* if none is active.

    :func:`terminal_tool` creates the environment on the first terminal command,
    but nothing else did â€” so under a non-local backend (ssh, docker, â€¦) a
    session whose first action is ``vision_analyze`` on a container-only path hit
    "no active sandbox session" because the SSH/Docker handshake never ran
    (issue #62825). vision reads such paths inside the sandbox (see
    ``tools.image_source``), so it calls this to bring the env up on demand,
    reusing the same creation machinery as the terminal tool.

    No-op on the local backend (images are read host-side). Returns the env
    instance, or ``None`` when local or when creation fails (best-effort: a
    failure leaves the caller's fail-closed error path intact).
    rª   rD  Nr«   rº  rÛ  r¼  rÙ  r¹  rÚ  r»  r   r”  r  rþ  ©	rª   rB  r”  r  rC  r|  rD  r�  r¬   z/Lazy %s environment init failed for task %s: %sé   z-%s environment lazily initialized for task %s)r3  r   rš  r¡  rZ   rz  rÃ  rB   r“  r„  r{  Ú
setdefaultr‰   ÚLockrs  r?  r,  rA  rÎ  re   r%   r&   ry  rŒ  )
r�  r6   rª   Úeffective_task_idÚexistingrž  rB  Ú	task_lockÚnew_envÚexcs
             r   Úensure_task_envr¥    s]  € õ ÑÔ€FØ�jÔ!€HØ�7ÒÐØˆtå2°7Ñ;Ô;Ðõ Ð/Ñ0Ô0€HØÐÝð 	<ð 	<Ý04´	±´�NÐ,Ñ-ð	<ð 	<ð 	<ñ 	<ô 	<ð 	<ð 	<ð 	<ð 	<ð 	<ð 	<øøøð 	<ð 	<ð 	<ð 	<àˆå& wÑ/Ô/€IØ�8ÒÐØ—’˜nÑ-Ô-ÐG°¸Ô1GˆˆØ	�]Ò	"Ð	"Ø—’Ð1Ñ2Ô2ÐQ°fÐ=PÔ6QˆˆØ	�WÒ	Ð	Ø—’˜mÑ,Ô,ÐE°°}Ô0EˆˆØ	�YÒ	Ð	Ø—’˜oÑ.Ô.ÐI°&¸Ô2IˆˆàˆåÑÔÐõ 
ð Tð TÝ#×.Ò.Ð/@Å)Ä.ÑBRÔBRÑSÔSˆ	ðTð Tð Tñ Tô Tð Tð Tð Tð Tð Tð Tøøøð Tð Tð Tð Tð 
ð !ð !Ý!Ð"3Ñ4Ô4ˆØÐØð!ð !ð !ð !ñ !ô !ð !ð !ð	Ý)Ø!ØØ˜5”MØ˜yÔ)Ø>FÈ%Ò>OÐ>OÕ2°6Ñ:Ô:Ð:ÐUYð  Õ#6Ð6Ð6õ 2°&Ñ9Ô9Ð9Ø<@à!Ø)Ý/°¸Ñ@Ô@ðñ ô ˆGˆGøõ ð 	ð 	ð 	Ý�NŠNØAØÐ+¨B¨Q¨BÔ/°ñô ð ð �4�4�4ð1!ð !ð !ñ !ô !ð !ð !ð !øøøøð&	øøøõ ð 	<ð 	<Ø6=Õ Ð!2Ñ3Ý04´	±´�NÐ,Ñ-ð	<ð 	<ð 	<ñ 	<ô 	<ð 	<ð 	<ð 	<ð 	<ð 	<ð 	<øøøð 	<ð 	<ð 	<ð 	<õ 	�ŠØ;ØÐ'¨¨¨Ô+ñ	
ô 	
ð 	
ð ðC!ð !ð !ð !ñ !ô !ð !ð !ð !ð !ð !ð !øøøð !ð !ð !ð !ð !ð !s…   ÁA.Á.A2Á5A2Ä1-E*Å*E.Å1E.Å7J6ÆAG8Ç7J6Ç8
H=È%H8È'J6È8H=È=
J6É&I9É-J6É9I=	É=J6Ê I=	Ê(J6Ê6J:Ê=J:c                 óŠ   — t          | ¦  «        }|€dS t          |dd¦  «        rdS t          t          |dd¦  «        ¦  «        S )u,  Return True if the active environment for task_id is configured for
    cross-turn persistence (``persistent_filesystem=True``).

    Used by the agent loop to skip per-turn teardown for backends whose whole
    point is to survive between turns (docker with ``container_persistent``,
    daytona, modal, etc.). Non-persistent backends (e.g. Morph) still get torn
    down at end-of-turn to prevent leakage. The idle reaper
    (``_cleanup_inactive_envs``) handles persistent envs once they exceed
    ``terminal.lifetime_seconds``.

    Session-scoped docker containers (per-session isolation mode) also count
    as persistent HERE: their lifetime is the SESSION, not the turn â€” they
    are removed by ``AIAgent.close()`` â†’ ``cleanup_vm`` at session teardown
    and by the idle reaper, not per-turn.
    NFr^  TÚ_persistent)rš  rt   rJ   )r�  r¤  s     r   Úis_persistent_envr¨  X  sO   € õ  ˜Ñ
!Ô
!€CØ
€{ØˆuÝˆsÐ% uÑ-Ô-ð ØˆtÝ•˜˜]¨EÑ2Ô2Ñ3Ô3Ð3r   c                  ót  — t          t                               ¦   «         ¦  «        } d}| D ]L}	 t          |¦  «         |dz  }Œ# t          $ r(}t
                               d||d¬¦  «         Y d}~ŒEd}~ww xY wt          ¦   «         }ddl}|                     t          |dz  ¦  «        ¦  «        D ]g}	 t          j        |d¬¦  «         t
                               d	|¦  «         Œ5# t          $ r&}t
                               d
||¦  «         Y d}~Œ`d}~ww xY w|dk    rt
                               d|¦  «         |S )z3Clean up ALL active environments. Use with caution.r   r¡   zError cleaning %s: %sTrX   NrV   )Úignore_errorszRemoved orphaned: %sz%Failed to remove orphaned path %s: %szCleaned %d environments)r�  ry  r¾  Ú
cleanup_vmre   r%   rE   r   r]   r   ÚshutilÚrmtreerŒ  rb   rc   )Útask_idsÚcleanedr�  rl   rh   r]   rj   s          r   Úcleanup_all_environmentsr°  r  s  € åÕ(×-Ò-Ñ/Ô/Ñ0Ô0€HØ€Gàð Mð Mˆð	MÝ�wÑÔÐØ�q‰LˆGˆGøÝð 	Mð 	Mð 	MÝ�LŠLÐ0°'¸1ÀtˆLÑLÔLÐLÐLÐLÐLÐLÐLøøøøð	Møøøõ #Ñ$Ô$€KØ€K€K€KØ—	’	�#˜k¨JÑ6Ñ7Ô7Ñ8Ô8ð Kð Kˆð	KÝŒM˜$¨dÐ3Ñ3Ô3Ð3Ý�KŠKÐ.°Ñ5Ô5Ð5Ð5øÝð 	Kð 	Kð 	KÝ�LŠLÐ@À$ÈÑJÔJÐJÐJÐJÐJÐJÐJøøøøð	Køøøð �‚{€{Ý�ŠÐ-¨wÑ7Ô7Ð7Ø€Ns/   ®AÁ
A5ÁA0Á0A5Â21C$Ã$
DÃ.DÄD©Úforce_remover²  c                ó  — d}t           5  t                               | d¦  «        }t                               | d¦  «         ddd¦  «         n# 1 swxY w Y   t          5  t
                               | d¦  «         ddd¦  «         n# 1 swxY w Y   	 ddlm}  || ¦  «         n# t          $ r Y nw xY w|€dS 	 t          |d¦  «        rSddl
}|                     |j        ¦  «        }d|j        v r|                     |¬¦  «         n^|                     ¦   «          nIt          |d¦  «        r|                     ¦   «          n$t          |d¦  «        r|                     ¦   «          t                                d	| ¦  «         dS # t$          $ rr}t'          |¦  «        }d
|v sd|                     ¦   «         v rt                                d| ¦  «         n"t                                d| |¦  «         Y d}~dS Y d}~dS d}~ww xY w)u$  Manually clean up a specific environment by task_id.

    *force_remove* (default False) is forwarded to backends that accept it
    â€” currently only ``DockerEnvironment``. The default of False matches
    session-lifecycle semantics: this function is called from
    ``AIAgent.close()`` (TUI session close, gateway session teardown) and the
    per-turn cleanup branch for non-persistent envs, both of which should
    honor the user's persist-mode preference. Stopping the container here
    would defeat the "ONE long-lived container shared across sessions"
    contract â€” exactly the bug Ben reported when the container was killed
    on every TUI session close.

    Pass ``force_remove=True`` for actual user-initiated teardown
    (e.g. ``/reset``-style flows that haven't been wired yet, or future
    "destroy my sandbox" commands).

    The idle reaper passes the env through ``env.cleanup()`` directly (not
    via this function), so persist-mode idle envs are similarly no-op'd â€”
    only the orphan reaper at next startup reclaims them.
    Nr   rw  ry  r²  r±  rz  r{  z,Manually cleaned up environment for task: %sr|  r}  r~  r  )r¡  ry  r–   rz  r„  r{  r…  rx  r‹  r†  ra  rb  ry  re  rz  r{  r%   rŒ  re   r   rÖ   r&   )r�  r²  r¤  rx  ra  Úsigrl   rŠ  s           r   r«  r«  �  sÃ  € ð0 €CÝ	ð *ð *Ý"×&Ò& w°Ñ5Ô5ˆÝ×Ò˜7 DÑ)Ô)Ð)ð*ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *õ
 
ð +ð +Ý×Ò˜G TÑ*Ô*Ð*ð+ð +ð +ñ +ô +ð +ð +ð +ð +ð +ð +øøøð +ð +ð +ð +ðØ9Ð9Ð9Ð9Ð9Ð9ØÐ˜WÑ%Ô%Ð%Ð%øÝð ð ð Øˆðøøøð €{ØˆðXÝ�3˜	Ñ"Ô"ð 	ð ˆNˆNˆNØ×#Ò# C¤KÑ0Ô0ˆCØ ¤Ð/Ð/Ø—’¨�Ñ6Ô6Ð6Ð6à—’‘”��Ý�S˜&Ñ!Ô!ð 	Ø�HŠH‰JŒJˆJˆJÝ�S˜+Ñ&Ô&ð 	Ø�MŠM‰OŒOˆOå�ŠÐBÀGÑLÔLÐLÐLÐLøåð Xð Xð XÝ˜‘F”Fˆ	Ø�IÐÐ °	·²Ñ0AÔ0AÐ!AÐ!AÝ�KŠKÐDÀgÑNÔNÐNÐNå�NŠNÐJÈGÐUVÑWÔWÐWÐWÐWÐWÐWÐWÐWð OÐNÐNÐNÐNÐNøøøøðXøøøsO   Š7AÁAÁAÁBÂBÂBÂB% Â%
B2Â1B2Â:CF Æ
G?ÆA!G:Ç:G?c                  óª  — t          ¦   «          t          r»t          t          ¦  «        } t                               d| ¦  «         t          t                               ¦   «         ¦  «        }t          ¦   «          |D ]W}t          |dd¦  «        }|€Œ	  |d¬¦  «         Œ$# t          $ r%}t           
                    d|¦  «         Y d}~ŒNd}~ww xY wdS dS )zBStop cleanup thread and shut down all remaining sandboxes on exit.z)Shutting down %d remaining sandbox(es)...Úwait_for_cleanupNg      .@r  z#wait_for_cleanup raised on exit: %s)r—  ry  r¦   r%   rŒ  r�  Úvaluesr°  rt   re   rc   )rA  Úenvs_to_waitr¤  Úwait_fnrl   s        r   Ú_atexit_cleanuprº  Ñ  s
  € åÑÔÐÝð GÝÕ(Ñ)Ô)ˆÝ�ŠÐ?ÀÑGÔGÐGõ Õ0×7Ò7Ñ9Ô9Ñ:Ô:ˆÝ Ñ"Ô"Ð"ð
  ð 	Gð 	GˆCÝ˜cÐ#5°tÑ<Ô<ˆGØˆØðGØ� Ð%Ñ%Ô%Ð%Ð%øÝð Gð Gð GÝ—’ÐBÀAÑFÔFÐFÐFÐFÐFÐFÐFøøøøðGøøøð%Gð Gð	Gð 	Gs   ÂBÂ
CÂ)C	Ã	CÚ	exit_codec                 óÄ  — |dk    rdS t          j        d| ¦  «        }|r|d         n|                      ¦   «         }|                     ¦   «         }d}|D ]7}d|v r|                     d¦  «        sŒ|                     d¦  «        d         } |sdS d	d
id	d
id	d
id	d
id	d
id	d
id	did	did	did	did	didddddœd	didœ}|                     |¦  «        }|r||v r||         S dS )a
  Return a human-readable note when a non-zero exit code is non-erroneous.

    Returns None when the exit code is 0 or genuinely signals an error.
    The note is appended to the tool result so the model doesn't waste
    turns investigating expected exit codes.
    r   Nz\s*(?:\|\||&&|[|;])\s*r2  r   r"  Ú-rž   r¡   zNo matches found (not an error)z%Files differ (expected, not an error)zGSome directories were inaccessible (partial results may still be valid)z5Condition evaluated to false (expected, not an error)zCould not resolve hostzFailed to connect to hostz2HTTP response code indicated error (e.g. 404, 500)zOperation timed out)é   é   r9  é   uL   Non-zero exit (often normal â€” e.g. 'git diff' returns 1 when files differ))ÚgrepÚegrepÚfgrepÚrgÚagÚackÚdiffÚ	colordiffr9  ÚtestÚ[ÚcurlÚgit)r$  r#  rC   r¥   rB   )	rµ   r»  ÚsegmentsÚlast_segmentÚwordsÚbase_cmdÚwÚ	semanticsÚcmd_semanticss	            r   Ú_interpret_exit_coderÔ  ô  st  € ð �A‚~€~Øˆtõ
 ŒxÐ1°7Ñ;Ô;€HØ$,Ð9�H˜R”L�L°'×@Ò@ÑBÔB€Lð ×ÒÑ Ô €EØ€HØð ð ˆØ�!ˆ8ˆ8˜AŸLšL¨Ñ-Ô-ˆ8ØØ—7’7˜3‘<”< Ô#ˆØàð Øˆtð
 Ð6Ð7ØÐ6Ð7ØÐ6Ð7ØÐ6Ð7ØÐ6Ð7ØÐ6Ð7àÐ<Ð=ØÐ@ÐAàÐ^Ð_àÐLÐMØÐLÐMð (Ø*ØDØ%ð	
ð 
ð ÐcÐdð1,ð ,€Ið6 —M’M (Ñ+Ô+€MØð (˜ mÐ3Ð3Ø˜YÔ'Ð'àˆ4r   c                 ó¦   — d                      |                      ¦   «                              ¦   «         ¦  «        }|                     d¦  «        od|v S )au  Return True when PTY mode would break stdin-driven commands.

    Some CLIs change behavior when stdin is a TTY. In particular,
    `gh auth login --with-token` expects the token to arrive via piped stdin and
    waits for EOF; when we launch it under a PTY, `process.submit()` only sends a
    newline, so the command appears to hang forever with no visible progress.
    Ú zgh auth loginz--with-token)rD   rÖ   r#  r¥   ©rµ   Ú
normalizeds     r   Ú_command_requires_pipe_stdinrÙ  4	  sL   € ð —’˜'Ÿ-š-™/œ/×/Ò/Ñ1Ô1Ñ2Ô2€Jà×Ò˜oÑ.Ô.ð 	)Ø˜jÐ(ðr   z=(?:^|[;&|]\s*|&&\s*|\|\|\s*|\$\(\s*)(?:nohup|disown|setsid)\bz\s&\sz\s&\s*(?:#.*)?$c                 óŠ   — t          j        dd| ¦  «        }t          j        dd|¦  «        }t          j        dd|¦  «        }|S )a:  Remove single- and double-quoted content so regex checks don't match inside strings.

    This prevents false positives when keywords like 'nohup' or 'setsid' appear
    in commit messages, Python -c code, echo arguments, or PR body text.
    Also strips backtick-quoted content and heredoc-style inline text.
    z'[^']*'z''z"(?:[^"\\]|\\.)*"z""z`[^`]*`z``)r$  Úsub)rµ   rS   s     r   Ú_strip_quotesrÜ  J	  sC   € õ ŒV�J  gÑ.Ô.€FåŒVÐ(¨$°Ñ7Ô7€FåŒV�J  fÑ-Ô-€FØ€Mr   z@\b(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:dev|start|serve|watch)\bz\bdocker\s+compose\s+up\bz\bnext\s+dev\bz\bvite(?:\s|$)z\bnodemon\bz\buvicorn\bz\bgunicorn\bz$\bpython(?:3)?\s+-m\s+http\.server\bc                 óØ   — d                      |                      ¦   «                              ¦   «         ¦  «        }d|v p-|                     d¦  «        pd|v p|                     d¦  «        S )zGReturn True for informational invocations that should never be blocked.rÖ  z --helpz -hz
 --versionz -v)rD   rÖ   r#  Úendswithr×  s     r   Ú#_looks_like_help_or_version_commandrß  f	  so   € à—’˜'Ÿ-š-™/œ/×/Ò/Ñ1Ô1Ñ2Ô2€Jà�ZÐð 	&Ø×Ò˜uÑ%Ô%ð	&à˜:Ð%ð	&ð ×Ò˜uÑ%Ô%ð	r   c                 ó4  — t          | ¦  «        rdS t          | ¦  «        }t                               |¦  «        r	 dS t                               |¦  «        st
                               |¦  «        r	 dS t          D ]}|                     |¦  «        r	  dS ŒdS )zÃSuggest background mode when a foreground command looks long-lived.

    Prevents workflows that start a server/watch process and then stall before
    follow-up checks or test commands run.
    Na	  Foreground command uses shell-level background wrappers (nohup/disown/setsid). Re-send WITHOUT the wrapper as terminal(command="<cmd>", background=true, notify_on_complete=true) so Hermes tracks the process, then run readiness checks and tests in separate commands.uã   Foreground command uses '&' backgrounding. Re-send WITHOUT the '&' as terminal(command="<cmd>", background=true) â€” add notify_on_complete=true for bounded jobs â€” then run health checks and tests in follow-up terminal calls.zÁThis foreground command appears to start a long-lived server/watch process. Run it with background=true, verify readiness (health endpoint/log signal), then execute tests in a separate command.)rß  rÜ  Ú_SHELL_LEVEL_BACKGROUND_REÚsearchÚ_INLINE_BACKGROUND_AMP_REÚ_TRAILING_BACKGROUND_AMP_REÚ_LONG_LIVED_FOREGROUND_PATTERNS)rµ   ÚunquotedÚpatterns      r   Ú_foreground_background_guidancerè  q	  sÑ   € õ +¨7Ñ3Ô3ð Øˆtõ ˜WÑ%Ô%€Hå!×(Ò(¨Ñ2Ô2ð 
ð5ð	
ð 	
õ !×'Ò'¨Ñ1Ô1ð 
Õ5P×5WÒ5WÐX`Ñ5aÔ5að 
ðað	
ð 	
õ 3ð ð ˆØ�>Š>˜(Ñ#Ô#ð 	ð<ðð ð ð	ð ˆ4r   Únotify_on_completeÚ
backgroundc                 ó"   — |r
| r|rd}d|fS |dfS )uK  Decide what to do when both notify_on_complete and watch_patterns are set.

    These flags produce duplicate, delayed notifications when combined â€” one
    notification per watch-pattern match AND one on process exit, with async
    delivery that can spam the user long after the process ends. When both are
    set, we drop watch_patterns in favor of notify_on_complete (the more useful
    "let me know when it's done" signal) and return a human-readable note.

    Returns:
        (watch_patterns_to_use, conflict_note). conflict_note is "" when there
        is no conflict.
    zuwatch_patterns ignored because notify_on_complete=True; these two flags produce duplicate notifications when combinedNr   rv   )ré  Úwatch_patternsrê  Únotes       r   Ú#_resolve_notification_flag_conflictrî  ˜	  s=   € ð$ ð Ð(ð ¨^ð ðLð 	ð �TˆzÐØ˜2ÐÐr   )r‹   rª   r1  c                 ó¢   — | r| S t          |¦  «        }|r7|t          v r.t          |¦  «        rt                               d|||¦  «         |S |p|S )uÄ  Return the cwd for a command. Explicit ``workdir=`` overrides everything.

    Otherwise the session's own cwd RECORD (``get_session_cwd``) wins â€” it is
    written after every completed command for this session, so it IS the
    session's ``cd`` state, with no shared-env ambiguity: another session's
    ``cd`` lands in another record and can't affect us. A session with no
    record yet (first command) runs in ``default_cwd`` (config/override cwd),
    which is also what seeds a fresh environment.

    ``env_type`` makes the record container-aware: on container backends a
    recorded HOST path (a desktop/TUI surface registering its host workspace
    via ``register_task_env_overrides`` â†’ ``record_session_cwd``) is unusable
    inside the sandbox â€” the shell prefixes every command with ``cd <host
    path>`` and fails with exit 126. Same guard class as the env-creation
    sanitizers (#50636, #54447); this is the per-command sibling site.
    zmIgnoring recorded session cwd %r for %s backend (host/relative path won't work in sandbox). Using %r instead.)rš  r,  rã  r%   rŒ  )rÃ   r1  r‹   rª   Úrecordeds        r   Ú_resolve_command_cwdrñ  ³	  sz   € ð. ð ØˆÝ˜{Ñ+Ô+€Hàð
àÕ+Ð+Ð+Ý& xÑ0Ô0ð ,õ 	�ŠðLà�h ñ	
ô 	
ð 	
ð
 ÐØÐ"�{Ð"r   Ú
session_idr   Úptyrì  c
                 óô%  ‡f‡g‡h— 	 t          | t          ¦  «        s]t                               dt	          | ¦  «        j        ¦  «         t          j        dddt	          | ¦  «        j        › �ddœd¬¦  «        S t          ¦   «         }
|
d	         }t          |¦  «        }t          |¦  «        }|d
k    r|                     d¦  «        p|
d         }nn|dk    r|                     d¦  «        p|
d         }nJ|dk    r|                     d¦  «        p|
d         }n&|dk    r|                     d¦  «        p|
d         }nd}|                     d¦  «        pt          |¦  «        p|
d         }t          |
|¦  «        }|t          v r@t          |¦  «        r1|rdn|
d         }||k    rt                               d|||¦  «         |}|
d         }|�|dk    rt#          d|› d�¦  «        S |p|}|s(|r&|t$          k    rt#          d|› dt$          › d�¦  «        S |s,t'          | ¦  «        }|rt          j        dd|ddœd¬¦  «        S t)          ¦   «          dŠgt*          5  |t,          v r|n|r|t,          v r|nd}|�+t/          j        ¦   «         t0          |<   t,          |         Šgd}nd}ddd¦  «         n# 1 swxY w Y   |�r.t2          5  |t4          vrt7          j        ¦   «         t4          |<   t4          |         }ddd¦  «         n# 1 swxY w Y   |5  t*          5  |t,          v r|n|r|t,          v r|nd}|�*t/          j        ¦   «         t0          |<   t,          |         Šgd}ddd¦  «         n# 1 swxY w Y   |�r\|dk    rt;          ¦   «          t                               d||dd…         ¦  «         	 |d k    rt=          |
¦  «        nd}|t          v rt?          |
¦  «        nd}d}|d!k    rd"|
                     d#d¦  «        i}tA          |||||||||¬$¦	  «	        }nO# tB          $ rB}t          j        ddtE          d%|› d&�¦  «        d'dœd¬¦  «        cY d}~cddd¦  «         S d}~ww xY wt*          5  |t,          |<   t/          j        ¦   «         t0          |<   |Šgddd¦  «         n# 1 swxY w Y   t                               d(||dd…         ¦  «         ddd¦  «         n# 1 swxY w Y   ‰g€J ‚dd)l#m$}  |d¬*¦  «        p|pd}tJ          j&                             d+¦  «        d,k    r±dd-l'm(Šfm)}m*}   | | ¦  «        rt          j        dd.d/ddœd¬¦  «        S t          |¦  «        }!|!€tW          ‰gdd¦  «        p|}!tY          ||!||¬0¦  «        Šhd1t          d2tZ          t                   fˆfˆgˆhfd3„}" || ‰h|"¬4¦  «        rt          j        dd.d5ddœd¬¦  «        S |r]t]          |¦  «        }#|#rLt                               d6|dd7…         t_          | ¦  «        ¦  «         t          j        dd|#d8dœd¬¦  «        S |d!k    rldd9l0m1}$ tY          |||¬:¦  «        Šh |$| ‰h¦  «        \  }%}&|%rCt                               d;t_          | ¦  «        ¦  «         t          j        dd.|&d8dœd¬¦  «        S d}'te          |¦  «        }(|�sutg          | |ti          |
¦  «        ¬<¦  «        })|)d=         sé|)                     d>¦  «        d?k    r…t          j        dddd?d|)                     d@| ¦  «        |)                     dAdB¦  «        |)                     dCd¦  «        |)                     dDd¦  «        |)                     dEd¦  «        dFœ
d¬¦  «        S |)                     dAdB¦  «        }*dG|*› dH�}+t          j        dd|)                     dI|+¦  «        d8dœd¬¦  «        S |)                     dJ¦  «        r|)                     dAdK¦  «        }*dL|*› dM�}'d}(n1|)                     dN¦  «        r|)                     dAdK¦  «        }*dO|*› dP�}'d},|}-|rtk          | ¦  «        rd}-dQ},|�rÒddRl6m7}. tY          ||||¬0¦  «        }/	 |d!k    r3|. 8                    | |/||ts          ‰gdS¦  «        r‰gj:        nd|-¬T¦  «        }0n|. ;                    ‰g| |/||¬U¦  «        }0dV|0j<        |0j=        dddWœ}1|'r|'|1dX<   |,r|,|1dY<   |r	|s|	sdZ|1d[<   |rG| rEd\| v pd]| v }2d^| v pd_| v pd`| v }3da| v p|2o|3}4|4r'|1                     d[d¦  «        }5db}6|5r|5dcz   |6z   n|6|1d[<   |r¹|s|	rµdddl>m?}7m@}8  |7¦   «         s/d}d}	d|1de<   df|1dg<   t                               dh|0j<        ¦  «         nt |8did¦  «        }9|9rf |8djd¦  «        }: |8dkd¦  «        }; |8dld¦  «        }< |8dmd¦  «        }= |8dnd¦  «        }>|9|0_A        |:|0_B        |<|0_C        |=|0_D        |;|0_E        |>|0_F        t�          te          |¦  «        |	te          |¦  «        ¬o¦  «        \  }	}?|?r&t                               dp|0j<        |?¦  «         |?|1dq<   |rd|rbd|0_H        d|1de<   |0jA        rOdr|0_I        |.jJ         K                    |0j<        dr||0jA        |0jB        |0jC        |0jD        |0jE        |0jF        ddsœ
¦  «         |	r |rt™          |	¦  «        |0_M        |0jM        |1dt<   t          j        |1d¬¦  «        S # tœ          $ r4}t          j        ddtE          du|› �¦  «        dvœd¬¦  «        cY d}~S d}~ww xY wdw}@d}Ad}Bd}C|(rddxlOmP}D  |D¦   «          |A|@k    �rs	 tY          ||||¬0¦  «        }C||Cddyœ}E ‰gjQ        | fi |E¤Ž}B�nH# tœ          $ �r:}t          |¦  «         R                    ¦   «         }Fd|Fv r#t          j        ddzd{|› d|�dvœd¬¦  «        cY d}~S |A|@k     rd|Ad.z  }Ad}|Az  }Gt                               d~|G|A|@t_          | ¦  «        t	          |¦  «        j        |||¦	  «	         t/          jS        |G¦  «         Y d}~Œît           T                    d|@t_          | ¦  «        t	          |¦  «        j        |||¦  «         t          j        ddtE          d€t	          |¦  «        j        › d�|› �¦  «        dvœd¬¦  «        cY d}~S d}~ww xY w	 |st«          |tW          ‰gdd¦  «        ¦  «         |B                     d‚d¦  «        }H|B                     dƒd¦  «        }I|B                     d„¦  «        }J|B                     d…¦  «        }Kt­          |H|¦  «        }Ht¯          |H¦  «        }Lt±          | |H¦  «        }M|Mr&t³          ¦   «         du}N|Nstµ          d†¦  «        r|Hd‡z  }H	 ddˆl[m\}O  |Od‰| |H|I|pd|¬Š¦  «        }P|PD ]}Qt          |Qt          ¦  «        r|Q}H nŒn# tœ          $ r Y nw xY wdd‹l]m^}R  |R¦   «         }St¿          |H¦  «        |Sk    r[tÁ          |SdŒz  ¦  «        }T|S|Tz
  }Ut¿          |H¦  «        |Tz
  |Uz
  }Vd�|V› dŽt¿          |H¦  «        › d��}W|Hd|T…         |Wz   |H|U d…         z   }Hdd�lamb}X  |X|H¦  «        }Hdd‘lcmd}Y |Hr |Y|H e                    ¦   «         | ¦  «        nd}HtÍ          | |I¦  «        }Zd}[|Idk    r)|Zs'	 dd’lgmh}\  |\| |I|H¦  «        }[n# tœ          $ r d}[Y nw xY w|H|Iddvœ}]	 tW          ‰gdd¦  «        }^|^rn|CrltJ          ji         j                    t          |^¦  «        ¦  «        tJ          ji         j                    t          |C¦  «        ¦  «        k    rt          |^¦  «        |]d<   n# tœ          $ r Y nw xY w|KrÉ	 t×          |K¦  «        }_|_ l                    d“d”¬•¦  «        }`|_ m                     |Y |X|`¦  «        | ¦  «        d“d”¬•¦  «         |J|]d„<   |K|]d…<   d–|Jd—›d˜|K› d™�|]dš<   n_# tœ          $ rR t           n                    d›d¬œ¦  «         	 t×          |K¦  «         o                    ¦   «          n# tà          $ r Y nw xY wY nw xY w	 dd�lqmr}a  |a| |C|p|p|pdž|I|H¬Ÿ¦  «        }b|brV|b                     d>¦  «        |b                     d ¦  «        |b                     d¡¦  «        |b                     d¢¦  «        d£œ|]d¤<   n,# tœ          $ r t           n                    d¥d¬œ¦  «         Y nw xY w|'r+|Id¦k    r d§|Hv r|' s                    d¨¦  «        d©z   |]dX<   n|'|]dX<   |Zr|Z|]dª<   |[r|[|]d[<   |Lrd|]d«<   |Mrd|]d¬<   t          j        |]d¬¦  «        S # tè          $ �rF}tK          ju        d­d®¦  «         e                    ¦   «          R                    ¦   «         }c|cd¯k    rqddlv}d|d w                    ¦   «         }et           T                    d°|e¦  «         t          j        ddtE          d±|› �¦  «        tE          |e¦  «        dd²œd¬¦  «        cY d}~S t                               d³|jx        ¦  «         	 tó          |¦  «         n,# tœ          $ r t           n                    d´d¬œ¦  «         Y nw xY wt          j        dddµ|jx        |jz        d¶|jx        › �d·œd¬¦  «        cY d}~S d}~wtœ          $ rv}ddlv}d|d w                    ¦   «         }et           T                    d°|e¦  «         t          j        ddtE          d±|› �¦  «        tE          |e¦  «        dd²œd¬¦  «        cY d}~S d}~ww xY w)¸u|  
    Execute a command in the configured terminal environment.

    Args:
        command: The command to execute
        background: Whether to run in background (default: False)
        timeout: Command timeout in seconds (default: from config)
        task_id: Unique identifier for environment isolation (optional)
        session_id: Conversation/session identifier for durable observability
        force: If True, skip dangerous command check (use after user confirms)
        workdir: Working directory for this command (optional, uses session cwd if not set)
        pty: If True, use pseudo-terminal for interactive CLI tools (local backend only)
        notify_on_complete: If True and background=True, you'll be notified exactly once when the process exits. The right choice for almost every long task. MUTUALLY EXCLUSIVE with watch_patterns.
        watch_patterns: List of strings to watch for in background output. HARD rate limit: 1 notification per 15s per process. After 3 strike windows in a row, watch_patterns is disabled and the session is auto-promoted to notify_on_complete. Use ONLY for rare, one-shot mid-process signals on long-lived processes (server readiness, migration-done markers). NEVER use in loops/batch jobs â€” error patterns there will hit the strike limit and get disabled. MUTUALLY EXCLUSIVE with notify_on_complete â€” set one, not both.

    Returns:
        str: JSON string with output, exit_code, and error fields

    Examples:
        # Execute a simple command
        >>> result = terminal_tool(command="ls -la /tmp")

        # Run a background task
        >>> result = terminal_tool(command="python server.py", background=True)

        # With custom timeout
        >>> result = terminal_tool(command="long_task.sh", timeout=300)
        
        # Force run after user confirmation
        # Note: force parameter is internal only, not exposed to model API
    z+Rejected invalid terminal command value: %sr   r2  z&Invalid command: expected string, got rE   )rÇ   r»  rE   ÚstatusF)Úensure_asciirª   r«   rº  rÛ  r¼  rÙ  r¹  rÚ  r»  r”  rÈ  zbRemapping host/relative cwd override %r for %s backend (won't exist in sandbox). Using %r instead.r  Nr   z2timeout must be a positive number of seconds (got z).zForeground timeout zs exceeds the maximum of zNs. Use background=true with notify_on_complete=true for long-running commands.Tz*Creating new %s environment for task %s...r�  rþ  rD  r=  r  rœ  z5Terminal tool disabled: environment creation failed (r7  Údisabledz %s environment ready for task %s)Úget_current_session_key)r   Ú_HERMES_GATEWAYr  )Ú_MAX_REFERENCED_SCRIPT_BYTESÚ7contains_gateway_lifecycle_command_or_referenced_scriptÚ!contains_launchctl_submit_commandr¡   zÜBlocked: launchctl submit/bootstrap registers a persistent KeepAlive job and is unsafe from inside the gateway process. Use Hermes cron for one-shot delayed work, or install an explicit LaunchAgent from a separate shell.)rÃ   r1  r‹   rª   Úscript_pathr
   c                 óÚ  •— ‰€dS 	 t          | ¦  «                             ¦   «         }|                     ¦   «         st          ‰¦  «        |z  }|                     ¦   «         r||                     ¦   «         }t	          j        |j        ¦  «        rO|j        ‰k    rD|                     ¦   «         }t          |¦  «        ‰k    rd|v rdS | 
                    dd¬¦  «        S n# t          $ r Y nw xY w	 ‰                     d‰dz   › dt          j        | ¦  «        › �¦  «        }|                     d	d
¦  «        dk    r |                     dd¦  «        }|rd|v rdS |S n# t          $ r Y nw xY wdS )aT  Best-effort script read; uses env.execute only when local read fails.

                For local backends the script path is on the host filesystem. For
                SSH/Modal/Daytona the same path is remote; the local read misses, so we
                fall back to a bounded ``env.execute('head -c ... < path')`` read.
                Nó    ré   rê   rë   zhead -c r¡   z < rL  r2  r   rÇ   r   ú )r   rË  Úis_absoluter_   r`   ÚS_ISREGÚst_modera   Ú
read_bytesr¦   rû   re   ÚexecuteÚshlexÚquoterB   )	rý  Ú
local_pathÚmetadataÚdatarS   rÇ   rú  r¤  Ú	guard_cwds	         €€€r   Ú_read_script_in_envz*terminal_tool.<locals>._read_script_in_envó
  sÂ  ø€ ð �;Ø˜4ðÝ!% kÑ!2Ô!2×!=Ò!=Ñ!?Ô!?�JØ%×1Ò1Ñ3Ô3ð BÝ%)¨)¡_¤_°zÑ%A˜
Ø!×)Ò)Ñ+Ô+ð NØ#-§?¢?Ñ#4Ô#4˜Ýœ<¨Ô(8Ñ9Ô9ð N¸hÔ>NÐRnÒ>nÐ>nØ#-×#8Ò#8Ñ#:Ô#:˜DÝ" 4™yœyÐ,HÒHÐHØ#*¨d ? ?ð ,0¨4Ø'+§{¢{°7À9 {Ñ'MÔ'MÐ MøøÝ ð ð ð Ø�DðøøøðØ Ÿ[š[ð8Ð#?À!Ñ#Cð 8ð 8Ý"œ[¨Ñ5Ô5ð8ð 8ñô �Fð —z’z ,°Ñ3Ô3°qÒ8Ð8Ø!'§¢¨H°bÑ!9Ô!9˜Ø!ð ( f°Ð&6Ð&6ð $( 4Ø%˜ð 9øõ !ð ð ð Ø�Dðøøøà�ts1   ‡B>C ÃC Ã
C,Ã+C,Ã0A&E ÅE Å
E(Å'E()r”  Úread_remote_scripta  Blocked: command or referenced script cannot restart or stop the gateway from inside the gateway process. The gateway would kill this command before it could complete (SIGTERM propagates to child processes). Run `hermes gateway restart` from a separate shell outside the running gateway.z+Blocked dangerous workdir: %s (command: %s)r  Úblocked)Údetect_self_repo_git_mutation)rÃ   r1  r‹   z,Blocked self-repo git mutation (command: %s))r¶   Úapprovedrõ  Úpending_approvalrµ   Údescriptionzcommand flaggedÚpattern_keyÚsmart_deniedÚallow_permanent)
rÇ   r»  rE   rõ  Úapproval_pendingrµ   r  r  r  r  zCommand denied: z?. Use the approval prompt to allow it, or rephrase the command.rp  Úuser_approvedzflagged as dangerouszCommand required approval (z) and was approved by the user.Úsmart_approvedzCommand was flagged (z&) and auto-approved by smart approval.zÉPTY disabled for this command because it expects piped stdin/EOF (for example gh auth login --with-token). For local background processes, call process(action='close') after writing so it receives EOF.ru  r¤  )rµ   r”  r�  r‹   Úenv_varsÚuse_pty)r¤  rµ   r”  r�  r‹   zBackground process started)rÇ   rò  Úpidr»  rE   ry   Úpty_noteu  background=true without notify_on_complete=true means this process runs SILENTLY â€” you will not be told when it exits. If this is a bounded task (test suite, build, CI poller, deploy, anything with a defined end), you almost certainly wanted notify_on_complete=true so the system pings you on exit. Re-launch with notify_on_complete=true, or call process(action='poll') / process(action='wait') yourself to learn the outcome. Only ignore this hint for genuine long-lived processes that never exit (servers, watchers, daemons).Úhintz
gh pr viewzgh pr checksz jq z| jqz$(jqÚstatusCheckRollupuR  This looks like a homebrewed CI poller built from `gh pr view --json statusCheckRollup` and/or `gh pr checks | jq`. That shape has burned us repeatedly in hermes-agent dev work (PRs #31329, #31448, #31695, #31709, #31745, #32264, #33131) â€” stdout buffering kills output capture, jq null-key edge cases silently exit the loop, conclusion-vs-status field confusion exits early with bogus all-green verdicts, TTY-only summary banners never appear when piped. Use the canonical snippets in the green-ci-policy skill instead: the exit-code-driven `gh pr checks $PR >/dev/null` (rc 0 = green, 8 = pending, else fail) for exit-on-first-fail behavior, or the column-2 awk-on-tabs poller (`awk -F"\t" "$2==\"pending\""`) for sharded matrices. Load skill_view(name='github/hermes-agent-dev', file_path='references/green-ci-policy.md') for the verbatim snippets. If you must roll a custom loop with rich structured output, write each tick to a known file (`tee -a /tmp/ci.log`) and rely on `process(action='log')` to read THAT file â€” do not rely on background-process stdout capture for line-buffered shell loops.z

)Úasync_delivery_supportedr‚   ré  u\  notify_on_complete / watch_patterns are not available in this session â€” it cannot receive an async completion after the turn ends (a one-shot runner such as `hermes -z`, a cron job, a Kanban worker, or a stateless HTTP endpoint). The process is running in the background; retrieve its result with process(action='poll') or process(action='wait').Únotify_unsupportedzjbackground proc %s: async delivery unsupported on this session; notify_on_complete/watch_patterns disabledÚHERMES_SESSION_PLATFORMÚHERMES_SESSION_CHAT_IDÚHERMES_SESSION_THREAD_IDÚHERMES_SESSION_USER_IDÚHERMES_SESSION_USER_NAMEÚHERMES_SESSION_MESSAGE_ID)ré  rì  rê  zbackground proc %s: %sÚwatch_patterns_ignoredr•  )
rò  Úcheck_intervalr‹   rí   Úchat_idÚuser_idÚ	user_nameÚ	thread_idÚ
message_idré  rì  z$Failed to start background process: )rÇ   r»  rE   r    )Úclear_current_thread_interrupt)r  r”  Úbounded_captureé|   zCommand timed out after z secondsr¢   zfExecution error, retrying in %ds (attempt %d/%d) - Command: %s - Error: %s: %s - Task: %s, Backend: %szWExecution failed after %d retries - Command: %s - Error: %s: %s - Task: %s, Backend: %szCommand execution failed: rÐ  rÇ   rL  Úoutput_total_charsÚfull_output_pathri  uu   

âš ï¸� Sudo authentication failed â€” cached password cleared. You will be prompted again on the next sudo command.)Úinvoke_hookÚtransform_terminal_output)rµ   rÇ   rL  r�  rª   )Úget_max_bytesgš™™™™™Ù?z

... [OUTPUT TRUNCATED - z chars omitted out of z total] ...

)Ú
strip_ansi)Úredact_terminal_output)Úannotate_failureré   rê   )Úencodingrì   zCOutput exceeded the capture window (head+tail shown). Full output (Ú,z chars) saved to u]    â€” search it with search_files or page it with read_file instead of re-running the command.Útruncation_notez-spill redaction failed; dropping spill handlerX   )Úrecord_terminal_resultr   )rµ   r”  rò  r»  rÇ   Úkindr’   Úcanonical_command)rõ  r=  r’   r>  Úverification_evidencez&verification evidence recording failedé‚   z[Command interrupted]ú.z, then interrupted.Úexit_code_meaningÚsudo_auth_failedÚsudo_cache_clearedÚTERMINAL_DEGRADED_MODEÚwarnÚfailzterminal_tool exception:
%szFailed to execute command: )rÇ   r»  rE   Ú	tracebackrõ  zterminal backend degraded: %szdegraded-env eviction failedÚdegradedzTerminal backend degraded: )rÇ   r»  rõ  ÚreasonÚ
retry_hintrE   ){r¤   r   r%   r&   r  r  rÑ  Údumpsr3  r   rÃ  rB   rš  rÎ  r,  rã  rŒ  r   ÚFOREGROUND_MAX_TIMEOUTrè  r“  r¡  ry  rZ   rz  r„  r{  r‰   rŸ  ro   r?  rA  rs  r‹  r   Útools.approvalrø  r!   rÛ   Úcron.lifecycle_guardrú  rû  rü  rt   rñ  r   rÆ   r  Útools.self_repo_guardr  rJ   rº   r´   rÙ  r€  rv  Úspawn_localr†  r¤  Úspawn_via_envrˆ   r  r‡   r  r‚   Úwatcher_platformÚwatcher_chat_idÚwatcher_user_idÚwatcher_user_nameÚwatcher_thread_idÚwatcher_message_idrî  ré  Úwatcher_intervalÚpending_watchersrò   r�  rì  re   Útools.interruptr.  r  rÖ   r  rE   r˜  rÑ   rØ   rÝ   rw   r   Úhermes_cli.lifecycler3  Útools.tool_output_limitsr5  r¦   r‰  Útools.ansi_stripr6  r   r7  rC   rÔ  Útools.terminal_hintsr8  rj   Úrealpathr   Ú	read_textÚ
write_textrc   Úunlinkrb   Úagent.verification_evidencer<  Úrstriprq  r"   rH  Ú
format_excrJ  Ú_evict_environment_for_taskrK  )irµ   rê  r  r�  rò  r   rÃ   ró  ré  rì  r6   rª   r   rž  rB  r”  r¬   ÚremappedÚdefault_timeoutÚeffective_timeoutÚguidanceÚ_existing_keyÚneeds_creationr¢  rC  r|  rD  r£  rl   rø  r‹   rû  rü  Úguard_cwd_baser  Úworkdir_errorr  Ú_self_repo_hitÚ_self_repo_msgÚapproval_noteÚ_approved_runry   ÚdescÚfallback_msgÚpty_disabled_reasonÚeffective_ptyrv  Úeffective_cwdÚproc_sessionÚresult_dataÚ_ghÚ_has_jqÚ
_bad_shaper¡  Úcanonical_hintÚ	_async_okÚ_gseÚ_gw_platformÚ_gw_chat_idÚ_gw_thread_idÚ_gw_user_idÚ_gw_user_nameÚ_gw_message_idÚconflict_noteÚmax_retriesÚretry_countrS   Úcommand_cwdr.  Úexecute_kwargsrŠ  Ú	wait_timerÇ   rL  Úspill_total_charsÚspill_file_pathrC  rD  rm  r3  Úhook_resultsÚhook_resultr5  ÚMAX_OUTPUT_CHARSÚ
head_charsÚ
tail_charsÚomittedÚtruncated_noticer6  r7  Ú	exit_noteÚfailure_hintr8  Úresult_dictÚpost_cwdÚ_spÚ	raw_spillr<  ÚevidenceÚdegraded_moderH  Útb_strrú  r¤  r  si                                                                                                         @@@r   Úterminal_toolrŸ  Û	  sB  øøø€ ðVNÝ˜'¥3Ñ'Ô'ð 
	#Ý�NŠNØ=Ý�W‘”Ô&ñô ð õ ”:ØØØZÅ$ÀwÁ-Ä-ÔBXÐZÐZØ!ð	ð ð
 "ð#ñ #ô #ð #õ !Ñ"Ô"ˆØ˜*Ô%ˆõ 7°wÑ?Ô?Ðõ +¨7Ñ3Ô3ˆ	ð �xÒÐØ—M’M .Ñ1Ô1ÐK°V¸NÔ5KˆEˆEØ˜Ò&Ð&Ø—M’MÐ"5Ñ6Ô6ÐU¸&ÐATÔ:UˆEˆEØ˜Ò Ð Ø—M’M -Ñ0Ô0ÐI°F¸=Ô4IˆEˆEØ˜Ò"Ð"Ø—M’M /Ñ2Ô2ÐM°f¸_Ô6MˆEˆEàˆEà�mŠm˜EÑ"Ô"ÐO¥o°gÑ&>Ô&>ÐOÀ&ÈÄ-ˆõ *¨&°'Ñ:Ô:ˆð Õ*Ð*Ð*Õ/IÈ#Ñ/NÔ/NÐ*Ø'/ÐB�|�|°V¸E´]ˆHØ�hŠˆÝ—’ðBà˜ 8ñô ð ð
 ˆCØ  Ô+ˆð Ð 7¨a¢< <ÝØPÀWÐPÐPÐPñô ð ð $Ð6 Ðð ð 	˜gð 	¨'Õ4JÒ*JÐ*JÝðF gð Fð FÝ)ðFð Fð Fñô ð ð ð 	'Ý6°wÑ?Ô?ˆHØð 'Ý”zØ Ø!#Ø%Ø%ð	#ð #ð
 !&ð'ñ 'ô 'ð 'õ 	ÑÔÐð ˆÝð 	&ð 	&ð &7Õ:NÐ%NÐ%NÐ!Ð!Ø!(ÐV¨WÕ8LÐ-LÐ-L�g�gÐRVð ð Ð(Ý04´	±´•˜}Ñ-Ý*¨=Ô9�Ø!&��à!%�ð	&ð 	&ð 	&ñ 	&ô 	&ð 	&ð 	&ð 	&ð 	&ð 	&ð 	&øøøð 	&ð 	&ð 	&ð 	&ð" ñ =	eå%ð ?ð ?Ø$­OÐ;Ð;Ý9B¼Ñ9IÔ9I•OÐ$5Ñ6Ý+Ð,=Ô>�	ð?ð ?ð ?ñ ?ô ?ð ?ð ?ð ?ð ?ð ?ð ?øøøð ?ð ?ð ?ð ?ð
 ð 6eð 6eåð /ð /à->ÕBVÐ-VÐ-VÐ)Ð)Ø)0Ð^°WÕ@TÐ5TÐ5T˜g˜gÐZ^ð "ð %Ð0Ý8<¼	¹¼� }Ñ5Ý2°=ÔA˜Ø).˜ð/ð /ð /ñ /ô /ð /ð /ð /ð /ð /ð /øøøð /ð /ð /ð /ð "ñ *eØ =Ò0Ð0Ý1Ñ3Ô3Ð3Ý—K’KÐ LÈhÐXiÐjlÐklÐjlÔXmÑnÔnÐnð /ØHPÐTYÒHYÐHYÕ%<¸VÑ%DÔ%DÐ%DÐ_c˜
ð  (Õ+>Ð>Ð>õ :¸&ÑAÔAÐAØDHð )ð
 (,˜Ø# wÒ.Ð.à ,¨f¯jªjÐ9KÈUÑ.SÔ.Sð,˜Lõ #6Ø%-Ø"'Ø #Ø$5Ø'1Ø-=Ø)5Ø$5Ø%-ð
#ñ 
#ô 
#˜˜øõ 'ð /ð /ð /Ý#œzØ&(Ø)+Ý%@Ø \ÐXYÐ \Ð \Ð \ñ&ô &ð '1ð+ð +ð ).ð /ñ  /ô  /ð /ð /ð /ð /ð /ðS6eð 6eð 6eð 6eñ 6eô 6eð 6eð 6eøøøøðP/øøøõ #ð &ð &ØBIÕ,Ð->Ñ?Ý<@¼I¹K¼K�Ð'8Ñ9Ø%˜ð&ð &ð &ñ &ô &ð &ð &ð &ð &ð &ð &øøøð &ð &ð &ð &õ —K’KÐ BÀHÐN_Ð`bÐabÐ`bÔNcÑdÔdÐdðm6eð 6eð 6eñ 6eô 6eð 6eð 6eð 6eð 6eð 6eð 6eøøøð 6eð 6eð 6eð 6eðp ˆˆˆð 	;Ð:Ð:Ð:Ð:Ð:à-Ð-°bÐ9Ñ9Ô9ÐL¸g¸mÈˆõ Œ:�>Š>Ð+Ñ,Ô,°Ò3Ð3ðð ð ð ð ð ð ð ð ð ð
 1Ð0°Ñ9Ô9ð 'Ý”zØ Ø!"ðFð
 &ð
#ð 
#ð !&ð
'ñ 
'ô 
'ð 
'õ -¨[Ñ9Ô9ˆNØÐ%Ý!(¨¨e°TÑ!:Ô!:Ð!A¸c�Ý,ØØ*Ø'Ø!ð	ñ ô ˆIð5µð 5½Å#¼ð 5ð 5ð 5ð 5ð 5ð 5ð 5ð 5ðn GÐFØØØ#6ðñ ô ð 'õ
 ”zØ Ø!"ðFð &ð#ð #ð !&ð'ñ 'ô 'ð 'ð ð 
	'Ý-¨gÑ6Ô6ˆMØð 'Ý—’ÐLØ& t¨ tœ}Õ.CÀGÑ.LÔ.LñNô Nð Nå”zØ Ø!#Ø*Ø'ð	#ð #ð
 !&ð'ñ 'ô 'ð 'ð �wÒÐØKÐKÐKÐKÐKÐKå,ØØØ'ðñ ô ˆIð
 .KÐ-JØ˜ñ.ô .Ñ*ˆN˜Nð ð 
'Ý—’ØBÝ)¨'Ñ2Ô2ñô ð õ ”zØ Ø!"Ø+Ø'ð	#ð #ð
 !&ð'ñ 'ô 'ð 'ð ˆõ
 ˜U™œˆØñ '	eÝ(Ø˜Ý 7¸Ñ ?Ô ?ðñ ô ˆHð ˜JÔ'ð 'à—<’< Ñ)Ô)Ð-?Ò?Ð?Ýœ:Ø"$Ø%'Ø!#Ø"4Ø,0Ø#+§<¢<°	¸7Ñ#CÔ#CØ'/§|¢|°MÐCTÑ'UÔ'UØ'/§|¢|°MÀ2Ñ'FÔ'FØ(0¯ª°^ÀUÑ(KÔ(KØ+3¯<ª<Ð8IÈ4Ñ+PÔ+Pð'ð 'ð %*ð+ñ +ô +ð +ð  —|’| MÐ3DÑEÔE�ðT tð Tð Tð Tð õ ”zØ Ø!#Ø%Ÿ\š\¨)°\ÑBÔBØ'ð	#ð #ð
 !&ð'ñ 'ô 'ð 'ð �|Š|˜OÑ,Ô,ð eØ—|’| MÐ3IÑJÔJ�Ø c¸dÐ cÐ cÐ c�Ø $��Ø—’Ð.Ñ/Ô/ð eØ—|’| MÐ3IÑJÔJ�Ø d¸Ð dÐ dÐ d�ð #ÐØˆØð 	Õ/°Ñ8Ô8ð 	Ø!ˆMðð  ð ñ 	?ð @Ð?Ð?Ð?Ð?Ð?å0ØØØ'Ø!ð	ñ ô ˆMðm'Ø˜wÒ&Ð&Ø#3×#?Ò#?Ø 'Ø)Ø 1Ø$/Ý,3°C¸Ñ,?Ô,?Ð!I ¤ ÀTØ -ð $@ñ $ô $�L�Lð $4×#AÒ#AØØ 'Ø)Ø 1Ø$/ð $Bñ $ô $�Lð ;Ø".¤/Ø'Ô+Ø!"Ø!ðð �ð !ð <Ø.;�K 
Ñ+Ø&ð BØ.A�K 
Ñ+ð ð Ð&8ð Àð ð	Hð   Ñ'ðT ð 0 'ð 0Ø'¨7Ð2ÐO°nÈÐ6O�Cà 'Ð)ÐS¨V°wÐ->ÐSÀ&ÈGÐBSð ð ,¨wÐ6ð -ð
  ˜O Gð ð "ð  Ø#.§?¢?°6¸2Ñ#>Ô#>˜ð=ð 'ð8 CKð 0˜H vÑ-°Ñ>Ð>Ø!/ð $ FÑ+ð ð )MÐ#5ð )M¸ð )Mðð ð ð ð ð ð ð ð %˜9™;œ;ð MØ-2Ð*Ø)-˜Ø<A˜Ð$8Ñ9ðPð $Ð$8Ñ9õ ŸšðRà(œOñô ð ð ð (, tÐ,EÀrÑ'JÔ'J˜Ø'ð MØ*.¨$Ð/GÈÑ*LÔ*L˜KØ,0¨DÐ1KÈRÑ,PÔ,P˜MØ*.¨$Ð/GÈÑ*LÔ*L˜KØ,0¨DÐ1KÈRÑ,PÔ,P˜MØ-1¨TÐ2MÈrÑ-RÔ-R˜NØ<H˜LÔ9Ø;F˜LÔ8Ø;F˜LÔ8Ø=J˜LÔ:Ø=J˜LÔ:Ø>L˜LÔ;õ 1TÝ'+Ð,>Ñ'?Ô'?Ø#1Ý# JÑ/Ô/ð1ñ 1ô 1Ñ-� ð
 !ð JÝ—N’NÐ#;¸\¼_ÈmÑ\Ô\Ð\Ø<I�KÐ 8Ñ9ð &ð ¨*ð Ø6:�LÔ3Ø8<�KÐ 4Ñ5ð
 $Ô4ð Ø89˜Ô5Ø(Ô9×@Ò@Ø*6¬/Ø./Ø+6Ø(4Ô(EØ'3Ô'CØ'3Ô'CØ)5Ô)GØ)5Ô)GØ*6Ô*IØ26ðBð Bñ ô ð ð "ð P jð PÝ26°~Ñ2FÔ2F�LÔ/Ø4@Ô4O�KÐ 0Ñ1å”z +¸EÐBÑBÔBÐBøÝð 'ð 'ð 'Ý”zØ Ø!#Ý8ØB¸qÐBÐBñô ð#ð #ð !&ð'ñ 'ô 'ð 'ð 'ð 'ð 'ð 'ð 'øøøøð'øøøð ˆKØˆKØˆFØˆKð ð 1ØJÐJÐJÐJÐJÐJØ.Ð.Ñ0Ô0Ð0à Ò,Ñ,ð,+Ý"6Ø 'Ø$'Ø$/Ø!)ð	#ñ #ô #�Kð $5Ø*ð ,0ð	&ð 	&�Nð )˜Sœ[¨ÐCÐC°NÐCÐC�F‘FøÝ ð +ñ +ð +Ý # A¡¤§¢¡¤�IØ  IÐ-Ð-Ý#œzØ&(Ø),Ø%[Ð@QÐ%[Ð%[Ð%[ð+ð +ð ).ð	 /ñ  /ô  /ð /ð /ð /ð /ð /ð /ð # [Ò0Ð0Ø# qÑ(˜Ø$%¨Ñ$4˜	ÝŸšð  (PØ'0°+¸{ÕLaÐbiÑLjÔLjÕlpÐqrÑlsÔlsÔl|Ð~ð  BSð  U]ñ^ô ^ð ^åœ
 9Ñ-Ô-Ð-Ø ˜˜˜˜å—L’LÐ!zØ!,Õ.CÀGÑ.LÔ.LÍdÐSTÉgÌgÔN^Ð`aÐctÐv~ñ@ô @ð @åœ:Ø"$Ø%'Ý!<ØP½¸a¹¼Ô9IÐPÐPÈQÐPÐPñ"ô "ð'ð 'ð %*ð+ñ +ô +ð +ð +ð +ð +ð +ð +øøøøð)+øøøð: ð ð KÝ" ;µ¸¸UÀDÑ0IÔ0IÑJÔJÐJð —Z’Z ¨"Ñ-Ô-ˆFØŸš L°!Ñ4Ô4ˆJð !'§
¢
Ð+?Ñ @Ô @ÐØ$ŸjšjÐ);Ñ<Ô<ˆOõ *¨&°(Ñ;Ô;ˆFå;¸FÑCÔCÐÝ!HØ˜ñ"ô "Ðð "ð Ý+FÑ+HÔ+HÐPTÐ+TÐ(Ø+ð ­Ð?SÑ/TÔ/Tð Øð#ñ�FðØ<Ð<Ð<Ð<Ð<Ð<Ø*˜{Ø/Ø#Ø!Ø)Ø-Ð3°Ø%ð ñ  ô  �ð $0ð ð �KÝ! +­sÑ3Ô3ð Ø!,˜Ø˜ðøøõ ð ð ð Ø�ðøøøð ?Ð>Ð>Ð>Ð>Ð>Ø,˜}™œÐÝ�6‰{Œ{Ð-Ò-Ð-Ý Ð!1°CÑ!7Ñ8Ô8�
Ø-°
Ñ:�
Ý˜f™+œ+¨
Ñ2°ZÑ?�ð;°7ð ;ð ;Ý! &™kœkð;ð ;ð ;ð !ð     Ô,Ð/?Ñ?À&È*ÈÈÈÔBVÑV�ð 4Ð3Ð3Ð3Ð3Ð3Ø�Z Ñ'Ô'ˆFð <Ð;Ð;Ð;Ð;Ð;ØHNÐVÐ+Ð+¨F¯LªL©N¬N¸GÑDÔDÐDÐTVˆFõ -¨W°jÑAÔAˆIð  ˆLØ˜QŠˆ yˆð(ØEÐEÐEÐEÐEÐEØ#3Ð#3°G¸ZÈÑ#PÔ#P�L�LøÝ ð (ð (ð (Ø#'�L�L�Lð(øøøð !Ø'Øðð ˆKðÝ" 3¨¨tÑ4Ô4�Øð 7 ð 7µ´×0@Ò0@ÅÀXÁÄÑ0OÔ0OÕSUÔSZ×ScÒScÕdgÐhsÑdtÔdtÑSuÔSuÒ0uÐ0uÝ),¨X©¬�K Ñ&øøÝð ð ð Ø�ðøøøð ð ðÝ˜Ñ/Ô/�CØ #§¢°wÀy Ñ QÔ Q�IØ—N’NØ.Ð.¨z¨z¸)Ñ/DÔ/DÀgÑNÔNØ!(°ð #ñ ô ð ð 9J�KÐ 4Ñ5Ø6E�KÐ 2Ñ3ðLØ(9ÐNðLð Là*ðLð Lð Lð  Ð 1Ñ2Ð2øõ !ð ð ð Ý—L’LÐ!PÐ[_�LÑ`Ô`Ð`ðÝ˜_Ñ-Ô-×4Ò4Ñ6Ô6Ð6Ð6øÝ"ð ð ð Ø˜ðøøøøøð	øøøðVØNÐNÐNÐNÐNÐNà1Ð1Ø#Ø#Ø)ÐV¨WÐVÐ8IÐVÈYØ(Ø!ðñ ô �ð ð à"*§,¢,¨xÑ"8Ô"8Ø (§¢¨VÑ 4Ô 4Ø!)§¢¨gÑ!6Ô!6Ø-5¯\ª\Ð:MÑ-NÔ-Nð	<ð <�KÐ 7Ñ8øøõ ð Vð Vð VÝ—’ÐEÐPT�ÑUÔUÐUÐUÐUðVøøøàð <ð  Ò$Ð$Ð)@ÀFÐ)JÐ)Jð
 /<×.BÒ.BÀ3Ñ.GÔ.GÐJ_Ñ._�K 
Ñ+Ð+à.;�K 
Ñ+Øð =Ø3<�Ð/Ñ0Øð 3Ø&2�˜FÑ#Øð 7Ø26�Ð.Ñ/Ø!ð 9Ø48�Ð0Ñ1å”:˜k¸Ð>Ñ>Ô>Ð>øå%ð %ñ %ð %õ œ	Ð":¸FÑCÔC×IÒIÑKÔK×QÒQÑSÔSˆØ˜FÒ"Ð"ØÐÐÐØ×)Ò)Ñ+Ô+ˆFÝ�LŠLÐ7¸Ñ@Ô@Ð@õ ”:ØØÝ4Ð5VÐSTÐ5VÐ5VÑWÔWÝ8¸Ñ@Ô@Ø!ðð ð "ð#ñ #ô #ð #ð #ð #ð #ð #ð #õ 	�ŠÐ6¸¼ÑAÔAÐAð	HÝ'¨Ñ0Ô0Ð0Ð0øÝð 	Hð 	Hð 	HÝ�LŠLÐ7À$ˆLÑGÔGÐGÐGÐGð	HøøøåŒzØØØ Ø”hØœ,Ø=°1´8Ð=Ð=ð
ð 
ð ðñ ô ð 	ð 	ð 	ð 	ð 	ð 	øøøøõ ð ð ð ØÐÐÐØ×%Ò%Ñ'Ô'ˆÝ�ŠÐ3°VÑ<Ô<Ð<õ ŒzØØÝ0Ð1RÈqÐ1RÐ1RÑSÔSÝ4°VÑ<Ô<Øð
ð 
ð ðñ ô ð 	ð 	ð 	ð 	ð 	ð 	øøøøðøøøsO  …A1AD( Á7E-AD( Ç%-AD( È-AD( ÉAD( ÉA
J.Ê"AD( Ê.J2Ê2AD( Ê5J2Ê6AD( Ë2LË5AD( ÌLÌAD( ÌLÌ	AD( ÌSÌAM)ÍSÍ)M-	Í-SÍ0M-	Í1>SÎ0A)PÐSÐ
Q&Ð$+Q!ÑQ&ÑSÑAD( Ñ!Q&Ñ&
SÑ0(R$ÒSÒ$R(	Ò(SÒ+R(	Ò,'SÓAD( ÓS#Ó#AD( Ó&S#Ó'A/AD( ÕB AD( ×AAD( Ø7A1AD( Ú)CAD( ÞA
AD( ßBAD( á(I6k ë
lë))lìlìAD( ìlì$AD( í'm+ í)AD( í+r0í6Ar+î8r0î9AD( î>A%r+ð#AD( ð(A=r+ò%r0ò&AD( ò+r0ò0CAD( ö7v; ö:AD( ö;
w÷AD( ÷w÷CAD( úz1 ú0AD( ú1{ ú=AD( ú?{ û 	AD( û
B} ýAD( ý
}ýAD( ý}ýAD( ýA( ÿAD( ÿ&A@$ÿ/!A@Á@A@$Á@
A@Á@A@$Á@A@Á@A@$Á@!AD( Á@#A@$Á@$AD( Á@(A4AB ÁBAD( ÁB&ACÁCAD( ÁCACÁCA!AD( ÁD(AK7ÁD3B*AI4ÁGAK7ÁG# AI4ÁHAHÁHAI4ÁH&AH=ÁH:AI4ÁH<AH=ÁH=1AI4ÁI.AK7ÁI4AK7ÁJA+AK2ÁK,AK7ÁK2AK7c                 óÈ  — t          | ¦  «        h}| r|                     | ¦  «         g }t          5  |D ]O}t                               |d¦  «        }t
                               |d¦  «         |�|                     |¦  «         ŒP	 ddd¦  «         n# 1 swxY w Y   |D ]C}	 |                     ¦   «          Œ# t          $ r t           
                    dd¬¦  «         Y Œ@w xY wdS )a  Drop any cached environment for *task_id* (and its collapsed key).

    Used when a backend reports an infrastructure failure: keeping the dead
    env cached would make every subsequent call fail against a stale
    connection, defeating automatic recovery.
    Nz&cleanup of degraded environment failedTrX   )r   r±  r¡  ry  r–   rz  rò   ry  re   r%   rc   )r�  r¾  Úevictedr—  r¤  s        r   rg  rg  ×  sU  € õ ' wÑ/Ô/Ð0€DØð Ø�Š�ÑÔÐØ€GÝ	ð $ð $Øð 	$ð 	$ˆCÝ&×*Ò*¨3°Ñ5Ô5ˆCÝ×Ò˜s DÑ)Ô)Ð)ØˆØ—’˜sÑ#Ô#Ð#øð		$ð$ð $ð $ñ $ô $ð $ð $ð $ð $ð $ð $øøøð $ð $ð $ð $ð ð Rð Rˆð	RØ�KŠK‰MŒMˆMˆMøÝð 	Rð 	Rð 	RÝ�LŠLÐAÈDˆLÑQÔQÐQÐQÐQð	RøøøðRð Rs$   ±ABÂBÂBÂ!B6Â6&CÃCc                  ól  — 	 t          ¦   «         } | d         }|dk    rdS |dk    r]ddlm}  |¦   «         }|st                               d¦  «         dS t          j        |d	gdd
t
          j        ¬¦  «        }|j        dk    S |dk    r[t          j
        d¦  «        pt          j
        d¦  «        }|r/t          j        |dgdd
t
          j        ¬¦  «        }|j        dk    S dS |dk    rH|                      d¦  «        r|                      d¦  «        st                               d¦  «         dS dS |dk    �rwt          |                      d¦  «        ¦  «        }|d         dk    rdS |d         dk    rþ|d         r*t                               dt          d¦  «        ¦  «         dS |d         dk    r*t                               dt          d¦  «        ¦  «         dS |d         dk    rEt          ¦   «         rt                               d¦  «         nt                               d¦  «         dS t          ¦   «         rt                               d¦  «         nt                               d ¦  «         dS t          j                             d¦  «        €t                               d"¦  «         dS dS |d#k    rt%          | ¦  «        S |d$k    rdd%lm} dd&lm}  |d'¦  «        d!uS t                               d(|¦  «         dS # t.          $ r(}	t                               d)|	d¬*¦  «         Y d!}	~	dS d!}	~	ww xY w)+z8Check if all requirements for the terminal tool are met.rª   rD  Tr«   r   )Úfind_dockerz?Docker executable not found in PATH or common install locationsFÚversionr•  )Úcapture_outputr  rF  rÛ  Ú	apptainerz	--versionrþ  r  r  z„SSH backend selected but TERMINAL_SSH_HOST and TERMINAL_SSH_USER are not both set. Configure both or switch TERMINAL_ENV to 'local'.rÙ  r  rR  rS  rU  rV  zîModal backend selected with TERMINAL_MODAL_MODE=managed, but Nous Tool Gateway access is not currently available and no direct Modal credentials/config were found. %s Choose TERMINAL_MODAL_MODE=direct/auto to use direct Modal credentials.rW  rX  zhModal backend selected with TERMINAL_MODAL_MODE=managed, but the managed tool gateway is unavailable. %sz¦Modal backend selected with TERMINAL_MODAL_MODE=direct, but no direct Modal credentials/config were found. Configure Modal or choose TERMINAL_MODAL_MODE=managed/auto.zžModal backend selected with TERMINAL_MODAL_MODE=direct, but no direct Modal credentials/config were found. Configure Modal or choose TERMINAL_MODAL_MODE=auto.z±Modal backend selected but no direct Modal credentials/config or managed tool gateway was found. Configure Modal, set up the managed gateway, or choose a different TERMINAL_ENV.z|Modal backend selected but no direct Modal credentials/config was found. Configure Modal or choose a different TERMINAL_ENV.NzFmodal is required for direct modal terminal backend: pip install modalrÜ  rÚ  )ÚDaytonar<   ÚDAYTONA_API_KEYzgUnknown TERMINAL_ENV '%s'. Use one of: local, docker, singularity, modal, daytona, vercel_sandbox, ssh.z&Terminal requirements check failed: %srX   )r3  rŠ  r£  r%   rE   rI  rJ  rK  rL  r¬  ÚwhichrB   r7  r   r   rF   rG   rH   rQ   rÚ  r§  rI   r=   re   )
r6   rª   r£  r«   rS   Ú
executablero  r§  r=   rl   s
             r   Úcheck_terminal_requirementsr«  ï  së  € ðmÝ Ñ"Ô"ˆØ˜*Ô%ˆà�wÒÐØ�4à˜Ò!Ð!Ø=Ð=Ð=Ð=Ð=Ð=Ø �[‘]”]ˆFØð Ý—’Ð^Ñ_Ô_Ð_Ø�uÝ”^ V¨YÐ$7ÈÐVWÕ_iÔ_qÐrÑrÔrˆFØÔ$¨Ò)Ð)à˜Ò&Ð&Ýœ kÑ2Ô2ÐQµf´lÀ=Ñ6QÔ6QˆJØð .Ý#œ¨°[Ð(AÐRVÐ`aÕisÔi{Ð|Ñ|Ô|�ØÔ(¨AÒ-Ð-Ø�5à˜ÒÐØ—:’:˜jÑ)Ô)ð °·²¸JÑ1GÔ1Gð Ý—’ðZñô ð ð �uØ�4à˜Ò Ñ Ý2°6·:²:¸lÑ3KÔ3KÑLÔLˆKØÐ-Ô.°)Ò;Ð;Ø�tàÐ-Ô.°(Ò:Ð:ØÐ5Ô6ð 
!Ý—L’Lð[õ >Ø5ñô ñô ð ð !˜5Ø˜vÔ&¨)Ò3Ð3Ý—L’Lð:å=Ø5ñô ñô ð ð !˜5Ø  Ô(¨HÒ4Ð4Ý1Ñ3Ô3ð ÝŸšð@ñô ð ð õ Ÿšð8ñô ð ð
 !˜5å1Ñ3Ô3ð 
ÝŸšðBñô ð ð õ ŸšðRñô ð ð !˜5åŒ~×'Ò'¨Ñ0Ô0Ð8Ý—’ÐeÑfÔfÐfØ�uà�4àÐ)Ò)Ð)Ý5°fÑ=Ô=Ð=à˜Ò"Ð"Ø'Ð'Ð'Ð'Ð'Ð'Ø5Ð5Ð5Ð5Ð5Ð5Ø�:Ð/Ñ0Ô0¸Ð<Ð<õ �LŠLð7àñô ð ð
 �5øÝð ð ð Ý�ŠÐ=¸qÈ4ˆÑPÔPÐPØˆuˆuˆuˆuˆuøøøøðøøøsh   ‚L  2L Á.L ÂAL Ã$A
L Ä25L Å)<L Æ'4L ÇAL È.AL É39L Ê0L ËL Ë$L Ì
L3ÌL.Ì.L3Ú__main__zTerminal Tool Modulez2==================================================z
Current Configuration:z  Environment type: z  Docker image: rº  z  Modal image: r¹  z  Working directory: z  Default timeout: Úsz  Lifetime: u;   
â�Œ Requirements not met. Please check the messages above.r¡   u   
âœ… All requirements met!z
Available Tool:z=  - terminal_tool: Execute commands in sandboxed environmentsz
Usage Examples:z  # Execute a commandz*  result = terminal_tool(command='ls -la')z  z  # Run a background taskzE  result = terminal_tool(command='python server.py', background=True)z
Environment Variables:rï  z  TERMINAL_ENV: rC  rD  z< (local/docker/singularity/modal/daytona/vercel_sandbox/ssh)z  TERMINAL_DOCKER_IMAGE: r  z  TERMINAL_SINGULARITY_IMAGE: r  r  z  TERMINAL_MODAL_IMAGE: r  z  TERMINAL_DAYTONA_IMAGE: r	  z  TERMINAL_CWD: rÕ  rÊ   z  TERMINAL_SANDBOX_DIR: ÚTERMINAL_SANDBOX_DIRz
/sandboxesz  TERMINAL_TIMEOUT: r  Ú60z  TERMINAL_LIFETIME_SECONDS: r  r€  )Úregistryrç  ÚobjectÚstringz The command to execute on the VM)r  r  Úbooleanu0  Run in the background, returning a session_id. Pair with notify_on_complete=true for anything with a defined end (tests, builds, deploys) â€” without it the process runs silently. Only servers/watchers/daemons that never exit should stay silent. Short commands: prefer foreground with a generous timeout.)r  r  r   z3Max seconds to wait (default: 180, foreground max: u   ). Returns INSTANTLY when command finishes â€” set high for long tasks, you won't wait unnecessarily. Foreground timeout above z7s is rejected; use background=true for longer commands.)r  r  Úminimumz^Working directory for this command (absolute path). Defaults to the session working directory.zœRun in pseudo-terminal (PTY) mode for interactive CLI tools like Codex, Claude Code, or Python REPL. Only works with local and SSH backends. Default: false.uñ   With background=true: get exactly one notification when the process exits. The right choice for nearly every bounded long task â€” set it and keep working. MUTUALLY EXCLUSIVE with watch_patterns (watch_patterns is dropped when both are set).Úarrayr  u×  Strings to watch for in background output. ONLY for rare one-shot mid-process signals on processes that never exit (e.g. ['Application startup complete'] on a server). NOT for end-of-run markers (use notify_on_complete) and NOT for per-iteration patterns like 'ERROR' in loops â€” rate-limited to 1 notification/15s; repeated over-firing auto-disables it and falls back to notify-on-exit. When in doubt, use notify_on_complete. MUTUALLY EXCLUSIVE with notify_on_complete.)r  rƒ  r  )rµ   rê  r  rÃ   ró  ré  rì  )r  Ú
propertiesÚrequired)r   r  re  c                 óŽ  — t          |                      d¦  «        |                      dd¦  «        |                      d¦  «        |                     d¦  «        |                     d¦  «        |                      d¦  «        |                      dd¦  «        |                      d	d¦  «        |                      d
¦  «        ¬¦	  «	        S )Nrµ   rê  Fr  r�  rò  rÃ   ró  ré  rì  )	rµ   rê  r  r�  rò  rÃ   ró  ré  rì  )rŸ  rB   )ÚargsÚkws     r   Ú_handle_terminalr»  Â  s¨   € ÝØ—’˜Ñ#Ô#Ø—8’8˜L¨%Ñ0Ô0Ø—’˜Ñ#Ô#Ø—’�yÑ!Ô!Ø—6’6˜,Ñ'Ô'Ø—’˜Ñ#Ô#Ø�HŠH�U˜EÑ"Ô"ØŸ8š8Ð$8¸%Ñ@Ô@Ø—x’xÐ 0Ñ1Ô1ð
ñ 
ô 
ð 
r   u   ðŸ’»i † )r   ÚtoolsetÚschemaÚhandlerÚcheck_fnÚemojiÚmax_result_size_chars)r
   N)F)rÞ   )r  )NNNr   N)r�  r3   )	FNNNFNFFN)ÅÚ__doc__Úimportlib.utilrF   rÑ  Úloggingr!   rí   r$  r  r`   rZ   r‰   Úatexitr¬  rI  Úpathlibr   Útypingr   r   r   r   Úutilsr   Ú	getLoggerr  r%   r   r   r[  r   r   Útools.registryr   Útools.environments.singularityr   Útools.tool_backend_helpersr   r   r   r   r   r*   r‰  rM  r)  rd   r+  r4   rJ   r5   rë  rQ   rT   Ú__annotations__r\   ro   rp   rŸ  r‘   rD  ru   rw   rz   r~   r€   r�   r“   r—   rš   rN  r›   r¹   r¨   r´   rº   Ú	frozensetrÁ   rÂ   rÆ   rÑ   r×   rØ   rÝ   r  r  r'  Útupler/  r?  rÜ   rO  rf  rp  Útools.environments.baserq  Útools.environments.localrr  r\  rs  r`  Útools.environments.sshrt  rj  rŠ  ru  r]  Útools.environments.modalrv  rg  Ú tools.environments.managed_modalrw  rf  Útools.managed_tool_gatewayrx  r  ÚTERMINAL_TOOL_DESCRIPTIONry  rz  r¡  r{  r„  r‘  r�  r‡  rˆ  r‘  r’  r“  r–  r˜  rš  rœ  r¥  rª  r¨  r§  r®  r³  r¸  r¿  rÀ  r   rÃ  rÎ  rÓ  rØ  rá  r,  rã  ré  r·  r3  r±  r7  r?  rA  rs  r‹  r�  r“  r—  rš  r¥  r¨  r°  r«  rº  ÚregisterrÔ  rÙ  ÚcompileÚ
IGNORECASEÚ	MULTILINErá  rã  rä  rÜ  rå  rß  rè  rî  rñ  rŸ  rg  r«  r  r6   ÚexitÚdefault_imgr"   rÌ   rË   rÐ   r°  ÚTERMINAL_SCHEMAr»  rv   r   r   ú<module>rÞ     sÿ  ðð ð  ð  ðD Ð Ð Ð Ø €€€Ø €€€Ø 	€	€	€	Ø €€€Ø 	€	€	€	Ø €€€Ø €€€Ø €€€Ø Ð Ð Ð Ø €€€Ø €€€Ø Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,à !Ð !Ð !Ð !Ð !Ð !à	ˆÔ	˜8Ñ	$Ô	$€ðR sð R¨sð Rð Rð Rð Rð =Ð <Ð <Ð <Ð <Ð <Ð <Ð <Ø %Ð %Ð %Ð %Ð %Ð %ð <Ð ;Ð ;Ð ;Ð ;Ð ;ðð ð ð ð ð ð ð ð ð ð ð ð ð ðØ
ðàðð ð	ð ð ð ð8 0Ð/Ø%ØØØñ	ô Ð ð #9Ð"8ØØ	Ø	Øñ	#ô #Ð ð 0Ð Ø?Ð ð@¨#ð @°$ð @ð @ð @ð @ð7¨t°C¸°H¬~ð 7À$ð 7ð 7ð 7ð 7ðx ),°uÐ=Ð=Ð �4Ð =Ð =Ñ =ØÐ ð&ð &ð &ð^ (*Ð �d˜3 ˜8”nÐ )Ð )Ñ )Ø*˜IœNÑ,Ô,Ð ð  �	”Ñ!Ô!€ð9ð 9ð 9ð4ð 4ð 4ð%ð %ð %ð ð  ð  ð-¨ð -ð -ð -ð -ð,3 3ð 3ð 3ð 3ð 3ð2¨ð 2°ð 2ð 2ð 2ð 2ð%ð %ð %ð %ðð ð ð ð ð ð
	¨sð 	°tð 	ð 	ð 	ð 	ð_ D¨¨c¨¤Nð _°tð _ð _ð _ð _ð /4ðCð C˜sð C¨cð CØ'+ðCØ8<ðCð Cð Cð Cð  &˜I oÑ6Ô6Ð ð;˜cð ; dð ;ð ;ð ;ð ;ð˜sð  s¨T¡zð ð ð ð ð& ð °ð ¸ð ð ð ð ð6 Ð ðM¨ð M°ð Mð Mð Mð MðØ�4‰ZðØ!$ðà	ðð ð ð ñ(z3ð z3¨sð z3¸Cð z3ð z3ð z3ð z3ñx	-ð 	- 3ð 	-¨sð 	-¸Sð 	-ð 	-ð 	-ð 	-ð= cð =¨dð =ð =ð =ð =ð!˜sð !¨3ð !°5¸¸c¸´?ð !ð !ð !ð !ðH=$¨Cð =$°E¸#¸s¸(´Oð =$ð =$ð =$ð =$ð@5¨#ð 5°#ð 5ð 5ð 5ð 5ðp˜dð ð ð ð ð4b¨#ð b°#ð bð bð bð bðJU S¨4¡Zð U°E¸#À¹*ÀcÈDÁjÐ:PÔ4Qð Uð Uð Uð Uðr ?Ð >Ð >Ð >Ð >Ð >Ø JÐ JÐ JÐ JÐ JÐ JØ \Ð \Ð \Ð \Ð \Ð \Ø DÐ DÐ DÐ DÐ DÐ DØ MÐ MÐ MÐ MÐ MÐ MØ JÐ JÐ JÐ JÐ JÐ JØ `Ð `Ð `Ð `Ð `Ð `Ø DÐ DÐ DÐ DÐ DÐ DØ 
€
€
€
ð	Ð ð (*Ð �d˜3 ˜8”nÐ )Ð )Ñ )Ø#%€��S˜%�ZÔ Ð %Ð %Ñ %ØˆIŒNÑÔ€	Ø-/€��c˜9œ>Ð)Ô*Ð /Ð /Ñ /Ø%�y”~Ñ'Ô'Ð Ø€ØÐ ð
 "Ð Ø+˜Yœ^Ñ-Ô-Ð ð>;°°c¸3°h´ð >;ÀDð >;ð >;ð >;ð >;ðR 24Ð �T˜#˜t C¨ Hœ~Ð-Ô.Ð 3Ð 3Ñ 3ð   "€ˆd�3˜�8ŒnÐ !Ð !Ñ !Ø"�I”NÑ$Ô$Ð ð$ H¨S¤Mð $¸À¼ð $È$ð $ð $ð $ð $ð"	% ¨#¤ð 	%°8¸C´=ð 	%ð 	%ð 	%ð 	%ð, 3ð ,¨4ð ,ð ,ð ,ð ,ð%¨ð %¸¸cÀ3¸h¼ð %ð %ð %ð %ðP	. cð 	.ð 	.ð 	.ð 	.ð$ &(Ð �D˜˜c˜”NÐ 'Ð 'Ñ 'Ø&˜	œÑ(Ô(Ð ð
M¨Cð 
MÀÈ#Äð 
MÐSWð 
Mð 
Mð 
Mð 
Mð cð ¨cð ð ð ð ðb¨4ð bð bð bð bð  %˜9ð &ð &ð &ñ ô Ð ð	U h¨s¤mð 	U¸ð 	Uð 	Uð 	Uð 	Uð#¨°¬ð #¸#ð #ð #ð #ð #ðL H¨S¤Mð °d¸3À¸8´nð ð ð ð ð() 4¨¨S¨¤>ð )¸HÀS¼Mð )ÈhÐWZÌmð )ð )ð )ð )ð\ >AÐT]ð 
ð 
˜ð 
 sð 
°sð 
Ècð 
ð 
ð 
ð 
ð D�cð Dð Dð Dð Dð$ :Ð à�iÐ _Ð _Ð _Ñ`Ô`Ð ð Cð ¨Dð ð ð ð ð2 %*Ð !ð,Vð ,Vð ,Vð ,Vð^B˜˜c 3˜hœð Bð Bð Bð BðJ¨°$©ð ¸4ÀÀSÀ¼>ð ð ð ð ð D¨¨c¨¤Nð °tð ð ð ð ð ¨$¨s°C¨x¬.ð ¸Tð ð ð ð ð6 KOØ-1Ø'0Ø26ñ	}
ð }
 #ð }
¨cð }
¸ð }
Àcð }
Ø$(ð}
ØCGð}
à&*ð}
ð "%ð}
ð #+¨3¤-ð	}
ð }
ð }
ð }
ñ@;\ð ;\¨Sð ;\ð ;\ð ;\ð ;\ð|ð ð ð$ð $ð $ðð ð ðU˜Cð Uð Uð Uð UñQð Q˜X cœ]ð Qð Qð Qð Qðh4˜sð 4 tð 4ð 4ð 4ð 4ð4ð ð ð6 6;ð AXð AXð AX˜ð AX¨dð AXð AXð AXð AXðHGð Gð Gð0 €„�Ñ  Ô  Ð  ð= #ð =°#ð =¸#À¹*ð =ð =ð =ð =ð@¨#ð °$ð ð ð ð ð (˜RœZØDÀbÄmÐVXÔVbÑFbñô Ð ð '˜BœJ xÑ0Ô0Ð Ø(˜bœjÐ);Ñ<Ô<Ð ð˜3ð  3ð ð ð ð ð" €B„JÐRÐTVÔTaÑbÔbØ€B„JÐ+¨R¬]Ñ;Ô;Ø€B„JÐ  "¤-Ñ0Ô0Ø€B„JÐ  "¤-Ñ0Ô0Ø€B„Jˆ~˜rœ}Ñ-Ô-Ø€B„Jˆ~˜rœ}Ñ-Ô-Ø€B„Jˆ ¤Ñ.Ô.Ø€B„JÐ6¸¼ÑFÔFð	#Ð ð°ð ¸ð ð ð ð ð$¨Sð $°S¸4±Zð $ð $ð $ð $ðNàðð ð	ð
 ðð ð ð ð> "&Ø"ð%#ð %#ð %#à�cŒ]ð%#ð ð%#ð ˜#”ð	%#ð
 �sŒmð%#ð 	ð%#ð %#ð %#ð %#ðT Ø!Ø!Ø $ØØ!ØØ$Ø*.ñyð yØðyàðyð �cŒ]ðyð �cŒ]ð	yð
 ˜”ðyð ðyð �cŒ]ðyð 
ðyð ðyð ˜T #œYÔ'ðyð 	ðyð yð yð yðxR¨°#¬ð R¸4ð Rð Rð Rð Rð0o Tð oð oð oð oðd ˆzÒÑà	€EÐ
 Ñ!Ô!Ð!Ø	€Eˆ(�O„O€Oàˆ_ÑÔ€FØ	€EÐ
$Ñ%Ô%Ð%Ø	€EÐ
5 ¨
Ô!3Ð
5Ð
5Ñ6Ô6Ð6Ø	€EÐ
5˜V NÔ3Ð
5Ð
5Ñ6Ô6Ð6Ø	€EÐ
3˜F =Ô1Ð
3Ð
3Ñ4Ô4Ð4Ø	€EÐ
1 &¨¤-Ð
1Ð
1Ñ2Ô2Ð2Ø	€EÐ
4  yÔ 1Ð
4Ð
4Ð
4Ñ5Ô5Ð5Ø	€EÐ
6˜Ð 2Ô3Ð
6Ð
6Ð
6Ñ7Ô7Ð7à&Ð&Ñ(Ô(ð ØˆÐLÑMÔMÐMØˆŒ�‰Œˆà	€EÐ
'Ñ(Ô(Ð(Ø	€EÐ
ÑÔÐØ	€EÐ
IÑJÔJÐJà	€EÐ
ÑÔÐØ	€EÐ
!Ñ"Ô"Ð"Ø	€EÐ
6Ñ7Ô7Ð7Ø	€Eˆ$�K„K€KØ	€EÐ
%Ñ&Ô&Ð&Ø	€EÐ
QÑRÔRÐRà	€EÐ
$Ñ%Ô%Ð%Ø>€KØ	€Eð	FØˆ2Œ9�^ WÑ-Ô-ð	Fð 	Fð 	Fñô ð ð
 
€EÐ
W i b¤iÐ0GÈÑ&UÔ&UÐ
WÐ
WÑXÔXÐXØ	€EÐ
o¨9¨2¬9Ð5QÐSlÐ_jÐSlÐSlÑ+mÔ+mÐ
oÐ
oÑpÔpÐpØ	€EÐ
U Y R¤YÐ/EÀ{Ñ%SÔ%SÐ
UÐ
UÑVÔVÐVØ	€EÐ
Y y r¤yÐ1IÈ;Ñ'WÔ'WÐ
YÐ
YÑZÔZÐZØ	€EÐ
H˜Y˜RœY ~°|°|±~´~ÑFÔFÐ
HÐ
HÑIÔIÐIØ<Ð<Ð<Ð<Ð<Ð<Ø	€EÐ
_ Y R¤YÐ/EÈ$È$É&Ì&ÐG\ÐG\ÐG\Ñ%]Ô%]Ð
_Ð
_Ñ`Ô`Ð`Ø	€EÐ
F  ¤Ð+=¸tÑ!DÔ!DÐ
FÐ
FÑGÔGÐGØ	€EÐ
Y¨)¨"¬)Ð4OÐQVÑ*WÔ*WÐ
YÐ
YÑZÔZÐZð $Ð #Ð #Ð #Ð #Ð #ð Ø,àð !ØAðð ð
 "ð  RØ ðð ð "ð  |ÐUkð   |ð   |ð  mCð   |ð   |ð   |Øðð ð !Øðð ð
 "ð  ~Ø ðð ð "ð  SØ ð#ð #ð  Ø  (Ð+ð  yðð ð;"
ð "
ðF �KðK&ð &ð*ð *€ðZð ð ð €Ô Ø	ØØØØ(Ø
Ø!ðñ ô ð ð ð r   