§
    øžyjCú  ã                   óZ  — 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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 ddlmZ ddlmZ dd	lmZ  ej        e¦  «        Z  e! ej"        d
¦  «        ¦  «        Z#e#re  $                    ej%        ¦  «          e	j&        ¦   «         Z'dZ( G d„ de)¦  «        Z* G d„ d¦  «        Z+dee,gdf         dz  ddfd„Z-dee,gdf         dz  fd„Z.de/de,ddfd„Z0defd„Z1dej2        de,ddfd„Z3	 d1de4e,         de,dz  dej2        fd„Z5dede/fd„Z6dede/ddfd „Z7d!e,de8e9e:f         dz  fd"„Z; G d#„ d$e¦  «        Z< G d%„ d&¦  «        Z=d'e,de,fd(„Z>d)Z? ej@        d*¦  «        ZA	 d2d,e,d-ee,         de,fd.„ZB G d/„ d0e¦  «        ZCdS )3aC  Base class for all Hermes execution environment backends.

Unified spawn-per-call model: every command spawns a fresh ``bash -c`` process.
A session snapshot (env vars, functions, aliases) is captured once at init and
re-sourced before each command. CWD persists via in-band stdout markers (remote)
or a temp file (local).
é    N)ÚABCÚabstractmethod)Údeque)ÚPath)ÚIOÚCallableÚIterableÚProtocol)Úget_hermes_home)Úwindows_hide_flags)Úis_interruptedÚHERMES_DEBUG_INTERRUPTl   ÿÿÿÿ c                   ó2   ‡ — e Zd ZdZddœdedefˆ fd„Zˆ xZS )ÚEnvironmentConnectionErroruÈ  Infrastructure/connection-class failure of a terminal backend.

    Raised when the backend itself is unreachable (SSH host down, Docker
    daemon not running, remote file sync failing on a dead link) â€” never
    for a command that merely exited nonzero.  Subclassing RuntimeError
    keeps every existing ``except RuntimeError`` catcher working.

    ``terminal_tool`` turns this into a structured ``status: "degraded"``
    tool result (config gate ``terminal.degraded_mode: warn|fail``) so the
    model gets an actionable reason + retry hint instead of a traceback.
    The failed backend is never cached, so a later call retries from
    scratch and simply works once the backend is reachable again.
    Ú )Ú
retry_hintÚreasonr   c                ój   •— t          ¦   «                              |¦  «         || _        |pd| _        d S )NuÒ   This is an infrastructure failure, not a command failure. Verify the backend is reachable (network, service running, credentials), then retry the same command â€” recovery is automatic once the backend is back.)ÚsuperÚ__init__r   r   )Úselfr   r   Ú	__class__s      €ú=/home/ragecks/.hermes/hermes-agent/tools/environments/base.pyr   z#EnvironmentConnectionError.__init__F   s:   ø€ Ý‰Œ×Ò˜Ñ Ô Ð ØˆŒØ$ð 
ð2ð 	Œˆˆó    )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ústrr   Ú__classcell__)r   s   @r   r   r   7   sd   ø€ € € € € ðð ð :<ð 
ð 
ð 
˜sð 
°3ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
ð 
r   r   c                   óž   — e Zd ZdZdZddeddfd„Zded	dfd
„Zdd„Z	e
d	efd„¦   «         Ze
d	efd„¦   «         Zded	dfd„Zddœded	efd„ZdS )Ú_BoundedOutputCollectoru_  Retain a bounded 40/60 head-tail window of streamed text.

    When ``spill_path`` is set, the collector also tees the FULL stream to
    that file once eviction begins (up to ``_SPILL_CAP_CHARS``), so a
    truncated foreground result is recoverable without re-running the
    command. Memory stays bounded either way â€” the spill is disk-only.
    i@KL NÚ	max_charsÚ
spill_pathzPath | Nonec                 óp  — t          dt          |¦  «        ¦  «        | _        t          | j        dz  ¦  «        | _        | j        | j        z
  | _        g | _        t          ¦   «         | _        d| _        d| _	        d| _
        t          j        ¦   «         | _        || _        d | _        d| _        d| _        d S )Né   çš™™™™™Ù?r   F)ÚmaxÚintr#   Ú_head_limitÚ_tail_limitÚ_headr   Ú_tailÚ_head_charsÚ_tail_charsÚ_total_charsÚ	threadingÚLockÚ_lockÚ_spill_pathÚ	_spill_fhÚ_spill_charsÚ_spill_capped)r   r#   r$   s      r   r   z _BoundedOutputCollector.__init__^   s    € Ý˜Q¥ I¡¤Ñ/Ô/ˆŒÝ˜tœ~°Ñ3Ñ4Ô4ˆÔØœ>¨DÔ,<Ñ<ˆÔØ "ˆŒ
Ý!&¡¤ˆŒ
ØˆÔØˆÔØˆÔÝ”^Ñ%Ô%ˆŒ
Ø%ˆÔØ)-ˆŒØˆÔØ"ˆÔÐÐr   ÚtextÚreturnc                 ó
  — | j         �| j        rdS 	 | j        €¡| j         j                             dd¬¦  «         t          | j         ddd¬¦  «        | _        d                     | j        ¦  «        d                     | j        ¦  «        z   }| j         	                    |¦  «         t          |¦  «        | _        | j        | j        z
  }|d	k    st          |¦  «        |k    rR| j         	                    |dt          d	|¦  «        …         ¦  «         | j         	                    d
¦  «         d| _        n| j         	                    |¦  «         | xj        t          |¦  «        z  c_        dS # t          $ r d| _        Y dS w xY w)zATee ``text`` to the spill file (opened lazily on first overflow).NT©ÚparentsÚexist_okÚwúutf-8Úreplace©ÚencodingÚerrorsr   r   z+
... [spill capped at 5,000,000 chars] ...
)r4   r7   r5   ÚparentÚmkdirÚopenÚjoinr,   r-   ÚwriteÚlenr6   Ú_SPILL_CAP_CHARSr(   ÚOSError)r   r8   ÚbacklogÚbudgets       r   Ú_maybe_spillz$_BoundedOutputCollector._maybe_spillm   s€  € àÔÐ# tÔ'9Ð#ØˆFð	&ØŒ~Ð%ØÔ Ô'×-Ò-°dÀTÐ-ÑJÔJÐJÝ!% dÔ&6¸ÀgÐV_Ð!`Ñ!`Ô!`�”ð Ÿ'š' $¤*Ñ-Ô-°·²¸¼
Ñ0CÔ0CÑC�Ø”×$Ò$ WÑ-Ô-Ð-Ý$'¨¡L¤L�Ô!ØÔ*¨TÔ->Ñ>ˆFØ˜Š{ˆ{�c $™iœi¨&Ò0Ð0Ø”×$Ò$ T¨/­3¨q°&©>¬>¨/Ô%:Ñ;Ô;Ð;Ø”×$Ò$Ð%TÑUÔUÐUØ%)�Ô"Ð"à”×$Ò$ TÑ*Ô*Ð*ØÐÔ¥ T¡¤Ñ*ÐÔÐÐøÝð 	&ð 	&ð 	&à!%ˆDÔÐÐÐð	&øøøs   ’EE- Å-FÆFú
str | Nonec                 óú   — | j         5  | j        €	 ddd¦  «         dS 	 | j                             ¦   «          n# t          $ r Y nw xY wd| _        t	          | j        ¦  «        cddd¦  «         S # 1 swxY w Y   dS )z8Close the spill file and return its path if it was used.N)r3   r5   ÚcloserK   r   r4   ©r   s    r   Úclose_spillz#_BoundedOutputCollector.close_spill†   sò   € àŒZð 	)ð 	)ØŒ~Ð%Øð	)ð 	)ð 	)ñ 	)ô 	)ð 	)ð 	)ð 	)ðØ”×$Ò$Ñ&Ô&Ð&Ð&øÝð ð ð Ø�ðøøøà!ˆDŒNÝ�tÔ'Ñ(Ô(ð	)ð 	)ð 	)ð 	)ñ 	)ô 	)ð 	)ð 	)ð 	)ð 	)ð 	)ð 	)øøøð 	)ð 	)ð 	)ð 	)ð 	)ð 	)s1   ˆ	A0Ÿ9¸A0¹
AÁA0ÁAÁA0Á0A4Á7A4c                 ób   — | j         5  | j        | j        z   cd d d ¦  «         S # 1 swxY w Y   d S ©N)r3   r.   r/   rR   s    r   Úbuffered_charsz&_BoundedOutputCollector.buffered_chars’   s|   € àŒZð 	7ð 	7ØÔ# dÔ&6Ñ6ð	7ð 	7ð 	7ð 	7ñ 	7ô 	7ð 	7ð 	7ð 	7ð 	7ð 	7ð 	7øøøð 	7ð 	7ð 	7ð 	7ð 	7ð 	7s   ˆ$¤(«(c                 óR   — | j         5  | j        cd d d ¦  «         S # 1 swxY w Y   d S rU   )r3   r0   rR   s    r   Útotal_charsz#_BoundedOutputCollector.total_chars—   st   € àŒZð 	%ð 	%ØÔ$ð	%ð 	%ð 	%ð 	%ñ 	%ô 	%ð 	%ð 	%ð 	%ð 	%ð 	%ð 	%øøøð 	%ð 	%ð 	%ð 	%ð 	%ð 	%s   ˆœ £ c                 ó¨  — |sd S | j         5  t          |¦  «        }| j        �/| j        €| j        |z   | j        k    r|                      |¦  «         | xj        |z  c_        d}| j        | j        k     rSt          | j        | j        z
  |¦  «        }|r4| j
                             |d |…         ¦  «         | xj        |z  c_        |}||z
  }|dk    s| j        dk    r	 d d d ¦  «         d S || j        k    r[| j                             ¦   «          | j                             || j         d …         ¦  «         | j        | _        	 d d d ¦  «         d S ||d …         }| j                             |¦  «         | xj        t          |¦  «        z  c_        | j        | j        k    r˜| j        | j        z
  }| j        d         }t          |¦  «        |k    r7| j                             ¦   «          | xj        t          |¦  «        z  c_        n"||d …         | j        d<   | xj        |z  c_        | j        | j        k    °˜d d d ¦  «         d S # 1 swxY w Y   d S )Nr   )r3   rI   r4   r5   r0   r#   rN   r.   r*   Úminr,   Úappendr+   r-   Úclearr/   Úpopleft)	r   r8   Útext_lenÚstartÚtakeÚ	remainingÚchunkÚexcessÚfirsts	            r   r[   z_BoundedOutputCollector.appendœ   sø  € Øð 	ØˆFØŒZð '	/ð '	/Ý˜4‘y”yˆHð ÔÐ+Ø”Ð*ØÔ$ xÑ/°$´.Ò@Ð@à×!Ò! $Ñ'Ô'Ð'ØÐÔ Ñ)ÐÔØˆEàÔ $Ô"2Ò2Ð2Ý˜4Ô+¨dÔ.>Ñ>ÀÑIÔI�Øð !Ø”J×%Ò% d¨5¨D¨5¤kÑ2Ô2Ð2ØÐ$Ô$¨Ñ,Ð$Ô$Ø �Eà  5Ñ(ˆIØ˜AŠ~ˆ~ Ô!1°QÒ!6Ð!6Øð+'	/ð '	/ð '	/ñ '	/ô '	/ð '	/ð '	/ð '	/ð, ˜DÔ,Ò,Ð,Ø”
× Ò Ñ"Ô"Ð"Ø”
×!Ò! $¨Ô(8Ð'8Ð':Ð':Ô";Ñ<Ô<Ð<Ø#'Ô#3�Ô Øð5'	/ð '	/ð '	/ñ '	/ô '	/ð '	/ð '	/ð '	/ð8 ˜˜˜”LˆEØŒJ×Ò˜eÑ$Ô$Ð$ØÐÔ¥ E¡
¤
Ñ*ÐÔØÔ" TÔ%5Ò5Ð5ØÔ)¨DÔ,<Ñ<�Øœ
 1œ�Ý�u‘:”: Ò'Ð'Ø”J×&Ò&Ñ(Ô(Ð(ØÐ$Ô$­¨E©
¬
Ñ2Ð$Ô$Ð$à$)¨&¨'¨'¤N�D”J˜q‘MØÐ$Ô$¨Ñ.Ð$Ô$ð Ô" TÔ%5Ò5Ð5ð?'	/ð '	/ð '	/ñ '	/ô '	/ð '	/ð '	/ð '	/ð '	/ð '	/ð '	/ð '	/øøøð '	/ð '	/ð '	/ð '	/ð '	/ð '	/s    ŒCIÃ+AIÅC)IÉIÉIr   ©Úsuffixrf   c          	      óB  — | j         5  t          |¦  «        | j        k    r|| j         d…         cddd¦  «         S d                     | j        ¦  «        }d                     | j        ¦  «        }| j        t          |¦  «        z
  }| j        |k    r||z   |z   cddd¦  «         S d}t          d¦  «        D ]n}t          d|t          |¦  «        z
  ¦  «        }t          |dz  ¦  «        }||z
  }	t          d| j        |z
  |	z
  ¦  «        }
