+
    lHàjúE ã                   óh  a € RÇ t¦0 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	H
t
 ^ RIHtHtHtHt ]P                   ! ]4      tR R lt^ RIHt ^ RIHtHtHtHtHt ^ RIHtHtHtH t H!t!H"t"H#t#H$t$H%t%H&t&H't'H(t(H)t)H*t* ^ R	I+H,t,H-t-H.t.H/t/H0t0 ^ R
I1H2t2H3t3 R R lt4]4! RR]5R4      t6]Pn                  ! 4       t8R t9R t:R t;R t<R R lt=R R lt>R R lt?^ RI@HAtB R R ltCR R ltDRÈR  R! lltE^ R"IFHGtG R#tH/ tI] ^ k / tJ] ^k ]P–                  ! 4       tL/ tM] ^k ]P–                  ! 4       tNRsORsPRsQ]P–                  ! 4       tRR$ R% ltS/ tT] ^k / tU] ^k ]P–                  ! 4       tV/ tW] ^k ]P–                  ! 4       tXR& R' ltYR( R) ltZR* R+ lt[R, R- lt\R. R/ lt]R0 R1 lt^R2 R3 lt_R4 R5 lt`R6 R7 ltaR8 R9 ltb]
! R:R;7       ! R< R=4      4       tcR> R? ltdR@ RA lteRB RC ltfRD RE ltgRF RG lthRH RI ltiRJ RK ltjRL RM ltkRNRORPRQRRRS/tlRT RU ltmRV RW ltnRX RY ltoRspRZ R[ ltqR\R]R^]-/trR_ R` ltsRa Rb lttRc Rd ltuRe tvRf twRg txRh ty]Pô                  ! ]y4       Ri Rj lt{^ RkI|H}t}H~t~HtH€t€H�t�H‚t‚ ^ RlIƒH„t„H…t…H†t† ^ RmI‡Hˆtˆ Rn Ro lt‰Rp Rq ltŠRr t‹RÉRs Rt lltŒRÉRu Rv llt�RwRRxRRyRRzR/R{ R| lltŽR}RÊR~R/R R€ llt�R� R‚ lt� ! Rƒ R„]‘4      t’]
 ! R… R†4      4       t“R‡ Rˆ lt”]
 ! R‰ RŠ4      4       t•R‹t–RŒ R� lt—RŽt˜R� R� lt™R‘ R’ ltšR“ R” lt›R•R:/R– R— lltœ^t�R˜ R™ ltžRštŸR› Rœ lt RËR� Rž llt¡RŸ R  lt¢^ R¡IH£t£ R¢R£R¤]HR¥R¦R§R¨R©R¦RªR¤R«/R¬R¦R­R¤R®R¯R/R°R¦RR¤R±]6 R²]6 R³2R´^/RµR¦RªR¤R¶/R·R¦R­R¤R¸R¯R/R¹R¤RºR»R¦R­/R¦R¼R½R¦Rª//./R¾R¦RR´^ R¯^ R¤R¿/RÀR¦R­R¯RR¤RÁ//RÂR©.//t¤RÃ t¥]£Pô                  ! R£R£]¤]¥]¢RÄRÅRÆ7       R# )Ìa;  Terminal tool: run shell commands in the configured backend.

Backends (``TERMINAL_ENV``): local (default), docker, modal (direct or
managed gateway), daytona, vercel_sandbox, ssh, plus plugin-registered
backends (the ``singularity`` catalog plugin, ...). Handles background
processes, sandbox lifecycle (per-task cache, idle reaper, atexit teardown)
and sudo password plumbing.
Cloud-sandbox persistent filesystems preserve working state across sandbox
recreation but do NOT guarantee the same live sandbox or long-running
processes survive cleanup, idle reaping, or Hermes exit.

Companion modules (re-exported here, so ``tools.terminal_tool.<name>`` stays the
import/patch target): ``terminal_tool_config`` (TERMINAL_* reads, ``_quiet``),
``terminal_tool_backends`` (env builders + requirement checkers),
``terminal_tool_lifecycle`` (reaper/teardown/ensure_task_env),
``terminal_tool_sudo`` (sudo password + shell rewrites), ``terminal_tool_guards``
(pre-exec blocks), ``terminal_tool_background`` (background spawn),
``terminal_tool_result`` (foreground result post-processing).
N)Ú	dataclass)ÚOptionalÚDictÚAnyÚListc                ó0   € V ^8„  d   QhR\         R\        /# )é   ÚvalueÚreturn)r   Ústr)Úformats   "Ú8/home/ubuntu/.hermes/hermes-agent/tools/terminal_tool.pyÚ__annotate__r   #   s   € ÷ Rñ R¤sð R¬sñ Ró    c                óL   € ^ RI Hp T! V f	   RRR7      # \        V 4      RR7      # )z?Force-redact text before serializing a terminal error envelope.)Úredact_sensitive_textÚ T©Úforce)Úagent.redactr   r   )r	   r   s   & r   Ú_redact_terminal_error_textr   #   s$   € å2á  u¢} ÈDÔQÐQ¼#¸e»*ÈDÔQÐQr   )Ú
tool_error)Ú_cleanup_inactive_envsÚ_create_configured_envÚ_evict_environment_for_taskÚcleanup_all_environmentsÚensure_task_env)Ú_is_container_backendÚ_is_host_cwdÚ_is_mounted_host_cwdÚ_is_unusable_container_cwdÚ_is_windows_drive_pathÚ_parse_env_varÚ_plugin_env_flagÚ_quietÚ_safe_getcwdÚ_tenvÚ
_tenv_boolÚ_in_sandbox_homeÚcoerce_ssh_remote_cwdÚtranslate_mounted_host_path)Ú_REQUIREMENT_CHECKERSÚ_VERCEL_SANDBOX_DEFAULT_CWDÚ_check_plugin_requirementsÚ_record_unavailable_reasonÚ#terminal_backend_unavailable_reason)Úcoerce_modal_modeÚmanaged_nous_tools_enabledc                ó<   € V ^8„  d   QhR\         R\        R\         /# )r   ÚnameÚdefaultÚ
type_label)r   r   )r   s   "r   r   r   <   s!   € ÷ ñ ¤ð ¬sð Ì3ñ r   c                óº   € \         P                  ! V 4      pVe   VR8X  d   V#  V! V4      #   \        \        3 d    \        P                  RYY14       Tu # i ; i)z�Parse a module-level numeric env var; a malformed value must never make
the module unloadable at import time (CLI, ACP, tests, tool discovery).r   z;Invalid value for %s: %r (expected %s). Falling back to %r.)ÚosÚgetenvÚ	TypeErrorÚ
ValueErrorÚloggerÚwarning)r3   r4   Ú	converterr5   Úraws   &&&& r   Ú_safe_parse_import_envr?   <   s_   € ô �)Š)�D‹/€CØ
‚{�c˜R”iØˆðÙ˜‹~ÐøÜ”zÐ"ô Ü�‰ØIØ�zô	
ð Šðús   ¥- ­*AÁAÚTERMINAL_MAX_FOREGROUND_TIMEOUTiX  Úintegerc                  ó$   € \        \        R R4      # )Úsudo_passwordN©ÚgetattrÚ_callback_tls© r   r   Ú_get_sudo_password_callbackrH   W   s   € Ü”= /°4Ó8Ð8r   c                  ó$   € \        \        R R4      # )ÚapprovalNrD   rG   r   r   Ú_get_approval_callbackrK   [   s   € Ü”= *¨dÓ3Ð3r   c                ó   € V \         n        R# )zCRegister the CLI's sudo password prompt callback (per-thread slot).N)rF   rC   ©Úcbs   &r   Úset_sudo_password_callbackrO   _   s
   € à"$„MÖr   c                ó   € V \         n        R# )zJRegister the dangerous-command approval prompt callback (per-thread slot).N)rF   rJ   rM   s   &r   Úset_approval_callbackrQ   d   s
   € à„MÖr   c                ó$   € V ^8„  d   QhR\         /# ©r   r
   ©r   )r   s   "r   r   r   i   s   € ÷ 5ñ 5œcñ 5r   c                 ó    € ^ RI Hp  V ! RR4      # )zŠActive gateway/WebUI session key, or "" outside sessions (ContextVar with
the ``get_session_env`` os.environ fallback for CLI/cron/tests).©Úget_session_envÚHERMES_SESSION_KEYr   ©Úgateway.session_contextrW   rV   s    r   Ú_current_session_keyr[   i   s   € õ 8áÐ/°Ó4Ð4r   c                ó$   € V ^8„  d   QhR\         /# rS   rT   )r   s   "r   r   r   q   s   € ÷ 9ñ 9¤#ñ 9r   c                 ó    € ^ RI Hp  V ! RR4      # )zeActive session's Hermes profile name, or "" (same lookup discipline as
:func:`_current_session_key`).rV   ÚHERMES_SESSION_PROFILEr   rY   rV   s    r   Ú_current_session_profiler_   q   s   € õ 8áÐ3°RÓ8Ð8r   c                ó$   € V ^8„  d   QhR\         /# rS   rT   )r   s   "r   r   r   y   s   € ÷  ñ  œCñ  r   c                 óÎ   € ^ RI Hp Hp ^ RIHp V ! 4       p\        4       pV'       d	   V! V4      MRpV'       d"   V'       d
   WT8w  d    V# V! V4      '       d   V# T;'       g    R# )a  Profile whose persistent container a session-bound command uses: the bound home's profile when it is not
the session's own (a profile-routed subagent runs in its target's home while the session, and the delivery
identity HERMES_SESSION_PROFILE carries, stay the parent's; that target may be the launch profile, reached
from a routed profile's chat), else the session's. A session with no profile name is the launch profile's,
so the launch home's own work keeps the session's key whatever the launch profile is named.©Úget_hermes_home_overrideÚprofile_name_for_home©Ú_is_routed_homeNr4   )Úhermes_constantsrc   rd   Útools.environments.localrf   r_   )rc   rd   rf   ÚoverrideÚsessionÚbounds         r   Ú_container_profilerl   y   sZ   € ÷ QÝ8á'Ó)€HÜ&Ó(€Gß/7Ñ! (Ô+¸T€Eß§g�%Õ"Øˆñ 4CÀ8×3LÒ3LØˆØ×Ð�iÐr   )Úcheck_all_command_guardsc                ó0   € V ^8„  d   QhR\         R\        /# )r   Úvolume_specr
   ©r   Úbool)r   s   "r   r   r   �   s   € ÷ ñ ¬sð ´tñ r   c                ó  € \        V \        4      '       g   R# V P                  4       p\        V4      ;'       dP    VP	                  R4      ;'       g7    \        V4      ^8¬  ;'       d!    V^,          R8H  ;'       d    V^,          R9   # )z>Return True when a docker volume spec bind-mounts a host path.FÚ:)Ú/Ú~z./z../)rt   Ú\)Ú
isinstancer   Ústriprq   Ú
startswithÚlen)ro   Úvols   & r   Ú_docker_volume_uses_host_pathr|   �   s{   € ä�k¤3×'Ò'ÙØ
×
Ñ
Ó
€CÜ�‹9÷ ð Ø�‰Ð.Ó/÷ 	Dð 	DÜ	ˆS‹�Q‰×	BÐ	B˜3˜q�6 S™=×	BÐ	B¨S°­V°{Ñ-Bðr   c                óR   € V ^8„  d   QhR\         \        \        3,          R\        /# )r   Úconfigr
   )Údictr   r   rq   )r   s   "r   r   r   š   s&   € ÷ _ñ _¤D¬¬c¨¥Nð _´tñ _r   c                ó:  € V P                  R4      R8w  d   R# V P                  R4      '       d   V P                  R4      '       d   R# \        ;QJ d,    R V P                  R. 4       4       F  '       g   K   R# 	  R# ! R V P                  R. 4       4       4      # )	zIReturn True when a Docker sandbox exposes host paths through bind mounts.Úenv_typeÚdockerFÚhost_cwdÚdocker_mount_cwd_to_workspaceTc              3   ó8   "  € T F  p\        V4      x € K  	  R # 5i©N)r|   )Ú.0r{   s   & r   Ú	<genexpr>Ú*_docker_has_host_access.<locals>.<genexpr>    s   é € Ð^Ñ=]°cÔ,¨S×1Ð1Ó=]ùs   ‚Údocker_volumes)ÚgetÚany)r~   s   &r   Ú_docker_has_host_accessr�   š   sz   € à‡z�z�*Ó Ô)ÙØ‡z�z�*×Ò &§*¡*Ð-L×"MÒ"MÙß‹3Ñ^¸V¿Z¹ZÐHXÐZ\Ô=]Ó^�3Œ3Ð^Š3Ð^ˆ3Ñ^¸V¿Z¹ZÐHXÐZ\Ô=]Ó^Ó^Ð^r   Fc                óH   € V ^8„  d   QhR\         R\         R\        R\        /# )r   Úcommandr�   Úhas_host_accessr
   )r   rq   r   )r   s   "r   r   r   £   s0   € ÷ Cñ Cœsð C¬cð CÜ'+ðCÜ8<ñCr   c                ó.   € \        W\        4       VR7      # )zADelegate to the consolidated command guard with the CLI callback.)Úapproval_callbackr�   )Ú_check_all_guards_implrK   )r�   r�   r�   s   &&&r   Ú_check_all_guardsr”   £   s   € ô " 'Ü4JÓ4LØ2AôCð Cr   )ÚEnvironmentConnectionErrorae  Execute shell commands on the OS, shell and backend named in your environment section. The working directory, files and exported variables persist between calls: activate a virtualenv or export once, not before every command.

Use read_file, search_files, patch and write_file instead of cat/head/tail, grep/find/ls, sed/awk and echo/heredoc. Output is auto-truncated with the full text saved to a file; never pipe through head/tail to shorten it.

Foreground (default) returns as soon as the command finishes. To wait a fixed time, run the wait in the foreground; never background a sleep or polling loop. Background is only for commands that must keep running after this call returns; health-check a server in a separate call and manage jobs with process_manage. When a command changes directory, trust the result's "cwd" instead of prefixing later commands with cd.
c                óJ   € V ^8„  d   QhR\         \        \        3,          RR/# )r   Úcontainer_configr
   N©r   r   r   )r   s   "r   r   r   Ä   s"   € ÷ *ñ *´´c¼3°hµð *ÀDñ *r   c                ót  € V P                  RR4      '       g   R# \        '       d   R# \        ;_uu_ 4        \        '       d    RRR4       R# RsRRR4        \        \	        RR4      4      p\        ^<V4      ^,          p ^ RIH	pH
p \        R4      ;_uu_ 4        T! T P                  R	R
4      4      pT! Y%R7      pT'       d   \        P                  RYe4       RRR4       R#   + '       g   i     LŸ; i  \
        \        3 d    Rp L¡i ; i  \         d     R# i ; i  + '       g   i     R# ; i)u  Run the docker orphan reaper once per process, if enabled.

Sweeps Exited containers labeled ``hermes-agent=1`` for the current
profile â€” leftovers of Hermes processes that died without firing
``atexit`` (SIGKILL, OOM, closed terminal). Conservative: only containers
older than ``2 Ã— lifetime_seconds``, profile-scoped. Gates:
``terminal.docker_orphan_reaper: false`` (operator opt-out, e.g. several
Hermes processes sharing a profile) and the once-per-interpreter flag so
parallel subagent / RL-rollout calls don't re-sweep.
Údocker_orphan_reaperTNÚTERMINAL_LIFETIME_SECONDSÚ300i,  )Úreap_orphan_containersÚ_container_identityzDocker orphan reaper raisedÚdocker_shared_container_keyr   )Úmax_age_secondsÚprofile_filterzADocker orphan reaper removed %d stale container(s) for profile %s)r‹   Ú_docker_orphan_reaper_ranÚ_docker_orphan_reaper_lockÚintr&   r9   r:   ÚmaxÚtools.environments.dockerr�   rž   ÚImportErrorr$   r;   Úinfo)r—   ÚlifetimeÚmax_ager�   rž   ÚprofileÚremoveds   &      r   Ú_maybe_reap_docker_orphansr­   Ä   s  € ð ×ÑÐ 6¸×=Ò=Ùß Ó Ùß	#Ö	#ß$Ó$Ø÷ 
$Ñ	#ð %)Ð!÷ 
$ðÜ”uÐ8¸%Ó@ÓAˆô �"�hÓ !Õ#€GðßYô 
Ð-×	.Õ	.Ù%Ð&6×&:Ñ&:Ð;XÐZ\Ó&]Ó^ˆÙ(¸ÔYˆßÜ�K‰KØSØô÷	 
/Ñ	.÷' 
$×	#ûô ”zÐ"ô ØŠðûô ô Úðú÷ 
/×	.Ð	.úsB   ·C(ÁC(ÁC; ÂD ÂA D&Ã(C8	Ã;DÄDÄD#Ä"D#Ä&D7	c                ó`   € V ^8„  d   QhR\         \        ,          R\         \        ,          RR/# )r   Úsession_keyÚcwdr
   N©r   r   )r   s   "r   r   r     s)   € ÷ 
