+
    lHàjc›  ã                   óô  a € R/ tL0 t R t^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
HtHt ^ RIHt ^ RIHtHt ^ RIHt ^ RIHtHtHt ^ RIHtHtHtHt ^ RIHtHtH t H!t!H"t"H#t# ^ R	I$H%t% ^ R
I&H't'H(t(H)t) ]PT                  ! ]+4      t,](! R4      t-Rt.]-'       d   ],P_                  ]P`                  4       ]Pb                  ! 4       t2/ t3] ^ k ]Ph                  ! ]Pj                  ! 4       4      t6Rs7^ s8Rt9R R lt:R R lt;R R lt<RR/R R llt= ! R R]>4      t?Rt@ ! R R]>4      tAR R ltBR R  ltCR! R" ltDR# R$ ltER% R& ltFR' R( ltG]Pb                  ! 4       tHR) R* ltIR+ R, ltJ ! R- R.]4      tKR# )0a³  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). Cohesive pieces live in sibling modules (``base_output``,
``base_session_env``, ``base_wait``, ``path_utils``).
N)ÚABCÚabstractmethod©ÚPath)ÚCallableÚIterable)Úget_hermes_home)Úconsume_yieldÚis_interruptedÚis_thread_interrupted)ÚProcessHandleÚ_finalize_wait_resultÚ_new_output_collectorÚ_start_drain_thread)Ú_SHELL_ENV_NAME_REÚ_SNAP_TMP_SUFFIXÚ_cwd_markerÚ_snapshot_bootstrap_scriptÚ_split_cwd_markerÚ_wrap_command_script)Ú
_WaitTrace)Úatomic_json_writeÚenv_var_enabledÚfile_signatureÚHERMES_DEBUG_INTERRUPTg       @Fg      à?c                ó$   € V ^8„  d   QhR\         /# ©é   Úreturn©Úbool)Úformats   "Ú</home/ubuntu/.hermes/hermes-agent/tools/environments/base.pyÚ__annotate__r#   D   s   € ÷ ñ ¤ñ ó    c                  ó¦   € \         ;_uu_ 4        \        '       d    R R R 4       R# \        ^,          s R R R 4       R#   + '       g   i     R # ; i)NFT)Ú_live_foreground_condÚ_exit_fencedÚ_spawns_in_flight© r$   r"   Ú_enter_foreground_spawnr*   D   s7   € ç	Ö	ß‹<Ø÷ 
Ñ	ô 	˜QÕÐØ÷	 
×	×	Ò	ús   �?§?¿A	c                ó(   € V ^8„  d   QhRRR\         /# )r   ÚenvÚBaseEnvironmentr   r   )r!   s   "r"   r#   r#   M   s   € ÷ ñ Ð!2ð Äñ r$   c                óØ   € \         ;_uu_ 4        \        ^,          sVe   W3\        \        V4      &   \         P	                  4        \
        uuRRR4       #   + '       g   i     R# ; i)zYPublish ``spawned`` (None: the spawn failed); True when the exit fence went up meanwhile.N)r&   r(   Ú_live_foregroundÚidÚ
notify_allr'   )r,   Úspawneds   &&r"   Ú_leave_foreground_spawnr3   M   sJ   € ÷ 
Ö	Ü˜QÕÐØÒØ-0¨NÔœR ›[Ñ)Ü×(Ñ(Ô*Ü÷ 
×	×	Ó	ús   �>AÁA)	c                ó(   € V ^8„  d   QhR\         RR/# )r   Úkillr   N)r   )r!   s   "r"   r#   r#   X   s   € ÷ Uñ U”hð U¨ñ Ur$   c                 ój   €  V ! V4       R#   \          d    \        P                  R RR7        R# i ; i)z-exit-time kill of a foreground command failedT©Úexc_infoN)Ú	ExceptionÚloggerÚdebug)r5   Úprocs   &&r"   Ú_quiet_killr=   X   s1   € ðUÙˆTŽ
øÜô UÜ�‰ÐDÈtˆ×TðUús   ‚ Œ"2±2Únowc                ó0   € V ^8„  d   QhR\         R\        /# )r   r>   r   )r    Úint)r!   s   "r"   r#   r#   _   s   € ÷ "ñ "¬4ð "¼Cñ "r$   c           	     ó€  € V '       ga   \         ;_uu_ 4        \        \        P                  4       4      pRRR4       X F  w  r#\	        VP
                  V4       K  	  \        V4      # \        P                  ! 4       \        ,           pRs
\         P                  \        R7      '       do    \         P                  R \        RV\        P                  ! 4       ,
          4      4       \        \        P                  4       4      p\         P                  4        M\        \        P                  4       4      p. pV FŒ  w  r#\        V\         P"                  4      '       d   \	        VP$                  V4       K=  VP'                  \(        P*                  ! \        VP$                  V3RR7      4       VR,          P-                  4        KŽ  	  V F8  pVP/                  \        RV\        P                  ! 4       ,
          4      4       K:  	  \        V4      #   + '       g   i     ELç; i  \         P                  4        i ; i)a  Kill every in-flight foreground command's process tree; returns how many were signalled.

``now=True`` is for a caller about to ``os._exit``: the graceful kill TERMs, waits and only then
KILLs, so a SIGTERM-ignoring command outlives a hard exit that lands inside that window. It also
raises the exit fence and waits for spawns already past it to register, so no command started
around the snapshot survives, and it never blocks past ``_HARD_KILL_BUDGET_S``: SDK cancels
(Modal, Daytona, Vercel) run on daemon threads under that one deadline.NT©Útimeoutc                  ó   € \         ^ 8H  # )é    )r(   r)   r$   r"   Ú<lambda>Ú0kill_live_foreground_processes.<locals>.<lambda>r   s
   € Ô3DÈÒ3Ir$   g        )ÚtargetÚargsÚdaemonéÿÿÿÿ)r&   Úlistr/   Úvaluesr=   Ú_kill_processÚlenÚtimeÚ	monotonicÚ_HARD_KILL_BUDGET_Sr'   ÚacquireÚwait_forÚmaxÚreleaseÚ
isinstanceÚ
subprocessÚPopenÚ_force_kill_processÚappendÚ	threadingÚThreadÚstartÚjoin)r>   Úliver,   r<   ÚdeadlineÚremoteÚts   $      r"   Úkill_live_foreground_processesrd   _   s•  € ÷ ß"Ö"ÜÔ(×/Ñ/Ó1Ó2ˆD÷ #ã‰IˆCÜ˜×)Ñ)¨4Ö0ñ ä�4‹yÐÜ�~Š~ÓÔ"5Õ5€HØ€LÜ×$Ñ$Ô-@Ð$×AÒAð	,Ü!×*Ñ*Ñ+IÌ3ÈsÐT\Ô_c×_mÒ_mÓ_oÕToÓKpÔqÜÔ(×/Ñ/Ó1Ó2ˆDä!×)Ñ)Õ+äÔ$×+Ñ+Ó-Ó.ˆØ€FÛ‰	ˆÜ�dœJ×,Ñ,×-Ò-Ü˜×/Ñ/°Ö6à�M‰Mœ)×*Ò*´+ÀS×E\ÑE\Ð^bÐDcÐlpÔqÔrØ�2�J×ÑÖñ ó ˆØ	�‰Œs�3˜¤4§>¢>Ó#3Õ3Ó4Ö5ñ äˆt‹9Ð÷1 #×"Ð"ûô "×)Ñ)Õ+ús   —HÂ,AH' ÈH$	È'H=c                   ó   € ] tR t^„tRtRtR# )ÚFileFetchErrorz:A file could not be extracted from the backend filesystem.r)   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__static_attributes__r)   r$   r"   rf   rf   „   s   † ÝDr$   rf   i,  c                   óJ   a a€ ] tR t^Œt oRtRR/V3R lV 3R llltRtVtV ;t# )ÚEnvironmentConnectionErroruš  Infrastructure/connection-class failure of a terminal backend (SSH host down, Docker
daemon not running, remote sync on a dead link) â€” never a command that merely exited
nonzero. Subclassing RuntimeError keeps every ``except RuntimeError`` catcher working.
``terminal_tool`` turns this into a structured ``status: "degraded"`` result; the failed
backend is never cached, so a later call retries from scratch.Ú
retry_hintÚ c                ó&   <€ V ^8„  d   QhRS[ RS[ /# )r   Úreasonro   ©Ústr)r!   Ú__classdict__s   "€r"   r#   Ú'EnvironmentConnectionError.__annotate__“   s   ø€ ÷ 3ñ 3™sð 3±3ñ 3r$   c               óT   <€ \         SV `  V4       Wn        T;'       g    R V n        R# )uÒ   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.N)ÚsuperÚ__init__rr   ro   )Úselfrr   ro   Ú	__class__s   &&$€r"   ry   Ú#EnvironmentConnectionError.__init__“   s.   ø€ Ü‰Ñ˜Ô ØŒØ$÷ 3ð 3ð2ð 	Žr$   )rr   ro   )	rg   rh   ri   rj   rk   ry   rl   Ú__classdictcell__Ú__classcell__)r{   ru   s   @@r"   rn   rn   Œ   s!   ù‡ € ñFð3¸÷ 3÷ 3õ 3r$   rn   c                óR   € V ^8„  d   QhR\         \        .R3,          R,          RR/# )r   ÚcbNr   ©r   rt   )r!   s   "r"   r#   r#   �   s*   € ÷ +ñ +œh¬ u¨d {Õ3°dÕ:ð +¸tñ +r$   c                ó   € V \         n        R# )z>Register a callback that _wait_for_process fires periodically.N)Ú_activity_callback_localÚcallback)r€   s   &r"   Úset_activity_callbackr…   �   s   € à(*ÔÖ%r$   c                óN   € V ^8„  d   QhR\         \        .R3,          R,          /# ©r   r   Nr�   )r!   s   "r"   r#   r#   ¢   s#   € ÷ ?ñ ?œx¬¨¨t¨Õ4°tÕ;ñ ?r$   c                 ó$   € \        \        RR4      # )u]  Thread-local activity callback; capture it before handing work to another thread.

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ƒ   r)   r$   r"   Úget_activity_callbackrŠ   ¢   s   € ô Ô+¨Z¸Ó>Ð>r$   c                ó4   € V ^8„  d   QhR\         R\        RR/# )r   ÚstateÚlabelr   N)Údictrt   )r!   s   "r"   r#   r#   ¬   s&   € ÷ ^ñ ^¤ð ^¬cð ^°dñ ^r$   c           	     óH  € \         P                  ! 4       pW R,          ,
          V P                  RR4      8  d   R# W R&    \        4       pV'       d'   V! V R\	        W R,          ,
          4       R24       R# R#   \
         d    \        P                  RR	R
7        R# i ; i)z©Fire the activity callback at most once every ``state['interval']`` (default 10 s).
*state* holds ``last_touch``/``start`` monotonic timestamps. Swallows all exceptions.Ú
last_touchÚintervalç      $@Nz (r^   z
s elapsed)z6activity callback failed during a long-running commandTr7   )rP   rQ   ÚgetrŠ   r@   r9   r:   r;   )rŒ   r�   r>   r€   s   &&  r"   Útouch_activity_if_duer”   ¬   s‘   € ô �.Š.Ó
€CØ
�<Õ Õ  5§9¡9¨Z¸Ó#>Ô>ÙØˆ,Ñð^Ü"Ó$ˆßÙ�%�˜œ3˜s¨7¥^Õ3Ó4Ð5°ZÐ@ÖAñ øäô ^Ü�‰ÐMÐX\ˆ×]ð^ús   Á6A; Á;"B!Â B!c                ó$   € V ^8„  d   QhR\         /# r   r   )r!   s   "r"   r#   r#   »   s   € ÷ ñ œñ r$   c                 ó    € \         P                  ! R4      p V '       d   \        V 4      M\        4       R,          pVP	                  RRR7       V# )z�Host-side root for all sandbox storage (Docker workspaces, plugin backends'
host-side state). ``TERMINAL_SANDBOX_DIR`` overrides ``{HERMES_HOME}/sandboxes``.ÚTERMINAL_SANDBOX_DIRÚ	sandboxesT©ÚparentsÚexist_ok)ÚosÚgetenvr   r   Úmkdir)ÚcustomÚps     r"   Úget_sandbox_dirr¡   »   s=   € ô �YŠYÐ-Ó.€FßŒˆVŒ¤OÓ$5¸Õ$C€AØ‡G�G�D 4€GÔ(Ø€Hr$   c                ó0   € V ^8„  d   QhR\         R\        /# ©r   Úpathr   ©r   rŽ   )r!   s   "r"   r#   r#   Ä   s   € ÷ 2ñ 2œ4ð 2¤Dñ 2r$   c                ó¶   €  \         P                  ! V P                  RR7      4      p\        T\        4      '       d   T# / #   \        \        3 d    / u # i ; i)z3Treat a missing or damaged snapshot store as empty.z	utf-8-sig)Úencoding)ÚjsonÚloadsÚ	read_textÚOSErrorÚ
ValueErrorrW   rŽ   ©r¤   Údatas   & r"   Ú_load_json_storer¯   Ä   sT   € ðÜ�zŠz˜$Ÿ.™.°+˜.Ó>Ó?ˆô ˜d¤D×)Ò)ˆ4Ð1¨rÐ1øô ”ZÐ ô ØŠ	ðús   ‚&A ÁAÁAc                ó4   € V ^8„  d   QhR\         R\        RR/# )r   r¤   r®   r   Nr¥   )r!   s   "r"   r#   r#   Í   s!   € ÷ ,ñ ,œ4ð ,¤tð ,°ñ ,r$   c                óZ   € V P                   P                  RRR7       \        W^R7       R# )zYWrite *data* as pretty-printed JSON to *path* atomically (readers never see a torn file).Tr™   )ÚindentN)Úparentrž   r   r­   s   &&r"   Ú_save_json_storer´   Í   s#   € à‡K�K×Ñ˜d¨TÐÔ2Ü�d¨×+r$   c                óP   € V ^8„  d   QhR\         R\        \        .R3,          RR/# )r   r¤   ÚupdateNr   )r   r   rŽ   )r!   s   "r"   r#   r#   Ö   s,   € ÷ )ñ )œTð )¬8´T°F¸D°LÕ+Að )Àdñ )r$   c                ó´  € ^ RI Hp ^ RIHp V P	                  V P
                   R24      pV! 4       ;_uu_ 4       p VP                  V! V\        RRV  R24      4       \        V 4      p\        V4      pV! V4       Wg8w  d   \        W4       R