d|
d›d| j        d›d	�}||k    r n|}Œot          d|t          |¦  «        z
  ¦  «        }t          |dz  ¦  «        }||z
  }	|	r||	 d…         nd}|d|…         |d|…         z   |z   |z   cddd¦  «         S # 1 swxY w Y   dS )
zARender within ``max_chars``, preserving a required status suffix.Nr   é   r   r'   z

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

)
r3   rI   r#   rG   r,   r-   r0   Úranger(   r)   )r   rf   ÚheadÚtailÚ	availableÚnoticeÚ_Úcontent_budgetÚ
head_charsÚ
tail_charsÚomittedÚupdatedÚrendered_tails                r   Úrenderz_BoundedOutputCollector.renderÈ   s�  € àŒZð 	Sð 	SÝ�6‰{Œ{˜dœnÒ,Ð,Ø˜tœ~˜oÐ/Ð/Ô0ð	Sð 	Sð 	Sð 	Sñ 	Sô 	Sð 	Sð 	Sð —7’7˜4œ:Ñ&Ô&ˆDØ—7’7˜4œ:Ñ&Ô&ˆDØœ­¨V©¬Ñ4ˆIØÔ  IÒ-Ð-Ø˜d‘{ VÑ+ð	Sð 	Sð 	Sð 	Sñ 	Sô 	Sð 	Sð 	Sð ˆFÝ˜1‘X”Xð !ð !�Ý!$ Q¨	µC¸±K´KÑ(?Ñ!@Ô!@�Ý  °#Ñ!5Ñ6Ô6�
Ø+¨jÑ8�
Ý˜a Ô!2°ZÑ!?À*Ñ!LÑMÔM�ðC°7ÐMð Cð CØ"Ô/ÐBðCð Cð Cð ð ˜fÒ$Ð$Ø�EØ ��å   Iµ°F±´Ñ$;Ñ<Ô<ˆNÝ˜^¨cÑ1Ñ2Ô2ˆJØ'¨*Ñ4ˆJØ2<ÐD˜D *   Ô.Ð.À"ˆMØ˜˜˜Ô$ v¨j¨y¨jÔ'9Ñ9¸MÑIÈFÑRð9	Sð 	Sð 	Sð 	Sñ 	Sô 	Sð 	Sð 	Sð 	Sð 	Sð 	Sð 	Søøøð 	Sð 	Sð 	Sð 	Sð 	Sð 	Ss   ˆ(F½AFÂ'C FÆFÆFrU   )r9   rO   )r   r   r   r   rJ   r)   r   r   rN   rS   ÚpropertyrV   rX   r[   rv   © r   r   r"   r"   Q   s/  € € € € € ðð ð !Ðð#ð # #ð #°=ð #ð #ð #ð #ð& ð &¨ð &ð &ð &ð &ð2
)ð 
)ð 
)ð 
)ð ð7 ð 7ð 7ð 7ñ „Xð7ð ð%˜Sð %ð %ð %ñ „Xð%ð*/˜3ð */ 4ð */ð */ð */ð */ðX ')ð Sð Sð S ð S¨Sð Sð Sð Sð Sð Sð Sr   r"   Úcbr9   c                 ó   — | t           _        dS )z>Register a callback that _wait_for_process fires periodically.N)Ú_activity_callback_localÚcallback)ry   s    r   Úset_activity_callbackr}   é   s   € à(*ÕÔ%Ð%Ð%r   c                  ó.   — t          t          dd¦  «        S )uj  Return the thread-local activity callback (see ``set_activity_callback``).

    Public accessor for callers outside this module that need to capture the
    calling thread's callback before handing work to another thread (the
    callback is thread-local, so a freshly spawned thread cannot read it
    back) â€” e.g. the manual cron-run heartbeat (#76502).
    r|   N)Úgetattrr{   rx   r   r   Úget_activity_callbackr€   î   s   € õ Õ+¨Z¸Ñ>Ô>Ð>r   ÚstateÚlabelc                 ó  — t          j        ¦   «         }|                      dd¦  «        }|| d         z
  |k     rdS || d<   	 t          ¦   «         }|r+t	          || d         z
  ¦  «        } ||› d|› d�¦  «         dS dS # t
          $ r Y dS w xY w)a_  Fire the activity callback at most once every ``state['interval']`` seconds.

    *state* must contain ``last_touch`` (monotonic timestamp) and ``start``
    (monotonic timestamp of the operation start).  An optional ``interval``
    key overrides the default 10 s cadence.

    Swallows all exceptions so callers don't need their own try/except.
    Úintervalg      $@Ú
last_touchNr_   z (z
s elapsed))ÚtimeÚ	monotonicÚgetr€   r)   Ú	Exception)r�   r‚   Únowr„   ry   Úelapseds         r   Útouch_activity_if_duerŒ   ù   sË   € õ Œ.Ñ
Ô
€CØ�yŠy˜ TÑ*Ô*€HØ
ˆU�<Ô Ñ  8Ò+Ð+ØˆØ€Eˆ,ÑðÝ"Ñ$Ô$ˆØð 	0Ý˜#  g¤Ñ.Ñ/Ô/ˆGØˆB�%Ð.Ð.˜7Ð.Ð.Ð.Ñ/Ô/Ð/Ð/Ð/ð	0ð 	0øõ ð ð ð Øˆˆðøøøs   Á9A> Á>
BÂBc                  ó¢   — t          j        d¦  «        } | rt          | ¦  «        }nt          ¦   «         dz  }|                     dd¬¦  «         |S )zÇReturn the host-side root for all sandbox storage (Docker workspaces,
    Singularity overlays/SIF cache, etc.).

    Configurable via TERMINAL_SANDBOX_DIR. Defaults to {HERMES_HOME}/sandboxes/.
    ÚTERMINAL_SANDBOX_DIRÚ	sandboxesTr;   )ÚosÚgetenvr   r   rE   )ÚcustomÚps     r   Úget_sandbox_dirr”     sT   € õ ŒYÐ-Ñ.Ô.€FØð ,Ý�‰LŒLˆˆåÑÔ Ñ+ˆØ‡G‚G�D 4€GÑ(Ô(Ð(Ø€Hr   ÚprocÚdatac                 óŽ   ‡ ‡‡— g Š‰‰ _         ˆˆˆ fd„}t          j        |d¬¦  «        }|‰ _        |                     ¦   «          dS )u  Write *data* to proc.stdin on a daemon thread to avoid pipe-buffer deadlocks.

    On Windows, text-mode stdin (``text=True`` / ``encoding="utf-8"``)
    translates ``\n`` â†’ ``\r\n`` as the data flows through the pipe â€”
    which corrupts every write_file / patch call because the bytes that
    land on disk include injected carriage returns.  The file IS created,
    but every subsequent byte-count / content compare against the
    caller's ``\n``-only string fails.

    Workaround: write through ``proc.stdin.buffer`` (the underlying byte
    buffer), encoding to UTF-8 ourselves.  That bypasses Python's
    newline translation entirely on every platform.  No behaviour change
    on POSIX â€” the byte sequence is identical to what text-mode would
    produce there.

    Encoding uses ``errors="surrogateescape"`` â€” the exact inverse of the
    surrogateescape decode, so original bytes are restored.  For
    surrogate-free strings it is byte-identical to strict UTF-8.
    Surrogates outside the round-trip range U+DC80â€“U+DCFF raise and are
    recorded on ``proc._hermes_stdin_errors`` while stdin is still closed
    in ``finally`` so the child sees EOF instead of hanging;
    ``_wait_for_process`` reads the recorded error and surfaces it as
    ``stdin_error`` on the result.
    c                  ó¤  •— ‰j         €$‰                     t          d¦  «        ¦  «         d S t          ‰j         d‰j         ¦  «        } 	 t	          ‰t
          ¦  «        r‰                     dd¦  «        n‰}|                      |¦  «        }|t          |¦  «        k    r#t          d|› dt          |¦  «        › d�¦  «        ‚n># t          t          f$ r Y n+t          $ r}‰                     |¦  «         Y d }~nd }~ww xY w	 |                      ¦   «          d S # t          $ r Y d S w xY w# 	 |                      ¦   «          w # t          $ r Y w w xY wxY w)Nzprocess stdin unavailableÚbufferr?   Úsurrogateescapezshort stdin write: z of z bytes)Ústdinr[   ÚRuntimeErrorr   Ú