$ñ 
$¤H¬S¥Mð 
$¼Ä½ð 
$È$ñ 
$r   c                ó:  € \        V\        4      '       d   VP                  4       '       g   R# \        \        T ;'       g    R4      4      p\        ;_uu_ 4        \
        P                  V4      V8w  d
   V\
        V&   RRR4       R#   + '       g   i     R# ; i)a/  Record *cwd* as *session_key*'s working directory (after a completed
command, or on workspace-override registration). None/empty keys collapse
to ``"default"``; non-string / empty cwds are ignored. Keys are routed-profile
qualified (:func:`_qualify_task_key`); the read/clear side qualifies identically.Nr4   )rw   r   rx   Ú_qualify_task_keyÚ_session_cwd_lockÚ_session_cwdr‹   )r¯   r°   Úkeys   && r   Úrecord_session_cwdr·     sg   € ô
 �cœ3×Ò s§y¡y§{¢{ÙÜ
œC × 8Ð 8¨yÓ9Ó
:€Cß	Ö	Ü×Ñ˜CÓ  CÔ'Ø #ŒL˜Ñ÷ 
×	×	Ò	ús   Á$B	Â	B	c                ó\   € V ^8„  d   QhR\         \        ,          R\         \        ,          /# )r   r¯   r
   r±   )r   s   "r   r   r     s&   € ÷ Rñ R¤¬#¥ð R´8¼Cµ=ñ Rr   c           
     ó¾   € \         ;_uu_ 4        \        P                  \        \	        T ;'       g    R4      4      4      uuRRR4       #   + '       g   i     R# ; i)z–Recorded cwd for *session_key*, or None. No fallback chain on purpose:
callers decide what an absent record means. None/empty keys read ``"default"``.r4   N)r´   rµ   r‹   r³   r   ©r¯   s   &r   Úget_session_cwdr»     s:   € ÷ 
Ö	Ü×ÑÔ 1´#°k×6NÐ6NÀYÓ2OÓ PÓQ÷ 
×	×	Ó	ús   �1AÁA	c                ó(   € V ^8„  d   QhR\         RR/# )r   r¯   r
   NrT   )r   s   "r   r   r     s   € ÷ ?ñ ?¤3ð ?¨4ñ ?r   c                óš   € \         ;_uu_ 4        \        P                  \        V 4      R4       RRR4       R#   + '       g   i     R# ; i)z/Drop a session's cwd record (session teardown).N)r´   rµ   Úpopr³   rº   s   &r   Úclear_session_cwdr¿     s-   € ç	Ö	Ü×ÑÔ*¨;Ó7¸Ô>÷ 
×	×	Ò	ús	   � 9¹A
	c                óR   € V ^8„  d   QhR\         R\        R\        \        ,          /# )r   ÚenvÚnew_cwdr
   )r   r   r   )r   s   "r   r   r   !  s%   € ÷ "ñ "¤Cð "´#ð "¼(Ä3½-ñ "r   c                ó‚  € \        V RR4      p\        W4      pV'       d   \        V4      '       g   V# \        V RR4      p\        V\        4      '       d   V'       d   TMRp\        WR7      '       g   V# V'       dA   \        V RR4      ;'       g    Rp\        W4      '       d   V# \        WV4      pV'       d   V# R# )a\  Cwd to write into a LIVE cached env, or None to leave it untouched.

On container backends a raw host path (a desktop/TUI session registering its
workspace, e.g. ``C:\Users\me`` or ``/Users/me/workspace``) cannot be the
in-sandbox workdir: every file-tools ``_exec`` wrapper does
``builtin cd -- <env.cwd> || exit 126``, so a host cwd poisons all later
file operations with an unrelated ``cd:`` error. Prefix-shaped host paths
are already rejected on the creation paths. This write classifies the
directory mounted at ``/workspace`` as unusable before that prefix
heuristic, then remaps the match (or a child of it) to its container mount
instead of storing the host path. SSH maps the Hermes subprocess home onto
the peer's home, as environment creation already does. Other backends apply
the override verbatim (ACP project-root switching must keep working).
r�   Nrƒ   ©Úmounted_hostÚhost_cwd_mountú
/workspace)rE   r)   r   rw   r   r    r   r*   )rÁ   rÂ   r�   Ú
host_mountÚmountedÚcontainer_mountÚ
translateds   &&     r   Ú_sanitize_cwd_for_live_envrÌ   !  s§   € ô �s˜J¨Ó-€HÜ# GÓ6€GßÔ0°×:Ò:ØˆÜ˜˜j¨$Ó/€JÜ& z´3×7Ò7¿J‰jÈD€Gô & g×DÓDØˆßä! #Ð'7¸Ó>×NÐNÀ,ˆÜ ×1Ò1Ø"Ð"Ü0°À?ÓSˆ
ßØÐÙr   c                óR   € V ^8„  d   QhR\         R\        \         \        3,          /# )r   Útask_idÚ	overrides©r   r   r   )r   s   "r   r   r   F  s"   € ÷ $ñ $¬ð $¼¼cÄ3¸h½ñ $r   c                óì  € V\         \        V 4      &   VP                  R4      p\        V\        4      '       d¨   VP                  4       '       d�   \        W4       \        V 4      p\        ;_uu_ 4        \        P                  V 4      ;'       g    \        P                  V4      pRRR4       Xe+   \        VRR4      e   \        WB4      pVe	   WTn        R# R# R# R# R# R#   + '       g   i     LD; i)u  Register per-task sandbox overrides (``docker_image``/``modal_image``/
``daytona_image`` or a plugin backend's ``<backend>_image``, ``env_type``,
``cwd``) before the agent loop runs.

A ``cwd`` override takes effect immediately: it becomes the session's
recorded cwd (until a ``cd`` changes it) and any live env's cwd is updated
too, so env-side seeding stays consistent (ACP switching project root
mid-session via ``session/load``). The session record keeps the RAW path
(host workspaces are tracked there on purpose); only the live-env write is
sanitized, since a host cwd can never be a container workdir.

Keyed like ``_session_cwd`` â€” routed-profile qualified (:func:`_qualify_task_key`) â€” so two
profiles registering the same task id never read each other's image/cwd (#123989).
r°   N)Ú_task_env_overridesr³   r‹   rw   r   rx   r·   Ú_resolve_container_task_idÚ	_env_lockÚ_active_environmentsrE   rÌ   r°   )rÎ   rÏ   rÂ   Úcontainer_idrÁ   Ú	sanitizeds   &&    r   Úregister_task_env_overridesrØ   F  sÃ   € ð 7@ÔÔ)¨'Ó2Ñ3à�m‰m˜EÓ"€GÜ�'œ3×Ò G§M¡M§O¢OÜ˜7Ô,ô 2°'Ó:ˆßŽYÜ&×*Ñ*¨7Ó3×]Ð]Ô7K×7OÑ7OÐP\Ó7]ˆC÷ àŠ?œw s¨E°4Ó8ÒDÜ2°3Ó@ˆIØÒ$Ø#–ñ %ñ  E‰?ñ %4Ñ÷ �Yús   Á43C#Ã#C3	c                ó$   € V ^8„  d   QhR\         /# )r   rÎ   rT   )r   s   "r   r   r   f  s   € ÷ .ñ .¤cñ .r   c                óÜ   € \         P                  \        V 4      R4       \        V 4       \        ;_uu_ 4        \
        P                  V R4       RRR4       R#   + '       g   i     R# ; i)zJDrop a task's overrides, cwd record and container alias (rollout cleanup).N)rÒ   r¾   r³   r¿   Ú_container_alias_lockÚ_container_aliases)rÎ   s   &r   Úclear_task_env_overridesrÝ   f  sE   € ä×ÑÔ-¨gÓ6¸Ô=Ü�gÔß	Ö	Ü×Ñ˜w¨Ô-÷ 
×	×	Ò	ús   ¹AÁA+	c                óJ   € V ^8„  d   QhR\         R\        \         ,          RR/# )r   Úchild_task_idÚparent_task_idr
   N©r   r   )r   s   "r   r   r   n  s+   € ÷ Mñ M¬Cð MÄÌ#Åð MÐSWñ Mr   c                ó¨   € V '       g   R# \         ;_uu_ 4        \        T;'       g    R4      \        V &   RRR4       R#   + '       g   i     R# ; i)z‹Make *child_task_id* resolve to *parent_task_id*'s container (called at
delegate_task spawn). A missing parent id aliases to ``"default"``.Nr4   )rÛ   r   rÜ   )rß   rà   s   &&r   Úregister_container_aliasrã   n  s7   € ÷ Ùß	Ö	Ü,/°×0KÐ0KÀ)Ó,LÔ˜=Ñ)÷ 
×	×	Ò	ús   ™A Á A	c                ó0   € V ^8„  d   QhR\         R\         /# ©r   rÎ   r
   rT   )r   s   "r   r   r   w  s   € ÷ ñ ¤cð ¬cñ r   c                óÖ   € \        4       pT p\        ;_uu_ 4        V\        9   d'   W!9  d!   VP                  V4       \        V,          pK1  RRR4       V#   + '       g   i     T# ; i)uA   Follow the childâ†’parent alias chain (cycle-safe) for *task_id*.N)ÚsetrÛ   rÜ   Úadd)rÎ   Úseenr¶   s   &  r   Ú_resolve_container_aliasrê   w  sR   € ä‹5€DØ
€Cß	Ö	ØÔ'Ô'¨C¬OØ�H‰H�SŒMÜ$ SÕ)ŠC÷ 
ð €J÷	 
Ö	ð €Jús   ›2AÁA(	c                ó0   € V ^8„  d   QhR\         R\        /# ©r   r¶   r
   rp   )r   s   "r   r   r   ‚  s   € ÷ 7ñ 7¤Cð 7¬Dñ 7r   c                ó>   € V R8H  ;'       g    V P                  R4      # )z]An image (``docker_image``, a plugin backend's ``<backend>_image``) or ``env_type`` override.r�   Ú_image)Úendswith)r¶   s   &r   Ú_is_isolation_override_keyrð   ‚  s   € à�*Ñ×6Ð6 §¡¨XÓ 6Ð6r   c                óF   € V ^8„  d   QhR\         \        ,          R\        /# rå   ©r   r   rq   )r   s   "r   r   r   ‡  s"   € ÷ ^ñ ^¤h¬s¥mð ^¼ñ ^r   c                óð   € V '       d   \         P                  \        V 4      4      MRp\        T;'       d=    \        ;QJ d$    R V 4       F  '       g   K   R4      # 	  R4      # ! R V 4       4      4      # )u¸   True when *task_id* registered image/env_type overrides â€” the single
"isolated RL/benchmark rollout" predicate shared by key resolution and
container creation so the two can't drift.Nc              3   óJ   "  € T F  p\        \        V4      4      x € K  	  R # 5ir†   )rð   r   )r‡   r¶   s   & r   rˆ   Ú+_has_isolation_overrides.<locals>.<genexpr>Œ  s   é € Ð!\ÑR[È3Ô"<¼SÀ»X×"FÐ"FÓR[ùs   ‚!#TF)rÒ   r‹   r³   rq   rŒ   )rÎ   rÏ   s   & r   Ú_has_isolation_overridesrö   ‡  s`   € ÷ HOÔ#×'Ñ'Ô(9¸'Ó(BÔCÐTX€IÜ�	×\Ð\Ÿc›cÑ!\ÑR[Ó!\ŸcœcÓ]Ð]šcÓ]Ð]˜cÑ!\ÑR[Ó!\Ó\Ó]Ð]r   T)Úfrozenc                   ó„   a € ] tR tRt o Rt]V 3R lR l4       t]V 3R lR l4       t]V 3R lR l4       tV 3R	 lt	R
t
V tR# )Ú_SessionScopei�  u�  Backend identity + scoping predicates for one call, read once.

``env_type`` is the scope-aware TERMINAL_ENV; ``persistent`` is
``TERMINAL_CONTAINER_PERSISTENT``. Derived predicates:

* ``session_isolated`` â€” non-persistent sandboxes get per-session identities:
  ``container_persistent: false`` means state must not survive or be shared
  across sessions, so one shared sandbox contradicts it. Docker, plus plugin
  backends declaring ``session_isolated_when_nonpersistent`` (sandboxes resumed
  by name, where a shared deterministic name would let two ephemeral runs
  attach one VM and delete it under each other).
* ``docker_session_isolated`` â€” docker-only view: the workspace mount and
  session-scoped teardown paths must not fire for other backends.
* ``docker_profile_scoped`` â€” docker + ``container_persistent: true``: ONE
  long-lived container per profile shared by every session (CLI, gateway,
  WebUI). The session-key fallback in :func:`_resolve_container_task_id` stops
  cross-profile SSH reuse; ungated it fragmented persistent Docker into one
  container per gateway session, so this restores profile scoping for exactly
  this backend/mode.
c                ó    <€ V ^8„  d   QhRS[ /# rS   ©rq   )r   Ú__classdict__s   "€r   r   Ú_SessionScope.__annotate__©  s   ø€ ÷ #ñ #¡$ñ #r   c                ó‚   € V P                   R 8w  d   \        V P                   R4      '       g   R# V P                  '       * # )r‚   Ú#session_isolated_when_nonpersistentF)r�   r#   Ú
persistent©Úselfs   &r   Úsession_isolatedÚ_SessionScope.session_isolated¨  s7   € à�=‰=˜HÔ$Ô-=Ø�M‰MÐ@÷.
ò .
ñ Ø—?‘?Ô"Ð"r   c                ó    <€ V ^8„  d   QhRS[ /# rS   rû   )r   rü   s   "€r   r   rý   ±  s   ø€ ÷ Cñ C©ñ Cr   c                óH   € V P                   R 8H  ;'       d    V P                  # ©r‚   )r�   r  r  s   &r   Údocker_session_isolatedÚ%_SessionScope.docker_session_isolated°  s   € à�}‰} Ñ(×BÐB¨T×-BÑ-BÐBr   c                ó    <€ V ^8„  d   QhRS[ /# rS   rû   )r   rü   s   "€r   r   rý   µ  s   ø€ ÷ =ñ =¡tñ =r   c                óH   € V P                   R 8H  ;'       d    V P                  # r  ©r�   r   r  s   &r   Údocker_profile_scopedÚ#_SessionScope.docker_profile_scoped´  s   € à�}‰} Ñ(×<Ð<¨T¯_©_Ð<r   c                ó2   <€ V ^8„  d   Qh/ S[ ;R&   S[;R&   # )r   r�   r   rp   )r   rü   s   "€r   r   rý   �  s   ø‡ ‚ ñ, �Mñ- ñ. Ñò/ r   rG   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Úpropertyr  r  r  Ú__annotate_func__Ú__static_attributes__Ú__classdictcell__©rü   s   @r   rù   rù   �  sP   ø‡ € ñð. ÷#ó ð#ð ÷Có ðCð ÷=ó ð=÷M ƒ r   rù   c                ó$   € V ^8„  d   QhR\         /# rS   )rù   )r   s   "r   r   r   ¹  s   € ÷ ñ œñ r   c                 óX   € \        4        \        \        RR4      \        RR4      R7      # )uJ   Bridge config â†’ env once, then snapshot the backend scope for this call.ÚTERMINAL_ENVÚlocalÚTERMINAL_CONTAINER_PERSISTENTÚtruer  )Ú_ensure_terminal_env_bridgedrù   r&   r'   rG   r   r   Ú_session_scoper!  ¹  s*   € ä Ô"ÜÜ�~ wÓ/ÜÐ=¸vÓFôð r   c                ó$   € V ^8„  d   QhR\         /# rS   rû   )r   s   "r   r   r   Â  s   € ÷ 4ñ 4¬4ñ 4r   c                 ó*   € \        4       P                  # )zOSee :attr:`_SessionScope.docker_session_isolated` (used by the docker builder).)r!  r  rG   r   r   Ú!_docker_session_isolation_enabledr$  Â  s   € äÓ×3Ñ3Ð3r   c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   Úprofile_scopedr
   )rq   r   r   )r   s   "r   r   r   Ç  s   € ÷ "ñ "¬$ð "´8¼Cµ=ñ "r   c                ó  € ^ RI HpHp ^ RIHp V! 4       pV'       d   V! V4      '       g   R# V '       d	   V! V4      MRpV'       d   VR8X  d   R# RV 2#  R\
        P                  P                  V4       2#   \         d	    RT 2u # i ; i)a  Key for a session-less task serving a routed (non-launch) profile home, else None.

A multiplexed host runs every profile's cron jobs without a session key; collapsing them all onto
``"default"`` made profile B's cron tool calls reuse the environment the launch profile's job
created (its ``.env`` residue, its bridged ``TERMINAL_*``, its shell), so B ran with A's settings.
Persistent Docker keys the profile name exactly like B's session-bound work, so B keeps ONE
container instead of a second one per home path.
rb   re   Nr4   úprofile:zhome:)	rg   rc   rd   rh   rf   r7   ÚpathÚrealpathÚOSError)r&  rc   rd   rf   ri   r«   s   &     r   Ú_routed_home_task_keyr,  Ç  sŒ   € ÷ QÝ8á'Ó)€Hß™?¨8×4Ò4Ùß1?Ñ# HÔ-ÀT€GßØ# yÔ0ˆyÐJ¸ÀÀ	Ð6JÐJð"Ø”r—w‘w×'Ñ'¨Ó1Ð2Ð3Ð3øÜô "Ø�x�jÐ!Ò!ð"ús   Á!A9 Á9BÂBc                ó0   € V ^8„  d   QhR\         R\         /# rì   rT   )r   s   "r   r   r   ß  s   € ÷ .ñ .œ3ð .¤3ñ .r   c                ó<   € \        RR7      pV'       d   V RV  2# T # )aC  Prefix a session-derived key with the routed profile/home, or return it unchanged.

A multiplexed host serves every profile in one process, and session ids are not
profile-unique (a header-less API client's ``api-<digest>`` fingerprint, a DM chat id
shared by two bots), so raw session keys in ``_active_environments`` / ``_session_cwd``
would hand profile B the sandbox and cwd profile A created (#123989). Persistent Docker
already keys the profile (branches 3/4); this covers the per-session keys. CLI and
single-profile gateways (no routed home) keep the historical raw key.
T)r&  rs   )r,  )r¶   Úscopes   & r   r³   r³   ß  s&   € ô "°Ô6€Eß$ˆeˆW�A�c�UÐÐ-¨#Ð-r   c                óF   € V ^8„  d   QhR\         \        ,          R\        /# rå   r±   )r   s   "r   r   r   í  s   € ÷ /3ñ /3¬´­ð /3¼#ñ /3r   c                ó  € V '       d   \        V 4      '       d   \        V 4      # \        4       pV '       d'   VP                  '       d   \        \	        V 4      4      # \        4       pVP                  '       d   \        RR4      P                  4       MRpV'       d   RV 2# V'       g    \        VP                  4      ;'       g    R# VP                  '       g   \        RV 24      # \        4       pVR8X  d   RMRV 2p\        WP4      # )uM  Map a tool-call ``task_id`` to the ``_active_environments`` key. Order matters â€”
earlier branches are authoritative where they apply:

1. Image/``env_type`` overrides (RL/benchmark rollouts) key their own sandbox;
   CWD-only overrides (ACP workspace tracking) are NOT isolation signals.
2. Per-session isolation (docker + ``container_persistent: false``): each
   session's task_id is its own key (a fresh chat gets a fresh sandbox with only
   ITS mounts); delegate_task children follow the alias registry to the parent.
   Routed profiles qualify the key (:func:`_qualify_task_key`, #123989).
3. Session key present (WebUI per-session, gateway per-message): persistent
   Docker is PROFILE-scoped â€” ``shared:<key>`` opt-in, else ``profile:<name>``,
   with the default profile staying literally ``"default"`` so CLI and
   default-profile gateway sessions share ONE container; other backends key
   ``session:<key>`` so switching profiles can't reuse another profile's
   SSHEnvironment on the wrong host.
4. No session key (CLI, cron): ``shared:<key>`` when opted in (else a CLI run of a
   keyed profile would split from its gateway sessions); a routed multiplexed profile
   keys its own home (``profile:<name>`` under persistent Docker, matching branch 3);
   else ``"default"``, which subagent ids collapse onto to share the parent's container.
Ú$TERMINAL_DOCKER_SHARED_CONTAINER_KEYr   zshared:r4   zsession:r(  )rö   r³   r!  r  rê   r[   r  r&   rx   r,  rl   Ú_workspace_container_key)rÎ   r/  r¯   Úsharedr«   Úbases   &     r   rÓ   rÓ   í  sæ   € ÷* Ô+¨G×4Ò4Ü  Ó)Ð)ÜÓ€Eß�5×)×)Ð)Ü Ô!9¸'Ó!BÓCÐCô 'Ó(€KØJO×Je×JeÐJeŒUÐ9¸2Ó>×DÑDÔFÐkm€Fßð ˜˜Ð!Ð!ßÜ$ U×%@Ñ%@ÓA×NÐNÀYÐNØ×&×&Ð&Ü  8¨K¨=Ð!9Ó:Ð:Ü Ó"€GØ 9Ô,‰9°H¸W¸IÐ2F€DÜ# DÓ2Ð2r   c                ó0   € V ^8„  d   QhR\         R\         /# )r   r°   r
   rT   )r   s   "r   r   r     s   € ÷ Eñ Eœ3ð E¤3ñ Er   c                óì   € ^ RI p\        P                  P                  \        P                  P	                  V 4      4      pVP                  VP                  R4      4      P                  4       R,          # )zÍThe ``:ws:`` digest of a host workspace: computed ONCE when the session binds it
(``gateway.session_policy.bind_turn_workspace``), so container keying never depends on live
filesystem state at lookup time.Nzutf-8:Né   N)Úhashlibr7   r)  r*  Ú
expanduserÚsha256ÚencodeÚ	hexdigest)r°   r9  Úresolveds   &  r   Úworkspace_key_forr?    sP   € ó Ü�w‰w×Ñ¤§¡× 2Ñ 2°3Ó 7Ó8€HØ�>‰>˜(Ÿ/™/¨'Ó2Ó3×=Ñ=Ó?ÀÕDÐDr   c                óR   € V ^8„  d   QhR\         R\        \         ,          R\         /# )r   r5  rÎ   r
   rá   )r   s   "r   r   r   (  s%   € ÷ ñ ¤3ð ´¼#µð Ä3ñ r   c                ó  € V'       g   V # VP                  V  R24      '       d   V# \        P                  V\        V4      34       Fº  p\        P                  \        V4      4      pV'       d   VP                  R4      R8w  d   KA  VP                  R4      pVP                  R4      pV'       g?   \        V\        4      '       d)   VP                  4       '       d   RV9  d   \        V4      pV'       g   K³  V  RV 2u # 	  V # )aË  Persistent Docker key for a session that registered a workspace: one container per
(profile, workspace), not per profile (#140665).

A gateway-owned CLI/Desktop session registers its client cwd as a ``cwd_source: "session"``
override (``gateway.session_policy.bind_turn_workspace``). Keyed by profile alone, every
concurrent session shared the container bound to whichever workspace created it first; sessions
in the same folder still share one. Sessions with no registered workspace keep the profile key.

Idempotent: an already-resolved ``<base>:ws:<digest>`` key maps to itself (``ensure_task_env``
hands the resolved key to ``get_active_env``, which resolves again). A ``delegate_task`` child has
only a container alias to its parent (``register_container_alias``), so the alias chain is
followed: the child runs in its parent's workspace container, never the profile's.
Reads the raw table (not :func:`resolve_task_overrides`, which calls back into key resolution).
z:ws:Ú
cwd_sourcerj   Úworkspace_keyr°   Ú )ry   r   Úfromkeysrê   rÒ   r‹   r³   rw   r   rx   r?  )r5  rÎ   r¶   rÏ   Údigestr°   s   &&    r   r3  r3  (  sÕ   € ÷ ØˆØ×Ñ˜T˜F $˜-×(Ò(ØˆÜ�}‰}˜gÔ'?ÀÓ'HÐIÖJˆÜ'×+Ñ+Ô,=¸cÓ,BÓCˆ	ß˜IŸM™M¨,Ó7¸9ÔDÙØ—‘˜Ó/ˆØ�m‰m˜EÓ"ˆßœ* S¬#×.Ò.°3·9±9·;²;À4ÈsÄ?Ü& sÓ+ˆFß‰6Ø�V˜4 ˜xÐ(Ò(ñ Kð €Kr   c                óh   € V ^8„  d   QhR\         \        ,          R\        \        \        3,          /# rå   )r   r   r   r   )r   s   "r   r   r   H  s&   € ÷ ñ ¤H¬S¥Mð ´d¼3Ä¸8µnñ r   c                ó¶   € T ;'       g    Rp\         P                  \        V4      4      ;'       g)    \         P                  \        V4      4      ;'       g    / # )aç  Return the env overrides for *task_id*, raw key first then collapsed.

``register_task_env_overrides`` writes under the *raw* task/session id, but
a CWD-only override collapses (:func:`_resolve_container_task_id`) to the
shared ``"default"`` container. Callers must therefore read the raw id
FIRST and only fall back to the collapsed container id, or the originating
session's override is silently dropped. Single source of that lookup so
the terminal and file layers can't drift apart.
r4   )rÒ   r‹   r³   rÓ   )rÎ   r>   s   & r   Úresolve_task_overridesrI  H  sU   € ð ×
Ð
�Y€Cä×ÑÔ 1°#Ó 6Ó7÷ 	ð 	Ü×"Ñ"Ô#=¸cÓ#BÓC÷	ð 	àðr   r‚   Údocker_imageÚmodalÚmodal_imageÚdaytonaÚdaytona_imagec                óŒ   € V ^8„  d   QhR\         R\        \         \        3,          R\        \         \        3,          R\         /# )r   r�   rÏ   r~   r
   rÐ   )r   s   "r   r   r   b  s9   € ÷ -ñ -œCð -¬D´´c°­Nð -ÄDÌÌcÈÅNð -ÔWZñ -r   c                ó²   € \         P                  V 4      pVf   VP                  V  R24      ;'       g    R# VP                  V4      ;'       g	    W#,          # )zàImage for *env_type*: per-task override first, then config; "" for imageless backends. A plugin