R
R
4       R
#   \        \        3 d    \        P                  RT RR	7        Ldi ; i  + '       g   i     R
# ; i)a­  Read-modify-write the JSON store at *path* under a cross-process lock.

Concurrent sandbox cleanups (delegate children, gateway sessions, the idle reaper) each
record a snapshot id; an unlocked load/mutate/save lets one cleanup drop the other's entry.
An unusable lock (no flock on the filesystem, a wedged holder) degrades to an unlocked
update: a sandbox lifecycle step (modal's restore fallback included) must not abort on it.)Ú	ExitStack)Ú
_file_lockz.lockr’   z/Timed out waiting for the snapshot store lock (Ú)zUpdating %s without its lockTr7   N)Ú
contextlibr¸   Úhermes_cli.authr¹   Ú	with_nameÚnameÚenter_contextÚ_JSON_STORE_LOCK_HOLDERr«   ÚTimeoutErrorr:   Úwarningr¯   rŽ   r´   )r¤   r¶   r¸   r¹   Ú	lock_pathÚstackr®   Úbefores   &&      r"   Ú_update_json_storerÆ   Ö   sÃ   € õ %å*à—‘ $§)¡) ¨EÐ2Ó3€IÙ	�Œ˜ð	PØ×Ñ¡
ØÔ2°DÐ<kÐlpÐkqÐqrÐ:só!ô ô
   Ó%ˆÜ�d“ˆÙˆtŒØŒ>Ü˜TÔ(÷ 
‰øô
 œÐ&ô 	PÜ�N‰NÐ9¸4È$ˆNÖOð	Pú÷ 
�ˆús.   ºC¼"BÁ/CÂ)CÃ CÃCÃCÃC	c                ót   € V ^8„  d   QhR\         R\        \        \        \        \        3,          R,          /# )r   Ú	host_pathr   N)rt   Útupler@   )r!   s   "r"   r#   r#   ð   s-   € ÷ ñ œsð ¤u¬S´#´s¼CÐ-?Õ'@À4Õ'Gñ r$   c                ól   €  \        \        V 4      P                  4       4      #   \         d     R# i ; i)zÐReturn the ``file_signature`` change key, or ``None`` if unreadable.

mtime + size alone miss a same-size credential refresh landing in the same mtime tick;
inode and ctime catch the atomic replace / rewrite.N)r   r   Ústatr«   )rÈ   s   &r"   Ú_file_mtime_keyrÌ   ð   s1   € ð
Üœd 9›o×2Ñ2Ó4Ó5Ð5øÜô Úðús   ‚!$ ¤3²3c                   ó²  a € ] tR tRt o RtRtRt^tRtRt	Rt
V 3R lR ltRHV 3R	 lR
 lltRRR^xRR/V 3R lR llt]R 4       tV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltV 3R lR ltR tV 3R lR lt]V 3R lR l4       tV 3R  lR! ltV 3R" lR# lt]V 3R$ lR% l4       tV 3R& lR' lt]V 3R( lR) l4       tRIR*RR+RR,RR-R/V 3R. lR/ lllt]! ]4      tV 3R0 lR1 lt V 3R2 lR3 lt!V 3R4 lR5 lt"V 3R6 lR7 lt#V 3R8 lR9 lt$V 3R: lR; lt%RJRRRRR<RR*RR-R/V 3R= lR> lllt&V 3R? lR@ lt'RA t(V 3RB lRC lt)^t*V 3RD lRE lt+V 3RF lt,RGt-V t.R# )Kr-   é   zîCommon interface and unified execution flow for all Hermes backends. Subclasses