isinstancer   ÚencoderH   rI   ÚBrokenPipeErrorrK   r‰   rQ   )ÚtargetÚrawÚwrittenÚexcr–   rC   r•   s       €€€r   Ú_writez_pipe_stdin.<locals>._writeD  s‘  ø€ ØŒ:ÐØ�MŠM�,Ð'BÑCÔCÑDÔDÐDØˆFõ ˜œ X¨t¬zÑ:Ô:ˆð	Ý=GÈÍcÑ=RÔ=RÐ\�$—+’+˜gÐ'8Ñ9Ô9Ð9ÐX\ˆCØ—l’l 3Ñ'Ô'ˆGØ�#˜c™(œ(Ò"Ð"õ #Ð#V¸Ð#VÐ#VÅcÈ#ÁhÄhÐ#VÐ#VÐ#VÑWÔWÐWð #øõ  ¥Ð)ð 	ð 	ð 	ØˆDÝð 	ð 	ð 	ð
 �MŠM˜#ÑÔÐÐÐÐÐÐøøøøð	øøøðØ—’‘”���øÝð ð ð Ø��ðøøøøðØ—’‘”��øÝð ð ð Ø�ðøøøøøøss   Á	A8C ÃD( ÃC=ÃD( Ã	C=ÃC8Ã3D( Ã8C=Ã=D( ÄD Ä
D%Ä$D%Ä(EÄ*D?Ä>EÄ?
EÅ	EÅEÅET©r    ÚdaemonN)Ú_hermes_stdin_errorsr1   ÚThreadÚ_hermes_stdin_threadr_   )r•   r–   r¤   ÚthreadrC   s   ``  @r   Ú_pipe_stdinr«   '  sg   øøø€ ð4 #%€FØ &€DÔðð ð ð ð ð ð õ8 Ô V°DÐ9Ñ9Ô9€FØ &€DÔØ
‡L‚L�N„N€N€N€Nr   ÚcmdÚ
stdin_datac           
      óø   — |                      dt          ¦   «         ¦  «         t          j        | ft          j        t          j        |�t          j        nt          j        ddddœ|¤Ž}|�t          ||¦  «         |S )a  Spawn a subprocess with standard stdout/stderr/stdin setup.

    If *stdin_data* is provided, writes it asynchronously via :func:`_pipe_stdin`.
    Backends with special Popen needs (e.g. local's ``preexec_fn``) can bypass
    this and call :func:`_pipe_stdin` directly.
    ÚcreationflagsNTr?   r@   )ÚstdoutÚstderrr›   r8   rB   rC   )Ú
setdefaultr   Ú
subprocessÚPopenÚPIPEÚSTDOUTÚDEVNULLr«   )r¬   r­   Úkwargsr•   s       r   Ú_popen_bashr¹   e  sŠ   € ð ×Ò�oÕ'9Ñ';Ô';Ñ<Ô<Ð<ÝÔØðåŒÝÔ Ø!+Ð!7�jŒoˆo½ZÔ=OØ˜G¨Iðð ð ðð €Dð ÐÝ�D˜*Ñ%Ô%Ð%Ø€Kr   Úpathc                 ó    — |                       ¦   «         r9	 t          j        |                      d¬¦  «        ¦  «        S # t          $ r Y nw xY wi S )z:Load a JSON file as a dict, returning ``{}`` on any error.r?   ©rB   )ÚexistsÚjsonÚloadsÚ	read_textr‰   )rº   s    r   Ú_load_json_storerÁ   |  sZ   € à‡{‚{�}„}ð ð	Ý”:˜dŸnšn°g˜nÑ>Ô>Ñ?Ô?Ð?øÝð 	ð 	ð 	ØˆDð	øøøà€Is   –'> ¾
AÁ
Ac                 ó”   — | j                              dd¬¦  «         |                      t          j        |d¬¦  «        d¬¦  «         dS )z.Write *data* as pretty-printed JSON to *path*.Tr;   é   )Úindentr?   r¼   N)rD   rE   Ú
write_textr¾   Údumps)rº   r–   s     r   Ú_save_json_storerÇ   †  sH   € à„K×Ò˜d¨TÐÑ2Ô2Ð2Ø‡O‚O•D”J˜t¨AÐ.Ñ.Ô.¸€OÑAÔAÐAÐAÐAr   Ú	host_pathc                 ó„   — 	 t          | ¦  «                             ¦   «         }|j        |j        fS # t          $ r Y dS w xY w)zIReturn ``(mtime, size)`` for cache comparison, or ``None`` if unreadable.N)r   ÚstatÚst_mtimeÚst_sizerK   )rÈ   Ústs     r   Ú_file_mtime_keyrÎ   Œ  sO   € ðÝ�)‰_Œ_×!Ò!Ñ#Ô#ˆØ”˜RœZÐ(Ð(øÝð ð ð Øˆtˆtðøøøs   ‚.1 ±
?¾?c                   ó”   — e Zd ZdZdedz  fd„Zd
d„Zddedz  defd„Ze	de
e         dz  fd„¦   «         Ze	dedz  fd	„¦   «         ZdS )ÚProcessHandlezÏDuck type that every backend's _run_bash() must return.

    subprocess.Popen satisfies this natively.  SDK backends (Modal, Daytona)
    return _ThreadedProcessHandle which adapts their blocking calls.
    r9   Nc                 ó   — d S rU   rx   rR   s    r   ÚpollzProcessHandle.poll¡  ó   € € € r   c                 ó   — d S rU   rx   rR   s    r   ÚkillzProcessHandle.kill¢  rÓ   r   Útimeoutc                 ó   — d S rU   rx   ©r   rÖ   s     r   ÚwaitzProcessHandle.wait£  rÓ   r   c                 ó   — d S rU   rx   rR   s    r   r°   zProcessHandle.stdout¥  ó   € Ø(+¨r   c                 ó   — d S rU   rx   rR   s    r   Ú
returncodezProcessHandle.returncode¨  rÛ   r   ©r9   NrU   )r   r   r   r   r)   rÒ   rÕ   ÚfloatrÙ   rw   r   r   r°   rÝ   rx   r   r   rÐ   rÐ   š  sœ   € € € € € ðð ð &�c˜D‘jÐ%Ð%Ð%Ð%ØÐÐÐØ<Ð<˜E D™LÐ<°CÐ<Ð<Ð<Ð<àØ+˜˜3œ $™Ð+Ð+Ð+ñ „XØ+àØ+˜C $™JÐ+Ð+Ð+ñ „XØ+Ð+Ð+r   rÐ   c                   óÄ   — e Zd ZdZ	 ddeg eeef         f         deg df         dz  fd„Ze	d„ ¦   «         Z
e	dedz  fd„¦   «         Zdedz  fd	„Zd
„ Zddedz  defd„ZdS )Ú_ThreadedProcessHandleal  Adapter for SDK backends (Modal, Daytona) that have no real subprocess.

    Wraps a blocking ``exec_fn() -> (output_str, exit_code)`` in a background
    thread and exposes a ProcessHandle-compatible interface.  An optional
    ``cancel_fn`` is invoked on ``kill()`` for backend-specific cancellation
    (e.g. Modal sandbox.terminate, Daytona sandbox.stop).
    NÚexec_fnÚ	cancel_fnc                 ó8  ‡ ‡— |‰ _         t          j        ¦   «         ‰ _        d ‰ _        d ‰ _        t          j        ¦   «         \  }}t          j        |ddd¬¦  «        ‰ _	        |‰ _
        ˆˆ fd„}t          j        |d¬¦  «        }|                     ¦   «          d S )NÚrr?   r@   rA   c                  ó  •— 	  ‰¦   «         \  } }|‰_         	 t          j        ‰j        |                      dd¬¦  «        ¦  «         n# t
          $ r Y nw xY wn%# t          $ r}|‰_        d‰_         Y d }~nd }~ww xY w	 t          j        ‰j        ¦  «         n# t
          $ r Y nw xY w‰j	         
                    ¦   «          d S # 	 t          j        ‰j        ¦  «         n# t
          $ r Y nw xY w‰j	         
                    ¦   «          w xY w)Nr?   r@   ©rC   r&   )Ú_returncoder�   rH   Ú	_write_fdrž   rK   r‰   Ú_errorrQ   Ú_doneÚset)ÚoutputÚ	exit_coder£   râ   r   s      €€r   Ú_workerz0_ThreadedProcessHandle.__init__.<locals>._workerÄ  sO  ø€ ð!Ø$+ G¡I¤IÑ!�˜	Ø#,�Ô ðÝ”H˜Tœ^¨V¯]ª]¸7È9¨]Ñ-UÔ-UÑVÔVÐVÐVøÝð ð ð Ø�Dðøøøøøåð %ð %ð %Ø!�”Ø#$�Ô Ð Ð Ð Ð Ð øøøøð%øøøðÝ”H˜Tœ^Ñ,Ô,Ð,Ð,øÝð ð ð Ø�Dðøøøà”
—’Ñ Ô Ð Ð Ð øð	Ý”H˜Tœ^Ñ,Ô,Ð,Ð,øÝð ð ð Ø�Dðøøøà”
—’Ñ Ô Ð Ð øøøsˆ   ƒA ˜/A ÁA Á
AÁA ÁAÁA ÁC Á
A;Á#A6Á1C Á6A;Á;C Á?B Â
B&Â%B&ÃD
ÃC ÃD
Ã 
C-Ã*D
Ã,C-Ã-D
Tr¥   )Ú
_cancel_fnr1   ÚEventrë   rè   rê   r�   ÚpipeÚfdopenÚ_stdoutré   r¨   r_   )r   râ   rã   Úread_fdÚwrite_fdrï   Úts   ``     r   r   z_ThreadedProcessHandle.__init__µ  s¤   øø€ ð
 $ˆŒÝ”_Ñ&Ô&ˆŒ