backend gets only its per-task ``<backend>_image`` override (batch runs register one); otherwise it
reads its own image setting.rî   r   )Ú_IMAGE_KEY_BY_BACKENDr‹   )r�   rÏ   r~   r¶   s   &&& r   Ú_select_imagerR  b  sP   € ô  ×
#Ñ
# HÓ
-€CØ
‚{Ø�}‰} ˜z¨Ð0Ó1×7Ð7°RÐ7Ø�=‰=˜Ó×,Ð, ¥Ð,r   c                óF   € V ^8„  d   QhR\         R\        \         ,          /# )r   Úeffective_task_idrÎ   rá   )r   s   "r   r   r   l  s   € ÷ ñ ¬#ð ¼Ä½ñ r   c                óš   € W3 FC  pV'       g   K  V\         9   g   K  \        P                  ! 4       \        V&   \         V,          u # 	  R# )av  Return the cached env for the collapsed id, else for the raw task_id, else None.

Caller holds ``_env_lock``. Per-session surfaces (ACP/gateway/dashboard)
with a CWD-only override collapse to ``"default"`` for container sharing,
yet an env may already be cached under the originating task_id; honor it
instead of spawning a duplicate. Refreshes ``_last_activity`` on a hit.
N)rÕ   ÚtimeÚ_last_activity)rT  rÎ   r¶   s   && r   Ú_lookup_active_envrX  l  s>   € ð "Ó+ˆß‰3�3Ô.Ö.Ü"&§)¢)£+ŒN˜3ÑÜ'¨Õ,Ò,ñ ,ñ r   c                óŠ   € V ^8„  d   QhR\         \        \        3,          R\        \        ,          R\        \        ,          /# )r   r~   rÎ   r
   )r   r   r   r   )r   s   "r   r   r   {  s2   € ÷ ñ ¤4¬¬S¨¥>ð ¼HÄS½Mð ÌhÔWZÍmñ r   c                óz  € V P                  R4      R8w  g   V P                  R4      '       g   R# \        4       '       d   \        V4      R8X  d   V P                  R4      # \        V4      pVP                  R4      pVP                  R4      R	8X  g-   \	        V\
        4      '       d   VP                  4       '       g   R# \        P                  P                  \        P                  P                  V4      4      p\        P                  P                  V4      '       d   VP                  R
4      '       d   R# V# )u’  Host directory to bind into *task_id*'s container.

Single owner of the cwd-mount policy for every creation site. Shared-
container mode: the ``TERMINAL_CWD``-derived ``config["host_cwd"]``.
Per-session isolation (docker + ``container_persistent: false``): only
the SESSION's own registered workspace may mount â€” the process env var is
a launch artifact that outlives the session that set it, so deriving a
fresh session's mount from it would leak the previous session's directory.
Overrides tagged ``cwd_source: "process"`` are refused for the same reason;
``cwd_source: "session"`` or untagged (ACP/RL) overrides mount.
A Windows drive path is not a mount source while the cwd-to-/workspace flag
is off. A raw host override must stay out of ``docker run -w`` and fall
back to the sanitized config cwd. The Windows bind, including when
``/workspace`` is already claimed, is the volume mount, not this override.
r�   r‚   r„   Nr4   rƒ   r°   rB  Úprocess©rÇ   ú/root)r‹   r$  rÓ   rI  rw   r   rx   r7   r)  Úabspathr:  Úisdirry   )r~   rÎ   rÏ   Ú	candidates   &&  r   Ú_resolve_task_host_cwdra  {  sâ   € ð  ‡z�z�*Ó Ô)°·±Ð<[×1\Ò1\Ùä,×.Ò.Ô2LÈWÓ2UÐYbÔ2bØ�z‰z˜*Ó%Ð%Ü& wÓ/€IØ—‘˜eÓ$€IØ‡}�}�\Ó" iÔ/´zÀ)ÌS×7QÒ7QÐYb×YhÑYh×YjÒYjÙÜ—‘—‘¤§¡× 2Ñ 2°9Ó =Ó>€Iä�7‰7�=‰=˜×#Ò# y×';Ñ';Ð<S×'TÒ'TÙØÐr   c                ó   € V ^8„  d   QhRR/# )r   r
   NrG   )r   s   "r   r   r      s   € ÷ -Cñ -C dñ -Cr   c                 ó†  € ^ RI Hp  V ! 4       e   R# ^ RIHp V! 4       e   R# \        '       d   R# Rs\        R4      ;_uu_ 4        ^ RIHpHp V! 4       p\        VP                  R4      \        4      '       d   V! RRR7       MR	\        P                  9  d   V! RR
R7       RRR4       R#   + '       g   i     R# ; i)u§  Backfill TERMINAL_* env vars from config.yaml when no launcher did.

CLI, gateway and TUI/dashboard PTY launches bridge ``terminal.*`` into env vars
at startup; processes that skip those paths (``hermes serve``, Desktop
in-process agents, desktop cron ticker, ACP) would otherwise fall back to the
local backend even when config selects docker â€” running on the host the user
meant to sandbox. Explicit keys in the ``terminal`` section override matching
env values (possibly stale from ``hermes setup``); env values for omitted keys
are preserved. Without a terminal section an existing TERMINAL_ENV is kept and
defaults are backfilled only when none is set. A per-turn terminal scope
suppresses the bridge entirely: writing scope values into the process-global
env would re-create the first-writer-wins cross-profile leak the scope fixes.

Ambient ``os.environ`` is the *launch* profile's authority only. Under a
context-local ``HERMES_HOME`` override (multiplexed dashboard / gateway
secondary profile), this bridge is a no-op â€” otherwise the first unscoped
call under that override would latch the secondary profile's ``terminal.*``
into process-global env and poison later unscoped launch-profile turns
(#107422 residual of #68559). Routed profiles must bind a terminal scope
instead (same rule as ``env_loader._reapply_terminal_config_bridge``).

terminal_tool reads ALL terminal settings from os.environ (TERMINAL_*). See #61115, #65696.
)Úget_terminal_scopeN)rc   Tu.   terminal config â†’ env fallback bridge failed)Úapply_terminal_config_to_envÚread_raw_configÚterminal)rÁ   ri   r  F)Útools.terminal_scoperd  rg   rc   Ú!_terminal_config_bridge_attemptedr$   Úhermes_cli.configre  rf  rw   r‹   r   r7   Úenviron)rd  rc   re  rf  Ú
raw_configs        r   r   r      sŽ   € õ0 8áÓÒ'Ùå9áÓ!Ò-Ùç(Ó(ÙØ(,Ð%ä	Ð@×	AÕ	AßSá$Ó&ˆ
Ü�j—n‘n ZÓ0´$×7Ò7Ù(¨T¸DÖAØ¤2§:¡:Ô-Ù(¨T¸EÕB÷ 
B×	A×	AÒ	Aús   ÁAB/Â/C 	Ússhru   Úvercel_sandboxc                ó0   € V ^8„  d   QhR\         R\         /# )r   r�   r
   rT   )r   s   "r   r   r   Ô  s   € ÷ 
ñ 
¤3ð 
¬3ñ 
r   c                 óÞ   € V R 8X  d   \        4       # V \        9   d   \        V ,          # \        V RR4      p\        V\        4      '       d!   VR8X  g   VP                  R4      '       d   V# R# )r  Údefault_cwdNru   rt   r]  )r%   Ú_DEFAULT_CWD_BY_BACKENDr#   rw   r   ry   )r�   Údeclareds   & r   Ú_backend_default_cwdrt  Ô  sa   € Ø�7ÔÜ‹~ÐØÔ*Ô*Ü& xÕ0Ð0Ü ¨-¸Ó>€Hô �(œC× Ò  h°#¤o¸×9LÑ9LÈS×9QÒ9QØˆÙr   c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r   r�   Úmount_docker_cwdr
   )r   rq   Útuple)r   s   "r   r   r   á  s!   € ÷ *ñ *¤#ð *¼ð *Ä%ñ *r   c                ót  € \        V 4      p\        RV4      p^ RIHp V'       d4   W28w  d.   V! W4      '       g    \        P
                  P                  V4      pRpV R8X  dÙ   V'       dÑ   \        P
                  P                  \        P
                  P                  \        R4      ;'       g    \        4       4      4      p\        V4      '       gb   \        P
                  P                  V4      '       dA   \        P
                  P                  V4      '       d   VP                  R4      '       g   TpRpW53# V R8X  d®   \        V4      '       d�   \        P
                  P                  V4      p\        P                  R8X  d    \        P
                  P                  V4      p\        P
                  P                  V4      '       d   TpTpW53# \        P!                  RW0V4       Tp W53# \#        V 4      '       d9   V'       d1   \%        V4      '       d    W28w  d   \        P!                  RW0V4       TpW53# )	zÿ``(cwd, host_cwd)`` from TERMINAL_CWD for *env_type*.