implement ``_run_bash()`` and ``cleanup()``; the base provides ``execute()`` with
snapshot sourcing, CWD tracking, interrupt handling and timeout enforcement.ÚpipeFTc                ó    <€ V ^8„  d   QhRS[ /# r   rs   )r!   ru   s   "€r"   r#   ÚBaseEnvironment.__annotate__  s   ø€ ÷ ñ ™cñ r$   c                ó   € R# )züReturn the backend temp directory used for session artifacts.

Most sandboxed backends use ``/tmp`` inside the target environment.
LocalEnvironment overrides this on hosts where ``/tmp`` may be missing
and ``TMPDIR`` is the portable writable location.
z/tmpr)   ©rz   s   &r"   Úget_temp_dirÚBaseEnvironment.get_temp_dir  s   € ñ r$   Nc                ó@   <€ V ^8„  d   QhRS[ RS[RS[R,          RS[/# )r   ÚcwdrC   r,   NÚpersist_env)rt   r@   rŽ   r    )r!   ru   s   "€r"   r#   rÑ   (  s.   ø€ ÷ &ñ &™Cð &©#ð &±D¸4µKð &ÑUYñ &r$   c                ó¾  € Wn         W n        T;'       g    / V n        W@n        \        P
                  ! 4       P                  R ,          V n        V P                  4       P                  R4      ;'       g    RpV RV P                   R2V n
        V RV P                   R2V n        \        V P                  4      V n        RV n        \        4       V n        RV n        R# )ºNé   NÚ/z/hermes-snap-z.shz/hermes-cwd-z.txtFN)r×   rC   r,   Ú_persist_envÚuuidÚuuid4ÚhexÚ_session_idrÔ   ÚrstripÚ_snapshot_pathÚ	_cwd_filer   Ú_snapshot_readyÚsetÚ_snapshot_passthrough_namesÚ_prefer_nonlogin)rz   r×   rC   r,   rØ   Útemp_dirs   &&&&& r"   ry   ÚBaseEnvironment.__init__(  sÁ   € ØŒØŒØ—9�9˜"ˆŒð (ÔäŸ:š:›<×+Ñ+¨CÕ0ˆÔØ×$Ñ$Ó&×-Ñ-¨cÓ2×9Ð9°cˆØ!) 
¨-¸×8HÑ8HÐ7IÈÐMˆÔØ$˜: \°$×2BÑ2BÐ1CÀ4ÐHˆŒÜ& t×'7Ñ'7Ó8ˆÔØ$ˆÔÜ58³UˆÔ(ð !&ˆÖr$   ÚloginrC   Ú
stdin_datac          
      óF   <€ V ^8„  d   QhRS[ RS[RS[RS[ R,          RS[/# )r   Ú
cmd_stringrë   rC   rì   Nr   )rt   r    r@   r   )r!   ru   s   "€r"   r#   rÑ   <  sB   ø€ ÷ Wñ WÙðWÙ)-ðWÙ@CðWÙWZÐ]aÕWaðWá	ñWr$   c               óD   € \        \        V 4      P                   R24      h)zGSpawn a bash process to run *cmd_string*; every backend overrides this.z must implement _run_bash())ÚNotImplementedErrorÚtyperg   )rz   rî   rë   rC   rì   s   &&$$$r"   Ú	_run_bashÚBaseEnvironment._run_bash<  s"   € ô "¤T¨$£Z×%8Ñ%8Ð$9Ð9TÐ"UÓVÐVr$   c                ó   € R# )z<Release backend resources (container, instance, connection).Nr)   rÓ   s   &r"   ÚcleanupÚBaseEnvironment.cleanupB  s   € ñ 	r$   c                ó0   <€ V ^8„  d   QhRS[ RS[RS[RR/# )r   Úremote_pathÚ
local_destÚ	max_bytesr   N)rt   r   r@   )r!   ru   s   "€r"   r#   rÑ   H  s*   ø€ ÷ +ñ +¡cð +±tð +É3ð +ÐSWñ +r$   c               óf  € ^ RI p^ RIpR\        P                  ! 4       P                  R,           R2p\
        P                  ! V4      pV P                  RV RV RV^,            RV R	V 2
\        R
R7      pVP                  R4      ;'       g    Rp	V	P                  V4      V	P                  V4      rº\        VP                  R4      ;'       g    ^ 4      ^ 8w  g   V
R8X  g   Wº8:  d   \        RV: R24      h VP                  RP                  Wš\!        V4      ,           V P#                  4       4      RR7      p\!        T4      T8”  d   \        T: RTR,           R24      h\)        T4      P+                  T4       R#   \$        TP&                  3 d   p\        RT: RT 24      ThRp?ii ; i)u   Copy a regular file out of the backend filesystem to ``local_dest`` on the host.

One transport for every backend: base64 over the exec channel, bounded INSIDE the sandbox
(``head -c max+1`` so /dev/zero can't stream unbounded data into host memory â€” the same
shape ``tools.image_source`` uses to read sandbox images). The payload is fenced between
unique markers so login-shell noise in the merged stdout/stderr can't corrupt the decode.
Raises :class:`FileFetchError` on a missing/unreadable/oversized file.
NÚ__HERMES_FETCH_rÚ   Ú__z[ -f z ] && echo z && head -c z < z | base64 && echo F)rC   Úrewrite_compound_backgroundÚoutputrp   Ú
returncodezcould not read z< in the sandbox (missing, not a regular file, or unreadable)T)Úvalidateztransfer of z was corrupted in transit: z exceeds the z MB delivery limitrK   i   )Úbase64ÚbinasciirÞ   rß   rà   ÚshlexÚquoteÚexecuteÚ_FETCH_TIMEOUT_SECONDSr“   ÚfindÚrfindr@   rf   Ú	b64decoder_   rO   Úsplitr¬   ÚErrorr   Úwrite_bytes)rz   rø   rù   rú   r  r  ÚmarkerÚquotedÚresultrÿ   ÚfirstÚlastr®   Úexcs   &&&$          r"   Ú
fetch_fileÚBaseEnvironment.fetch_fileH  s¡  € ó 	ÛØ"¤4§:¢:£<×#3Ñ#3°CÕ#8Ð"9¸Ð<ˆÜ—’˜[Ó)ˆð —‘Ø�F�8˜; v h¨l¸9Àq½=¸/ÈÈVÈHÐTfÐgmÐfnÐoÜ*Èð ó Oˆð —‘˜HÓ%×+Ð+¨ˆØ—k‘k &Ó)¨6¯<©<¸Ó+?ˆtÜˆv�z‰z˜,Ó'×,Ð,¨1Ó-°Ô2°e¸r´kÀTÄ]Ü  ?°;±/ÐA}Ð!~ÓÐð	jØ×#Ñ# B§G¡G¨F¼3¸v»;Õ3FÀtÐ,L×,RÑ,RÓ,TÓ$UÐ`dÐ#ÓeˆDô ˆt‹9�yÔ Ü  K¡?°-À	ÈkÕ@ZÐ?[Ð[mÐ!nÓoÐoÜˆZÓ×$Ñ$ TÖ*øô	 ˜HŸN™NÐ+ô 	jÜ  <°©Ð>YÐZ]ÐY^Ð!_Ó`ÐfiÐiûð	jús   Ã:AF ÆF0ÆF+Æ+F0c                ó4   <€ V ^8„  d   QhRS[ RS[ R,          /# )r   rø   r   Nrs   )r!   ru   s   "€r"   r#   rÑ   f  s#   ø€ ÷ Dñ D©#ð D±#¸µ*ñ Dr$   c                ó4  € V P                  R\        P                  ! V4       R2RR7      p\        VP	                  R4      ;'       g    ^ 4      ^ 8w  d   R# \        R \        VP	                  R4      ;'       g    R	P                  4       4       4       R4      # )
zG``readlink -f`` inside the backend, or None when it cannot be resolved.zreadlink -f z 2>/dev/nullF)rþ   r   Nc              3   óŽ   "  € T F;  qP                  4       P                  R 4      '       g   K)  VP                  4       x € K=  	  R# 5i)rÜ   N)ÚstripÚ
startswith)Ú.0Úlns   & r"   Ú	<genexpr>Ú1BaseEnvironment.fetch_realpath.<locals>.<genexpr>k  s1   é € Ð|Ñ*] B×aiÑaiÓak×avÑavÐwz×a{”Z�R—X‘X—Z�ZÓ*]ùs
   ‚&A­Arÿ   rp   )r  r  r  r@   r“   ÚnextÚreversedÚ