Ø'+ˆÔØ(,ˆŒõ œG™IœIÑˆ�Ý”y ¨#¸È	ÐRÑRÔRˆŒØ!ˆŒð	!ð 	!ð 	!ð 	!ð 	!ð 	!õ& Ô G°DÐ9Ñ9Ô9ˆØ	�Š‰	Œ	ˆ	ˆ	ˆ	r   c                 ó   — | j         S rU   )rô   rR   s    r   r°   z_ThreadedProcessHandle.stdoutÚ  s
   € àŒ|Ðr   r9   c                 ó   — | j         S rU   )rè   rR   s    r   rÝ   z!_ThreadedProcessHandle.returncodeÞ  s   € àÔÐr   c                 óF   — | j                              ¦   «         r| j        nd S rU   )rë   Úis_setrè   rR   s    r   rÒ   z_ThreadedProcessHandle.pollâ  s#   € Ø#'¤:×#4Ò#4Ñ#6Ô#6Ð@ˆtÔÐ¸DÐ@r   c                 ód   — | j         r(	 |                       ¦   «          d S # t          $ r Y d S w xY wd S rU   )rð   r‰   rR   s    r   rÕ   z_ThreadedProcessHandle.killå  sS   € ØŒ?ð 	ðØ—’Ñ!Ô!Ð!Ð!Ð!øÝð ð ð Ø��ðøøøð	ð 	s   ‰ Ÿ
-¬-rÖ   c                 óF   — | j                              |¬¦  «         | j        S )N©rÖ   )rë   rÙ   rè   rØ   s     r   rÙ   z_ThreadedProcessHandle.waitì  s!   € ØŒ
�Š ˆÑ(Ô(Ð(ØÔÐr   rU   )r   r   r   r   r   Útupler   r)   r   rw   r°   rÝ   rÒ   rÕ   rß   rÙ   rx   r   r   rá   rá   ¬  s  € € € € € ðð ð 04ð#ð #à˜"˜e C¨ HœoÐ-Ô.ð#ð ˜B ˜HÔ%¨Ñ,ð#ð #ð #ð #ðJ ðð ñ „Xðð ð ˜C $™Jð  ð  ð  ñ „Xð ðA�c˜D‘jð Að Að Að Aðð ð ð ð  ˜E D™Lð  °Cð  ð  ð  ð  ð  ð  r   rá   Ú
session_idc                 ó   — d| › d�S )NÚ__HERMES_CWD_Ú__rx   )r   s    r   Ú_cwd_markerr  ö  s   € Ø)˜:Ð)Ð)Ð)Ð)r   z`^declare -x (HERMES_SESSION_|HERMES_UI_SESSION_ID|HERMES_CRON_AUTO_DELIVER_|HERMES_CRON_SESSION)z^[A-Za-z_][A-Za-z0-9_]*$rx   Útmp_pathÚexcluded_namesc                 ó�   — d„ |D ¦   «         }d                      d„ t          |¦  «        D ¦   «         ¦  «        }|rd|› �}d|› d| › �S )u  Return a shell snippet that dumps ``export -p`` to *tmp_path* minus the
    per-session bridged vars (see ``_SNAPSHOT_EXCLUDED_ENV_REGEX``) and any
    additional names supplied by the caller.

    Unset the bridged vars in a subshell *before* ``export -p``. A line-based
    ``grep -vE`` filter is unsafe: bash 3.2 prints a value containing a newline
    as a multi-line ``declare -x NAME="â€¦`` block, so only the opener matches the
    regex and continuation lines (e.g. ``curl â€¦ | bash #`` smuggled into a
    Matrix room/display name via ``HERMES_SESSION_CHAT_NAME``) land in the
    snapshot and execute on the next ``source`` (issue #71296). Unsetting first
    means ``export -p`` never emits those vars â€” including any continuation
    lines. ``|| true`` keeps the success contract for callers that chain on it.

    The dump MUST be wrapped in a brace group with the redirection applied to
    the group. *tmp_path* is typically a shell-variable expansion (a
    mktemp-allocated per-writer temp name); a redirection attached to a
    pipeline segment would expand it inside that segment's subshell,
    potentially inconsistently with the parent that expands the follow-up
    ``mv``. The brace-group redirect is expanded in the current shell,
    keeping both expansions consistent.
    c                 ó@   — h | ]}t          |t          ¦  «        ¯|¯|’ŒS rx   )r�   r   ©Ú.0Únames     r   ú	<setcomp>z6_export_dump_excluding_session_vars.<locals>.<setcomp>/  s@   € ð ð ð ØÝ�d�CÑ Ô ðà%)ðØðð ð r   Ú c              3   ó>   K  — | ]}t          j        |¦  «        V — Œd S rU   ©ÚshlexÚquoter	  s     r   ú	<genexpr>z6_export_dump_excluding_session_vars.<locals>.<genexpr>3  s,   è è € ÐLÐL°�5œ; tÑ,Ô,ÐLÐLÐLÐLÐLÐLr   zR{ ( unset ${!HERMES_SESSION_*} ${!HERMES_CRON_AUTO_DELIVER_*} HERMES_UI_SESSION_IDz( 2>/dev/null; export -p; ) || true; } > )rG   Úsorted)r  r  Ú
safe_namesÚextra_unsets       r   Ú#_export_dump_excluding_session_varsr    s…   € ð:ð Ø'ðñ ô €Jð —(’(ÐLÐL½À
Ñ9KÔ9KÐLÑLÔLÑLÔL€KØð (Ø'˜+Ð'Ð'ˆð	à*ð	ð 	ð
 ð	ð 	ðr   c                   ó2  — e Zd ZU dZdZeed<   dZeed<   dZ	e
ed<   defd	„Zd6dededefd„Zddd
dœdede
deded
z  def
d„Zed„ ¦   «         Zdee         fd„Zdeedf         fd„Zd„ Zededefd„¦   «         Zdedefd„Zdededefd„Zedededefd„¦   «         Z	 d7dd œd!eded"e
defd#„Zed$d%d&ed'ed
z  defd(„¦   «         Zd!efd)„Zd*efd+„Zd*efd,„Z d8d-„Z!	 d9d
d
d/dd0œdededed
z  ded
z  d1e
d"e
defd2„Z"d3„ Z#d4„ Z$dedeeed
z  f         fd5„Z%d
S ):ÚBaseEnvironmenta  Common interface and unified execution flow for all Hermes backends.

    Subclasses implement ``_run_bash()`` and ``cleanup()``.  The base class
    provides ``execute()`` with session snapshot sourcing, CWD tracking,
    interrupt handling, and timeout enforcement.
    rò   Ú_stdin_modeé   Ú_snapshot_timeoutFÚ_profile_scoped_passthroughr9   c                 ó   — dS )a,  Return the backend temp directory used for session artifacts.

        Most sandboxed backends use ``/tmp`` inside the target environment.
        LocalEnvironment overrides this on platforms like Termux where ``/tmp``
        may be missing and ``TMPDIR`` is the portable writable location.
        z/tmprx   rR   s    r   Úget_temp_dirzBaseEnvironment.get_temp_dirX  s	   € ð ˆvr   NÚcwdrÖ   Úenvc                 óŒ  — || _         || _        |pi | _        t          j        ¦   «         j        d d…         | _        |                      ¦   «                              d¦  «        pd}|› d| j        › d�| _	        |› d| j        › d�| _
        t          | j        ¦  «        | _        d| _        t          ¦   «         | _        d| _        d S )Né   ú/z/hermes-snap-z.shz/hermes-cwd-z.txtF)r  rÖ   r   ÚuuidÚuuid4ÚhexÚ_session_idr  ÚrstripÚ_snapshot_pathÚ	_cwd_filer  Ú_snapshot_readyrì   Ú_snapshot_passthrough_namesÚ_prefer_nonlogin)r   r  rÖ   r   Útemp_dirs        r   r   zBaseEnvironment.__init__a  sÇ   € ØˆŒØˆŒØ�9˜"ˆŒåœ:™<œ<Ô+¨C¨R¨CÔ0ˆÔØ×$Ò$Ñ&Ô&×-Ò-¨cÑ2Ô2Ð9°cˆØ!)ÐMÐM¸Ô8HÐMÐMÐMˆÔØ$ÐHÐH°$Ô2BÐHÐHÐHˆŒÝ& tÔ'7Ñ8Ô8ˆÔØ$ˆÔÝ58±U´UˆÔ(ð !&ˆÔÐÐr   éx   ©ÚloginrÖ   r­   Ú
cmd_stringr1  r­   c                óJ   — t          t          | ¦  «        j        › d�¦  «        ‚)z®Spawn a bash process to run *cmd_string*.

        Returns a ProcessHandle (subprocess.Popen or _ThreadedProcessHandle).
        Must be overridden by every backend.
        z must implement _run_bash())ÚNotImplementedErrorÚtyper   )r   r2  r1  rÖ   r­   s        r   Ú	_run_bashzBaseEnvironment._run_bashv  s$   € õ "¥T¨$¡Z¤ZÔ%8Ð"UÐ"UÐ"UÑVÔVÐVr   c                 ó   — dS )z<Release backend resources (container, instance, connection).Nrx   rR   s    r   ÚcleanupzBaseEnvironment.cleanup…  s	   € ð 	ˆr   c                 ó   — dS )zAReturn backend-specific names that must not persist in snapshots.rx   rx   rR   s    r   Ú,_additional_profile_scoped_passthrough_namesz<BaseEnvironment._additional_profile_scoped_passthrough_namesŽ  s   € àˆrr   .c                 óh  — | j         sdS 	 ddlm}  |¦   «         rKddlm} g  |¦   «         ¢|                      ¦   «         ¢R }| j                             d„ |D ¦   «         ¦  «         n,# t          $ r t           
                    dd¬¦  «         Y nw xY wt          t          | j        ¦  «        ¦  «        S )	aY  Return profile-scoped names that must not persist in the snapshot.

        The set is monotonic for the environment lifetime. A skill/config
        allowlist can be cleared after a value was captured; retaining the
        exclusion prevents that old value from becoming visible to a later
        profile through the shared snapshot.
        rx   r   )Úis_multiplex_active)Úget_all_passthroughc              3   óx   K  — | ]5}t          |t          ¦  «        ¯t                               |¦  «        ¯1|V — Œ6d S rU   )r�   r   Ú_SHELL_ENV_NAME_REÚ	fullmatchr	  s     r   r  zGBaseEnvironment._snapshot_excluded_passthrough_names.<locals>.<genexpr>¤  s_   è è € ð 8ð 8àÝ! $­Ñ,Ô,ð8õ 2D×1MÒ1MÈdÑ1SÔ1Sð8Øð8ð 8ð 8ð 8ð 8ð 8r   z4Could not refresh profile-scoped snapshot exclusionsT)Úexc_info)r  Úagent.secret_scoper<  Útools.env_passthroughr=  r:  r,  Úupdater‰   ÚloggerÚdebugrÿ   r  )r   r<  r=  Únamess       r   Ú$_snapshot_excluded_passthrough_namesz4BaseEnvironment._snapshot_excluded_passthrough_names’  s  € ð Ô/ð 	Ø�2ð	Ø>Ð>Ð>Ð>Ð>Ð>Ø"Ð"Ñ$Ô$ð 
ØEÐEÐEÐEÐEÐEðØ(Ð(Ñ*Ô*ðà×FÒFÑHÔHðð �ð Ô0×7Ò7ð 8ð 8à %ð8ñ 8ô 8ñ ô ð øøõ
 ð 	ð 	ð 	Ý�LŠLØFØð ñ ô ð ð ð ð	øøøõ
 •V˜DÔ<Ñ=Ô=Ñ>Ô>Ð>s   ‹AA' Á'&BÂBc                 ó„  — |                       | j        ¦  «        }|                      | j        ¦  «        }|                      | j        dz   ¦  «        }d}|                      ¦   «         }d|› dt          ||¦  «        › d|› d|› d|› d|› d	|› d
|› d|› d|› d|› d| j        › d| j        › d�}	 |                      |d| j        ¬¦  «        }|  	                    || j        ¬¦  «        }t          |                     d¦  «        pd¦  «        dk    r%t          d|                     d¦  «        › �¦  «        ‚d| _        |                      |¦  «         t                               d| j        | j        ¦  «         dS # t$          $ �r?}	d| _        t'          |	¦  «        }
d}	 |                      ddt)          d| j        ¦  «        ¬¦  «        }|  	                    |t)          d| j        ¦  «        ¬¦  «        }t          |                     d¦  «        pd¦  «        dk    }|s+|                     d¦  «        p|
                     ¦   «         p|
}
n# t$          $ r}|
› d|› �}
Y d}~nd}~ww xY w|| _        |r"t                               d| j        |	¦  «         n't                               d| j        |
¦  «         Y d}	~	dS Y d}	~	dS d}	~	ww xY w) züCapture login shell environment into a snapshot file.

        Called once after backend construction.  On success, sets
        ``_snapshot_ready = True`` so subsequent commands source the snapshot
        instead of running with ``bash -l``.
        ú.tmp.XXXXXXXXXXú"$__hermes_snap_tmp"z%umask 077
__hermes_snap_tmp=$(mktemp z) || exit 1
z�
__hermes_fns=$(declare -F | awk '{print $3}' | grep -vE '^_[^_]') || true
[ -n "$__hermes_fns" ] && declare -f $__hermes_fns >> z! 2>/dev/null || true
alias -p >> z#
echo 'shopt -s expand_aliases' >> z
echo 'set +e' >> z
echo 'set +u' >> z
mv -f r  z
 || rm -f z
builtin cd -- z 2>/dev/null || true
printf '\nú%sz\n' "$(pwd -P)"
T)r1  rÖ   rþ   rÝ   r   z)snapshot bootstrap failed with exit code z-Session snapshot created (session=%s, cwd=%s)FÚtrueé   r°   z; non-login probe: Nu_   init_session failed (session=%s): %s â€” login bash unusable; falling back to non-login bash -cuL   init_session failed (session=%s): %s â€” falling back to bash -l per command)Ú_quote_cwd_for_cdr  Ú_quote_shell_pathr)  rH  r  r  r6  r  Ú_wait_for_processr)   rˆ   rœ   r+  Ú_update_cwdrE  Úinfor'  r‰   r   rZ   Ústripr-  Úwarning)r   Ú_quoted_cwdÚ_quoted_snapÚ_snap_tmp_templateÚ	_snap_tmpÚsnapshot_excludedÚ	bootstrapr•   Úresultr£   ÚdetailÚprefer_nonloginÚprobeÚprobe_resultÚ	probe_excs                  r   Úinit_sessionzBaseEnvironment.init_session°  sö  € ð  ×,Ò,¨T¬XÑ6Ô6ˆð ×-Ò-¨dÔ.AÑBÔBˆð* "×3Ò3°DÔ4GÐJ[Ñ4[Ñ\Ô\ÐØ*ˆ	Ø ×EÒEÑGÔGÐðUØ*<ðUð Uå2°9Ð>OÑPÔPðUð Uð" ð#Uð Uð$ %ð%Uð Uð& 2;ð'Uð Uð( !*ð)Uð Uð* !*ð+Uð Uð0 ð1Uð Uð0 ".ð1Uð Uð0 :Cð1Uð Uð2 )ð3Uð Uð4 Ô*ð5Uð Uð4 /3Ô.>ð5Uð Uð Uð 	ð:-	Ø—>’> )°4ÀÔAW�>ÑXÔXˆDØ×+Ò+¨D¸$Ô:PÐ+ÑQÔQˆFÝ�6—:’:˜lÑ+Ô+Ð0¨qÑ1Ô1°QÒ6Ð6Ý"ØZÀÇ
Â
È<Ñ@XÔ@XÐZÐZñô ð ð $(ˆDÔ Ø×Ò˜VÑ$Ô$Ð$Ý�KŠKØ?ØÔ Ø”ñô ð ð ð øõ
 ð 	ñ 	ð 	Ø#(ˆDÔ õ
 ˜‘X”XˆFØ#ˆOðCØŸš v°UÅCÈÈDÔLbÑDcÔDc˜ÑdÔd�Ø#×5Ò5°eÅSÈÈTÔMcÑEdÔEdÐ5ÑeÔe�Ý"% l×&6Ò&6°|Ñ&DÔ&DÐ&IÈÑ"JÔ"JÈaÒ"O�Ø&ð VØ*×.Ò.¨xÑ8Ô8ÐB¸F×IÒIÑKÔKÐUÈv�FøøÝð Cð Cð CØ"ÐBÐB°yÐBÐB������øøøøðCøøøð %4ˆDÔ!Øð Ý—’ðMàÔ$Øñ	ô ð ð õ —’ð:àÔ$Øñ	ô ð ð ð ð ð ð ð ðð ð ð ð ð øøøøð'	øøøsE   Â+CE5 Å5J?Æ J:ÆB*IÉJ:É
IÉIÉJ:ÉIÉAJ:Ê:J?c                 ó²   — | dk    r| S | dk    rdS |                       d¦  «        rdt          j        | dd…         ¦  «        › �S t          j        | ¦  «        S )z7Quote a ``cd`` target while preserving ``~`` expansion.Ú~z~/z$HOMEz$HOME/rÃ   N)Ú
startswithr  r  )r  s    r   rO  z!BaseEnvironment._quote_cwd_for_cd/  sd   € ð �#Š:ˆ:ØˆJØ�$Š;ˆ;Ø�7Ø�>Š>˜$ÑÔð 	3Ø2�EœK¨¨A¨B¨B¬Ñ0Ô0Ð2Ð2Ð2ÝŒ{˜3ÑÔÐr   rº   c                 ó*   — t          j        |¦  «        S )zöQuote *path* for interpolation into a bash script.

        LocalEnvironment overrides this to rewrite native/mixed Windows
        paths to ``/c/...`` before quoting. Remote backends leave paths
        as-is (they already speak POSIX).
        r  )r   rº   s     r   rP  z!BaseEnvironment._quote_shell_path:  s   € õ Œ{˜4Ñ Ô Ð r   Úcommandc                 óV  — |                      dd¦  «        }|                      | j        ¦  «        }|                      | j        dz   ¦  «        }d}g }|                      ¦   «         }g }	|D ]_}
d|
› �}|› d�}|› d�}|	                     |
||f¦  «         |                     |› d|
› d	�¦  «         |                     |› d|
› d
�¦  «         Œ`| j        r|                     d|› d�¦  «         |	D ]C\  }
}}|                     d|› d|
› d|› d|
› d�	¦  «         |                     d|› d|› �¦  «         ŒD|                      |¦  «        }|                     d|› d�¦  «         |                     d|› d�¦  «         |                     d¦  «         |                     d¦  «         | j        r3|                     d|› dt          ||¦  «        › d|› d|› d|› d�¦  «         |                     d| j        › d| j        › d �¦  «         |                     d!¦  «         d" 	                    |¦  «        S )#zwBuild the full bash script that sources snapshot, cd's, runs command,
        re-dumps env vars, and emits CWD markers.ú'z'\''rJ  rK  Ú_HERMES_RUNTIME_PASSTHROUGH_Ú_PRESENTÚ_VALUEz=${z+x}z-}zsource z >/dev/null 2>&1 || truezif [ "$z" = x ]; then export z="$z"; else unset z; fizunset r  zbuiltin cd -- z || exit 126zeval 'z__hermes_ec=$?z	umask 077z__hermes_snap_tmp=$(mktemp z) && { z
 && mv -f z; } 2>/dev/null || rm -f z 2>/dev/null || truez