Container backends are sanity-checked: with Docker cwd passthrough the host
path is remapped to /workspace and tracked as host_cwd; otherwise host paths
are discarded in favor of the backend default.
ÚTERMINAL_CWD)Ú_is_ssh_remote_tilde_cwdNr‚   rÇ   ÚntzeIgnoring TERMINAL_CWD=%r for %s backend (host/relative path won't work in sandbox). Using %r instead.r\  )rt  r&   rj  rz  r7   r)  r:  r^  r%   r   Úisabsr_  ry   r!   r3   r;   r¨   r   r    )r�   rv  rq  r°   rz  rƒ   r`  s   &&     r   Ú_resolve_config_cwdr}  á  s»  € ô ' xÓ0€KÜ
� Ó
,€CÝ:ç
ˆsÔ!Ñ*BÀ8×*QÒ*QÜ�g‰g× Ñ  Ó%ˆØ€HØ�8Ô× 0Ü—G‘G—O‘O¤B§G¡G×$6Ñ$6´u¸^Ó7L×7^Ð7^ÔP\ÓP^Ó$_Ó`ˆ	ä˜×#Ò#Ü—‘—‘˜i×(Ò(¬R¯W©W¯]©]¸9×-EÒ-EÈi×NbÑNbÐcz×N{ÒN{à ˆHØˆCð* ˆ=Ðð) 
�XÔ	Ô"8¸×"=Ò"=ô —G‘G×&Ñ& sÓ+ˆ	Ü�7‰7�dŒ?ÜŸ™Ÿ™¨	Ó2ˆIÜ�7‰7�=‰=˜×#Ò#Ø ˆHØˆCð ˆ=Ðô �K‰Kð Xà {ô4ð ‰Cð ˆ=Ðô 
˜x×	(Ò	(¯SÔ5OÐPS×5TÒ5TÐY\ÔYkÜ�‰ð Tà ;ô	0ð ˆØˆ=Ðr   c                óF   € V ^8„  d   QhR\         \        \        3,          /# rS   r˜   )r   s   "r   r   r     s   € ÷ Gñ Gœœc¤3˜h�ñ Gr   c            
     ó  € ^ RI Hp  \        4        \        RR4      p\	        RR4      p\        V4      '       d,   \        RR\        R4      p\        R	R
4      p\        RR4      pMRRRrTpVR8X  d~   \        RR\        P                  R4      p\        RR\        P                  R4      p\        RR\        P                  R4      p\        RR\        P                  R4      p	\        RR4      p
M. . / . R3w  rgr‰p
\        W4      w  r¼/ RVbR\        \        RR4      4      bR\        RV 4      bR \        R!R"4      R8H  bR#VbR$\        R%V 4      bR&\        R'V 4      bR(\        R)R*4      P                  4       bR+\        R,R*4      P                  4       bR-VbR.VbR/VbR0\        R1R24      bR3\        R4R54      bR6\        R7R*4      bR8\        R9R*4      bR:\        R;R<4      b/ R=\        R>R*4      bR?\	        R@\        RARB4      4      bRC\	        RDRB4      bREVbRFVbRGVbRH\	        RIRB4      bRJVbRKVbRL\	        RMR4      bRN\	        ROR4      bRP\	        RQRB4      bRRV	bRSV
bRT\	        RURB4      bRV\        RWR*4      P                  4       bRX\	        RYRB4      bC# )ZzAResolve the terminal configuration dict from TERMINAL_* env vars.)ÚDEFAULT_SANDBOX_IMAGEr  r  Ú&TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACEÚfalseÚTERMINAL_CONTAINER_CPUÚ1ÚnumberÚTERMINAL_CONTAINER_MEMORYÚ5120ÚTERMINAL_CONTAINER_DISKÚ51200g      ð?i   i È  r‚   ÚTERMINAL_DOCKER_FORWARD_ENVz[]z
valid JSONÚTERMINAL_DOCKER_VOLUMESÚTERMINAL_DOCKER_ENVz{}ÚTERMINAL_DOCKER_EXTRA_ARGSÚTERMINAL_DOCKER_SHM_SIZEÚ1gr�   Ú
modal_modeÚTERMINAL_MODAL_MODEÚautorJ  ÚTERMINAL_DOCKER_IMAGEÚdocker_image_pinnedÚTERMINAL_DOCKER_IMAGE_PINNEDÚ0Údocker_forward_envrL  ÚTERMINAL_MODAL_IMAGErN  ÚTERMINAL_DAYTONA_IMAGEÚvercel_runtimeÚTERMINAL_VERCEL_RUNTIMEr   Úvercel_imageÚTERMINAL_VERCEL_IMAGEr°   rƒ   r„   ÚtimeoutÚTERMINAL_TIMEOUTÚ180Úlifetime_secondsr›   rœ   Ússh_hostÚTERMINAL_SSH_HOSTÚssh_userÚTERMINAL_SSH_USERÚssh_portÚTERMINAL_SSH_PORTÚ22Ússh_keyÚTERMINAL_SSH_KEYÚssh_persistentÚTERMINAL_SSH_PERSISTENTÚTERMINAL_PERSISTENT_SHELLr  Úlocal_persistentÚTERMINAL_LOCAL_PERSISTENTÚcontainer_cpuÚcontainer_memoryÚcontainer_diskÚcontainer_persistentr  rŠ   Ú
docker_envÚdocker_run_as_host_userÚ TERMINAL_DOCKER_RUN_AS_HOST_USERÚdocker_snap_compatÚTERMINAL_DOCKER_SNAP_COMPATÚdocker_networkÚTERMINAL_DOCKER_NETWORKÚdocker_extra_argsÚdocker_shm_sizeÚdocker_persist_across_processesÚ(TERMINAL_DOCKER_PERSIST_ACROSS_PROCESSESrŸ   r2  rš   ÚTERMINAL_DOCKER_ORPHAN_REAPER)Úhermes_cli.config_defaultsr€  r   r&   r'   r   r"   ÚfloatÚjsonÚloadsr}  r0   rx   )Údefault_imager�   rv  r°  r±  r²  r—  rŠ   r´  r»  r¼  r°   rƒ   s                r   Ú_get_env_configrÅ    s™  € åQÜ Ô"Ü�^ WÓ-€HÜ!Ð"JÈGÓTÐô
 ˜X×&Ò&Ü&Ð'?ÀÄeÈXÓVˆÜ)Ð*EÀvÓNÐÜ'Ð(AÀ7ÓK‰à:=¸tÀU¨ˆà�8ÔÜ+Ð,IÈ4ÔQU×Q[ÑQ[Ð]iÓjÐÜ'Ð(AÀ4ÌÏÉÐUaÓbˆÜ#Ð$9¸4ÄÇÁÈ\ÓZˆ
Ü*Ð+GÈÌtÏzÉzÐ[gÓhÐÜÐ :¸DÓA‰à]_ÐacÐegÐikÐmqÐ]qÑZÐ¨JÈ?ä'¨ÓC�M€Cð+Ø�Hð+àÔ'¬Ð.CÀVÓ(LÓMð+ð 	œÐ5°}ÓEð+ð 	œuÐ%CÀSÓIÈSÑPð	+ð
 	Ð0ð+ð 	”uÐ3°]ÓCð+ð 	œÐ7¸ÓGð+ð 	œ%Ð 9¸2Ó>×DÑDÓFð+ð 	œÐ5°rÓ:×@Ñ@ÓBð+ð 	ˆsð+ð 	�Hð+ð 	(Ð)9ð+ð 	”>Ð"4°eÓ<ð+ð 	œNÐ+FÈÓNð+ð  	”EÐ-¨rÓ2ð!+ð" 	”EÐ-¨rÓ2ð#+ð$ 	”NÐ#6¸Ó=ñ%+ð& 	”5Ð+¨RÓ0ð'+ð, 	œ*Ø%¤uÐ-HÈ&Ó'Qó
ð-+ð2 	œJÐ'BÀFÓKð3+ð6 	˜ð7+ð8 	Ð,ð9+ð: 	˜.ð;+ð< 	¤
Ð+JÈFÓ Sð=+ð> 	˜.ð?+ð@ 	�jðA+ðB 	"¤:Ð.PÐRYÓ#ZðC+ðD 	œjÐ)FÈÓPðE+ðF 	œ*Ð%>ÀÓGðG+ðH 	Ð.ðI+ðJ 	˜?ðK+ðP 	*¬:Ð6`ÐbhÓ+iðQ+ðR 	&¤uÐ-SÐUWÓ'X×'^Ñ'^Ó'`ðS+ðT 	¤
Ð+JÈFÓ SñU+ð +r   c                 óB  € \         '       d€   \        R\        P                  R7      ;_uu_ 4        \	        \        4       R,          4       RRR4       \        ^<4       F(  p \         '       g    Ko  \        P                  ! ^4       K*  	  K‹  R#   + '       g   i     LK; i)zKBackground thread worker that periodically cleans up inactive environments.zError in cleanup thread)Úlevelr¡  N)	Ú_cleanup_runningr$   ÚloggingÚWARNINGr   rÅ  ÚrangerV  Úsleep)Ú_s    r   Ú_cleanup_thread_workerrÎ  X  s_   € ç
Ó
ÜÐ-´W·_±_×EÖEÜ"¤?Ó#4Ð5GÕ#HÔI÷ Fä�r–ˆAß#Ó#ÚÜ�JŠJ�qŽMó ñ ßE×Eús   °BÂB	c                 ó  € \         ;_uu_ 4        \        e   \        P                  4       '       g3   Rs\        P
                  ! \        RR7      s\        P                  4        RRR4       R#   + '       g   i     R# ; i)z;Start the background cleanup thread if not already running.NT)ÚtargetÚdaemon)rÔ   Ú_cleanup_threadÚis_aliverÈ  Ú	threadingÚThreadrÎ  ÚstartrG   r   r   Ú_start_cleanup_threadr×  c  sO   € ÷ 
ŽÜÒ"¬/×*BÑ*B×*DÒ*DØ#ÐÜ'×.Ò.Ô6LÐUYÔZˆOÜ×!Ñ!Ô#÷	 
��Šús   �"A.²2A.Á.A?	c                 ó|   € Rs \        e    \        P                  ^R7       R# R#   \        \        3 d     R# i ; i)z#Stop the background cleanup thread.FN©rž  )rÈ  rÒ  ÚjoinÚ
SystemExitÚKeyboardInterruptrG   r   r   Ú_stop_cleanup_threadrÝ  n  sE   € ð ÐÜÒ"ð	Ü× Ñ ¨Ð Ö+ñ #øô Ô-Ð.ô 	Úð	ús   Œ& ¦;º;c                 ó`  € \        4        \        '       dŒ   \        P                  R\	        \        4      4       \        \        P                  4       4      p \        4        V  F;  p\        VRR4      pVf   K  \        R4      ;_uu_ 4        V! RR7       RRR4       K=  	  R\        P                  9   dP   \        R4      ;_uu_ 4        \        P                  R,          P                  P                  RR7       RRR4       R# R#   + '       g   i     K¶  ; i  + '       g   i     R# ; i)	zFStop the cleanup thread and shut down all remaining sandboxes on exit.z)Shutting down %d remaining sandbox(es)...Úwait_for_cleanupNzwait_for_cleanup raised on exitg      .@rÙ  ztools.environments.dockerzteardown drain raised on exit)rÝ  rÕ   r;   r¨   rz   ÚlistÚvaluesr   rE   r$   ÚsysÚmodulesÚDockerEnvironmentÚwait_for_all_teardowns)Úenvs_to_waitrÁ   Úwait_fns      r   Ú_atexit_cleanuprè  y  sÛ   € äÔßÓÜ�‰Ð?ÄÔEYÓAZÔ[ô
 Ô0×7Ñ7Ó9Ó:ˆÜ Ô"ÛˆCÜ˜cÐ#5°tÓ<ˆGØÔ"ÜÐ=×>Õ>Ù DÕ)÷ ?Ñ>ñ  ð #¤c§k¡kÔ1ÜÐ3×4Õ4Ü�K‰KÐ3Õ4×FÑF×]Ñ]ÐfjÐ]Ôk÷ 5Ñ4ñ 2÷ ?×>Ð>ú÷ 5×4Ð4ús   Â
DÃ
2DÄDÄD-	c                ó0   € V ^8„  d   QhR\         R\        /# ©r   r�   r
   rp   )r   s   "r   r   r   ‘  s   € ÷ Sñ S¬#ð S´$ñ Sr   c                ó˜   € RP                  V P                  4       P                  4       4      pVP                  R4      ;'       d    RV9   # )z¿True when PTY mode would break a stdin-driven command: `gh auth login
--with-token` waits for EOF on piped stdin, and under a PTY
`process.submit()` only sends a newline, so it hangs forever.Ú zgh auth loginz--with-token)rÚ  ÚlowerÚsplitry   )r�   Ú
normalizeds   & r   Ú_command_requires_pipe_stdinrð  ‘  s?   € ð —‘˜'Ÿ-™-›/×/Ñ/Ó1Ó2€JØ× Ñ  Ó1×RÐR°nÈ
Ñ6RÐRr   )Ú_foreground_background_guidanceÚ_safe_command_previewÚ_validate_workdirÚgateway_lifecycle_blockÚself_repo_blockÚtrailing_amp_background_command)Ú_YIELDED_NOTEÚspawn_background_processÚyield_to_background_handler)Úfinalize_foreground_resultc                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   Únotify_on_completeÚ
backgroundr
   )rq   rw  )r   s   "r   r   r   ¡  s#   € ÷ 
ñ 
¼tð 
Ôaeð 
Ôjoñ 
r   c                ó>   € V'       d   V '       d   V'       d   R# VR3# )u+  Resolve notify_on_complete + watch_patterns both set: drop watch_patterns
(combined they produce duplicate async notifications â€” one per match plus
one on exit â€” that can spam the user long after the process ends).
Returns ``(watch_patterns_to_use, conflict_note)``; note is "" without conflict.r   )Nzuwatch_patterns ignored because notify_on_complete=True; these two flags produce duplicate notifications when combinedrG   )rü  Úwatch_patternsrý  s   $$$r   Ú#_resolve_notification_flag_conflictr   ¡  s#   € ÷
 ×(¯^ð
ð 	
ð ˜2ÐÐr   c                ó>   € V ^8„  d   QhR\         R\         R,          /# )r   r)  r
   NrT   )r   s   "r   r   r   ®  s   € ÷ :ñ :¤ð :¬c°D­jñ :r   c                óº   € Ve	   V '       g   R# \        VRR4      p\        VRR4      p\        V\        4      '       d   V'       d	   V'       g   R# \        WV4      # )zFContainer path for *path* when *env* bind-mounted that host directory.Nrƒ   rÆ   )rE   rw   r   r*   )r)  rÁ   ÚhostÚmounts   &&  r   Ú_rewrite_via_env_mountr  ®  sJ   € à
‚{Ÿ$ÙÜ�3˜
 DÓ)€DÜ�CÐ)¨4Ó0€EÜ�dœC× Ò ¯·EÙÜ& t°5Ó9Ð9r   c                 óJ   € V e   V .# \        \        P                  4       4      # r†   )rà  rÕ   rá  )rÁ   s   &r   Ú_mount_envsr  ¹  s#   € Ø
‚ØˆuˆÜÔ$×+Ñ+Ó-Ó.Ð.r   c                óJ   € V ^8„  d   QhR\         R\         R,          R\         /# )r   r)  r�   Nr
   rT   )r   s   "r   r   r   ¿  s%   € ÷ ñ ¤ð ´°dµ
ð Ìñ r   c                 ó¢   € V '       d   \        T;'       g    R 4      '       g   V # \        V4       F  p\        W4      pV'       g   K  Vu # 	  V # )r   )r   r  r  )r)  r�   rÁ   ÚitemrË   s   &&&  r   Ú_container_visible_cwdr  ¿  sF   € ßÔ,¨X¯^¨^¸×<Ò<ØˆÜ˜CÖ ˆÜ+¨DÓ7ˆ
ß‰:ØÒñ !ð €Kr   c                óJ   € V ^8„  d   QhR\         R\         R,          R\         /# )r   rq  r�   Nr
   rT   )r   s   "r   r   r   É  s&   € ÷ ñ ¬Cð ¼3À½:ð ÔTWñ r   c                ó   € \        T;'       g    R4      '       g   V # \        V4       FQ  p\        VRR4      p\        VRR4      pV'       d   V'       d   W@8X  d   K5  V R8X  g   \        V 4      '       g   KO  Vu # 	  V # )zXPoint a planner ``/workspace`` assumption at the mount that actually holds the host cwd.r   rÆ   Nrƒ   rÇ   )r   r  rE   r    )rq  r�   rÁ   r
  r  r  s   &&&   r   Ú_container_visible_defaultr  É  sr   € ä  § ¨R×0Ò0ØÐÜ˜CÖ ˆÜ˜Ð.°Ó5ˆÜ�t˜Z¨Ó.ˆßŸD EÔ$8ÙØ˜,Ô&Ô*DÀ[×*QÔ*QØŠLñ !ð Ðr   r¯   r�   rÅ   rÁ   c                ó¸   € V ^8„  d   QhR\         \        ,          R\        R\         \        ,          R\         \        ,          R\         \        ,          R\        /# )r   Úworkdirrq  r¯   r�   rÅ   r
   r±   )r   s   "r   r   r   ×  s^   € ÷ /oñ /oä”c�]ð/oô ð/oô œ#•ð	/oô
 ”s�mð/oô œ3•-ð/oô 	ñ/or   c                óÌ  € V '       d   \        \        WV4      V4      # \        V4      pV'       d•   \        V4      '       d„   \	        WdR7      '       dr   \        We4      '       ga   \        WcV4      pWv8w  d   V# \        Wd4      '       d   \        P                  RWc4       R# \        P                  RWcV4       \        WV4      # \        T;'       g    \        WV4      V4      # )uH  cwd for a command: explicit ``workdir`` > the session's own cwd record >
``default_cwd``.

The record is written after every completed command of THIS session, so
it is the session's ``cd`` state with no shared-env ambiguity. On
container backends a recorded HOST path (a desktop/TUI surface registering
its workspace) is unusable in the sandbox â€” ``cd <host path>`` fails with
exit 126 â€” so it is discarded in favor of ``default_cwd``.

A recorded cwd that IS the host directory mounted at ``/workspace`` is
classified unusable before the ``/Users`` / ``/home`` / drive-letter
heuristic (``/mnt/...``, ``/srv/...`` are absolute and miss that heuristic)
and remapped to ``/workspace`` so the session wrapper does not ``cd`` to it.

Same guard class as the env-creation sanitizers (#50636, #54447); this is the per-command sibling site.
rÄ   zfRemapping recorded session cwd %r for %s backend (mounted host directory). Using '/workspace' instead.rÇ   zmIgnoring recorded session cwd %r for %s backend (host/relative path won't work in sandbox). Using %r instead.)
r)   r  r»   r   r    r(   r   r;   r¨   r  )r  rq  r¯   r�   rÅ   rÁ   ÚrecordedÚvisibles   $$$$$$  r   Ú_resolve_command_cwdr  ×  sÑ   € ÷2 Ü$Ô%;¸GÈsÓ%SÐU]Ó^Ð^Ü˜{Ó+€HßÔ)¨(×3Ò3Ô8RØ÷9ó 9ä˜x×-Ò-Ü(¨¸SÓAˆØÔØˆNÜ ×7Ò7Ü�K‰KðHàôñ
  Ü�‰ðLà ô	
ô
 *¨+ÀÓEÐEÜ  ×!cÐ!cÔ-GÈÐ_bÓ-cÐemÓnÐnr   Ú	exit_codeÚstatusc                ó^   € V ^8„  d   QhR\         R\        R\        \         ,          R\         /# )r   Úerrorr  r  r
   )r   r¤   r   )r   s   "r   r   r   	  s-   € ÷ 0ñ 0”sð 0¬#ð 0¼HÄS½Mð 0Ô^añ 0r   c               ót   € RRRVRV /pVe   W$R&   VP                  V4       \        P                  ! VRR7      # )zWThe terminal error envelope: ``output``/``exit_code``/``error`` (+ ``status``, extras).Úoutputr   r  r  r  F©Úensure_ascii)ÚupdaterÂ  Údumps)r  r  r  ÚextraÚbodys   &$$, r   Ú_error_jsonr!  	  s>   € à$ b¨+°yÀ'È5ÐQ€DØÒØˆX‰Ø‡K�K�ÔÜ�:Š:�d¨Ô/Ð/r   c                ó0   € V ^8„  d   QhR\         R\        /# )r   Úer
   )ÚBaseExceptionr   )r   s   "r   r   r     s   € ÷ ñ œð ¬3ñ r   c                óÄ   € ^ RI pVP                  4       p\        P                  RV4       \        P
                  ! RRRRR\        RV  24      R\        V4      R	R/R
R7      # )zÔLog the traceback and return the redacted error+traceback envelope.

Exception text can embed the failing command line (and any secrets inline
in it), so both fields are force-redacted before reaching the model.
Nzterminal_tool exception:
%sr  r   r  r  zFailed to execute command: Ú	tracebackr  Fr  éÿÿÿÿ)r&  Ú
format_excr;   r  rÂ  r  r   )r#  r&  Útb_strs   &  r   Ú_fatal_error_jsonr*    sl   € ó Ø×!Ñ!Ó#€FÜ
‡L�LÐ/°Ô8Ü�:Š:Ø�"Ø�RØÔ,Ð/JÈ1È#Ð-NÓOØÔ0°Ó8Ø�'ðð ôð r   c                   óB   a a€ ] tR tRt oRtV3R lV 3R lltRtVtV ;t# )Ú	_Rejectedi$  z¶Carries a finished tool-result JSON out of the planning/guard helpers, so
each early-return site is one ``raise`` instead of an isinstance-checked
``str | plan`` union at the caller.c                ó    <€ V ^8„  d   QhRS[ /# )r   Úresult_jsonrT   )r   rü   s   "€r   r   Ú_Rejected.__annotate__)  s   ø€ ÷ 'ñ '¡Cñ 'r   c                ó2   <€ \         SV `  V4       Wn        R # r†   )ÚsuperÚ__init__r.  )r  r.  Ú	__class__s   &&€r   r2  Ú_Rejected.__init__)  s   ø€ Ü‰Ñ˜Ô%Ø&Ör   )r.  )	r  r  r  r  r  r2  r  r  Ú__classcell__)r3  rü   s   @@r   r,  r,  $  s   ù‡ € ñ+÷'÷ 'ó 'r   r,  c                   ó8   a € ] tR tRt o RtRtRtV 3R ltRtV t	R# )Ú_ApprovalVerdicti.  aS  Outcome of the pre-exec guard pass.