splitlines)rz   rø   r  s   && r"   Úfetch_realpathÚBaseEnvironment.fetch_realpathf  s†   € à—‘ ¬U¯[ª[¸Ó-EÐ,FÀlÐSÐqv�ÓwˆÜˆv�z‰z˜,Ó'×,Ð,¨1Ó-°Ô2ÙÜÑ|¬(°F·J±J¸xÓ4H×4NÐ4NÈB×3ZÑ3ZÓ3\Ô*]Ó|ð  Có  Dð  	Dr$   c                ó0   <€ V ^8„  d   QhRS[ S[,          /# r   )r   rt   )r!   ru   s   "€r"   r#   rÑ   n  s   ø€ ÷ ñ ¹hÁs½mñ r$   c                ó   € R# )zAReturn backend-specific names that must not persist in snapshots.r)   r)   rÓ   s   &r"   Ú,_additional_profile_scoped_passthrough_namesÚ<BaseEnvironment._additional_profile_scoped_passthrough_namesn  s   € àˆ	r$   c                ó4   <€ V ^8„  d   QhRS[ S[R3,          /# )r   r   .)rÉ   rt   )r!   ru   s   "€r"   r#   rÑ   r  s   ø€ ÷ ?ñ ?±e¹CÀ¸Hµoñ ?r$   c                ób  € V P                   '       g   R#  ^ RIHp V! 4       '       dC   ^ RIHp . V! 4       OV P                  4       O5pV P                  P                  R V 4       4       \        \        T P                  4      4      #   \         d    \        P                  RRR7        LBi ; i)zíProfile-scoped names that must not persist in the snapshot. Monotonic for the
environment lifetime: an allowlist can be cleared after a value was captured, and
retaining the exclusion keeps that old value from leaking to a later profile.)Úis_multiplex_active)Úget_all_passthroughc              3   ó’   "  € T F=  p\        V\        4      '       g   K  \        P                  ! V4      '       g   K9  Vx € K?  	  R # 5i©N)rW   rt   r   Ú	fullmatch)r  r¾   s   & r"   r  ÚGBaseEnvironment._snapshot_excluded_passthrough_names.<locals>.<genexpr>}  s0   é € ð 8lÙ%*˜T¬j¸¼s×.C”DÔHZ×HdÒHdÐei×Hj—D’D£Uùs   ‚AŸA½
Az4Could not refresh profile-scoped snapshot exclusionsTr7   r)   )Ú_profile_scoped_passthroughÚagent.secret_scoper*  Útools.env_passthroughr+  r&  rç   r¶   r9   r:   r;   rÉ   Úsorted)rz   r*  r+  Únamess   &   r"   Ú$_snapshot_excluded_passthrough_namesÚ4BaseEnvironment._snapshot_excluded_passthrough_namesr  s§   € ð ×/×/Ð/ØˆIð	`Ý>Ù"×$Ò$ÝEØfÑ-Ó/Ðf°$×2cÑ2cÓ2eÑf�Ø×0Ñ0×7Ñ7ñ 8lÙ%*ó8lô lô ”V˜D×<Ñ<Ó=Ó>Ð>øô ô 	`Ü�L‰LÐOÐZ^ˆLÖ_ð	`ús   –B	 ©AB	 Â	"B.Â-B.c                ó&   <€ V ^8„  d   QhRS[ RS[/# ©r   r×   r   )rt   rŽ   )r!   ru   s   "€r"   r#   rÑ   ƒ  s   ø€ ÷ )ñ )©3ð )±4ñ )r$   c                óÌ   € \        V P                  V4      V P                  V P                  4      V P                  V P                  \        ,           4      V P
                  R7      # )zñQuoting inputs shared by the bootstrap and per-command wrapper scripts.
``_quote_cwd_for_cd`` / ``_quote_shell_path`` (not bare shlex.quote) let the Windows
subclass rewrite ``C:\...`` to ``/c/...`` so ``cd`` resolves and MSYS doesn't choke.)Ú
quoted_cwdÚquoted_snapÚsnap_tmp_templateÚ
cwd_marker)rŽ   Ú_quote_cwd_for_cdÚ_quote_shell_pathrã   r   r   )rz   r×   s   &&r"   Ú_snapshot_script_kwargsÚ'BaseEnvironment._snapshot_script_kwargsƒ  sV   € ô Ø×-Ñ-¨cÓ2Ø×.Ñ.¨t×/BÑ/BÓCØ"×4Ñ4°T×5HÑ5HÔK[Õ5[Ó\Ø×'Ñ'ô	)ð 	)r$   c                ó.  € \        RRV P                  4       /V P                  V P                  4      B p V P	                  VRV P
                  R7      pV P                  W P
                  R7      p\        VP                  R4      ;'       g    ^ 4      ^ 8w  d   \        RVP                  R4       24      hRV n
        V P                  V4       \        P                  RV P                  V P                  4       R#   \         d�   pRT n
        T P!                  \#        T4      4      w  T n        pT P$                  '       d(   \        P'                  R	T P                  T4        Rp?R# \        P'                  R