printf '\nrL  z\n' "$(pwd -P)"zexit $__hermes_ecÚ
)
r@   rP  r)  rH  r[   r+  rO  r  r  rG   )r   rg  r  ÚescapedrW  rX  rY  ÚpartsÚpassthrough_namesÚsaved_namesr  ÚmarkerÚpresentÚvalueÚ
quoted_cwds                  r   Ú_wrap_commandzBaseEnvironment._wrap_commandC  s+  € ð —/’/ # wÑ/Ô/ˆð ×-Ò-¨dÔ.AÑBÔBˆð "×3Ò3°DÔ4GÐJ[Ñ4[Ñ\Ô\ÐØ*ˆ	àˆØ ×EÒEÑGÔGÐð 35ˆØ%ð 	2ð 	2ˆDØ:°DÐ:Ð:ˆFØÐ)Ð)Ð)ˆGØÐ%Ð%Ð%ˆEØ×Ò  g¨uÐ5Ñ6Ô6Ð6Ø�LŠL˜GÐ3Ð3¨Ð3Ð3Ð3Ñ4Ô4Ð4Ø�LŠL˜EÐ0Ð0 tÐ0Ð0Ð0Ñ1Ô1Ð1Ð1ð Ôð 	Ø�LŠLØ@˜,Ð@Ð@Ð@ñô ð ð %0ð 	5ð 	5Ñ ˆD�'˜5Ø�LŠLð)˜'ð )ð )¸ð )ð )Àð )ð )Ø"ð)ð )ð )ñô ð ð �LŠLÐ3 'Ð3Ð3¨EÐ3Ð3Ñ4Ô4Ð4Ð4ð ×+Ò+¨CÑ0Ô0ˆ
à�ŠÐ> jÐ>Ð>Ð>Ñ?Ô?Ð?ð 	�ŠÐ(˜gÐ(Ð(Ð(Ñ)Ô)Ð)Ø�ŠÐ%Ñ&Ô&Ð&ð 	�Š�[Ñ!Ô!Ð!ð Ôð 	Ø�LŠLðHÐ.@ð Hð HÝ9¸)ÐEVÑWÔWðHð Hà%ðHð Hà(4ðHð Hð )2ðHð Hð Hñô ð ð 	�ŠØR˜$Ô*ÐRÐR¨dÔ.>ÐRÐRÐRñ	
ô 	
ð 	
ð 	�ŠÐ(Ñ)Ô)Ð)à�yŠy˜ÑÔÐr   c                 ób   — dt          j        ¦   «         j        dd…         › �}| › d|› d|› d|› �S )z;Append stdin_data as a shell heredoc to the command string.ÚHERMES_STDIN_Nr"  z << 'z'
rm  )r$  r%  r&  )rg  r­   Ú	delimiters      r   Ú_embed_stdin_heredocz$BaseEnvironment._embed_stdin_heredoc§  sG   € ð <¥D¤J¡L¤LÔ$4°S°b°SÔ$9Ð;Ð;ˆ	ØÐGÐG 	ÐGÐG¨jÐGÐG¸IÐGÐGÐGr   )Úbounded_capturer•   r{  c          
      ó¸  ‡‡‡‡— |r$	 ddl m}  |¦   «         }n# t          $ r d}Y nw xY wt          }d}|rû	 t	          ¦   «         dz  dz  }|dt          t          j        ¦   «         ¦  «        › dt          j        ¦   «         › dt          ‰¦  «        d	z  d