``note`` is the audit note attached to the result. ``approved_run`` is True
when the user explicitly approved (or pre-confirmed via ``force``); it drives
the clean-interrupt-slate clear before ``env.execute`` so an approved command
can't be SIGINT-killed by a bit that landed during the approval-wait.
NFc                óB   <€ V ^8„  d   Qh/ S[ S[,          ;R&   S[;R&   # )r   ÚnoteÚapproved_runrò   )r   rü   s   "€r   r   Ú_ApprovalVerdict.__annotate__.  s#   ø‡ ‚ ñ ‘3�-Ññ ñ Ñò r   rG   )
r  r  r  r  r  r9  r:  r  r  r  r  s   @r   r7  r7  .  s   ø‡ € ñð €DØ€L÷ ƒ r   r7  c          
      óv   € V ^8„  d   QhR\         R\         R\        \         \        3,          R\        R\        /# )r   r�   r�   r~   r   r
   )r   r   r   rq   r7  )r   s   "r   r   r   ;  s9   € ÷ !ñ !¤#ð !´ð !¼dÄ3ÌÀ8½nð !ÔX\ð !Ôaqñ !r   c               ó  € V'       d   \        RR7      # \        W\        V4      R7      pVR,          '       gê   VP                  R4      R8X  dm   \	        \        RRRVP                  RV 4      VP                  R	R
4      VP                  RR4      VP                  RR4      VP                  RR4      R7      4      hVP                  R	R
4      pRV R2p\	        \        VP                  RV4      3RR/VP                  R4      '       d   RVR,          /B 4      h/ B 4      hVP                  R	R4      pVP                  R4      '       d   \        RV R2RR7      # VP                  R4      '       d   \        RV R2R7      # \        4       # )z”Run the command guards; ``force`` skips them entirely.
Raises :class:`_Rejected` when the command may not run (denied, or pending
gateway approval).T)r:  )r�   Úapprovedr  Úpending_approvalr   r�   Údescriptionzcommand flaggedÚpattern_keyÚsmart_deniedFÚallow_permanent)r  Úapproval_pendingr�   r@  rA  rB  rC  zCommand denied: z?. Use the approval prompt to allow it, or rephrase the command.ÚmessageÚblockedÚuser_summaryzflagged as dangerousÚuser_approvedzCommand required approval (z) and was approved by the user.)r9  r:  Úsmart_approvedzCommand was flagged (z&) and auto-approved by smart approval.)r9  )r7  r”   r�   r‹   r,  r!  )r�   r�   r~   r   rJ   ÚdescÚfallback_msgs   &&&$   r   Ú_run_approval_guardsrL  ;  s¨  € ÷ Ü¨TÔ2Ð2Ü  ÔD[Ð\bÓDcÔd€HØ�J×ÔØ�<‰<˜Ó!Ð%7Ô7ÜœKØÐ-Ø!%Ø Ÿ™ Y°Ó8Ø$ŸL™L¨Ð8IÓJØ$ŸL™L¨¸Ó;Ø%Ÿ\™\¨.¸%Ó@Ø (§¡Ð->ÀÓ Eôó ð ð �|‰|˜MÐ+<Ó=ˆà˜t˜fð %Lð Lð 	ô œ H§L¡L°¸LÓ$Iñ |ÐR[ð |ØU]×UaÑUaÐbp×UqÒUq¨¸ÀÕ8PÐ'Qñ|ó }ð 	}Øwyñ|ó }ð 	}à�<‰<˜Ð'=Ó>€DØ‡|�|�O×$Ò$ÜØ.¨t¨fÐ4SÐTØô
ð 	
ð ‡|�|Ð$×%Ò%ÜÐ'<¸T¸FÐBhÐ%iÔjÐjÜÓÐr   c                   ó8   a € ] tR tRt o RtRtRtV 3R ltRtV t	R# )Ú	_ExecPlani_  zIPer-call execution parameters resolved before any environment is touched.Nc                óÌ   <€ V ^8„  d   Qh/ S[ S[S[3,          ;R&   S[;R&   S[;R&   S[;R&   S[;R&   S[S[,          ;R&   S[;R&   S[S[,          ;R&   S[S[,          ;R	&   # )
r   r~   r�   rT  Úimager°   rƒ   Úeffective_timeoutÚ promoted_from_foreground_timeoutÚauto_background_command)r   r   r   r   r¤   )r   rü   s   "€r   r   Ú_ExecPlan.__annotate___  s‹   ø‡ ‚ ñ ‘‘c��NÑñ ñ �Mñ	 ñ
 Ññ ñ �Jñ ñ 
�Hñ ñ ‘s�mÑñ ñ Ññ ñ '/©s¥mÑ:ñ ñ &¡c�]Ñ1ò r   rG   )
r  r  r  r  r  rR  rS  r  r  r  r  s   @r   rN  rN  _  s   ø‡ € áSð 7;Ð$ð .2Ð÷ ƒ r   rN  aR  Requested foreground timeout {requested}s exceeds the {cap}s cap, so this command was started as a tracked background process with notify_on_complete=true instead of being refused. Do NOT re-run it. Its completion (exit code + output tail) arrives as a notification; poll with process(action="poll", session_id=...) if you need it sooner.c                óŒ   € V ^8„  d   QhR\         R\        \        ,          R\        \        ,          R\        R\        R\
        /# )r   r�   rÎ   rž  rý  Ú_host_localr
   )r   r   r   r¤   rq   rN  )r   s   "r   r   r   y  sN   € ÷ Xñ XÜðXÜ&¤s�mðXÜ6>¼sµmðXäðXä#'ðXô ñXr   c               ó  € \        V \        4      '       gV   \        P                  R\	        V 4      P
                  4       \        \        R\	        V 4      P
                   2RR7      4      h\        4       pV'       d   RMVR,          pV'       g   ^ RI	H
p V! 4        \        V4      pV'       d   RV 2p\        V4      p	\        WiV4      p
\        V	P                  R	4      ;'       g    \!        V4      ;'       g
    VR	,          V4      p\#        WQ4      p\%        V4      '       dE   \'        W¼R
7      '       d3   V'       d   RMVR	,          pW½8w  d   \        P)                  RW¶V4       TpVe    V^ 8:  d   \        \+        RV R24      4      hRpV'       gO   \-        V 4      pVf?   \/        V 4      pV'       d   \        \        VRR7      4      hV'       d   V\0        8”  d   TpMRp\3        YVTY«YÂ;'       g
    VR,          WïR7	      # )zñResolve backend, env-cache key, image, cwd and timeout for one call.

Raises :class:`_Rejected` when the call is rejected up front (non-string
command, non-positive or over-cap timeout, a foreground command that must
run in the background).
z+Rejected invalid terminal command value: %sz&Invalid command: expected string, got r  ©r  r  r�   )Úenforce_no_refusalzhost-local-r°   rÄ   rÇ   zbRemapping host/relative cwd override %r for %s backend (won't exist in sandbox). Using %r instead.Nz2timeout must be a positive number of seconds (got z).rž  )	r~   r�   rT  rP  r°   rƒ   rQ  rR  rS  )rw   r   r;   r<   Útyper  r,  r!  rÅ  rh  rY  rÓ   rI  rR  r)   r‹   r»   ra  r   r    r¨   r   rö  rñ  ÚFOREGROUND_MAX_TIMEOUTrN  )r�   rÎ   rž  rý  rV  r~   r�   rY  rT  rÏ   rP  r°   rƒ   ÚremappedÚpromotedÚauto_bgÚguidances   &$$$$            r   Ú_plan_executionr`  y  sØ  € ô �gœs×#Ò#Ü�‰ÐDÄdÈ7Ãm×F\ÑF\Ô]ÜœØ4´T¸'³]×5KÑ5KÐ4LÐMÐV]ô
ó ð 	ô Ó€Fß%‰w¨6°*Õ+=€H÷ Ý;áÔä2°7Ó;Ðßð *Ð*;Ð)<Ð=Ðô
 ' wÓ/€IÜ˜(¨vÓ6€Eä
Ø�‰�eÓ×IÐI¤°Ó 8×IÐI¸FÀ5½MÈ8óU€Cä% fÓ6€Hô ˜X×&Ò&Ô+EÀc×+aÓ+aß#+‘<°¸µˆØŒ?Ü�K‰Kð>à˜xôð
 ˆð Ò˜w¨!œ|Üœ
Ð%WÐX_ÐW`Ð`bÐ#cÓdÓeÐeØ€Hßô 2°'Ó:ˆØŠ?Ü6°wÓ?ˆHßÜ¤¨H¸WÔ EÓFÐFß˜7Ô%;Ô;Ø"�øàˆäØÐ<MØ x×C_ÐC_ÈfÐU^ÕN_Ø)1ôð r   a&  Requested foreground timeout {requested}s exceeds the {cap}s cap, so this command was started as a tracked background process instead of being refused. Do NOT re-run it. This session cannot receive completion notifications, so poll it with process(action="poll", session_id=...) until it exits.c                ó<   € V ^8„  d   QhR\         R\        R\         /# )r   r.  Úrequested_timeoutr
   )r   r¤   )r   s   "r   r   r   Û  s!   € ÷ 0ñ 0¤Sð 0¼Sð 0ÄSñ 0r   c                ój  €  \         P                  ! V 4      p\	        T\
        4      '       d   TP                  R4      '       d   T # TP                  R4      '       d   \        M\        pTP                  T\        R7      TR&   \         P                  ! TRR7      #   \        \        3 d    T u # i ; i)a   Attach the foreground->background promotion note to a spawn result (unchanged on error). The
note only promises a notification when the spawn actually kept notify_on_complete (finite sessions
such as one-shot runners cannot route one back; the spawn already said so and cleared the flag).r  rü  )Ú	requestedÚcapÚpromoted_from_foregroundFr  )rÂ  rÃ  r9   r:   rw   r   r‹   Ú_PROMOTED_NOTEÚ_PROMOTED_NOTE_POLL_ONLYr   r[  r  )r.  rb  ÚdataÚtemplates   &&  r   Ú_with_promoted_noterk  Û  s–   € ðÜ�zŠz˜+Ó&ˆô �dœD×!Ò! T§X¡X¨g×%6Ò%6ØÐØ!%§¡Ð*>×!?Ò!?�~ÔE]€HØ'/§¡ÐARÔXn Ó'o€DÐ	#Ñ$Ü�:Š:�d¨Ô/Ð/øô ”zÐ"ô ØÒðús   ‚B ÂB2Â1B2c                óR   € V ^8„  d   QhR\         R\        \        ,          R\        /# )r   ÚplanrÎ   r
   )rN  r   r   r   )r   s   "r   r   r   ê  s%   € ÷ )ñ )”yð )¬8´C­=ð )¼Sñ )r   c                óJ  € \        4        V P                  V P                  r2\        ;_uu_ 4        \	        W14      pRRR4       Xe   V# \
        ;_uu_ 4        \        P                  V\        P                  ! 4       4      pRRR4       X;_uu_ 4        \        ;_uu_ 4        \	        W14      pRRR4       Ve   VuuRRR4       # \        P                  RW#R,          4        \        V P                  W P                  V P                  V P                   W0P"                  R7      p\        ;_uu_ 4        T\,        T&   \.        P.                  ! 4       \0        T&   RRR4       \        P                  R	Y#R,          4       TuuRRR4       #   + '       g   i     ELY; i  + '       g   i     EL'; i  + '       g   i     EL; i  \$         d)   p\'        \)        \+        RT R24      RR7      4      hRp?ii ; i  + '       g   i     L«; i  + '       g   i     R# ; i)
a6  Cached env for the task, else create it under the per-task creation lock.