T P                  T4        Rp?R# Rp?ii ; i)uS  Capture the login shell environment into the snapshot file (once, after construction).
On success ``_snapshot_ready`` is set so commands source the snapshot instead of running
under ``bash -l``. On failure, fall back to ``bash -l`` per command â€” unless a non-login
probe shows login bash itself is dead, in which case prefer ``bash -c``.Úexcluded_namesT©rë   rC   rB   r   z)snapshot bootstrap failed with exit code z-Session snapshot created (session=%s, cwd=%s)Fu_   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 commandNr)   )r   r5  r@  r×   rò   Ú_snapshot_timeoutÚ_wait_for_processr@   r“   ÚRuntimeErrorrå   Ú_update_cwdr:   Úinforá   r9   Ú_probe_nonlogin_fallbackrt   rè   rÂ   )rz   Ú	bootstrapr<   r  r  Údetails   &     r"   Úinit_sessionÚBaseEnvironment.init_session�  sg  € ô
 /ñ rØ×DÑDÓFðrØJN×JfÑJfÐgk×goÑgoÓJpñrˆ	ð	.Ø—>‘> )°4À×AWÑAW�>ÓXˆDØ×+Ñ+¨D×:PÑ:PÐ+ÓQˆFÜ�6—:‘:˜lÓ+×0Ð0¨qÓ1°QÔ6Ü"Ð%NÈvÏzÉzÐZfÓOgÐNhÐ#iÓjÐjØ#'ˆDÔ Ø×Ñ˜VÔ$Ü�K‰KÐGÈ×IYÑIYÐ[_×[cÑ[cÖdøÜô 	.Ø#(ˆDÔ Ø,0×,IÑ,IÌ#ÈcË(Ó,SÑ)ˆDÔ! 6Ø×$×$Ð$Ü—‘ðMà×$Ñ$ c÷+ò +ô
 —‘ØbØ×$Ñ$ f÷.ò .ûð	.ús   ¶CC; Ã;FÄAFÅ(!FÆFc                ó<   <€ V ^8„  d   QhRS[ RS[S[S[ 3,          /# )r   rL  r   )rt   rÉ   r    )r!   ru   s   "€r"   r#   rÑ   ©  s(   ø€ ÷ Dñ D©sð D±u¹TÁ3¸YÕ7Gñ Dr$   c                óˆ  € \        ^V P                  4      p V P                  RRVR7      pV P                  W2R7      p\	        VP                  R4      ;'       g    ^ 4      ^ 8H  pV'       g4   VP                  R4      ;'       g    TP                  4       ;'       g    TpWQ3#   \         d   pRT RT 23u Rp?# Rp?ii ; i)	zHRun ``true`` under non-login bash; return ``(prefer_nonlogin, detail)``.ÚtrueFrD  rB   r   Ústdoutz; non-login probe: N)ÚminrE  rò   rF  r@   r“   r  r9   )rz   rL  Úprobe_timeoutÚprobeÚprobe_resultÚprefer_nonloginÚ	probe_excs   &&     r"   rJ  Ú(BaseEnvironment._probe_nonlogin_fallback©  sÁ   € ä˜B × 6Ñ 6Ó7ˆð	DØ—N‘N 6°À�NÓNˆEØ×1Ñ1°%Ð1ÓOˆLÜ! ,×"2Ñ"2°<Ó"@×"EÐ"EÀAÓFÈ!ÑKˆOß"Ø&×*Ñ*¨8Ó4×>Ð>¸×EÑEÓG×QÐQÈ6�Ø"Ð*Ð*øÜô 	DØ˜V˜HÐ$7¸	°{ÐCÐCÕCûð	Dús0   ˜AB# Á-B# ÂB# ÂB# Â#CÂ.B<Â6CÂ<Cc                ó&   <€ V ^8„  d   QhRS[ RS[ /# r8  rs   )r!   ru   s   "€r"   r#   rÑ   ¸  s   ø€ ÷ 	 ñ 	 ™sð 	 ¡sñ 	 r$   c                óÀ   € V R8X  d   V # V R8X  d   R# V P                  R4      '       d!   R\        P                  ! V R,          4       2# \        P                  ! V 4      # )z€Quote a ``cd`` target while preserving ``~`` expansion (``~/...``
goes through ``$HOME`` so suffixes with spaces stay one word).Ú~z~/z$HOMEz$HOME/:r   NN)r  r  r  )r×   s   &r"   r>  Ú!BaseEnvironment._quote_cwd_for_cd·  sS   € ð �#Œ:ØˆJØ�$Œ;ÙØ�>‰>˜$×ÒØœEŸKšK¨¨B­Ó0Ð1Ð2Ð2Ü�{Š{˜3ÓÐr$   c                ó&   <€ V ^8„  d   QhRS[ RS[ /# r£   rs   )r!   ru   s   "€r"   r#   rÑ   Ã  s   ø€ ÷ !ñ !¡cð !©cñ !r$   c                ó.   € \         P                  ! V4      # )z�Quote *path* for a bash script. LocalEnvironment overrides this to
rewrite native/mixed Windows paths to ``/c/...``; remote backends are POSIX.©r  r  )rz   r¤   s   &&r"   r?  Ú!BaseEnvironment._quote_shell_pathÃ  s   € ô �{Š{˜4Ó Ð r$   c                ó,   <€ V ^8„  d   QhRS[ RS[ RS[ /# )r   Úcommandr×   r   rs   )r!   ru   s   "€r"   r#   rÑ   È  s"   ø€ ÷ 1ñ 1¡Sð 1©sð 1±sñ 1r$   c           	     óˆ   € \        V3RV P                  4       RV P                  RV P                  /V P	                  V4      B # )zJFull bash script: source snapshot, cd, run, re-dump env, emit CWD markers.Úpassthrough_namesÚsnapshot_readyrØ   )r   r5  rå   rÝ   r@  )rz   rc  r×   s   &&&r"   Ú_wrap_commandÚBaseEnvironment._wrap_commandÈ  sX   € ä#Øñ1à"×GÑGÓIð1ð  ×/Ñ/ð1ð ×)Ñ)ð	1ð
 ×*Ñ*¨3Ó/ñ1ð 	1r$   c                ó,   <€ V ^8„  d   QhRS[ RS[ RS[ /# )r   rc  rì   r   rs   )r!   ru   s   "€r"   r#   rÑ   Ò  s"   ø€ ÷ 	.ñ 	.¡cð 	.±sð 	.¹sñ 	.r$   c                óp   € R\         P                  ! 4       P                  R,           2pRV  RV RV RV 2# )aþ  Redirect stdin_data to the complete command with a shell heredoc (SDK backends).
A heredoc body always ends in a newline stdin_data may lack, and write_file verifies a
byte-exact hash, so a process substitution re-emits the body minus that last character.
Redirections apply left to right, so the substitution inherits the heredoc as its stdin;
the heredoc stays outside ``<( )`` because bash 3.2 mis-parses bodies inside it. ``|| :``
keeps an inherited ``set -e`` from killing the reader on read's EOF status.ÚHERMES_STDIN_rÚ   z{
z
} << 'z7' < <(IFS= read -r -d '' s || :; printf '%s' "${s%?}")
Ú
)rÞ   rß   rà   )rc  rì   Ú	delimiters   && r"   Ú_embed_stdin_heredocÚ$BaseEnvironment._embed_stdin_heredocÑ  sG   € ð $¤D§J¢J£L×$4Ñ$4°SÕ$9Ð#:Ð;ˆ	Ø�w�i˜y¨¨Ð3oØ�,˜b  ð-ð 	.r$   c                ó    <€ V ^8„  d   QhRS[ /# r   rs   )r!   ru   s   "€r"   r#   rÑ   Ý  s   ø€ ÷ >ñ >¡Cñ >r$   c                óœ   € V P                  4       P                  R4      ;'       g    RpV R\        P                  ! 4       P                   2# )z:Unique sandbox path for staging a payload-mode stdin file.rÜ   z/.hermes-stdin-)rÔ   râ   rÞ   rß   rà   )rz   ré   s   & r"   Ú_staged_stdin_pathÚ"BaseEnvironment._staged_stdin_pathÝ  sA   € à×$Ñ$Ó&×-Ñ-¨cÓ2×9Ð9°cˆØ�˜?¬4¯:ª:«<×+;Ñ+;Ð*<Ð=Ð=r$   c                ó,   <€ V ^8„  d   QhRS[ RS[ RS[ /# )r   rc  r¤   r   rs   )r!   ru   s   "€r"   r#   rÑ   ã  s'   ø€ ÷ Wñ W©3ð W±cð W¹cñ Wr$   c                óD   € \         P                  ! V4      pRV RV RV  2# )zŽPrefix ``command`` so the shell reads stdin from the staged ``path`` and
unlinks it before ``command`` runs (the shell then owns the payload).zexec 0< z || exit $?
rm -f -- z || exit $?
r`  )rc  r¤   r  s   && r"   Ú_redirect_stdin_from_fileÚ)BaseEnvironment._redirect_stdin_from_fileâ  s,   € ô —’˜TÓ"ˆØ˜&˜Ð!7¸°x¸}ÈWÈIÐVÐVr$   Úbounded_captureÚwatch_interrupt_tidrÿ   Úyield_handlerc                óv   <€ V ^8„  d   QhRS[ RS[RS[RS[R,          RS[S[ S[.S[3,          R,          RS[/# )r   r<   rC   rx  ry  Nrz  r   )r   r@   r    r   rt   rŽ   )r!   ru   s   "€r"   r#   rÑ   ê  sc   ø€ ÷ fñ fÙ!ðfÙ,/ðfáðfá<?À$½Jðfñ %-©m¹SÐ-AÁ4Ð-GÕ$HÈ4Õ$Oðfñ \`ñfr$   c               ó‚  a aa€ Vf   \        SV4      pVe   \        P                  ! 4       MRp\        SWW4      o\        P
                  ! 4       pW‚,           p	RVRV/p
\        SV\        \        R7      pVP                  4        VVV 3R lp RpSP                  4       EfÍ   V;P                  ^,          un        \        4       '       g   \        V4      '       d@   VP                  4        V! 4        / S P                  WUP!                  RR7      ^‚4      CR	R
/C# Ve~   \#        V4      '       dm   VP%                  4        SP'                  ^R7        V! SVP!                  4       4      pVe   VP-                  4        V# VP/                  4        \        SWW4      o\        P
                  ! 4       V	8”  dg   VP1                  4        V! 4        VP!                  RV R2R7      pVP2                  ^ 8X  d   VP5                  4       p/ S P                  W_^|4      CRR
/C# \7        V
R4       VP9                  4        \        P:                  ! V4       VR8  g   EKÉ  \=        VR,          R4      pEKß   SP'                  ^R7        SPD                  PG                  4        TPI                  SPJ                  4       \M        SRR4      pTe   TP'                  ^R7       TP!                  4       pS P                  Y_SPJ                  4      p\M        SRR4      ;p'       d(   \O        T^ ,          4      ;TR&   pTRT R2,           TR&   T#   \(         d    \        P+                  RR
R7       Rp ELi ; i  \>        \@        3 d,    TPC                  4         T! 4        h   \(         d     h i ; ii ; i  \(         d     EL i ; i)u3  Poll-based wait with interrupt checking and stdout draining (shared, not overridden).
``yield_handler(proc, output_so_far)``: when the tool thread is asked to yield
(``tools.interrupt.request_yield`` â€” a user message arrived mid-command), the drain
thread is stopped, the still-running process is handed to the handler and its dict
is returned as the result; the process is NOT killed.
``bounded_capture=True`` (foreground terminal-tool path only) retains at most
``tool_output.max_bytes`` in a head/tail window so a verbose subprocess cannot OOM the
process; the default keeps full fidelity for internal consumers. Fires the activity
callback every 10s so the gateway's inactivity timeout doesn't kill long commands.
``watch_interrupt_tid`` is the tool-worker thread that submitted this wait: ``execute()``
may move the wait onto a ``run_bounded_sync`` worker while ``/stop`` still interrupts the
original tid, so both bits are honored. ``KeyboardInterrupt``/``SystemExit`` mid-poll
kills the process first â€” the local backend spawns into its own process group, so an
unkilled child would be orphaned.

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. See #64435.
Nr�   r^   )Úenabledr:   c                  óN   <€ SP                  S4       S P                  ^R7       R# )r   rB   N)rN   r_   )Údrain_threadr<   rz   s   €€€r"   Ú_kill_and_joinÚ9BaseEnvironment._wait_for_process.<locals>._kill_and_join  s"   ø€ Ø×Ñ˜tÔ$Ø×Ñ aÐÖ(r$   g{®Gázt?z
[Command interrupted]©ÚsuffixÚhermes_interruptedTrB   z6yield-to-background handoff failed; continuing to waitr7   ú
[Command timed out after ús]Úhermes_timed_outzterminal command runninggš™™™™™É?g      ø?Ú_hermes_stdin_threadÚ_hermes_stdin_errorsÚstdin_errorz
[stdin write failed: Ú]rÿ   )(r   r\   ÚEventr   rP   rQ   r   Ú_DEBUG_INTERRUPTr:   ÚenterÚpollÚ
iterationsr
   r   Úinterruptedr   Úrenderr	   ræ   r_   r9   rÂ   Úclose_spillÚclearÚ	timed_outÚtotal_charsÚlstripr”   Ú	heartbeatÚsleeprS  ÚKeyboardInterruptÚ
SystemExitÚexception_exitrR  ÚcloseÚnatural_exitr   r‰   rt   )rz   r<   rC   rx  ry  rÿ   rz  Ú
drain_stopÚ_nowra   Ú_activity_stateÚtracer€  Ú_poll_sleepÚhandedÚrenderedÚstdin_threadr  Ústdin_errorsÚerrr  s   ff&$$$$             @r"   rF  Ú!BaseEnvironment._wait_for_processê  sz  ú€ ð. Š>Ü*¨4°ÓAˆFØ*7Ò*C”Y—_’_Ô&Èˆ
Ü*¨4°ÓDˆÜ�~Š~ÓˆØ•>ˆØ'¨¨w¸Ð=ˆÜ˜4 Ô2BÌ6ÔRˆØ�‰Œ÷	)ð+	ð  ˆKØ—)‘)“+Ó%Ø× Ò  AÕ%Õ Ü!×#Ò#Ô'<Ð=P×'QÒ'QØ×%Ñ%Ô'Ù"Ô$ð8˜d×8Ñ8¸ÇÁÐVoÀÓApÐruÓvð 8Ø0°$ñ8ð 8à Ò,´Ð?R×1SÒ1SØ—N‘NÔ$Ø ×%Ñ%¨aÐ%Ô0ð&Ù!.¨t°V·]±]³_Ó!E˜ð Ò)Ø×*Ñ*Ô,Ø%˜Ø×$Ñ$Ô&Ü#6°t¸VÓ#P�LÜ—>’>Ó# hÔ.Ø—O‘OÔ%Ù"Ô$Ø%Ÿ}™}Ð6QÐRYÐQZÐZ\Ð4]˜}Ó^�HØ×)Ñ)¨QÔ.Ø#+§?¡?Ó#4˜àj˜d×8Ñ8¸È3ÓOÐjÐQcÐeiÑjÐjÜ% oÐ7QÔRØ—‘Ô!Ü—
’
˜;Ô'Ø ×$Ü"% k°CÕ&7¸Ó"=“KðA &ðV 	×Ñ !ÐÔ$ð	Ø�K‰K×ÑÔð 	×Ñ˜4Ÿ?™?Ô+ô
 ˜tÐ%;¸TÓBˆØÒ#Ø×Ñ aÐÔ(Ø—=‘=“?ˆØ×+Ñ+¨F¸d¿o¹oÓNˆÜ" 4Ð)?ÀÓFÐFˆ<ÖFÜ*-¨l¸1­oÓ*>Ð>ˆF�=Ñ! CØ'Ð,CÀCÀ5ÈÐ*JÕJˆF�8ÑØˆøôc %ô &ÜŸ™Ð'_Ðjn˜ÔoØ!%›ð&ûô* "¤:Ð.ô 	Ø× Ñ Ô"ðÙÔ ð øô ô ØØðúð		ûô ô 	Úð	ús€   ÂBM0 Ä7M0 ÅM Å+M0 ÆBM0 È6M0 ÉM0 ÊN/ Í$M-Í)M0 Í,M-Í-M0 Í0!N,ÎNÎN,ÎN(Î%N,Î'N(Î(N,Î/N>Î=N>c                ó    <€ V ^8„  d   QhRS[ /# ©r   r<   ©r   )r!   ru   s   "€r"   r#   rÑ   T  s   ø€ ÷ ñ ¡-ñ r$   c                ób   €  VP                  4        R#   \        \        \        3 d     R# i ; i)zDTerminate a process. Subclasses may override for process-group kill.N)r5   ÚProcessLookupErrorÚPermissionErrorr«   ©rz   r<   s   &&r"   rN   ÚBaseEnvironment._kill_processT  s)   € ð	Ø�I‰IŽKøÜ"¤O´WÐ=ô 	Úð	ús   ‚ ”.­.c                ó    <€ V ^8„  d   QhRS[ /# r«  r¬  )r!   ru   s   "€r"   r#   rÑ   [  s   ø€ ÷ !ñ !©ñ !r$   c                ó(   € V P                  V4       R# )zVKill without waiting, for a host that hard-exits next. Subclasses kill the whole tree.N)rN   r°  s   &&r"   rZ   Ú#BaseEnvironment._force_kill_process[  s   € à×Ñ˜4Ö r$   c                ó    <€ V ^8„  d   QhRS[ /# ©r   r  ©rŽ   )r!   ru   s   "€r"   r#   rÑ   `  s   ø€ ÷ .ñ .¡$ñ .r$   c                ó(   € V P                  V4       R# )zDExtract CWD from command output. Override for local file-based read.N)Ú_extract_cwd_from_output)rz   r  s   &&r"   rH  ÚBaseEnvironment._update_cwd`  s   € à×%Ñ% fÖ-r$   c                ó    <€ V ^8„  d   QhRS[ /# r¶  r·  )r!   ru   s   "€r"   r#   rÑ   d  s   ø€ ÷ #ñ #©tñ #r$   c                óœ   € \        VP                  RR4      V P                  4      pVf   R# Vw  r4V'       d   W0n        RVR&   W1R&   WAR&   R# )a—  Parse the ``__HERMES_CWD_{session}__`` marker from ``result["output"]``, update
``self.cwd`` and strip the marker line. ``result["cwd_observed"]``/``["cwd"]`` are set
only when THIS command emitted a marker: a killed/timed-out command emits none and
``self.cwd`` keeps the previous value. The environment is shared across sessions, so
concurrent callers must read ``result["cwd"]`` rather than ``self.cwd``.rÿ   rp   NTÚcwd_observedr×   )r   r“   r   r×   )rz   r  r  Úcwd_pathÚcleaneds   &&   r"   r¹  Ú(BaseEnvironment._extract_cwd_from_outputd  sR   € ô " &§*¡*¨X°rÓ":¸D×<LÑ<LÓMˆØŠ=ÙØ!ÑˆßØŒHØ%)ˆF�>Ñ"Ø$�5‰MØ"ˆxÓr$   c                ó   <€ V ^8„  d   QhRR/# r‡   r)   )r!   ru   s   "€r"   r#   rÑ   u  s   ø€ ÷ Tñ T ñ Tr$   c                ó   € R# )zˆHook before each command. Remote backends (SSH, Modal, Daytona)
trigger their FileSyncManager here; bind-mount backends and Local don't.Nr)   rÓ   s   &r"   Ú_before_executeÚBaseEnvironment._before_executeu  s   ‚ r$   c                ó   <€ V ^8„  d   QhRR/# r‡   r)   )r!   ru   s   "€r"   r#   rÑ   y  s   ø€ ÷ .ñ . ñ .r$   c                ó   € RV n         R# )u€  Flag that the live container/sandbox was replaced while serving the
current command. ``execute`` folds the flag into the result as
``environment_recreated`` so the tool layer can warn the model that
background processes died and non-persisted files may be gone â€”
without this the recovery is silent and the model keeps assuming the
old workspace state (lobehub/lobehub#19329 class).TN)Ú_recreated_notice_pendingrÓ   s   &r"   Ú_mark_recreatedÚBaseEnvironment._mark_recreatedy  s   € ð *.ˆÖ&r$   rþ   c                ó�   <€ V ^8„  d   QhRS[ RS[ RS[R,          RS[ R,          RS[RS[RS[S[S[ .S[3,          R,          R	S[/# )
r   rc  r×   rC   Nrì   rþ   rx  rz  r   )rt   r@   r    r   r   rŽ   )r!   ru   s   "€r"   r#   rÑ   ƒ  sƒ   ø€ ÷ rñ ráðrñ ðrñ
 �t•ðrñ ˜$•Jðrñ &*ðrñ ðrñ  ¡±Ð 4±dÐ :Õ;¸dÕBðrñ OSñrr$   c               óÌ  a aaaaaaaaaa€ S P                  4        S P                  V4      w  r‰V'       d   ^ RIHp
 V