›d�z  }| 
                    ¦   «         rpt          j        ¦   «         dz
  }|                     d¦  «        D ]D}		 |	                     ¦   «         j        |k     r|	                     ¦   «          Œ5# t          $ r Y ŒAw xY wn# t          $ r d}Y nw xY wt!          ||¬¦  «        Š t#          j        d¦  «        d¬¦  «        Šˆˆfd„Šˆˆˆˆfd„}
t'          j        |
d¬¦  «        }|                     ¦   «          t          j        ¦   «         |z   }t          j        ¦   «         }||dœ}t'          j        ¦   «         j        }t3          ‰dd¦  «        }d}|}d}t5          ¦   «         du }t6          r/t8                               d||||sdndt=          ¦   «         ¦  «         	 d}‰                     ¦   «         �€\|dz  }t=          ¦   «         r•t6          r8t8                               d|||t          j        ¦   «         |d         z
  ¦  «         |                       ‰¦  «         | !                    d ¬!¦  «         |  "                    ‰‰ #                    d"¬#¦  «        d$¦  «        S t          j        ¦   «         |k    r´t6          rt8                               d%||||¦  «         |                       ‰¦  «         | !                    d ¬!¦  «         d&|› d'�}|  "                    ‰‰j$        dk    r(‰ #                    |¬#¦  «         %                    ¦   «         n‰ #                    |¬#¦  «        d(¦  «        S tM          |d)¦  «         t6          r�t          j        ¦   «         |z
  d*k    rvt5          ¦   «         du }t8                               d+|||t          j        ¦   «         |d         z
  t=          ¦   «         |sdnd|r|sd,nd-¦  «         t          j        ¦   «         }|}t          j'        |¦  «         |d.k     rtQ          |d/z  d.¦  «        }‰                     ¦   «         �®\n’# tR          tT          f$ r~ t6          r8t8                               d0|||t          j        ¦   «         |d         z
  ¦  «         	 |                       ‰¦  «         | !                    d ¬!¦  «         n# t          $ r Y nw xY w‚ w xY w| !                    d ¬!¦  «         	 ‰j+         ,                    ¦   «          n# t          $ r Y nw xY wt6          r>t8                               d1|||t          j        ¦   «         |d         z
  ‰j-        ¦  «         t3          ‰d2d¦  «        }|�| !                    d3¬!¦  «         ‰ #                    ¦   «         }|  "                    ‰|‰j-        ¦  «        }t3          ‰d4d¦  «        }|r&t]          |d         ¦  «        }||d5<   |d6|› d7�z   |d8<   |S )9uÛ  Poll-based wait with interrupt checking and stdout draining.

        Shared across all backends â€” not overridden.

        ``bounded_capture=True`` (foreground terminal-tool path only) retains
        at most ``tool_output.max_bytes`` of output in a head/tail window
        while draining, so a verbose subprocess cannot OOM the process
        (#64435). The default (False) preserves full-fidelity capture for
        internal consumers â€” file-operation ``cat`` reads feeding the patch
        engine, code-execution RPC reads, log reads â€” where truncation would
        corrupt data.

        Fires the ``activity_callback`` (if set on this instance) every 10s
        while the process is running so the gateway's inactivity timeout
        doesn't kill long-running commands.

        Also wraps the poll loop in a ``try/finally`` that guarantees we
        call ``self._kill_process(proc)`` if we exit via ``KeyboardInterrupt``
        or ``SystemExit``.  Without this, the local backend (which spawns
        subprocesses with ``os.setsid`` into their own process group) leaves
        an orphan with ``PPID=1`` when python is shut down mid-tool â€” the
        ``sleep 300``-survives-30-min bug Physikal and I both hit.
        r   )Úget_max_bytesiPÃ  NÚcachezterminal-outputzout-Ú-iÿÿ  Úxz.logi€:	 z	out-*.log)r$   r?   r@   rç   c                 ó
  •— 	 | D ]e}|€Œt          |t          ¦  «        r)‰                     ‰                     |¦  «        ¦  «         ŒC‰                     t	          |¦  «        ¦  «         Œfn# t
          $ r Y nw xY w	 ‰                     dd¬¦  «        }|r‰                     |¦  «         d S d S # t
          $ r Y d S w xY w# 	 ‰                     dd¬¦  «        }|r‰                     |¦  «         w w # t
          $ r Y w w xY wxY w)Nr   T©Úfinal)r�   Úbytesr[   Údecoder   r‰   )ÚstreamÚpiecerl   Údecoderrí   s      €€r   Ú_drain_iterablez:BaseEnvironment._wait_for_process.<locals>._drain_iterable  sZ  ø€ ðØ#ð 2ð 2�EØ�}Ø Ý! %­Ñ/Ô/ð 2ØŸš g§n¢n°UÑ&;Ô&;Ñ<Ô<Ð<Ð<àŸš¥c¨%¡j¤jÑ1Ô1Ð1Ð1ð2øõ ð ð ð Ø�ðøøøðØ"Ÿ>š>¨#°T˜>Ñ:Ô:�DØð ,ØŸš dÑ+Ô+Ð+Ð+Ð+ð,ð ,øå ð ð ð Ø�D�Dðøøøøð	Ø"Ÿ>š>¨#°T˜>Ñ:Ô:�DØð ,ØŸš dÑ+Ô+Ð+Ð+ð,øå ð ð ð Ø�Dðøøøøøøs`   ƒA(A, Á+C  Á,
A9Á6C  Á8A9Á9C  Á=.B/ Â/
B=Â<B=Ã DÃ.C2Ã0DÃ2
C?Ã<DÃ>C?Ã?Dc                  óP  •— ‰j         } | €d S t          | dd ¦  «        }	 t          |¦  «        r
 |¦   «         nd }n# t          $ r d }Y nw xY wt	          |t
          ¦  «        r|dk     r ‰| ¦  «         d S t          j        dk    râ	 	 t          j        |d¦  «        }|sn)‰
 	                    ‰	 
                    |¦  «        ¦  «         ŒAn# t          t          f$ r Y nw xY w	 ‰	 
                    dd¬¦  «        }|r‰
 	                    |¦  «         nU# t          $ r Y nIw xY w# 	 ‰	 
                    dd¬¦  «        }|r‰
 	                    |¦  «         w w # t          $ r Y w w xY wxY wd S d}	 	 	 t          j        |gg g d¦  «        \  }}}n# t          t          f$ r Y nƒw xY w|r\	 t          j        |d¦  «        }n# t          t          f$ r Y nSw xY w|snL‰
 	                    ‰	 
                    |¦  «        ¦  «         d}n ‰                     ¦   «         �|d	z  }|d
k    rnŒ´	 ‰	 
                    dd¬¦  «        }|r‰
 	                    |¦  «         d S d S # t          $ r Y d S w xY w# 	 ‰	 
                    dd¬¦  «        }|r‰
 	                    |¦  «         w w # t          $ r Y w w xY wxY w)NÚfilenor   ÚntTé   r   r‚  gš™™™™™¹?r&   é   )r°   r   Úcallabler‰   r�   r)   r�   r  Úreadr[   r…  Ú