Concurrent calls for the same task_id wait for the first sandbox instead
of each creating their own; the cache is re-checked under that lock.
Raises :class:`_Rejected` with the ``"disabled"`` envelope when creation
raises ImportError.
Nz*Creating new %s environment for task %s...:Né   N)rP  r°   rž  rÎ   rƒ   z5Terminal tool disabled: environment creation failed (Ú)ÚdisabledrX  z %s environment ready for task %s)r×  r�   rT  rÔ   rX  Ú_creation_locks_lockÚ_creation_locksÚ
setdefaultrÔ  ÚLockr;   r¨   r   r~   rP  r°   rQ  rƒ   r§   r,  r!  r   rÕ   rV  rW  )rm  rÎ   r�   ÚeffrÁ   Ú	task_lockÚnew_envr#  s   &&      r   Ú_acquire_envry  ê  sƒ  € ô ÔØ—M‘M 4×#9Ñ#9ˆcç	ŽÜ% cÓ3ˆ÷ 
à
‚Øˆ
ç	Ö	Ü#×.Ñ.¨s´I·N²NÓ4DÓEˆ	÷ 
÷ 
ŠßŽYÜ$ SÓ2ˆC÷ àŠ?Ø÷	 
Šô 	�‰Ð@À(ÐPRÍGÔTð		Ü,Ø—‘˜X¯Z©Z¸T¿X¹XØ×.Ñ.¸ÇmÁmôˆG÷ ŽYØ(/Ô  Ñ%Ü"&§)¢)£+ŒN˜3Ñ÷ ô 	�‰Ð6¸ÀbÅ'ÔJØ÷- 
Š÷ 
�ˆú÷
 
×	Ð	ú÷ �YˆYûô ô 	ÜœKÜ+Ð.cÐdeÐcfÐfgÐ,hÓiØ!ôó ð ûð	ú÷ �Yú÷% 
�ˆús~   °FÁ*F ÂHÂ#F4	Â/HÃHÃ%AGÄ'HÄ5&G>	Å&HÆF	Æ F1	Æ4GÆ?	HÇG;Ç#G6Ç6G;Ç;HÇ>HÈ	HÈH"	c                ó0   € V ^8„  d   QhR\         R\        /# rê  )r   r   )r   s   "r   r   r     s   € ÷ Eñ Eœ3ð E¬$ñ Er   c                ó0   € \        RRV /VB pVe   RV/# / # )zI``env.execute`` kwargs enabling yield-to-background (local backend only).r�   Úyield_handlerrG   )rù  )r�   ÚctxÚhandlers   &, r   Ú_yield_kwargsr    s)   € ä)ÑA°'ÐA¸SÑA€GØ)0Ò)<ˆO˜WÐ%ÐDÀ"ÐDr   Úmeteredc                óô   € V ^8„  d   QhR\         R\        R\        R\        \         ,          R\        \         ,          R\         R\        \         ,          R\        \         ,          R	\        R
\        R\         /# )r   r�   rÁ   rm  rÎ   Ú
session_idr¯   r  Úapproval_noteÚclear_interruptr€  r
   )r   r   rN  r   rq   )r   s   "r   r   r     s�   € ÷ Añ AÜðAÜðAÜ"+ðAä”c�]ðAä(0´­ðAäDGðAô ”c�]ðAô ,4´C­=ðAô LPðAô ð	Aô
 	ñAr   c               óÚ  € ^ RI Hp
 ^pVP                  VP                  VP                  rípV'       d   ^ RIHp V! 4        \        V^,           4       Fb  p \        YbP                  Y\\        VRR4      ;'       g    VP                  VR7      pVP                  ! V 3RVRVRR	/\        WVVW5R
7      B p M	  XP7                  R4      '       dS   \8        P:                  ! RVP7                  RR4      RRRRRRRVR,          RVP7                  R4      RR	R\<        /RR7      # V	'       d
   V
! WV4       \?        V VWVW4WVXVR7      #   \         Ed   pR\        T4      P!                  4       9   d   \#        RT R2^|R7      u Rp?u # TT8  dm   ^T^,           ,          p\$        P'                  RTT^,           T\)        T 4      \+        T4      P,                  TYÜ4	       \.        P0                  ! T4        Rp?EK¨  \$        P3                  RT\)        T 4      \+        T4      P,                  TYÜ4       \#        \5        R\+        T4      P,                   RT 24      4      u Rp?u # Rp?ii ; i) z—Execute in the foreground with retry on transient errors, then finalize. ``metered``
is False for Hermes' own control-plane commands (``_host_local``).)Úrecord_terminal_outcome)Úclear_current_thread_interruptrƒ   N)r  rq  r¯   r�   rÅ   rÁ   rž  r°   Úbounded_captureT)r�   r°   rT  rÎ   r¯   zCommand timed out after z seconds)r  zfExecution error, retrying in %ds (attempt %d/%d) - Command: %s - Error: %s: %s - Task: %s, Backend: %szWExecution failed after %d retries - Command: %s - Error: %s: %s - Task: %s, Backend: %szCommand execution failed: z: Úyielded_session_idr  r   r  r  r  Úyielded_to_backgroundr‚  Úpidrü  r9  Fr  )r�   ÚresultrÁ   r�   rT  rÎ   r‚  r¯   r  Úcommand_cwdrƒ  ) Ú/hermes_cli.observability.shared_metrics_harnessr†  r�   rT  rQ  Útools.interruptr‡  rË  r  r°   rE   rƒ   Úexecuter  Ú	Exceptionr   rí  r!  r;   r<   rò  rZ  r  rV  rÌ  r  r   r‹   rÂ  r  r÷  rú  )r�   rÁ   rm  rÎ   r‚  r¯   r  rƒ  r„  r€  r†  Úmax_retriesr�   rv  rQ  r‡  Úretry_countr�  rŒ  r#  Ú	wait_times   &&&$$$$$$$           r   Ú_run_foregroundr•    sh  € õ XØ€KØ'+§}¡}°d×6LÑ6LÈd×NdÑNdÐ$€H÷ ÝBÙ&Ô(ä˜[¨1�_Ö-ˆð	rÜ.Ø¯X©XÀ;Ü$ S¨*°dÓ;×LÐL¸t¿}¹}ØôˆKð —[’[ØñØ!2ðØ8CðØUYðä ÀÐ_bØ(/ôJñˆFñ
 ñ .ð@ ‡z�zÐ&×'Ò'Ü�zŠzØ�f—j‘j ¨2Ó.°¸TÀ7ÈDØÐ-¨|¸VÐDXÕ=YØ�6—:‘:˜eÓ$Ð&:¸DÀ&Ì-ð
ð ô	ð 	÷
 Ù °6Ô:Ü%Ø ¨CÐVYØ¸KØ¨}ôð øô1 õ 	rð œC ›FŸL™L›NÔ*Ü"Ð%=Ð>OÐ=PÐPXÐ#YÐehÔi×ià˜[Ô(Ø +°¥/Õ2�	Ü—‘ð   HØ(¨+¸­/¸;ÔH]Ð^eÓHfÔhlÐmnÓho×hxÑhxÐz{ð  ~AôLä—
’
˜9Ô%ÞÜ�L‰LÐrØ$Ô&;¸GÓ&DÄdÈ1Ãg×FVÑFVÐXYÐ[^ôjäÔ:Ð=WÔX\Ð]^ÓX_×XhÑXhÐWiÐikÐlmÐknÐ;oÓpÓq×qûð	rús3   ÁAEÅI*Å.I%Æ I*ÆA,I%Ç;A"I%ÉI*É%I*c                óz   € V ^8„  d   QhR\         R\        R\         R\         R\        \         ,          R\         RR/# )	r   r�   rÁ   r�   r°   r  r¯   r
   N)r   r   r   )r   s   "r   r   r   f  sJ   € ÷ %ñ %Üð%Üð%Ü),ð%Ü36ð%ä”c�]ð%ä),ð%ð 
ñ%r   c          	     óJ  € \        WW#WER7      pV'       d   \        V4      hV'       dQ   \        V4      pV'       d>   \        P	                  RVR,          \        V 4      4       \        \        VRR7      4      hVR8X  d#   \        WWER7      pV'       d   \        V4      hR# R# )	zæRaise :class:`_Rejected` with the blocked-result JSON when the command must not run.

Order matters: gateway lifecycle first (protects the running gateway),
then the dangerous-workdir check, then the self-repo guard (local only).
)r�   rÁ   r�   r°   r  r¯   z+Blocked dangerous workdir: %s (command: %s):NéÈ   NrF  rX  r  )r�   r°   r  r¯   N)rô  r,  ró  r;   r<   rò  r!  rõ  )r�   rÁ   r�   r°   r  r¯   rF  Úworkdir_errors   &$$$$$  r   Ú_pre_exec_blockrš  f  s’   € ô &Ø¨8Àgô€G÷ Ü˜Ó Ð ßÜ)¨'Ó2ˆßÜ�N‰NÐHØ" 4�=Ô*?ÀÓ*HôJäœK¨¸iÔHÓIÐIØ�7ÔÜ!¨'ÀGÔeˆßÜ˜GÓ$Ð$ñ ñ r   zÉPTY disabled for this command because it expects piped stdin/EOF (for example gh auth login --with-token). For local background processes, call process(action='close') after writing so it receives EOF.c                óR   € V ^8„  d   QhR\         R\        \        ,          R\        /# )r   r#  rÎ   r
   )r•   r   r   )r   s   "r   r   r   ˆ  s&   € ÷ ñ Ô2ð ¼XÄc½]ð Ìsñ r   c                ó°  € \        RR4      P                  4       P                  4       R8X  d   \        V 4      # \        P                  RV P                  4       \        R4      ;_uu_ 4        \        V4       RRR4       \        P                  ! RRR	RR
RRV P                  RV P                  RRV P                   2/RR7      #   + '       g   i     LU; i)zùInfrastructure failure (SSH host down, Docker daemon unreachable), distinct
from a nonzero exit. ``terminal.degraded_mode``: warn (default) returns a
structured degraded result with a retry hint; fail preserves the historical
error+traceback result.ÚTERMINAL_DEGRADED_MODEÚwarnÚfailzterminal backend degraded: %szdegraded-env eviction failedNr  r   r  r  ÚdegradedÚreasonÚ
retry_hintr  zTerminal backend degraded: Fr  r'  )r&   rx   rí  r*  r;   r<   r¡  r$   r   rÂ  r  r¢  )r#  rÎ   s   &&r   Ú_degraded_resultr£  ˆ  s³   € ô
 Ð% vÓ.×4Ñ4Ó6×<Ñ<Ó>À&ÔHÜ  Ó#Ð#Ü
‡N�NÐ2°A·H±HÔ=ä	Ð.×	/Õ	/Ü# GÔ,÷ 
0ä�:Š:Ø�"Ø�RØ�*Ø�!—(‘(Ø�a—l‘lØÐ.¨q¯x©x¨jÐ9ðð ôð ÷ 
0×	/ús   Á,CÃC	c                óP  € V ^8„  d   QhR\         R\        R\        \        ,          R\        \         ,          R\        \         ,          R\        R\        \         ,          R\        R	\        R
\        \        \         ,          ,          R\        R\        R\        R\        R\         /# )r   r�   rý  rž  rÎ   r‚  r   r  Úptyrü  rÿ  rV  Ú_completion_output_charsÚ	heartbeatÚpersist_on_releaser
   )r   rq   r   r¤   rà  )r   s   "r   r   r   �  sÙ   € ÷ }fñ }fÜð}fäð}fô ”c�]ð}fô ”c�]ð	}fô
 œ•ð}fô ð}fô ”c�]ð}fô 
ð}fô ð}fô œT¤#�YÕ'ð}fô ð}fô "ð}fô ð}fô ð}fô 	ñ}fr   c                óT  a aaaaa € ^ RI Hp Rp \        S W2WR7      p\        VRR4      pVe   VRuo p\	        Wó4      oVP
                  VP                  VP                  uoop^ RIH	p V! RR7      ;'       g    T;'       g    Ro ^ R	I
Hp ^ R
IHp \        VP                  \         4      pVP#                  \$        P&                  ! 4       P(                  4      p V! V VVVV V3R lVRR7      pVP+                  V4       VP,                  '       d   \/        \1        RV R2RR7      4      h\3        S SVP4                  VR7      pT;'       d    \7        S 4      pVP8                  e   RRRr˜pV'       dÚ   \;        R*/ RS bRSbRSbRVbRVbRS bRSbRSbR\        SRR4      ;'       g    VP<                  bRT;'       d    V'       * bRVbRV	bR VP>                  bR!V'       d   \@        MRbR"VbR#VbR$VbR%VRJ;'       d    VP8                  RJ b pVP8                  e   \C        VVP8                  4      pT! V
'       d   RV4      # TV4      # T! V
'       d   RMT\E        S SVW4S SVP>                  VPF                  V
'       * R&7
      4      #   TP+                  T4       i ; i  \.         d   pTPH                  u Rp?# Rp?i\J         d*   pT! T