! V4      pT;'       g    S P                  oT;'       g    S P
                  pV	e   Y”;'       g    R,           MToS'       d&   S P                  R8X  d   S P                  VS4      pRoS P                  W‹4      oS P                  '       * ;'       d    S P                  '       * o\        P                  ! 4       P                  o\        4       o. o. oR VVVVVVVVV VV3R llpR VV 3R llp^ R	IHp  \#        S4      pV\(        ,          p V! WÏR\+        S 4      P,                   2VR7      pTP2                  '       de   RS R2pS'       d=   S^ ,          pS P5                  TTP7                  TR7      P9                  R4      ^|4      pMRTP9                  4       R^|/pRTR&   MTP:                  pS P=                  T4       \?        S RR4      '       d   RS n         RTR&   T#   \$        \&        3 d    R
p Løi ; i  \.        \0        3 d
    T! 4        h i ; i)uÃ  Execute a command, return {"output": str, "returncode": int}. ``bounded_capture=True``
caps retention at ``tool_output.max_bytes`` WHILE draining; only the foreground terminal
tool may set it â€” internal full-fidelity consumers (file-op ``cat`` reads feeding the
patch engine, RPC reads, log reads) MUST leave it False or data is corrupted. The wait is
bounded by ``agent.deadline.run_bounded_sync`` so a wedged poll loop cannot hang past
``timeout`` and silently disable every asyncio timer in the process.