ValueErrorrK   ÚselectrÒ   )r†  r‹  Úfdrb   rl   Úidle_after_exitÚreadyro   r‰  rˆ  rí   r•   s           €€€€r   Ú_drainz1BaseEnvironment._wait_for_process.<locals>._drain   s—  ø€ ð ”[ˆFØˆ~Ø�Ý˜V X¨tÑ4Ô4ˆFðÝ!)¨&Ñ!1Ô!1Ð;�V�V‘X”X�X°t��øÝð ð ð Ø���ðøøøå˜b¥#Ñ&Ô&ð ¨"¨qª&¨&Ø� Ñ'Ô'Ð'Ø�õ Œw˜$Šˆðð=Ý "¤¨¨DÑ 1Ô 1˜Ø$ð "Ø!ØŸš g§n¢n°UÑ&;Ô&;Ñ<Ô<Ð<ð	=ð "øå"¥GÐ,ð ð ð Ø�DðøøøðØ&Ÿ~š~¨c¸˜~Ñ>Ô>˜Øð 0Ø"ŸMšM¨$Ñ/Ô/Ð/øøÝ$ð ð ð Ø˜ðøøøøð	Ø&Ÿ~š~¨c¸˜~Ñ>Ô>˜Øð 0Ø"ŸMšM¨$Ñ/Ô/Ð/Ð/ð0øå$ð ð ð Ø˜ðøøøøøøà�ØˆOðð"ðÝ&,¤m°R°D¸"¸bÀ#Ñ&FÔ&F™˜˜q ! !øÝ&­Ð0ð ð ð Ø˜ðøøøàð "ð"Ý$&¤G¨B°Ñ$5Ô$5˜E˜EøÝ *­GÐ4ð "ð "ð "Ø!˜Eð"øøøà$ð "Ø!ØŸš g§n¢n°UÑ&;Ô&;Ñ<Ô<Ð<Ø*+˜˜ØŸš™œÐ0ð (¨1Ñ,˜Ø*¨aÒ/Ð/Ø!ð)"ð2Ø"Ÿ>š>¨#°T˜>Ñ:Ô:�DØð ,ØŸš dÑ+Ô+Ð+Ð+Ð+ð,ð ,øå ð ð ð Ø�D�Dðøøøøð	Ø"Ÿ>š>¨#°T˜>Ñ:Ô:�DØð ,ØŸš dÑ+Ô+Ð+Ð+ð,øå ð ð ð Ø�Dðøøøøøøsû   Ÿ; »A
Á	A
ÂAC	 ÃD  Ã	CÃD  ÃCÃD  Ã!.D Ä
DÄDÄ E"Ä".EÅE"Å
EÅE"ÅEÅE"Å*I# Å,F	 ÆI# Æ	FÆI# ÆFÆI# Æ#F9 Æ8I# Æ9GÇ
I# ÇGÇAI# È .I É
I ÉI É#J%É%.JÊJ%Ê
J"ÊJ%Ê!J"Ê"J%Tr¥   )r…   r_   ÚpidFzg[interrupt-debug] _wait_for_process ENTER tid=%s pid=%s timeout=%ss activity_cb=%s initial_interrupt=%srì   ÚMISSINGg{®Gázt?r&   ut   [interrupt-debug] _wait_for_process INTERRUPT DETECTED tid=%s pid=%s iter=%d elapsed=%.1fs â€” killing process groupr_   rÃ   rþ   z
[Command interrupted]re   é‚   zM[interrupt-debug] _wait_for_process TIMEOUT tid=%s pid=%s iter=%d timeout=%ssz
[Command timed out after zs]é|   zterminal command runningg      >@zo[interrupt-debug] _wait_for_process HEARTBEAT tid=%s pid=%s iter=%d elapsed=%.0fs interrupt=%s activity_cb=%s%sz (LOST during run)r   gš™™™™™É?g      ø?uƒ   [interrupt-debug] _wait_for_process EXCEPTION_EXIT tid=%s pid=%s iter=%d elapsed=%.1fs â€” killing subprocess group before re-raisezd[interrupt-debug] _wait_for_process EXIT (natural) tid=%s pid=%s iter=%d elapsed=%.1fs returncode=%sr©   é   r§   Ústdin_errorz
[stdin write failed: Ú]rí   )/Útools.tool_output_limitsr}  r‰   Ú_UNBOUNDED_CAPTURE_CHARSr   r)   r†   r�   ÚgetpidÚidÚis_dirÚglobrÊ   rË   ÚunlinkrK   r"   ÚcodecsÚgetincrementaldecoderr1   r¨   r_   r‡   Úcurrent_threadÚidentr   r€   Ú_DEBUG_INTERRUPTrE  rS  r   rÒ   Ú_kill_processrG   Ú_finalize_wait_resultrv   rX   ÚlstriprŒ   ÚsleeprZ   ÚKeyboardInterruptÚ
SystemExitr°   rQ   rÝ   r   ) r   r•   rÖ   r{  r}  Úcapture_limitr$   Ú	spill_dirÚcutoffÚoldr–  Údrain_threadÚdeadlineÚ_nowÚ_activity_stateÚ_tidÚ_pidÚ_iter_countÚ_last_heartbeatÚ_last_interrupt_stateÚ_cb_was_noneÚ_poll_sleepÚtimeout_msgÚ_cb_now_noneÚstdin_threadÚrenderedr\  Ústdin_errorsÚerrr‰  rˆ  rí   s     `                           @@@r   rQ  z!BaseEnvironment._wait_for_process±  sŒ  øøøø€ ð4 ð 	5ð'ØBÐBÐBÐBÐBÐBà - ¡¤��øÝð 'ð 'ð 'Ø &���ð'øøøõ 5ˆMØˆ
Øð 	"ð"Ý+Ñ-Ô-°Ñ7Ð:KÑK�	Ø&Ð)jµµD´I±K´KÑ0@Ô0@Ð)jÐ)jÅ2Ä9Á;Ä;Ð)jÐ)jÕQSÐTXÑQYÔQYÐ\bÑQbÐ)jÐ)jÐ)jÐ)jÑj�
à×#Ò#Ñ%Ô%ð !Ý!œY™[œ[¨9Ñ4�FØ(Ÿ~š~¨kÑ:Ô:ð !ð !˜ð!Ø"Ÿxšx™zœzÔ2°VÒ;Ð;Ø #§
¢
¡¤ øøÝ&ð !ð !ð !Ø ˜Dð!øøøøøåð "ð "ð "Ø!�
�
�
ð"øøøå(¨À:ÐNÑNÔNˆð4 8•&Ô.¨wÑ7Ô7¸yÐIÑIÔIˆð	ð 	ð 	ð 	ð 	ð 	ð4F	ð F	ð F	ð F	ð F	ð F	ð F	ð F	õP !Ô'¨v¸dÐCÑCÔCˆØ×ÒÑÔÐÝ”>Ñ#Ô# gÑ-ˆÝŒ~ÑÔˆàØð
ð 
ˆõ Ô'Ñ)Ô)Ô/ˆÝ�t˜U DÑ)Ô)ˆØˆØˆØ %ÐÝ,Ñ.Ô.°$Ð6ˆÝð 	Ý�KŠKðBà�d˜GØ)Ð8��¨yÝÑ Ô ñô ð ðW	ØˆKØ—)’)‘+”+Ñ%Ø˜qÑ �Ý!Ñ#Ô#ð Ý'ð ÝŸšð\à  $¨µT´^Ñ5EÔ5EÈÐX_ÔH`Ñ5`ñô ð ð
 ×&Ò& tÑ,Ô,Ð,Ø ×%Ò%¨aÐ%Ñ0Ô0Ð0Ø×5Ò5ØØŸšÐ-F˜ÑGÔGØñô ð õ
 ”>Ñ#Ô# hÒ.Ð.Ý'ð ÝŸšð@à  $¨°Wñô ð ð
 ×&Ò& tÑ,Ô,Ð,Ø ×%Ò%¨aÐ%Ñ0Ô0Ð0Ø"KÀÐ"KÐ"KÐ"K�KØ×5Ò5Øà!Ô-°Ò2Ð2ð Ÿš¨[˜Ñ9Ô9×@Ò@ÑBÔBÐBà#Ÿ]š]°+˜]Ñ>Ô>Øñô ð õ & oÐ7QÑRÔRÐRõ
 $ð 0­¬Ñ(8Ô(8¸?Ñ(JÈdÒ(RÐ(RÝ#8Ñ#:Ô#:¸dÐ#B�LÝ—K’Kð8ð ˜d KÝœÑ(Ô(¨?¸7Ô+CÑCÝ&Ñ(Ô(Ø%1Ð@˜˜°yØ0<ÐYÀ\ÐYÐ,Ð,ÐWYñ	ô 	ð 	õ '+¤nÑ&6Ô&6�OØ#/�Lõ ”
˜;Ñ'Ô'Ð'Ø Ò$Ð$Ý"% k°CÑ&7¸Ñ"=Ô"=�KðA —)’)‘+”+Ñ%øøõB "¥:Ð.ð 	ð 	ð 	õ  ð Ý—’ðgà˜$ Ý”NÑ$Ô$ °wÔ'?Ñ?ñ	ô ð ðØ×"Ò" 4Ñ(Ô(Ð(Ø×!Ò!¨!Ð!Ñ,Ô,Ð,Ð,øÝð ð ð Ø�ðøøøàð)	øøøð2 	×Ò !ÐÑ$Ô$Ð$ð	ØŒK×ÒÑÔÐÐøÝð 	ð 	ð 	ØˆDð	øøøõ ð 	Ý�KŠKðDà�d˜KÝ”Ñ Ô  ?°7Ô#;Ñ;Ø”ñô ð õ ˜tÐ%;¸TÑBÔBˆØÐ#Ø×Ò aÐÑ(Ô(Ð(Ø—=’=‘?”?ˆØ×+Ò+¨F°H¸d¼oÑNÔNˆÝ˜tÐ%;¸TÑBÔBˆØð 	KÝ�l 1”oÑ&Ô&ˆCØ$'ˆF�=Ñ!Ø'Ð*JÀCÐ*JÐ*JÐ*JÑJˆF�8ÑØˆs”   ˆ ™(§(·B$D Ã1DÄD Ä
DÄD ÄDÄD ÄD.Ä-D.È<B>R0 Ë;C
R0 ÏC)R0 Ò0AT?Ô+T-Ô,T?Ô-
T:Ô7T?Ô9T:Ô:T?ÕU3 Õ3
V Õ?V Ú	collectorr"   rÂ  rÝ   c                 óZ   — ||dœ}|                       ¦   «         }|r| j        |d<   ||d<   |S )zHAssemble a wait result, attaching spill metadata when overflow occurred.)rí   rÝ   Úoutput_total_charsÚfull_output_path)rS   rX   )rÅ  rÂ  rÝ   r\  Úspills        r   r«  z%BaseEnvironment._finalize_wait_result  sH   € ð %°JÐ?Ð?ˆØ×%Ò%Ñ'Ô'ˆØð 	/Ø+4Ô+@ˆFÐ'Ñ(Ø).ˆFÐ%Ñ&Øˆr   c                 ól   — 	 |                      ¦   «          dS # t          t          t          f$ r Y dS w xY w)zDTerminate a process. Subclasses may override for process-group kill.N)rÕ   ÚProcessLookupErrorÚPermissionErrorrK   )r   r•   s     r   rª  zBaseEnvironment._kill_process  sA   € ð	Ø�IŠI‰KŒKˆKˆKˆKøÝ"¥OµWÐ=ð 	ð 	ð 	ØˆDˆDð	øøøs   ‚ ˜3²3r\  c                 ó0   — |                       |¦  «         dS )zDExtract CWD from command output. Override for local file-based read.N)Ú_extract_cwd_from_output)r   r\  s     r   rR  zBaseEnvironment._update_cwd  s   € à×%Ò% fÑ-Ô-Ð-Ð-Ð-r   c                 óB  — |                      dd¦  «        }| j        }|                     |¦  «        }|dk    rdS t          d|dz
  ¦  «        }|                     |||¦  «        }|dk    s||k    rdS ||t	          |¦  «        z   |…                              ¦   «         }|r|| _        |                     dd|¦  «        }|dk    r|}|                     d|t	          |¦  «        z   ¦  «        }	|	dk    r|	dz   nt	          |¦  «        }	|d|…         ||	d…         z   |d<   dS )	zÙParse the __HERMES_CWD_{session}__ marker from stdout output.

        Updates self.cwd and strips the marker from result["output"].
        Used by remote backends (Docker, SSH, Modal, Daytona, Singularity).
        rí   r   éÿÿÿÿNr   r�  rm  r&   )rˆ   r  Úrfindr(   rI   rT  r  Úfind)
r   r\  rí   rr  ÚlastÚsearch_startrd   Úcwd_pathÚ
line_startÚline_ends
             r   rÎ  z(BaseEnvironment._extract_cwd_from_output  s:  € ð —’˜H bÑ)Ô)ˆØÔ!ˆØ�|Š|˜FÑ#Ô#ˆØ�2Š:ˆ:ØˆFõ ˜1˜d T™kÑ*Ô*ˆØ—’˜V \°4Ñ8Ô8ˆØ�BŠ;ˆ;˜% 4š-˜-ØˆFà˜%¥# f¡+¤+Ñ-°Ð4Ô5×;Ò;Ñ=Ô=ˆØð 	 ØˆDŒHð —\’\ $¨¨5Ñ1Ô1ˆ
Ø˜ÒÐØˆJØ—;’;˜t T­C°©K¬KÑ%7Ñ8Ô8ˆØ#+¨r¢> >�8˜a‘<�<µs¸6±{´{ˆà! + : +Ô.°¸¸	¸	Ô1BÑBˆˆxÑÐÐr   c                 ó   — dS )u>  Hook called before each command execution.

        Remote backends (SSH, Modal, Daytona) override this to trigger
        their FileSyncManager.  Bind-mount backends (Docker, Singularity)
        and Local don't need file sync â€” the host filesystem is directly
        visible inside the container/process.
        Nrx   rR   s    r   Ú_before_executezBaseEnvironment._before_executeA  s	   € ð 	ˆr   r   T)rÖ   r­   Úrewrite_compound_backgroundr{  rÚ  c                óì  — |                       ¦   «          |                      |¦  «        \  }}|rddlm}	  |	|¦  «        }|p| j        }
|p| j        }|�|�||z   }n|�|}n|}|r#| j        dk    r|                      ||¦  «        }d}|                      ||¦  «        }| j	         o| j
         }|                      |||
|¬¦  «        }|                      ||
|¬¦  «        }|                      |¦  «         |S )u�  Execute a command, return {"output": str, "returncode": int}.

        ``bounded_capture=True`` caps stdout/stderr retention at
        ``tool_output.max_bytes`` WHILE the stream is drained (head/tail
        window) instead of holding the full output in memory (#64435).
        It must only be set by callers whose output is destined for the
        model/tool payload (the foreground terminal tool). Internal
        full-fidelity consumers â€” file operations ``cat`` reads that feed
        the patch engine, code-execution RPC reads, log reads â€” MUST leave
        it False: truncating those corrupts data, not just display.
        r   )Ú_rewrite_compound_backgroundNÚheredocr0  )rÖ   r{  )rÙ  Ú_prepare_commandÚtools.terminal_toolrÜ  rÖ   r  r  rz  rv  r+  r-  r6  rQ  rR  )r   rg  r  rÖ   r­   rÚ  r{  Úexec_commandÚ
sudo_stdinrÜ  Úeffective_timeoutÚeffective_cwdÚeffective_stdinÚwrappedr1  r•   r\  s                    r   ÚexecutezBaseEnvironment.executeO  s]  € ð* 	×ÒÑÔÐà#'×#8Ò#8¸Ñ#AÔ#AÑ ˆ�jð 'ð 	FØHÐHÐHÐHÐHÐHØ7Ð7¸ÑEÔEˆLØ#Ð3 t¤|ÐØ˜˜tœxˆð Ð! jÐ&<Ø(¨:Ñ5ˆOˆOØÐ#Ø(ˆOˆOà(ˆOð ð 	#˜tÔ/°9Ò<Ð<Ø×4Ò4°\À?ÑSÔSˆLØ"ˆOà×$Ò$ \°=ÑAÔAˆð Ô(Ð(ÐF°Ô1FÐ-Fˆà�~Š~Ø˜5Ð*;Èð ñ 
ô 
ˆð ×'Ò'ØÐ+¸_ð (ñ 
ô 
ˆð 	×Ò˜Ñ Ô Ð àˆr   c                 ó.   — |                       ¦   «          dS )z.Alias for cleanup (compat with older callers).N)r8  rR   s    r   ÚstopzBaseEnvironment.stop‘  s   € à�Š‰Œˆˆˆr   c                 óR   — 	 |                       ¦   «          d S # t          $ r Y d S w xY wrU   )r8  r‰   rR   s    r   Ú__del__zBaseEnvironment.__del__•  s:   € ð	Ø�LŠL‰NŒNˆNˆNˆNøÝð 	ð 	ð 	ØˆDˆDð	øøøs   ‚ ˜
&¥&c                 ó$   — ddl m}  ||¦  «        S )z6Transform sudo commands if SUDO_PASSWORD is available.r   )Ú_transform_sudo_command)rß  rì  )r   rg  rì  s      r   rÞ  z BaseEnvironment._prepare_command›  s%   € à?Ð?Ð?Ð?Ð?Ð?à&Ð& wÑ/Ô/Ð/r   rU   )r/  rÞ   )r   )&r   r   r   r   r  r   Ú__annotations__r  r)   r  Úboolr  Údictr   rÐ   r6  r   r8  r	   r:  rÿ   rH  rb  ÚstaticmethodrO  rP  rv  rz  rQ  r«  rª  rR  rÎ  rÙ  ræ  rè  rê  rÞ  rx   r   r   r  r  E  s  € € € € € € ðð ð €K�ÐÐÑð  Ð�sÐÐÑð
 ).Ð Ð-Ð-Ñ-ð˜cð ð ð ð ð&ð &˜Cð &¨#ð &°Dð &ð &ð &ð &ð2 ØØ!%ðWð Wð WàðWð ð	Wð
 ðWð ˜$‘JðWð 
ðWð Wð Wð Wð ðð ñ „^ðð¸hÀs¼mð ð ð ð ð?°e¸CÀ¸H´oð ?ð ?ð ?ð ?ð<yð yð yð~ ð ˜sð   sð  ð  ð  ñ „\ð ð! cð !¨cð !ð !ð !ð !ð^  Sð ^ ¨sð ^ °sð ^ ð ^ ð ^ ð ^ ðH ðH cð H°sð H¸sð Hð Hð Hñ „\ðHð 36ðNØRWðNð Nð NØ!ðNØ,/ðNØKOðNà	ðNð Nð Nð Nð`
 ðÐ)Bð Ø(+ðØ9<¸t¹ðØHLðð ð ñ „\ðð -ð ð ð ð ð. $ð .ð .ð .ð .ð C¨tð  Cð  Cð  Cð  CðLð ð ð ð" ð<ð
 #Ø!%Ø,0Ø %ð<ð <ð <àð<ð ð<ð
 �t‘ð<ð ˜$‘Jð<ð &*ð<ð ð<ð 
ð<ð <ð <ð <ðDð ð ðð ð ð0¨ð 0°°c¸3À¹:°oÔ0Fð 0ð 0ð 0ð 0ð 0ð 0r   r  rU   )rx   )Dr   r¥  r¾   Úloggingr�   Úrer’  r  r³   r1   r†   r$  Úabcr   r   Úcollectionsr   Úpathlibr   Útypingr   r   r	   r
   Úhermes_constantsr   Úhermes_cli._subprocess_compatr   Útools.interruptr   Ú	getLoggerr   rE  rî  r‘   r©  ÚsetLevelÚINFOÚlocalr{   rŸ  rœ   r   r"   r   r}   r€   rï  rŒ   r”   r´   r«   Úlistr¹   rÁ   rÇ   rÿ   rß   r)   rÎ   rÐ   rá   r  Ú_SNAPSHOT_EXCLUDED_ENV_REGEXÚcompiler?  r  r  rx   r   r   ú<module>r     sŠ  ððð ð €€€Ø €€€Ø €€€Ø 	€	€	€	Ø 	€	€	€	Ø €€€Ø €€€Ø Ð Ð Ð Ø Ð Ð Ð Ø €€€Ø €€€Ø #Ð #Ð #Ð #Ð #Ð #Ð #Ð #Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3à ,Ð ,Ð ,Ð ,Ð ,Ð ,Ø <Ð <Ð <Ð <Ð <Ð <Ø *Ð *Ð *Ð *Ð *Ð *à	ˆÔ	˜8Ñ	$Ô	$€ð �4˜	˜œ	Ð":Ñ;Ô;Ñ<Ô<Ð àð "ð
 ‡O‚O�G”LÑ!Ô!Ð!ð +˜9œ?Ñ,Ô,Ð ð %Ð ð
ð 
ð 
ð 
ð 
 ñ 
ô 
ð 
ð4USð USð USð USð USñ USô USð USðp+˜h¨ u¨d {Ô3°dÑ:ð +¸tð +ð +ð +ð +ð
?˜x¨¨¨t¨Ô4°tÑ;ð ?ð ?ð ?ð ?ðØðàðð 
ðð ð ð ð4˜ð ð ð ð ð(;�jÔ&ð ;¨cð ;°dð ;ð ;ð ;ð ;ð~ .2ðð Ø	ˆcŒðØ # d¡
ðàÔðð ð ð ð.˜4ð  Dð ð ð ð ðB˜4ð B tð B°ð Bð Bð Bð Bð˜sð  u¨U°C¨ZÔ'8¸4Ñ'?ð ð ð ð ð,ð ,ð ,ð ,ð ,�Hñ ,ô ,ð ,ð$B ð B ð B ð B ð B ñ B ô B ð B ðT*˜Cð * Cð *ð *ð *ð *ð. gð ð  �R”ZÐ ;Ñ<Ô<Ð ð
 %'ð+ð +Øð+à˜S”Mð+ð 	ð+ð +ð +ð +ðfZ0ð Z0ð Z0ð Z0ð Z0�cñ Z0ô Z0ð Z0ð Z0ð Z0r   