'       d   RMT\M        TT4      R'R(7      u Rp?# Rp?i\N         d)   pT! T
'       d   RMT\Q        T4      R)R(7      u Rp?# Rp?ii ; i)+u´  Execute *command* in the configured terminal environment; returns a JSON string.

``force`` (internal, not in the model schema) skips the dangerous-command
check after the user confirmed. ``workdir`` is per-command and never
recorded as the session cwd. ``pty`` applies to the local backend only.
``notify_on_complete`` and ``watch_patterns`` are mutually exclusive
background-only flags: on conflict watch_patterns is dropped. watch_patterns
is hard rate-limited (1 notification / 15s / process) and auto-disabled
after repeated strikes or a lifetime cap, promoting to notify_on_complete â€”
use it only for rare one-shot signals on long-lived processes. ``heartbeat`` (seconds,
background-only, implies notify_on_complete) emits a "still running + output since last
time" event every N seconds so the agent stays current on a long job without polling.
``persist_on_release`` (background-only) keeps the process alive across agent-lifecycle
cleanup â€” session end, context compression, error recovery, max-iteration stop â€” all of
which kill the task's background processes; the user can still stop it on purpose via
process_manage kill (#41225).
``_completion_output_chars`` (internal) sizes the completion notification's output for a
spawner whose output is the payload (a bot DM's reply); 0 keeps the usual tail.
``_host_local`` forces the local backend for Hermes-owned control-plane
children (kept in a separate env cache from the configured backend).
)Úrecord_terminal_backendN)rÎ   rž  rý  rV  rS  T)Úget_current_session_keyr   )r4   )Úrun_bounded_sync)Úacting_for_tidc            	      ó&   <€ \        S SSSSSR 7      # ))rÁ   r�   r°   r  r¯   )rš  )r�   r°   rÁ   r�   r¯   r  s   €€€€€€r   Ú<lambda>Úterminal_tool.<locals>.<lambda>è  s   ø€ œØ ¨x¸SÈ'Ð_jõr   zterminal.pre-exec-guard)Úlabelz3Terminal pre-execution guard did not finish within zKs (process-identity probe wedged); the command was not run. Retry the call.r  rX  r   r�   rÁ   r�   rT  rÎ   r¯   r  r°   rÅ   rƒ   Úeffective_ptyrü  rÿ  rƒ  Úpty_disabled_reasonÚcompletion_output_charsÚheartbeat_secondsr¨  Úauto_backgrounded)rÎ   r‚  r¯   r  rƒ  r„  r€  r   )Úerror_classÚ	exceptionrG   ))Ú,hermes_cli.observability.shared_metrics_looprª  r`  rE   ry  r�   r°   rT  Útools.approvalr«  Úagent.deadliner¬  r�  r­  r¥   rQ  Ú_PRE_EXEC_GUARD_MIN_TIMEOUT_Srç   rÔ  Úcurrent_threadÚidentÚresetÚ	timed_outr,  r!  rL  r~   rð  rR  rø  rƒ   r9  Ú_PTY_DISABLED_REASONrk  r•  r:  r.  r•   r£  r‘  r*  )!r�   rý  rž  rÎ   r‚  r   r  r¥  rü  rÿ  rV  r¦  r§  r¨  Ú_meteredrm  r^  rT  r«  r¬  r­  Úguard_timeoutÚ_acting_tokenÚbounded_guardÚverdictÚpty_disabledrŒ  Úrr#  r°   rÁ   r�   r¯   s!   f&&&&&f&&&&&&&               @@@@r   Úterminal_toolrÉ  �  sd  ý€ õJ aØ€DðVfÜØ˜WÀ*ô
ˆô ˜$Ð 9¸4Ó@ˆØÒð #*¨4ÐˆG�ZÜ˜4Ó)ˆØ+/¯=©=¸$¿(¹(ÀD×DZÑDZÐ(ˆ�#Ð(õ
 	;á-°bÔ9×LÐL¸g¿m¸mÈˆõ 	4Ý2ô ˜D×2Ñ2Ô4QÓRˆØ&×*Ñ*¬9×+CÒ+CÓ+E×+KÑ+KÓLˆð		0Ù,÷ñ ð Ø/ôˆMð × Ñ  Ô/Ø×"×"Ð"ÜœKØEÀmÀ_ð U\ð \àôó ð ô ' w°¸$¿+¹+ÈUÔSˆà×DÐDÔ;¸GÓDˆØ×0Ñ0Ò<ð >BÀ4È¨NˆJßÜ-ò ÙðÙ%(ðÙ3;ðÙO`ðáðá-8ðáBIðáORðô % S¨*°dÓ;×LÐL¸t¿}¹}øðð "×6Ð6¨,Ô&6øð	ñ L^ð	ñ
  .ðð
 >E¿\º\ð÷ =IÕ$8Èdøðñ )Aðñ #,ðñ $6ðð #*°Ð"5×"gÐ"g¸$×:_Ñ:_ÐcgÐ:gøðˆFð ×4Ñ4Ò@Ü,¨V°T×5ZÑ5ZÓ[�Ù§K˜D¸6ÓBÐB°T¸6ÓBÐBÙ§™°´Ø�S˜$ØÀØ¨7¯<©<È×I]ÑI]Ø#”Oô	8
ó ð 	øðA × Ñ  Õ/ûôL ô Ø�}‰}ÕûÜ%ô oÙ§™°Ô7GÈÈ7Ó7SÐamÔnÕnûÜô fÙ§™°Ô7HÈÓ7KÐYdÔeÕeûðfús¯   �A3J# ÂAJ# ÃJ Ã0"J# Ä;J# Å&J# Å63J# Æ*J# Ç#J# Ç%J# È>J# ÉJ# ÉJ# É	J# É3J# ÊJ Ê J# Ê#L'Ê.J?Ê9L'Ê?L'ËL'ËK1Ë+L'Ë1L'Ë>L'Ë?L"ÌL'Ì"L'c                ó$   € V ^8„  d   QhR\         /# rS   rû   )r   s   "r   r   r     s   € ÷ 
ñ 
¤Tñ 
r   c                 óê   €  \        4       p \        P                  ! V R,          \        4      pV! V 4      #   \         d2   p\
        P                  RTRR7       \        RT 24        Rp?R# Rp?ii ; i)z¨Check if all requirements for the terminal tool are met. The reason for a failure is kept for
:func:`terminal_backend_unavailable_reason` (CLI startup notice / doctor).r�   z&Terminal requirements check failed: %sT)Úexc_infozthe requirements check failed: NF)rÅ  r+   r‹   r-   r‘  r;   r  r.   )r~   Úcheckerr#  s      r   Úcheck_terminal_requirementsrÎ    sg   € ðÜ Ó"ˆÜ'×+Ò+¨F°:Õ,>Ô@ZÓ[ˆÙ�v‹ÐøÜô Ü�‰Ð=¸qÈ4ˆÔPÜ"Ð%DÀQÀCÐ#HÔIÝûðús   ‚36 ¶A2Á&A-Á-A2)Úregistryr3   rg  r@  Ú
parametersrZ  ÚobjectÚ
propertiesr�   ÚstringzThe shell command to executerý  Úbooleanz;Keep running after this call returns; returns a session_id.r4   rž  z)Max seconds (default 180, foreground max z@). Finishing early returns at once, so set it generously. Above zws the command runs as a tracked background process with notify_on_complete=true (the result says so; do not re-run it).Úminimumr  z1Absolute working directory for this command only.r¥  z‘With background=true: pseudo-terminal for interactive CLIs (REPLs, coding agents); drive it with process_manage write/submit. Local backend only.Únotifya  With background=true. true: one notification on exit; use it for anything that ends (builds, tests, deploys), or the job runs silently. ['pattern', ...]: notify when a line matches, only for one-shot readiness on processes that never exit; rate-limited. Omit for servers/daemons.ÚanyOfÚarrayÚitemsr§  z½With background=true: also notify every N seconds (min 60) with new output; quiet ticks are skipped. For bounded jobs you must react to mid-run, never servers. Implies notify=true; 0 = off.r¨  z¤With background=true: survive session end, /new, compression and other cleanup (not host exit). Only for jobs the user explicitly wants to outlive the conversation.Úrequiredc                 ó&  € ^ RI Hp V! V 4       RV 9  d   RV 9   d   \        R4      # V P                  R4      pV P                  RR4      pV P                  R4      pV P                  R	4      ;'       g    ^ p\	        V P                  R
R4      4      p\        V\        4      '       d   \        V\        4      '       g   V^ 8  d   \        R4      # V P                  RR4      '       g\   V'       g   V'       g	   V'       d   \        R4      # ^ pV P                  RR4      '       d   \        R4      # V'       d   \        R4      # VeB   \        V\        4      '       d   TpRpM&\        V\        4      '       d   TpRpM\        R4      # V'       d   Rp\        V P                  R4      V P                  RR4      V P                  R4      VP                  R4      VP                  R4      V P                  R4      V P                  RR4      VVVVR7      # )é    )Úvalidate_prepared_terminalr�   Úcodez¥terminal received a 'code' parameter, but it requires a shell command in 'command'. Use execute_code(code=...) for Python; for shell, retry as terminal(command=...).rÖ  rü  Frÿ  r§  r¨  z`heartbeat must be a whole number of seconds (0 disables; positive values are clamped to min 60).rý  zžnotify only applies to background commands (foreground results return directly). Either drop it, or run as terminal(command=..., background=true, notify=...).r¥  zÊpty requires background=true (a PTY session is interacted with via process(action='write'/'submit'), which needs a tracked background process). Retry as terminal(command=..., background=true, pty=true).zÅpersist_on_release only applies to background commands (a foreground process is awaited inline and has nothing to persist). Retry as terminal(command=..., background=true, persist_on_release=true).Nzanotify must be true/false (notify on exit) or a list of strings (notify on output pattern match).Trž  rÎ   r‚  r  )r�   rý  rž  rÎ   r‚  r  r¥  rü  rÿ  r§  r¨  )	Úagent.terminal_approval_batchrÝ  r   r‹   rq   rw   r¤   rà  rÉ  )ÚargsÚkwrÝ  rÖ  rü  rÿ  r§  r¨  s   &,      r   Ú_handle_terminalrâ  d  sí  € ÝHÙ˜tÔ$ð ˜Ô ¨4¤Üð9ó
ð 	
ð �X‰X�hÓ€FØŸ™Ð"6¸Ó>ÐØ—X‘XÐ.Ó/€NØ—‘˜Ó%×*Ð*¨€IÜ˜dŸh™hÐ';¸UÓCÓDÐÜ�i¤×%Ò%¬°I¼t×)DÒ)DÈ	ÐTUÌÜÐ|Ó}Ð}Ø�8‰8�L %×(Ò(ß—^×'9ÜðFóð ð
 ˆ	Ø�8‰8�E˜5×!Ò!Üð.óð ÷ ÜðSóð ð
 ÒÜ�fœd×#Ò#Ø!'ÐØ!‰NÜ˜¤×%Ò%Ø#ˆNØ!&Ñäð<óð ÷ Ø!ÐÜØ—‘˜Ó#Ø—8‘8˜L¨%Ó0Ø—‘˜Ó#Ø—‘�yÓ!Ø—6‘6˜,Ó'Ø—‘˜Ó#Ø�H‰H�U˜EÓ"Ø-Ø%ØØ-ôð r   u   ðŸ’»i † )r3   ÚtoolsetÚschemar~  Úcheck_fnÚemojiÚmax_result_size_charsc                ó
  € V ^8„  d   Qh/ ^ \         9   d   \        \        \        3,          ;R&   ^\         9   d   \        \        \        3,          ;R&   ^\         9   d%   \        \        \
        P                  3,          ;R&   ^\         9   d,   \        \        \        \        \        3,          3,          ;R&   ^\         9   d   \        \        \        3,          ;R&   ^\         9   d   \        \        \        3,          ;R&   # )r   rÕ   rW  rs  rÒ   rµ   rÜ   )Ú__conditional_annotations__r   r   r   rÁ  rÔ  ru  )r   s   "r   r   r      sÅ   € ÷ ñ ÷j *Ò )”dœ3¤˜8•nÑ )ñk÷l &Ò %””Sœ%�ZÕ Ñ %ñm÷p 0Ò /””cœ9Ÿ>™>Ð)Õ*Ñ /ñq÷d 4Ò 3”Tœ#œt¤C¬ H�~Ð-Õ.Ñ 3ñe÷t "Ò !Œd”3œ�8�nÑ !ñu÷B (Ò '”Dœœc˜•NÑ 'òCr   )Fr†   r'  )FNNNFNFFNFrÜ  rÜ  F)§ré  r  rÂ  rÉ  r7   râ  rV  rÔ  ÚatexitÚdataclassesr   Útypingr   r   r   r   Ú	getLoggerr  r;   r   Útools.registryr   Útools.terminal_tool_lifecycler   r   r   r   r   Útools.terminal_tool_configr   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   Útools.terminal_tool_backendsr+   r,   r-   r.   r/   Útools.tool_backend_helpersr0   r1   r?   r¤   r[  r  rF   rH   rK   rO   rQ   r[   r_   rl   rº  rm   r“   r|   r�   r”   Útools.environments.baser•   ÚTERMINAL_TOOL_DESCRIPTIONrÕ   rW  ru  rÔ   rs  rr  rÒ  rÈ  r¢   r£   r­   rÒ   rµ   r´   rÜ   rÛ   r·   r»   r¿   rÌ   rØ   rÝ   rã   rê   rð   rö   rù   r!  r$  r,  r³   rÓ   r?  r3  rI  rQ  rR  rX  ra  ri  r   rr  rt  r}  rÅ  rÎ  r×  rÝ  rè  Úregisterrð  Útools.terminal_tool_guardsrñ  rò  ró  rô  rõ  rö  Útools.terminal_tool_backgroundr÷  rø  rù  Útools.terminal_tool_resultrú  r   r  r  r  r  r  r!  r*  r‘  r,  r7  rL  rN  rg  r`  rh  rk  ry  r  r•  r¼  rš  rÁ  r£  rÉ  rÎ  rÏ  ÚTERMINAL_SCHEMArâ  r   )ré  s   @r   Ú<module>rú     s!  øðöó( Û Û 	Û 
Û Û Û Ý !ß ,Ó ,à	×	Ò	˜8Ó	$€õRõ &÷õ ÷÷ ÷ ÷ ÷
õ ÷
 Uõñ" 0Ð0QÐSVÐX[Ð]fÓgÐ ð —’Ó!€ò9ò4ò%ò
 õ
5õ9õ õ"õ
õ_÷Cõ ?ðÐ ð (*Ð Ó )Ø#%€Ó %Ø�NŠNÓ€	Ø-/€Ó /Ø —~’~Ó'Ð Ø€ØÐ ð "Ð Ø&Ÿ^š^Ó-Ð õ*ð` 24Ð Ó 3ð  "€Ó !Ø—N’NÓ$Ð ð &(Ð Ó 'Ø!ŸšÓ(Ð õ
$õRõ?õ"õJ$õ@.õMõõ7õ
^ñ �$Ô÷&=ð &=ó ð&=õRõ4õ
"õ0.õ/3õdEõõ@ð( ˆnØˆ]ØˆðÐ õ-õõðD %*Ð !õ-Cðb ! #Ð'7Ð9TÐUÐ õ
õ*õZGòTò$òòlð* ‡‚�Ô  õS÷÷ ÷ pÑ oÝ Aõ
õ:ò/÷÷ð/oð "&ð	/oð
 #ð/oð #'ð/oð 	÷/oðd0°ð 0ÈD÷ 0õô$'�	ô 'ð ÷	ð 	ó ð	õ!ðH ÷2ð 2ó ð2ð$Fð õXðxið õ0õ)õXEðAð ÷	AðN !#Ð õ%ð6ð õ÷*}fõ@
õ $ð ˆJØÐ,ØØ�ØØØ˜ØÐ=ðð Ø˜	ØÐ\Ø˜5ðð
 Ø˜	ØÐ!JÐKaÐJbð  ccð  dzð  c{ð  {rð   sØ˜1ðð
 Ø˜ØÐRðð Ø˜	Øð   sØ˜5ðð
 Øð   yØØ˜YÐ'Ø˜W g°¸Ð/AÐBððð Ø˜	Ø˜1Ø˜1Øð   _ð	ð !Ø˜	Ø˜5Øð   Fð#ðK-
ð\ 	�Y�Kða1ð5€òpJðZ 	× Ò Ø	ØØØØ(Ø
Ø!÷r   