``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).
See #94285.
)Ú_rewrite_compound_backgroundNrp   Úheredocc                ó$   € V ^8„  d   QhR\         /# r   r·  )r!   s   "r"   r#   Ú-BaseEnvironment.execute.<locals>.__annotate__¶  s   € ÷ 	<ñ 	<¤ñ 	<r$   c                  ó¼  <€ Se   \        S4       \        4       '       g   RRR^‚/# R p  SP                  SSSSR7      p \        SV 4      pS
P	                  V 4       V'       d   SP                  V 4       \        V S4      pSP	                  V4        SP                  ! V 3RSRSRS	RV/Se   RS/M/ B \        ;_uu_ 4        \        P                  \        V 4      R 4       R R R 4       #   \        ST 4      pi ; i  + '       g   i     # ; i  \        ;_uu_ 4        \        P                  \        T 4      R 4       R R R 4       i   + '       g   i     i ; i; i)	Nrÿ   z&[host is exiting: command not started]r   )rë   rC   rì   rC   rx  ry  rz  )r…   r*   rò   r3   r[   rZ   r   rF  r&   r/   Úpopr0   )r2   Úfencedrÿ   rx  Úeffective_stdinÚeffective_timeoutrë   Úoutput_holderÚparent_activity_cbÚ
parent_tidÚproc_holderrz   Úwrappedrz  s      €€€€€€€€€€€r"   Ú_spawn_and_waitÚ0BaseEnvironment.execute.<locals>._spawn_and_wait¶  sN  ø€ Ø!Ò-Ü%Ð&8Ô9Ü*×,Ò,Ø Ð"JÈLÐZ]Ð^Ð^ØˆGð@ØŸ.™.¨¸ÐGXÐet˜.Óu�ä0°°wÓ?�Ø×Ñ˜wÔ'ßØ×(Ñ(¨Ô1Ü*¨7°OÓDˆFØ× Ñ  Ô(ð<Ø×-Ò-Øñ_Ø%6ð_ØHWð_à(2ð_à;Að_ð <IÒ;T˜¨Ñ7ÐZ\ñ_÷
 +Ö*Ü$×(Ñ(¬¨G«°dÔ;÷ +Ð*øô 1°°wÓ?‘ú÷ +×*û×*Ö*Ü$×(Ñ(¬¨G«°dÔ;÷ +×*×*Ð*ýs;   ªC, Â"D Ã C=Ã,C:Ã=DÄEÄ E	Ä?	EÅEÅEc                ó   € V ^8„  d   QhRR/# r‡   r)   )r!   s   "r"   r#   rÏ  Î  s   € ÷ 	8ñ 	8˜Tñ 	8r$   c                  óL   <€ S '       d   SP                  S ^ ,          4       R# R# )rE   N)Ú_kill_spawned_tree)rØ  rz   s   €€r"   Ú_on_timeoutÚ,BaseEnvironment.execute.<locals>._on_timeoutÎ  s   ø€ ßØ×'Ñ'¨°A­Ö7ñ r$   )Úrun_bounded_syncg      ^@zterminal.wait:)r�   Ú
on_timeoutr…  r†  r‚  rl  rÿ   r   Tr‡  rÇ  FÚenvironment_recreated)!rÃ  Ú_prepare_commandÚtools.terminal_tool_sudorÌ  rC   r×   Ú_stdin_modern  rg  rå   rè   r\   Úcurrent_threadÚidentrŠ   Úagent.deadlinerá  ÚfloatÚ	TypeErrorr¬   Ú_EXECUTE_WAIT_BOUND_GRACE_Srñ   rg   rš  r›  r•  r   r’  r—  ÚvaluerH  r‰   rÇ  )rz   rc  r×   rC   rì   rþ   rx  rz  Úexec_commandÚ
sudo_stdinrÌ  Úeffective_cwdrÚ  rß  rá  Úbound_sÚboundedrƒ  Ú	collectorr  rÓ  rÔ  rë   rÕ  rÖ  r×  rØ  rÙ  s   f&&$$$dd            @@@@@@@@r"   r  ÚBaseEnvironment.executeƒ  sJ  ÿú€ ð* 	×ÑÔà#'×#8Ñ#8¸Ó#AÑ ˆ÷ 'ÝMÙ7¸ÓEˆLØ#×3Ð3 t§|¡|ÐØŸ˜˜tŸx™xˆð >HÒ=S˜*×(8Ð(8°bÖ9ÐYcˆß˜t×/Ñ/°9Ô<Ø×4Ñ4°\À?ÓSˆLØ"ˆOà×$Ñ$ \ÓAˆð ×(Ñ(Ô(×FÐF°×1FÑ1FÔ-Fˆä×-Ò-Ó/×5Ñ5ˆ
ô 3Ó4ÐØˆØ ˆ÷	<÷ 	<ò 	<÷0	8ñ 	8õ 	4ð	ÜÐ-Ó.ˆGð 	Ô.Õ.ˆð	Ù&Ø°.ÄÀdÃ×ATÑATÐ@UÐ0VÐcnôpˆGð ××ÐØ2Ð3DÐ2EÀRÐHˆFßØ)¨!Õ,�	Ø×3Ñ3°I¸y×?OÑ?OÐW]Ð?OÓ?^×?eÑ?eÐfjÓ?kÐmpÓq‘à" F§M¡M£O°\À3ÐG�Ø)-ˆFÐ%Ò&à—]‘]ˆFØ×Ñ˜Ô Ü�4Ð4°e×<Ò<Ø-2ˆDÔ*Ø.2ˆFÐ*Ñ+Øˆøô3 œ:Ð&ô 	ØŠGð	ûô "¤:Ð.ô 	ÙŒMØð	ús   ÅH0 Å!I	 È0IÉIÉ	I#c                ó   <€ V ^8„  d   QhRR/# r‡   r)   )r!   ru   s   "€r"   r#   rÑ   ÷  s   ø€ ÷ Xñ X¨Tñ Xr$   c                ó*  €  V P                  V4       \	        VRR4      pV'       g   R#  ^ RIHp V! \        V4      4       R#   \         d    \        P                  RRR7        LUi ; i  \         d    \        P                  RRR7        R# i ; i)zJBest-effort kill of a wedged spawned process and its tree (backstop path).z'terminal wait-bound kill_process failedTr7   ÚpidN)Úkill_process_treez,terminal wait-bound kill_process_tree failed)rN   r9   r:   r;   r‰   ré  rø  r@   )rz   r2   r÷  rø  s   &&  r"   rÞ  Ú"BaseEnvironment._kill_spawned_tree÷  s‰   € ð	SØ×Ñ˜wÔ'ô �g˜u dÓ+ˆßÙð	XÝ8Ùœc #›hÖ'øô ô 	SÜ�L‰LÐBÈTˆLÖRð	Sûô ô 	XÜ�L‰LÐGÐRVˆL×Wð	Xús"   ‚A «A, Á"A)Á(A)Á,"BÂBc                óL   €  V P                  4        R #   \         d     R # i ; ir-  )rõ   r9   rÓ   s   &r"   Ú__del__ÚBaseEnvironment.__del__  s"   € ð	Ø�L‰LŽNøÜô 	Úð	ús   ‚ ”#¢#c                óJ   <€ V ^8„  d   QhRS[ RS[S[ S[ R,          3,          /# )r   rc  r   N)rt   rÉ   )r!   ru   s   "€r"   r#   rÑ     s(   ø€ ÷ 
ñ 
©ð 
±±c¹3À½:°oÕ0Fñ 
r$   c                óN   € ^ RI Hp ^ RIHp V! V! V4      V P                  R7      # )a  Rewrite sudo for a piped password, or leave it alone when this backend has NOPASSWD.

Also applies the macOS ``open`` frontmost raise-ladder (a pure string
rewrite, no-op on non-Darwin) so files opened via tool calls are
brought to the front instead of landing behind the Hermes window.
)Ú_transform_macos_open_command)Ú_transform_sudo_command)Úsudo_nopasswd_check)Útools.terminal_tool_macos_openrÿ  rå  r   Ú_sudo_nopasswd_works)rz   rc  rÿ  r   s   &&  r"   rä  Ú BaseEnvironment._prepare_command  s)   € õ 	QÝDÙ&Ù)¨'Ó2Ø $× 9Ñ 9ô
ð 	
r$   c                ó    <€ V ^8„  d   QhRS[ /# r   r   )r!   ru   s   "€r"   r#   rÑ     s   ø€ ÷ 	ñ 	¡dñ 	r$   c                óæ   € V P                   '       g   R#  V P                  RV P                  R7      pV P                  WP                  R7      P	                  R4      ^ 8H  #   \
         d     R# i ; i)z¦``sudo -n true`` inside THIS backend (host sudo state must not leak into a sandbox).
Fails closed: any error or a timed-out probe means "assume a password is needed".Fzsudo -n truerB   r   )Ú"_passwordless_sudo_probe_supportedrò   Ú_SUDO_PROBE_TIMEOUT_SrF  r“   r9   r°  s   & r"   r  Ú$BaseEnvironment._sudo_nopasswd_works  sn   € ð ×6×6Ð6Ùð	Ø—>‘> .¸$×:TÑ:T�>ÓUˆDØ×)Ñ)¨$×8RÑ8RÐ)ÓS×WÑWÐXdÓeÐijÑjÐjøÜô 	Úð	ús   –A
A! Á!A0Á/A0c                ób   <€ V ^8„  d   Qh/ S[ ;R&   S[;R&   S[;R&   S[;R&   S[;R&   S[;R&   # )r   ræ  Úis_localrE  rÝ   r  r0  )rt   r    r@   )r!   ru   s   "€r"   r#   rÑ      sS   ø‡ ‚ ñ Ññ ñ Ññ ñ  Ññ! ñ& Ññ' ñ2 )-Ñ4ñ3 ñ: "&Ñ-ò; r$   )rä   r   rÝ   rè   rÇ  rá   rç   rã   rå   r×   r,   rC   )NT)éx   )rp   )/rg   rh   ri   rj   rk   ræ  r  rE  rÝ   r  r0  rÔ   ry   rò   r   rõ   r  r"  r&  r5  r@  rM  rJ  Ústaticmethodr>  r?  rg  rn  rr  rv  rF  r   rN   rZ   rH  r¹  rÃ  rÈ  r  rÞ  rû  rä  r  r  Ú__annotate_func__rl   r}   )ru   s   @r"   r-   r-      s&  ø‡ € ñTð €Kð €Hð  Ðð €Lð 05Ð&ð ).Ð÷ð ÷&ò &ð(WØ05ðWØFIðWØdh÷Wò Wð ñó ð÷
+ð +÷<Dð D÷ð ÷?ð ?÷")ð )ò.÷8Dð Dð ÷	 ó ð	 ÷!ð !÷
1ð 1ð ÷	.ó ð	.÷>ð >ð
 ÷Wó ðWñfà %ðfàIMðfð ðfð SW÷fó fñP )Ð)>Ó?Ð÷ð ÷!ð !÷
.ð .÷#ð #÷"Tð T÷.ð .ñrð
 #ðrð "&ðrð -1ðrð !&ðrð FJ÷ró r÷hXð Xò ÷
ð 
ð Ð÷	ð 	÷{ ƒ r$   r-   c                ó8   € V ^8„  d   Qh/ ^ \         9   d   R;R&   # )r   z0dict[int, tuple[BaseEnvironment, ProcessHandle]]r/   ©Ú__conditional_annotations__)r!   s   "r"   r#   r#      s"   € ÷ ñ ÷t JÒ IÐDÑ Iòur$   )Mr  rk   r¨   Úloggingrœ   r  rX   r\   rP   rÞ   Úabcr   r   Úpathlibr   Útypingr   r   Úhermes_constantsr   Útools.interruptr	   r
   r   Útools.environments.base_outputr   r   r   r   Ú#tools.environments.base_session_envr   r   r   r   r   r   Útools.environments.base_waitr   Úutilsr   r   r   Ú	getLoggerrg   r:   r�  rì  ÚsetLevelÚINFOÚlocalrƒ   r/   Ú	ConditionÚRLockr&   r'   r(   rR   r*   r3   r=   rd   rG  rf   r  rn   r…   rŠ   r”   r¡   r¯   r´   rÀ   rÆ   rÌ   r-   r#   r  s   @r"   Ú<module>r"     s]  øðöó Û Û 	Û Û Û Û Û ß #Ý ß %å ,ß PÑ P÷ó ÷÷ õ 4ß DÑ Dà	×	Ò	˜8Ó	$€ñ #Ð#;Ó<Ð ð "Ð çð ‡O�O�G—L‘LÔ!ð %Ÿ?š?Ó,Ð ð
 HJÐ Ó Ið "×+Ò+¨I¯OªOÓ,=Ó>Ð Ø€ØÐ ØÐ õõõUð"°%÷ "ôJE�\ô Eð
 Ð ô3 ô 3õ"+õ
?õ^õõ2õ,ð $Ÿ/š/Ó+Ð õ)õ4ô f�cö fr$   