+
    lHàj“�  ã                  óÀ  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
t
^ RIHt ^ RIHt ^ RIHtHt ^ RIHt ^ RIHt ]P,                  ! ]4      t]! ]4      P5                  R4      t^^YuttR‰t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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. RŠOR. R‹OR. RŒO/t R% R& lt!R' R( lt"R) R* lt#R+ R, lt$R- R. lt%R/ R0 lt&R1 R2 lt'] ! R3 R44      4       t(R5 R6 lt)R7 R8 lt*R9 R: lt+R; R< lt,R= R> lt-]! R?4      t.]! R@4      t/RA RB lt0RC RD lt1RE RF lt2RG RH lt3R�RI RJ llt4]! ]Pj                  Pm                  RK4      ;'       g    ]Pn                  ! 4       RL,          4      RM,          t8]Pr                  RN RO l4       t:RP RQ lt;RR RS lt<RŽRT RU llt=RV RW lt>RX RY lt?RZ R[ lt@^tAR\ R] ltBR^ R_ ltCR` Ra ltDRb Rc ltERd Re ltFRf Rg ltGRh Ri ltHRj Rk ltIRl tJRm Rn ltKRo Rp ltLRq Rr ltMRŽRs Rt lltNRu Rv ltORw Rx ltPRyRz/R{ R| lltQR} R~ ltRR R€ ltSR� R‚ ltTRƒ R„ ltUR… R† ltVR‡ Rˆ ltWR# )�aJ  Bot Desktop runtime: one headless Xfce desktop per Hermes profile, served over RFB on a private
Unix socket, viewed and driven from Hermes Desktop.

Layout under ``<HERMES_HOME>/bot-desktop/``: ``display`` (allocated X display number), ``rfb.sock``
(Xvnc RFB Unix socket, 0600), ``Xauthority``, ``env`` (DISPLAY/XAUTHORITY/DBUS_SESSION_BUS_ADDRESS
published by the launcher once Xfce's bus exists), ``launcher.pid``, ``launcher.log``, ``xdg/``
(per-profile XDG_CONFIG_HOME so two profiles never share xfconf). Everything is profile-scoped via
``get_hermes_home()`` so N profiles in one gateway get N desktops: one screen per bot on the shared
machine.

The launcher is ``launcher.sh`` next to this module; :func:`desktop_env` is what cua-driver and headed
Chromium spawns merge in so the agent acts on this profile's screen and nowhere else.
)ÚannotationsN)Ú	dataclass)ÚPath)ÚDictÚOptional©Úget_hermes_home)Ú	placementzlauncher.shÚXvncÚxfwm4úxfce4-panelÚ	xfdesktopÚxfsettingsdúdbus-run-sessionÚxauthÚxdpyinfoÚ	setxkbmapÚxpropÚaptútigervnc-standalone-serverÚ
xfdesktop4úxfce4-settingsúdbus-x11ú	x11-utilsúx11-xkb-utilsÚdnfútigervnc-x11-serverúdbus-daemonúxorg-x11-xauthÚpacmanÚtigervncÚdbusú
xorg-xauthúxorg-xdpyinfoúxorg-setxkbmapú
xorg-xpropc               ó   € V ^8„  d   QhRR/# )é   Úreturnr   © )Úformats   "Ú>/home/ubuntu/.hermes/hermes-agent/tools/bot_desktop/runtime.pyÚ__annotate__r,   K   s   € ÷ -ñ -�4ñ -ó    c                 ó$   € \        4       R ,          # )zbot-desktopr   r)   r-   r+   Ú	state_dirr/   K   s   € ÜÓ˜}Õ,Ð,r-   c               ó   € V ^8„  d   QhRR/# ©r'   r(   Úboolr)   )r*   s   "r+   r,   r,   O   s   € ÷ ,ñ ,˜4ñ ,r-   c                 ó@   € \         P                  P                  R 4      # )Úlinux)ÚsysÚplatformÚ
startswithr)   r-   r+   Úis_supported_hostr8   O   s   € Ü�<‰<×"Ñ" 7Ó+Ð+r-   c               ó   € V ^8„  d   QhRR/# )r'   r(   ú	list[str]r)   )r*   s   "r+   r,   r,   S   s   € ÷ Eñ E˜)ñ Er-   c                 ól   € \          U u. uF  p \        P                  ! V 4      e   K  V NK!  	  up # u up i ©N)ÚREQUIRED_BINARIESÚshutilÚwhich)Úbs    r+   Úmissing_binariesrA   S   s(   € Ý(ÓDÑ(�!¬F¯LªL¸«O�AˆAÑ(ÑDÐDùÒDs   ‰1¨1c               ó   € V ^8„  d   QhRR/# ©r'   r(   úOptional[str]r)   )r*   s   "r+   r,   r,   W   s   € ÷ ñ ˜ñ r-   c                 ón   € R F.  p \         P                  ! V 4      '       g   K!  V R 8X  d   Ru # T u # 	  R# )úapt-getr   N)rF   r   r   )r>   r?   )Úpms    r+   Úpackage_managerrH   W   s1   € Û*ˆÜ�<Š<˜×ÔØ )œO�5Ò3°Ò3ñ +ñ r-   c               ó   € V ^8„  d   QhRR/# rC   r)   )r*   s   "r+   r,   r,   ^   s   € ÷ 1ñ 1˜ñ 1r-   c                 ó¸   € \        4       p V f   R# RP                  \        V ,          4      pRRV 2RRV 2RRV 2/V ,          p\        4       '       d   V# R	V 2# )
a0  The distro command that installs the Bot Desktop packages, as the human would type it on THIS host:
prefixed with ``sudo`` unless Hermes already runs as root, so it is both what the pane shows and what
:mod:`tools.bot_desktop.install` runs. ``None`` when no package manager is present.

Not a promise that it can run here: see :func:`installable`. The published Docker image supervises
every service under ``s6-setuidgid hermes`` (UID 10000 by default) and ships no ``sudo`` binary, so an
install on a hosted instance is impossible no matter what this returns.NÚ r   z+apt-get install -y --no-install-recommends r   zdnf install -y r   zpacman -S --needed --noconfirm zsudo )rH   ÚjoinÚPACKAGESÚis_root)rG   ÚpkgsÚbodys      r+   Úinstall_commandrQ   ^   sv   € ô 
Ó	€BØ	‚zÙØ�8‰8”H˜R•LÓ!€DàÐ<¸T¸FÐCØ�  Ð'ØÐ3°D°6Ð:ðð 	õ	
€Dô
 —9’9ˆ4Ð0 E¨$¨ .Ð0r-   c               ó   € V ^8„  d   QhRR/# r1   r)   )r*   s   "r+   r,   r,   r   s   € ÷ 8ñ 8�ñ 8r-   c                 ób   € \        \        R 4      ;'       d    \        P                  ! 4       ^ 8H  # )Úgeteuid)ÚhasattrÚosrT   r)   r-   r+   rN   rN   r   s"   € Ü”2�yÓ!×7Ð7¤b§j¢j£l°aÑ&7Ð7r-   c               ó   € V ^8„  d   QhRR/# r1   r)   )r*   s   "r+   r,   r,   v   s   € ÷ 9ñ 9�Tñ 9r-   c                 ór   € \        4       f   R# \        4       ;'       g    \        P                  ! R4      RJ# )a  Whether :func:`install_command` could actually succeed on this host.

False on an unprivileged process with no ``sudo`` to reach for, which is exactly the published Docker
image: services drop to the ``hermes`` user and no ``sudo`` binary is installed. The packages can only
arrive in the image there, so :func:`start` says that instead of printing a sudo line the user has no
way to run. ``status()`` still reports ``install_command`` for the pane; surfacing this there needs a
wire-contract change and is deliberately out of scope.
NFÚsudo)rH   rN   r>   r?   r)   r-   r+   ÚinstallablerZ   v   s.   € ô ÓÒ ÙÜ‹9×8Ð8œŸš VÓ,°DÐ8Ð8r-   c                  óØ   € ] tR t^„t$ 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]R&   RtR	]R&   RtR	]R&   RtR]R&   Rt	R]R&   R R lt
RtR# )ÚDesktopStatusÚstrÚprofiler2   Ú	supportedÚ	installedr:   ÚmissingÚrunningúOptional[int]ÚpidrD   ÚdisplayÚsocketÚgeometryrQ   ÚbrowserNÚblockerÚmemory_available_mbÚmemory_limit_mbÚgatewayr	   zOptional[dict[str, object]]Úimage_switchc               ó   € V ^8„  d   QhRR/# )r'   r(   zdict[str, object]r)   )r*   s   "r+   r,   ÚDesktopStatus.__annotate__—   s   € ÷ #ñ #Ð*ñ #r-   c                	ó,   € \        V P                  4      # r<   )ÚdictÚ__dict__)Úselfs   &r+   Úas_dictÚDesktopStatus.as_dict—   s   € Ü�D—M‘MÓ"Ð"r-   r)   )Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__annotations__ri   rj   rk   r	   rm   rt   Ú__static_attributes__r)   r-   r+   r\   r\   „   s}   ‡ àƒLØƒOØƒOØÓØƒMØ	ÓØÓØÓØƒMØ"Ó"ØÓØ!€Gˆ]Ó!Ø)-Ð˜Ó-Ø%)€O�]Ó)Ø€IˆsÓØ04€LÐ-Ó4÷#ñ #r-   r\   c               ó    € V ^8„  d   QhRRRR/# )r'   Úpathr   r(   rD   r)   )r*   s   "r+   r,   r,   ›   s   € ÷ ñ �ð ˜ñ r-   c                ó|   €  V P                  R R7      P                  4       ;'       g    R#   \         d     R# i ; i)ú	utf-8-sig©ÚencodingN)Ú	read_textÚstripÚOSError©r}   s   &r+   Ú_readr†   ›   s;   € ðØ�~‰~ {ˆ~Ó3×9Ñ9Ó;×CÐC¸tÐCøÜô Úðús   ‚&, ©, ¬;º;c               ó    € V ^8„  d   QhRRRR/# )r'   rd   Úintr(   r2   r)   )r*   s   "r+   r,   r,   ¢   s   € ÷ ñ �Cð ˜Dñ r-   c                ó”   € ^ RI p VP                  V 4      P                  4       VP                  8g  #   TP                   d     R# i ; i)zÇA zombie is dead for our purposes: a SIGKILLed launcher stays a zombie in the gateway until the next
Popen reaps it, and reporting it as running would hide its orphaned X server behind a live status.NF)ÚpsutilÚProcessÚstatusÚSTATUS_ZOMBIEÚError©rd   rŠ   s   & r+   Ú
_pid_aliver�   ¢   sE   € ó ðØ�~‰~˜cÓ"×)Ñ)Ó+¨v×/CÑ/CÑCÐCøØ�<‰<ô Úðús   †+2 ²AÁAc               ó    € V ^8„  d   QhRRRR/# )r'   rd   rˆ   r(   úOptional[float]r)   )r*   s   "r+   r,   r,   ¬   s   € ÷ ñ �cð ˜oñ r-   c                ó�   € ^ RI p VP                  V 4      P                  4       #   TP                  \        \
        3 d     R# i ; i)é    N)rŠ   r‹   Úcreate_timerŽ   ÚOverflowErrorÚ
ValueErrorr�   s   & r+   Ú_create_timer˜   ¬   s?   € ÛðØ�~‰~˜cÓ"×.Ñ.Ó0Ð0øØ�L‰Lœ-¬Ð4ô Úðús   †% ¥AÁAc               ó   € V ^8„  d   QhRR/# ©r'   r(   rc   r)   )r*   s   "r+   r,   r,   ´   s   € ÷ añ a�}ñ ar-   c                 óv  € \        \        4       R,          4      p T ;'       g    RP                  R4      w  rpVP                  4       '       d	   V'       g   R#  \	        V4      \        V4      rT\        T4      pTe*   \        Ye,
          4      R8  d   \        T4      '       d   T# R#   \         d     R# i ; i)a  The live launcher's pid, or None. ``launcher.pid`` holds ``"<pid> <create_time>"``: a recycled pid
with a different start time is somebody else's process and must never be reported as ours nor
killed by :func:`stop`. The pre-identity single-number format is treated as not running.úlauncher.pidÚ rK   Ng{®Gáz„?)
r†   r/   Ú	partitionÚisdigitrˆ   Úfloatr—   r˜   Úabsr�   )ÚrawÚpid_sÚ_Úborn_srd   ÚbornÚactuals          r+   Ú_launcher_pidr¨   ´   sœ   € ô ”	“˜nÕ,Ó
-€CØŸ	˜	˜r×,Ñ,¨SÓ1Ñ€EˆfØ�=‰=�?Š?§&ÙðÜ˜“J¤ f£ˆTô ˜#Ó€FØÒ$¬¨V­]Ó);¸dÔ)BÄzÐRUÇÂˆ3Ð`Ð\`Ð`øô ô Úðús   ÁB) Â)B8Â7B8c               ó   € V ^8„  d   QhRR/# rš   r)   )r*   s   "r+   r,   r,   Ä   s   € ÷ >ñ > ñ >r-   c                 óÄ   € \        \        4       R,          4      ;'       g    RP                  R4      w  rpV P                  4       '       d   V'       d   \	        V 4      # R# )zbThe pid ``launcher.pid`` names, alive or not (the orphan sweep matches process groups against it).rœ   r�   rK   N)r†   r/   rž   rŸ   rˆ   )r£   r¤   r¥   s      r+   Ú_recorded_launcher_pidr«   Ä   sF   € äœi›k¨NÕ:Ó;×AÐA¸r×LÑLÈSÓQÑ€EˆfØŸ™Ÿš¯VŒ3ˆu‹:Ð=¸Ð=r-   z/tmpz/proc/net/unixc               ó    € V ^8„  d   QhRRRR/# )r'   Únumrˆ   r(   rc   r)   )r*   s   "r+   r,   r,   Î   s   € ÷ ñ �Sð ˜]ñ r-   c                ó¤   €  \        \        R V  R2,          P                  RR7      P                  4       4      #   \        \
        3 d     R# i ; i)ú.Xú-lockr   r€   N)rˆ   Ú_X_LOCK_DIRr‚   rƒ   r„   r—   )r­   s   &r+   Ú_x_lock_pidr²   Î   sM   € ðÜ”K B s e¨5 /Õ1×<Ñ<ÀkÐ<ÓR×XÑXÓZÓ[Ð[øÜ”ZÐ ô Úðús   ‚7: ºAÁAc               ó    € V ^8„  d   QhRRRR/# ©r'   r­   rˆ   r(   r2   r)   )r*   s   "r+   r,   r,   Õ   s   € ÷ 	kñ 	k˜ð 	k ñ 	kr-   c                óæ   a €  \         P                  RR7      P                  4       p\        ;QJ d    T 3R lT 4       F  '       g   K   R# 	  R# ! T 3R lT 4       4      #   \         d     R# i ; i)a2  A running X server keeps ``@/tmp/.X11-unix/X<n>`` (abstract namespace) bound for its whole life; the
kernel drops it only when the process exits. A /tmp reaper can remove the lock file under a live Xvnc,
and only this binding then still says the number is taken (a new server on it dies 'already running').r   r€   Fc              3  óª   <"  € T FH  qP                  4       '       g   K  VP                  4       R,          P                  R4      RS 28H  x € KJ  	  R# 5i)é   Ú@z/tmp/.X11-unix/XNéÿÿÿÿ)rƒ   ÚsplitÚlstrip)Ú.0Úliner­   s   & €r+   Ú	<genexpr>Ú"_x_socket_bound.<locals>.<genexpr>Þ   sB   øé € ÐjÑTYÈD×]gÑ]g×]iÔGˆt�z‰z‹|˜BÕ×&Ñ& sÓ+Ð1AÀ#ÀÐ/GÖGÓTYùs
   ƒAŸ4AT)Ú_X_UNIX_TABLEr‚   Ú
splitlinesr„   Úany)r­   Úliness   f r+   Ú_x_socket_boundrÄ   Õ   se   ø€ ðÜ×'Ñ'°Ð'Ó=×HÑHÓJˆ÷ ‹3ÔjÑTYÓj�3Œ3ÐjŠ3Ðjˆ3ÔjÑTYÓjÓjÐjøô ô Úðús   ƒ$A! Á!A0Á/A0c               ó    € V ^8„  d   QhRRRR/# r´   r)   )r*   s   "r+   r,   r,   á   s   € ÷ Iñ I˜ð I ñ Ir-   c                ól   € \        V 4      pVRJ;'       d    \        V4      ;'       g    \        V 4      # )zÃA live X server owns ``:num``: its lock file names a running pid, or its X11 socket is bound. A lock
left by a crashed server (dead pid, no socket) does not count, so the number can be reclaimed.N)r²   r�   rÄ   )r­   rd   s   & r+   Ú_display_in_userÇ   á   s1   € ô �cÓ
€CØ�tˆO×/Ð/¤
¨3£×HÐH´OÀCÓ4HÐHr-   c               ó    € V ^8„  d   QhRRRR/# ©r'   Úsdr   r(   r2   r)   )r*   s   "r+   r,   r,   è   s   € ÷ #ñ #˜dð # tñ #r-   c                ó  a a€ ^ RI pR V 3R llo\        S R,          4      pV'       d+   VP                  4       '       d   \        \	        V4      4      MRpVe   \        V4      '       g-   \        V3R lVP                  R.4       4       R4      pVf   R# \        4       p \        P                  ! V4      pVP                  V4      P                  4       pYT8w  d   S! T4      '       g   R# \        P!                  RYCT;'       g    R	4       \#        YT8X  d   TMRT4       T'       d"   \$        R
T R2,          P'                  RR7       R F  pS T,          P'                  RR7       K  	  R#   \        TP                  3 d     R# i ; i)u$  Caller holds ``start.lock`` and has established that no live launcher exists. The launcher runs Xvnc in
its own session, so a SIGKILLed launcher leaves the X server alive, holding the display and ``rfb.sock``;
``status()`` keys on the launcher and says stopped, and a naive restart allocates a second server next
to it and overwrites the socket path both now claim. The X lock of the recorded display names that
server: it is ours when it sits in the dead launcher's process group or its command line binds OUR
socket. When a /tmp reaper took the lock too (or the failed launch dropped ``display``), the socket path
on the Xvnc command line is the remaining handle â€” without it one X server leaks per occurrence. Kill it
(group first), drop the state it left, and report whether anything was signalled.Nc               ó    € V ^8„  d   QhRRRR/# )r'   ÚcmdlineÚlistr(   r2   r)   )r*   s   "r+   r,   Ú+_reap_orphaned_server.<locals>.__annotate__ó   s   € ÷ fñ f 4ð f¨Dñ fr-   c                ó�   <€ R \        V '       d
   V ^ ,          MR4      P                  9   ;'       d    \        SR,          4      V 9   # )r
   r�   úrfb.sock)r   Únamer]   )rÍ   rÊ   s   &€r+   Ú_binds_our_socketÚ0_reap_orphaned_server.<locals>._binds_our_socketó   s8   ø€ Øœ¯G˜g ažj¸Ó<×AÑAÑA×eÐeÄcÈ"ÈzÍ/ÓFZÐ^eÑFeÐer-   re   c              3  ó’   <"  € T F<  pS! VP                   R ,          ;'       g    . 4      '       g   K.  VP                  x € K>  	  R# 5i)rÍ   N)Úinford   )r¼   ÚprÓ   s   & €r+   r¾   Ú(_reap_orphaned_server.<locals>.<genexpr>ù   s7   øé € ÐrÑ#C˜aÑGXÐYZ×Y_ÑY_Ð`iÕYj×YpÐYpÐnp×Gq”E�A—E–EÓ#Cùs   ƒ A¤
A³ArÍ   FzRBot Desktop launcher %s is gone but its X server (pid %s) survived on :%s; reapingÚ?r¯   r°   T©Ú
missing_ok©rœ   ÚenvrÑ   )rŠ   r†   rŸ   r²   rˆ   r�   ÚnextÚprocess_iterr«   rV   Úgetpgidr‹   rÍ   ÚProcessLookupErrorrŽ   ÚloggerÚwarningÚ_kill_group_then_waitr±   Úunlink)	rÊ   rŠ   Úrecordedrd   ÚlauncherÚpgidrÍ   rÒ   rÓ   s	   f       @r+   Ú_reap_orphaned_serverré   è   sL  ù€ ó ÷fð fô �R˜)•^Ó$€Hß(0°X×5EÑ5E×5GÒ5GŒ+”c˜(“mÔ
$ÈT€CØ
‚{œ* SŸ/š/ÜÔr 6×#6Ñ#6¸	°{Ô#CÓrÐtxÓyˆØŠ;ÙÜ%Ó'€HðÜ�zŠz˜#‹ˆØ—.‘. Ó%×-Ñ-Ó/ˆð ÔÑ 1°'× :Ò :ÙÜ
‡N�NÐgØ (§/ /¨cô3ä $Ô"2™$¸¸cÔBßÜ	˜˜H˜: UÐ+Õ	+×3Ñ3¸tÐ3ÔDÛ3ˆØ	ˆd�×Ñ dÐÖ+ñ 4áøô  §¡Ð-ô Úðús   Â"5E/ Å/F
Æ	F
c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r'   rè   rc   rd   rˆ   Úgracer    r(   ÚNoner)   )r*   s   "r+   r,   r,     s)   € ÷ $ñ $ ð $°Cð $Àð $ÐPTñ $r-   c                óž  a a€ R V V3R llpR V V3R llpR V3R llpV! \         P                  4       \        P                  ! 4       V,           p\        P                  ! 4       V8  d/   V! 4        V! 4       '       g   R# \        P                  ! R4       KH  V! \         P
                  4       \        P                  ! R	4       V! 4        R# )
zUSIGTERM the group (or the lone pid), SIGKILL whatever is still there after ``grace``.c               ó    € V ^8„  d   QhRRRR/# )r'   Úsigrˆ   r(   rì   r)   )r*   s   "r+   r,   Ú+_kill_group_then_wait.<locals>.__annotate__  s   € ÷ "ñ "�Sð "˜Tñ "r-   c                óö   <€ \         P                  ! \        \        4      ;_uu_ 4        Se   \        P
                  ! SV 4       M\        P                  ! SV 4       R R R 4       R #   + '       g   i     R # ; ir<   )Ú
contextlibÚsuppressrá   ÚPermissionErrorrV   ÚkillpgÚkill)rï   rè   rd   s   &€€r+   Ú_signalÚ&_kill_group_then_wait.<locals>._signal  sI   ø€ Ü× Ò Ô!3´_×EÕEØÒÜ—	’	˜$ Õ$ä—’˜˜SÔ!÷	 F×E×EÒEús   ©4A'Á'A8	c               ó   € V ^8„  d   QhRR/# r1   r)   )r*   s   "r+   r,   rð     s   € ÷ ñ ˜Dñ r-   c                 ó”   <€ S f   \        S4      #  \        P                  ! S ^ 4       R#   \         d     R# \         d     R# i ; i)NFT)r�   rV   rõ   rá   rô   )rè   rd   s   €€r+   Ú_anything_leftÚ-_kill_group_then_wait.<locals>._anything_left  sK   ø€ ð Š<Ü˜c“?Ð"ð	Ü�IŠI�d˜AÔñ
 øô	 "ô 	ÚÜô 	Úð	ús   ’+ «A¹AÁAÁAc               ó   € V ^8„  d   QhRR/# ©r'   r(   rì   r)   )r*   s   "r+   r,   rð   #  s   € ÷ (ñ (˜4ñ (r-   c                 óÚ   <€ \         P                  ! \        \        4      ;_uu_ 4        \        P
                  ! S \        P                  4       R R R 4       R #   + '       g   i     R # ; ir<   )rò   ró   ÚChildProcessErrorr„   rV   ÚwaitpidÚWNOHANG)rd   s   €r+   Ú_reap_if_oursÚ,_kill_group_then_wait.<locals>._reap_if_ours#  s:   ø€ ô × Ò Ô!2´G×<Õ<Ü�JŠJ�sœBŸJ™JÔ'÷ =×<×<Ò<ús   ©&AÁA*	Ngš™™™™™©?çš™™™™™¹?)ÚsignalÚSIGTERMÚtimeÚ	monotonicÚsleepÚSIGKILL)rè   rd   rë   r÷   rû   r  Údeadlines   ff&    r+   rä   rä     sˆ   ù€ ÷"ñ "÷ñ ÷(ð (ñ ŒF�N‰NÔÜ�~Š~Ó %Õ'€HÜ
�.Š.Ó
˜XÔ
%ÙŒÙ×ÒÙÜ�
Š
�4ÖÙŒF�N‰NÔÜ‡J‚Jˆs„OÙ†Or-   ÚXDG_RUNTIME_DIRz.cachezhermes-bot-desktop-alloc.lockc               ó   € V ^8„  d   QhRR/# )r'   r}   r   r)   )r*   s   "r+   r,   r,   <  s   € ÷ 4ñ 4�4ñ 4r-   c              #  óŽ  "  € ^ RI p\        V RRR7      ;_uu_ 4       pVP                  VP                  4       VP                  4        Vx € VP                  VP                  4       VP
                  4        RRR4       R#   TP                  TP                  4       TP
                  4       i ; i  + '       g   i     R# ; i5i)r”   Nza+úutf-8r€   )ÚfcntlÚopenÚflockÚfilenoÚLOCK_EXÚLOCK_UN)r}   r  Úfhs   &  r+   Ú_flockedr  ;  s‚   é € ãÜ	ˆd�D 7×	+Õ	+¨rØ�‰�B—I‘I“K §¡Ô/ð	4ØŠHà�K‰K˜Ÿ	™	› U§]¡]Õ3÷ 
,Ñ	+øð
 �K‰K˜Ÿ	™	› U§]¡]Õ3ú÷ 
,×	+Ð	+üs4   ‚C�+B1Á	BÁ*B1Á8
CÂ,B.Â.B1Â1C	Â<	Cc               ó   € V ^8„  d   QhRR/# ©r'   r(   rˆ   r)   )r*   s   "r+   r,   r,   F  s   € ÷ 	Kñ 	K�sñ 	Kr-   c                 ó@  € \        \        4       R,          4      p V '       d<   V P                  4       '       d&   \        \	        V 4      4      '       g   \	        V 4      # \        \        \        ^,           4       F  p\        V4      '       d   K  Vu # 	  \        R4      h)zÆCaller holds ``_ALLOC_LOCK``. The recorded number is only reused when no OTHER server holds it now:
after profile A stops, B may have taken A's number, and A's launcher must never unlink B's socket.re   z0no free X display number in the Bot Desktop band)	r†   r/   rŸ   rÇ   rˆ   ÚrangeÚ_DISPLAY_MINÚ_DISPLAY_MAXÚRuntimeError)ræ   r­   s     r+   Ú_pick_displayr   F  sr   € ô ”Y“[ 9Õ,Ó-€Hß�H×$Ñ$×&Ò&¬¼sÀ8»}×/MÒ/MÜ�8‹}ÐÜ”\¤<°!Õ#3Ö4ˆÜ˜s×#Ô#ØŠJñ 5ô ÐIÓ
JÐJr-   c               ó   € V ^8„  d   QhRR/# r  r)   )r*   s   "r+   r,   r,   R  s   € ÷ ñ ˜3ñ r-   c                 óÆ   € \         P                  P                  R R RR7       \        \         4      ;_uu_ 4        \	        4       uuRRR4       #   + '       g   i     R# ; i)TéÀ  ©ÚparentsÚexist_okÚmodeN)Ú_ALLOC_LOCKÚparentÚmkdirr  r   r)   r-   r+   Ú_allocate_displayr+  R  s<   € Ü×Ñ×Ñ T°D¸uÐÔEÜ	”+×	Õ	Ü‹÷ 
×	×	Ó	ús   º
AÁA 	c               ó    € V ^8„  d   QhRRRR/# )r'   Úbase_envzOptional[dict[str, str]]r(   údict[str, str]r)   )r*   s   "r+   r,   r,   X  s   € ÷ ñ Ð2ð ¸nñ r-   c                óÞ   € \        V f   \        P                  MT 4      p\        4       pV'       d<   \	        4        VP                  V4       VP                  RR4       ^ RIHp V! V4       V# )a  ``base_env`` (default ``os.environ``) with this profile's DISPLAY/XAUTHORITY/DBUS_SESSION_BUS_ADDRESS
merged in when its desktop is running. Unchanged otherwise, so hosts with a real seat keep it.
Pure: never starts anything (it is called from env builders, status probes and tests).NÚWAYLAND_DISPLAY)Úenv_for_agent)	rq   rV   ÚenvironÚpublished_envÚtouch_activityÚupdateÚpopÚtools.bot_desktop.browserr1  )r-  rÝ   Ú	publishedr1  s   &   r+   Údesktop_envr9  X  sT   € ô ˜XÒ-Œr�zŠz°8Ó
<€CÜ“€IßÜÔØ�
‰
�9ÔØ�‰Ð! 4Ô(Ý;Ù�cÔØ€Jr-   c               ó   € V ^8„  d   QhRR/# rþ   r)   )r*   s   "r+   r,   r,   g  s   € ÷ ?ñ ? ñ ?r-   c                 ó4  € \        4       P                  R4      '       d   \        4        R# \        P                  ! 4       p V P
                  \        P                  8X  d   R# V P
                  \        P                  8X  d    \        4        R# \        \        P                  4      '       g   R#  \        4        R#   \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i  \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)aà  Tool-boundary hook (``computer_use`` dispatch and the headed Chromium spawn sites of the browser tool).

Under ``terminal`` placement the sandbox screen is brought up on first use unconditionally: the sandbox is
the boundary the user chose, a screen inside it touches nothing outside it, and the tools below refuse
rather than run on the host when it is not up. On the gateway host, ``bot_desktop.auto_start`` (opt-in,
default off) starts a Linux host's screen when it has NO display and the packages installed, so a headless
gateway works the first time. Host failure is not an error here (the tool's own "no display" diagnosis is
the right message then); a sandbox start failure is logged and left for :func:`tool_placement` to raise.ÚDISPLAYNz2Bot Desktop sandbox start deferred to the tool: %sz"Bot Desktop auto-start skipped: %s)r3  Úgetr4  r	   ÚresolveÚwhereÚREFUSEDÚTERMINALÚstartÚ	Exceptionrâ   rÖ   Ú_should_auto_startrV   r2  )r?  Úexcs     r+   Úensure_started_for_toolrF  g  sÍ   € ô ƒ×Ñ˜9×%Ò%ÜÔÙÜ×ÒÓ€EØ‡{�{”i×'Ñ'Ô'ÙØ‡{�{”i×(Ñ(Ô(ð	SÜŒGñ 	ÜœbŸj™j×)Ò)Ùð?ÜŽøô ô 	SÜ�K‰KÐLÈc×RÐRÙûð	Sûô ô ?Ü�‰Ð8¸#×>Ò>ûð?ús0   Â
B< Â0
C+ Â<C(ÃC#Ã#C(Ã+DÃ6DÄDc               ó   € V ^8„  d   QhRR/# ©r'   r(   r]   r)   )r*   s   "r+   r,   r,   „  s   € ÷ ñ ˜ñ r-   c                 ó„  € \         P                  ! 4       p V P                  \         P                  8X  d   \	        V P
                  4      hV P                  \         P                  8X  d   \         P                  # \        4       '       d    \        4       P                  R4      '       g   \        4        \         P                  # )uÈ  Where the browser / cua-driver a tool is about to spawn MUST run: ``placement.GATEWAY`` or
``placement.TERMINAL``. Policy first, liveness second: a ``terminal`` placement whose screen is down gets
it started here (raising with the blocker when it cannot come up) and a ``refused`` placement raises its
reason. Neither ever yields the host â€” a screen that happens to be down is not permission to run the
agent's browser outside the sandbox the user chose.r<  )r	   r>  r?  r@  r  ÚreasonÚGATEWAYÚsandbox_screen_runningr3  r=  rB  rA  )r?  s    r+   Útool_placementrM  „  s}   € ô ×ÒÓ€EØ‡{�{”i×'Ñ'Ô'Ü˜5Ÿ<™<Ó(Ð(Ø‡{�{”i×'Ñ'Ô'Ü× Ñ Ð Ü!×#Ò#¬=«?×+>Ñ+>¸y×+IÒ+IÜŒÜ×ÑÐr-   c               ó    € V ^8„  d   QhRRRR/# )r'   rÝ   r.  r(   r2   r)   )r*   s   "r+   r,   r,   ”  s   € ÷ .ñ .˜Nð .¨tñ .r-   c                ó(  € \        4       '       d/   V P                  R 4      '       g   V P                  R4      '       d   R# \        4       '       d   R# ^ RIHp V! 4       P                  R4      ;'       g    / p\        VP                  RR4      4      # )r<  r0  F©Úload_config_readonlyÚbot_desktopÚ
auto_start)r8   r=  rA   Úhermes_cli.configrQ  r2   )rÝ   rQ  Úcfgs   &  r+   rD  rD  ”  sk   € Ü×Ò #§'¡'¨)×"4Ò"4¸¿¹Ð@Q×8RÒ8RÙÜ×ÒÙÝ6Ù
Ó
 ×
$Ñ
$ ]Ó
3×
9Ð
9°r€CÜ�—‘˜ eÓ,Ó-Ð-r-   c               ó   € V ^8„  d   QhRR/# rþ   r)   )r*   s   "r+   r,   r,   ¦  s   € ÷ ñ ˜ñ r-   c                 óœ   € \        4       R ,          p  V P                  4        \        P                  ! V R4       R#   \         d     R# i ; i)ÚactivityN)r/   ÚtouchrV   Úutimer„   r…   s    r+   r4  r4  ¦  s<   € Ü‹;˜Õ#€DðØ�
‰
ŒÜ
�Š��tÖøÜô Úðús   “'< ¼AÁ
Ac               ó   € V ^8„  d   QhRR/# )r'   r(   r’   r)   )r*   s   "r+   r,   r,   ¯  s   € ÷ ñ �oñ r-   c                 óØ   € R FQ  p  \        R\        P                  ! 4       \        4       V ,          P                  4       P                  ,
          4      u # 	  R#   \
         d     Ke  i ; i)zªSeconds since the last stamped use; None when the screen never recorded one (falls back to the
env file's publish time so a screen started and then forgotten still ages).ç        N)rX  rÝ   )Úmaxr  r/   ÚstatÚst_mtimer„   )rÒ   s    r+   Úidle_secondsra  ¯  sZ   € ó $ˆð	Ü�sœDŸIšI›K¬9«;¸Õ+=×*CÑ*CÓ*E×*NÑ*NÕNÓOÒOñ $ñ
 øô ô 	Úð	ús   ‡AAÁA)Á(A)c               ó   € V ^8„  d   QhRR/# )r'   r(   r    r)   )r*   s   "r+   r,   r,   º  s   € ÷ "ñ "˜5ñ "r-   c                 óî   € ^ RI Hp  V ! 4       P                  R4      ;'       g    / p \        VP                  R\        4      4      p\        RV4      ^<,          #   \
        \        3 d
    \        p L,i ; i)r”   rP  rR  Úidle_stop_minutesr]  )rT  rQ  r=  r    ÚDEFAULT_IDLE_STOP_MINUTESÚ	TypeErrorr—   r^  )rQ  rU  Úminutess      r+   Úidle_stop_secondsrh  º  sk   € Ý6Ù
Ó
 ×
$Ñ
$ ]Ó
3×
9Ð
9°r€Cð,Ü˜Ÿ™Ð 3Ô5NÓOÓPˆô ˆs�GÓ˜rÕ!Ð!øô ”zÐ"ô ,Ü+Šð,ús   ¨A ÁA4Á3A4c               ó   € V ^8„  d   QhRR/# r1   r)   )r*   s   "r+   r,   r,   Ä  s   € ÷ ñ �dñ r-   c                 ó6  € \        4       p V ^ 8:  g   \        4       '       g   R# \        4       pVe   W8  d   R# ^ RIHp VP                  4       P                  VP                  8X  d   R# \        P                  R\        4       V^<,          4       \        4       # )zpStop this profile's screen when it has been idle past the limit and no human holds it. True when
it was stopped.F)Úleasez6Bot Desktop for profile %s idle for %.0f min; stopping)rh  Ú
is_runningra  Útools.bot_desktoprk  r=  ÚholderÚHUMANrâ   rÖ   Ú_profile_nameÚstop)ÚlimitÚidleÚ	_bd_leases      r+   Ústop_if_idleru  Ä  sn   € ô Ó€EØ�„zœŸšÙÜ‹>€DØ‚|�t”|ÙÝ4Ø‡}�}ƒ×Ñ §¡Ô0ÙÜ
‡K�KÐHÌ-Ë/Ð[_ÐbdÕ[dÔeÜ‹6€Mr-   c               ó   € V ^8„  d   QhRR/# ©r'   r(   r.  r)   )r*   s   "r+   r,   r,   Ô  s   € ÷ ñ �~ñ r-   c                 ód  € ^ RI Hp  V P                  4       '       d   \        4       # \	        4       f   / # \        \        4       R,          4      pV'       g   / # / pVP                  4        FA  pVP                  R4      w  rEpV'       g   K!  VP                  4       W$P                  4       &   KC  	  V# )ad  Variables the launcher wrote once Xfce's private bus existed; empty when the desktop is down.

Pure file reads on the common path: this is called from every browser / cua-driver env builder, so it
must not load config (that initializes HERMES_HOME). A sandbox-hosted screen leaves a host-side marker at
start; only its presence routes to the sandbox probe.©Úsandbox_hostrÝ   Ú=)
rm  rz  Ú_read_markerÚ_sandbox_published_envr¨   r†   r/   rÁ   rž   rƒ   )rz  r¢   Úoutr½   ÚkeyÚsepÚvalues          r+   r3  r3  Ô  s�   € õ /Ø× Ñ ×"Ò"Ü%Ó'Ð'ÜƒÒØˆ	Ü
”	“˜eÕ#Ó
$€CßØˆ	Ø€CØ—‘Ö ˆØŸ.™.¨Ó-‰ˆ�%ß‰3Ø$Ÿ{™{›}ˆC—	‘	“Óñ !ð €Jr-   c               ó   € V ^8„  d   QhRR/# )r'   r(   zOptional[Path]r)   )r*   s   "r+   r,   r,   ê  s   € ÷ Kñ K˜ñ Kr-   c                 ó¬   € ^ RI Hp  V P                  4       '       d   R# \        4       R,          p\	        4       e   VP                  4       '       d   V# R# )zœHost path of the RFB socket; None when down OR when the screen lives in a sandbox (use
:func:`open_rfb_stream` there: the socket is not on this filesystem).ry  NrÑ   )rm  rz  r|  r/   r¨   Úexists)rz  Úsocks     r+   Úrfb_socket_pathr†  ê  sA   € õ /Ø× Ñ ×"Ò"ÙÜ‹;˜Õ#€DÜ “?Ò.°4·;±;·=²=ˆ4ÐJÀdÐJr-   c               ó   € V ^8„  d   QhRR/# r1   r)   )r*   s   "r+   r,   r,   ô  s   € ÷ ;ñ ;�Dñ ;r-   c                 ób   € \         P                  ! 4       P                  \         P                  8H  # )z]True when this profile's screen is placed inside the terminal backend (policy; reads config).)r	   r>  r?  rA  r)   r-   r+   Ú
in_sandboxr‰  ô  s"   € ä×ÒÓ×$Ñ$¬	×(:Ñ(:Ñ:Ð:r-   c               ó   € V ^8„  d   QhRR/# r1   r)   )r*   s   "r+   r,   r,   ù  s   € ÷ ñ  ñ r-   c                 óØ   € ^ RI Hp  V P                  4       pV'       g   R# \        RR7      e   R# V P	                  V4      '       d   R# V P                  4       P                  RR7       R# )uG  True when a sandbox-hosted screen is UP for this profile: the start marker exists AND the sandbox it
names is alive â€” registered in this process, or (after a gateway restart emptied the registry) the
marker's recorded container still running. Only a sandbox that is provably gone (its container removed
out from under us) drops the marker, so the next start rebuilds instead of the browser exec-ing into a
dead container; an unregistered-but-alive one is re-attached by ``_sandbox_env(create=True)`` at the
next spawn (the terminal planner reuses the persisted container by label).ry  F©ÚcreateTrÚ   )rm  rz  r|  Ú_sandbox_envÚmarker_sandbox_aliveÚ_markerrå   )rz  Úmarkers     r+   rL  rL  ù  sZ   € õ /Ø×&Ñ&Ó(€FßÙÜ˜5Ô!Ò-ÙØ×(Ñ(¨×0Ò0ÙØ×ÑÓ×!Ñ!¨TÐ!Ô2Ùr-   c                 ó°   € ^ RI Hp  V P                  4       pV'       g   R# \        RR7      pVe   V# V P	                  V4      '       d   \        RR7      # R# )zéThe environment hosting the screen the marker records, re-attaching after a restart when the recorded
sandbox is still alive; None when there is no marker or its sandbox is gone. Never builds a sandbox for
a screen that is not there.ry  NFrŒ  T)rm  rz  r|  rŽ  r�  )rz  r‘  rÝ   s      r+   Ú_owned_sandbox_envr“    sN   € õ /Ø×&Ñ&Ó(€FßÙÜ
˜eÔ
$€CØ
‚Øˆ
Ø×(Ñ(¨×0Ò0Ü 4Ô(Ð(Ùr-   c               ó   € V ^8„  d   QhRR/# r1   r)   )r*   s   "r+   r,   r,     s   € ÷ 0ñ 0�Dñ 0r-   c                 óF   € \        \        4       P                  R 4      4      # )r<  )r2   r3  r=  r)   r-   r+   rl  rl    s   € Ü”“×#Ñ# IÓ.Ó/Ð/r-   c               ó   € V ^8„  d   QhRR/# )r'   r(   zsubprocess.Popenr)   )r*   s   "r+   r,   r,      s   € ÷ >ñ >Ð)ñ >r-   c                 óx   € ^ RI Hp  \        RR7      pVf   \        R4      hV P	                  V\        4       4      # )z]Popen whose stdin/stdout carry RFB bytes for a sandbox-hosted screen (``in_sandbox()`` only).ry  FrŒ  z.the sandbox hosting this screen is not running)rm  rz  rŽ  r  Úopen_rfb_streamrp  ©rz  rÝ   s     r+   r˜  r˜     s5   € å.Ü
˜eÔ
$€CØ
‚{ÜÐKÓLÐLØ×'Ñ'¨¬]«_Ó=Ð=r-   c               ó   € V ^8„  d   QhRR/# rH  r)   )r*   s   "r+   r,   r,   )  s   € ÷ 2ñ 2�#ñ 2r-   c                 ó–   € ^ RI Hp  V ! 4       P                  R4      ;'       g    / p\        VP                  R4      ;'       g    R4      # )r”   rP  rR  rg   Ú1440x900)rT  rQ  r=  r]   )rQ  rU  s     r+   rg   rg   )  s<   € Ý6Ù
Ó
 ×
$Ñ
$ ]Ó
3×
9Ð
9°r€CÜˆs�w‰w�zÓ"×0Ð0 jÓ1Ð1r-   c               ó    € V ^8„  d   QhRRRR/# ©r'   r^   rD   r(   r\   r)   )r*   s   "r+   r,   r,   /  s   € ÷ ñ �Mð ¨]ñ r-   c                óÌ  € ^ RI Hp ^ RI Hp ^ RI Hp \        P
                  ! 4       pVP                  \        P                  8X  g   VP                  4       '       d   \        W4      # \        4       '       d   \        4       M\        \        4      p\        4       p\        4       pVRJ;'       d    \!        VP#                  R4      4      p\        4       '       d   VP%                  4       MVP'                  RR4      p	\)        T ;'       g    \+        4       \        4       V'       * TTTVP#                  R4      \-        4       '       d   \/        \-        4       4      MR\1        4       V'       d   \3        4       MR\        4       '       d   VP5                  4       MRV'       g   V'       g   \        4       '       g   RMVP7                  V	4      V	P8                  V	P:                  R7      # )r”   )rh   ©Ú	resourcesry  Nr<  )r^   r_   r`   ra   rb   rd   re   rf   rg   rQ   rh   ri   rj   rk   )rm  rh   r¡  rz  r	   r>  r?  rA  r|  Ú_sandbox_statusr8   rA   rÎ   r=   r¨   r3  r2   r=  Úmemory_infoÚ
MemoryInfor\   rp  r†  r]   rg   rQ   Ú
executableÚmemory_blockerÚavailable_mbÚlimit_mb)
r^   Ú_bd_browserr¡  rz  r?  ra   rd   rÝ   rb   Úmems
   &         r+   rŒ   rŒ   /  sU  € Ý8Ý+Ý.Ü×ÒÓ€EØ‡{�{”i×(Ñ(Ô(¨L×,EÑ,E×,GÒ,Gô ˜wÓ.Ð.Ü/@×/BÒ/BÔ)Ô+ÌÔM^ÓH_€GÜ
‹/€CÜ
‹/€CØ˜ˆo×:Ð:¤$ s§w¡w¨yÓ'9Ó":€GÜ%6×%8Ò%8ˆ)×
Ñ
Ô
!¸i×>RÑ>RÐSWÐY]Ó>^€CÜØ×*Ð*œ=›?Ü#Ó%Ø”+ØØØØ—‘˜	Ó"Ü)8×):Ò):Œs”?Ó$Ô%ÀÜ“ß-4œÔ)¸$Ü,=×,?Ò,?�×&Ñ&Ô(ÀTç§7Ô2C×2EÒ2E‘È9×KcÑKcÐdgÓKhØ×,Ñ,ØŸ™ôð r-   c               ó    € V ^8„  d   QhRRRR/# rž  r)   )r*   s   "r+   r,   r,   P  s   € ÷ .ñ .˜]ð .°mñ .r-   c                óÜ  € ^ RI Hp \        4       ;'       g    \        RR7      pVe   VP	                  V4      M. pVe$   TP                  Y0;'       g    \        4       4      M/ p\        VP                  R4      4      pRpRpV'       då   VP                  VP                  4      ;'       g    RVP                   RVP                   R2p	R	R
P                  V4       RV	^ ,          P                  4        V	R,           R2pVP                  R8X  d^   ^ RIHp
 V
! 4       pVeM   RVP                   RVP"                  R\%        VP&                  4      /pRVP                    RVP"                   R2p\)        R(/ RT ;'       g    \        4       bRRbRRbRVbRVbRRbRVP                  R4      bRRbR\+        4       bR RbR!RbR"VbR#RbR$RbR%\,        P.                   R&VP                   2bR'Vb # ))zÊStatus of a sandbox-placed screen. Package presence is only known once the sandbox exists; before
that the pane shows "installed" with the image hint carried in ``install_command`` so Start can explain.ry  FrŒ  Nr<  zuse z as terminal.z8_image (the default sandbox base plus the desktop stack)z+The terminal backend's sandbox image lacks ú, z. :r·   NNz(, or set bot_desktop.placement: gateway.Údocker)ÚpendingÚcurrent_imageÚtarget_imageÚ
containersz"Your sandbox container still runs z%, which has no desktop. Switch it to zh: files in /root and /workspace stay, packages installed inside the container are reinstalled on demand.r^   r_   Tr`   ra   rb   rd   re   rf   rg   rQ   rh   ri   rj   rk   r	   Ú:rm   r)   )rm  rz  r“  rŽ  rA   r3  rp  r2   r=  Úplugin_image_adviceÚbackendÚSANDBOX_IMAGE_HINTrL   ÚupperÚhermes_cli.sandbox_image_switchr¯  r°  r±  Úlenr²  r\   rg   r	   rA  )r^   r?  rz  rÝ   ra   r8  rb   ri   rm   Úadvicer¯  Úsws   &&          r+   r¢  r¢  P  sK  € õ /Ü
Ó
×
<Ð
<¤,°eÔ"<€CØ47²Oˆl×+Ñ+¨CÔ0È€GØORÊ�×*Ñ*¨3×0JÐ0J¼=»?ÔKÐdf€IÜ�9—=‘= Ó+Ó,€Gð €GØ€LßØ×1Ñ1°%·-±-Ó@÷ (ð (Ø�<×2Ñ2Ð3°=ÀÇÁÀð P&ð 'ð 	ð AÀÇÁÈ7ÓASÐ@TÐTVÐW]Ð^_ÕW`×WfÑWfÓWhÐViÐjpÐqsÕjtÐiuð v<ð =ˆà�=‰=˜HÔ$õ @Ù“ˆBØŠ~Ø /°×1AÑ1AÀ>ÐSU×SbÑSbØ ,¬c°"·-±-Ó.@ð B�à?À×@PÑ@PÐ?Qð R+Ø+-¯?©?Ð*;ð <WðX�ô ò Ø×*Ð*œ=›?øðáðñ ðñ ð	ñ
 ðñ ðð —‘˜iÔ(ðñ ðô ”ðñ ðñ ðñ ðñ !ðñ ðô ×'Ñ'Ð(¨¨%¯-©-¨Ñ9ðñ  "ð!ð r-   c               ó   € V ^8„  d   QhRR/# rH  r)   )r*   s   "r+   r,   r,   �  s   € ÷ ñ �sñ r-   c                 óV   €  ^ RI Hp  V ! 4       ;'       g    R#   \         d     R# i ; i)r”   ©Úget_active_profile_nameÚdefault)Úhermes_cli.profilesr¿  rC  r¾  s    r+   rp  rp  �  s-   € ðÝ?Ù&Ó(×5Ð5¨IÐ5øÜô Úðús   ‚ – ™(§(Úwait_secondsg      .@c               ó    € V ^8„  d   QhRRRR/# ©r'   rÂ  r    r(   r\   r)   )r*   s   "r+   r,   r,   �  s   € ÷ :ñ :˜5ð :¨Mñ :r-   c                ój  € \         P                  ! 4       pVP                  \         P                  8X  d   \	        VP
                  4      hVP                  \         P                  8X  d   \        V 4      # \        4       '       g   \	        R4      h\        4       pV'       df   RRP                  V4       R2p\        4       f   \	        V R24      h\        4       '       g   \	        V R24      h\	        V R\        4        24      h\        4       pVP                  R	R	R
7       \         P"                  ! VR4       \%        VR,          4      ;_uu_ 4        \'        4       e4   \)        4       P+                  R4      '       d   \-        4       uuRRR4       # ^ RIHp VP3                  4       pVP5                  4       pVP7                  WvR7      ;pe   \	        V4      hVP8                  eA   VP8                  VP;                  V4      8  d!   \<        P?                  RVP8                  4       \'        4       f   \A        V4       \B        PD                  P                  R	R	RR7        \G        W@4      uuRRR4       #   \         d    TR,          PI                  R	R7       h i ; i  + '       g   i     R# ; i)aÃ  Start this profile's desktop (idempotent). Blocks until the launcher publishes its env file or
``wait_seconds`` pass; raises ``RuntimeError`` naming the blocker.

``bot_desktop.placement`` decides WHERE: inside the configured terminal backend (docker/ssh/a streaming plugin backend;
``sandbox_host``), or on the gateway host (the rest of this function). A sandbox backend that cannot host
a screen refuses rather than silently falling back to the host beside it.

Two locks: the per-profile ``start.lock``, held from the running-check to the launcher's publish so two
start() calls for one profile spawn one launcher (the loser sees it running), and the host-wide
display-allocation lock, held only until this Xvnc has written ``/tmp/.X<n>-lock`` (a second profile
picking the same number before that would fail and its stale-lock cleanup could remove our socket).
Holding it for the whole Xfce bring-up serialized every profile's start behind one desktop launch.z,Bot Desktop runs on Linux gateway hosts onlyzBot Desktop needs r­  z on the gateway hostNz¦, and no supported package manager (apt/dnf/pacman) is available to install them. Install TigerVNC (Xvnc) and the Xfce core components with this distro's own tooling.zÊ, and this host cannot install them: the process is unprivileged and there is no sudo. On the published Docker image the packages have to be baked in, so this needs a newer image rather than an install.z. Install: T©r%  r&  r#  ú
start.lockr<  r   )Úneedz`Bot Desktop starting with %d MB available; a browser with a few pages open can use most of that.r$  re   rÚ   )%r	   r>  r?  r@  r  rJ  rA  Ú_start_in_sandboxr8   rA   rL   rH   rZ   rQ   r/   r*  rV   Úchmodr  r¨   r3  r=  rŒ   rm  r¡  Úmin_free_mbr£  r¦  r§  Útight_headroom_mbrâ   rã   ré   r(  r)  Ú_spawn_and_waitrå   )	rÂ  r?  ra   rÈ  rÊ   r¡  Úfloorrª  ri   s	   $        r+   rB  rB  �  sL  € ô ×ÒÓ€EØ‡{�{”i×'Ñ'Ô'Ü˜5Ÿ<™<Ó(Ð(Ø‡{�{”i×(Ñ(Ô(Ü  Ó.Ð.Ü×ÒÜÐIÓJÐJÜÓ €Gßà# D§I¡I¨gÓ$6Ð#7Ð7KÐLˆÜÓÒ$ÜØ�&ð gð góhð hô �}Š}ÜØ�&ð 6ð 6ó7ð 7ô ˜d˜V ;¬Ó/@Ð.AÐBÓCÐCÜ	‹€BØ‡H�H�T D€HÔ)Ü‡H‚HˆR�ÔÜ	�"�|Õ#×	$Õ	$Ü‹?Ò&¬=«?×+>Ñ+>¸y×+IÒ+IÜ“8÷ 
%Ò	$õ 	0Ø×%Ñ%Ó'ˆØ×#Ñ#Ó%ˆØ ×/Ñ/°Ð/Ó@Ð@ˆGÒMÜ˜wÓ'Ð'Ø×ÑÒ'¨C×,<Ñ,<¸y×?ZÑ?ZÐ[`Ó?aÔ,aÜ�N‰NðØ×,Ñ,ô.ô ‹?Ò"Ü! "Ô%Ü×Ñ× Ñ ¨¸À5Ð ÔIð	Ü" 2Ó4÷! 
%Ò	$øô" ô 	ð �)�^×#Ñ#¨tÐ#Ô4Øð		ú÷# 
%×	$Ð	$ús%   Å5J!ÆCJ!É#
I8É8&JÊJ!Ê!J2	c               ó$   € V ^8„  d   QhRRRRRR/# )r'   rÊ   r   rÂ  r    r(   r\   r)   )r*   s   "r+   r,   r,   Ì  s&   € ÷ :~ñ :~˜ð :~¨Eð :~°mñ :~r-   c                óN  € \         P                  ! 4       ;_uu_ 4       pVP                  \        \        4      4       \        4       pV R,          P                  \        V4      RR7       V R,          pVP                  RR7       ^ RI	H
p V! RR	7      pVR
,          VR&   R) F  pVP                  VR4       K  	  VP                  R\        4       R\        V4      R\        V R,          4      R\        V R,          4      R\        V4      R\        V R,          4      R\        4       /4       ^ RIHpHp	 V	! 4       ;p
e   V
^ ,          VR&   V! V
!  VR&   \%        V R,          R4      p\&        P(                  ! R\        \*        4      .V\&        P,                  W»RRR7      pVP/                  4        \1        VP2                  4      pV R,          P                  VP2                   RVe   TM^  2RR7       \4        P6                  ! 4       V,           p\4        P6                  ! 4       V8  dþ   \9        V4      e   VP/                  4        VP;                  4       eF   V R,          P=                  4       R*R P?                  RR 4      p\A        R!VPB                   R"V 24      hVPE                  4       '       d[   V R,          PE                  4       '       d>   \F        PI                  R#\        4       V4       \K        4        \M        4       uuRRR4       # \4        PN                  ! R$4       EK  \Q        VP2                  VP2                  4       VPS                  4        R+ F  pV V,          P                  RR7       K  	  \A        R%VR& R'V R,           R(24      h  + '       g   i     R# ; i),zcCaller holds ``start.lock``. Takes ``_ALLOC_LOCK`` itself, from picking the number to Xvnc's claim.re   r  r€   rÝ   TrÚ   )Úserved_profile_child_envF)Úinherit_credentialsÚHERMES_REAL_HOMEÚHOMENÚHERMES_BD_PROFILEÚHERMES_BD_DISPLAY_NUMÚHERMES_BD_SOCKETrÑ   ÚHERMES_BD_XAUTHÚ
XauthorityÚHERMES_BD_ENV_FILEÚHERMES_BD_CONFIG_HOMEÚxdgÚHERMES_BD_GEOMETRY)Údock_exec_lineÚdock_launchÚHERMES_BD_BROWSER_EXECÚHERMES_BD_BROWSER_EXEC_LINEzlauncher.logÚwbÚbash)rÝ   ÚstdinÚstdoutÚstderrÚstart_new_sessionÚ	close_fdsrœ   rK   Úreplacez!Bot Desktop launcher exited with z:
z$Bot Desktop for profile %s up on :%sr  z/Bot Desktop did not publish its display within z.0fzs (see Ú))r<  Ú
XAUTHORITYr0  ÚDBUS_SESSION_BUS_ADDRESSÚSESSION_MANAGERi0øÿÿrÜ   )*rò   Ú	ExitStackÚenter_contextr  r(  r   Ú
write_textr]   rå   Útools.environments.localrÑ  r6  r5  rp  rg   r7  rÞ  rß  r  Ú
subprocessÚPopenÚ	_LAUNCHERÚDEVNULLÚcloser˜   rd   r  r	  r²   ÚpollÚ
read_bytesÚdecoder  Ú
returncoder„  râ   rÖ   r4  rŒ   r
  rä   Úwait)rÊ   rÂ  Úallocr­   Úenv_filerÑ  Ú	child_envr  rÞ  rß  rh   ÚlogÚprocr¦   r  ÚtailrÒ   s   &&               r+   rÍ  rÍ  Ì  s   € ä	×	Ò	×	Ô	 5Ø×ÑœH¤[Ó1Ô2Ü‹oˆØ	ˆi�×#Ñ#¤C¨£H°wÐ#Ô?Ø˜•:ˆØ�‰ 4ˆÔ(õ 	FÙ,ÀÔGˆ	Ø%Ð&8Õ9ˆ	�&ÑÛnˆCØ�M‰M˜#˜tÖ$ñ oà×ÑØ¤£Ø#¤S¨£XØ¤ B¨¥OÓ 4Øœs 2¨Õ#4Ó5Ø ¤# h£-Ø#¤S¨¨e­£_Ø ¤(£*ð
ô 	÷ 	JÙ"“}Ð$ˆGÒ1à29¸!µ*ˆIÐ.Ñ/Ù7EÀwÑ7OˆIÐ3Ñ4ä�2˜Õ&¨Ó-ˆÜ×ÒØ”Sœ“^Ð$¨)¼:×;MÑ;MÐVYØ"¨dô4ˆð 	�	‰	ŒÜ˜DŸH™HÓ%ˆØ	ˆnÕ	×(Ñ(¨D¯H©H¨:°Q¸tÒ?O±tÐUVÐ6WÐ)XÐcjÐ(Ôkä—>’>Ó# lÕ2ˆÜ�nŠnÓ Ô)Ü˜3ÓÒ+Ø—‘”Ø�y‰y‹{Ò&Ø˜^Õ+×7Ñ7Ó9¸%¸&ÐA×HÑHÈÐR[Ó\�Ü"Ð%FÀtÇÁÐFWÐWZÐ[_ÐZ`Ð#aÓbÐbØ�‰× Ò  b¨:¥o×%=Ñ%=×%?Ò%?Ü—‘ÐBÄMÃOÐUXÔYÜÔ Ü“x÷_ 
 Ò	ô` �JŠJ�s�Oô 	˜dŸh™h¨¯©Ô1Ø�	‰	ŒÛ7ˆDØ�$�Y×Ñ¨$ÐÖ/ñ 8äÐLÈ\ÐZ]ÐL^Ð^eÐfhÐkyÕfyÐezÐz{Ð|Ó}Ð}÷q 
 ×	Ð	ús   žJNÊ4NË2NÌBNÎN$	c               ó   € V ^8„  d   QhRR/# )r'   r�  r2   r)   )r*   s   "r+   r,   r,   	  s   € ÷ 9ñ 9˜Dñ 9r-   c                ó0   € \         P                  ! V R7      # )z‘The terminal environment hosting this profile's screen, or None. ``create=False`` for status probes
(a status call must never build a container).rŒ  )r	   Úterminal_environmentrŒ  s   $r+   rŽ  rŽ  	  s   € ô ×)Ò)°Ô8Ð8r-   c               ó    € V ^8„  d   QhRRRR/# rÄ  r)   )r*   s   "r+   r,   r,     s   € ÷ ñ  Eð ¨mñ r-   c                ó°  € ^ RI Hp \        RR7      pVf   \        R4      h\	        4       pVP                  RRR7       \        P                  ! VR4       \        VR,          4      ;_uu_ 4        ^ R	I	H
p VP                  V4      pV'       d   WT! WQP                  V4      RR
7      3MRpVP                  V\        4       \        4       \!        V R4      V^ ,          V^,          R7      pRRR4       VR,          P#                  RP%                  R XP'                  4        4       4      RR7       \)        4        \+        4       #   + '       g   i     Lb; i)r”   ry  TrŒ  NzZthe terminal backend's sandbox could not be started, so there is nowhere to put the screenrÆ  r#  rÇ  )rÞ  )Úsandbox_bypassg      4@)rg   rÂ  Úbrowser_execÚbrowser_exec_linerÝ   r�   c              3  ó6   "  € T F  w  rV R V R2x € K  	  R# 5i)r{  Ú
Nr)   )r¼   ÚkÚvs   &  r+   r¾   Ú$_start_in_sandbox.<locals>.<genexpr>  s    é € Ð#OÑ=N±T°Q q c¨¨1¨#¨R¥LÓ=Nùs   ‚r  r€   )NN)rm  rz  rŽ  r  r/   r*  rV   rÊ  r  r7  rÞ  Úchromium_executableÚbrowser_profile_dirrB  rp  rg   r^  rð  rL   Úitemsr4  rŒ   )rÂ  rz  rÝ   rÊ   rÞ  Úexerh   r8  s   &       r+   rÉ  rÉ    s  € Ý.Ü
˜dÔ
#€CØ
‚{ÜÐwÓxÐxÜ	‹€BØ‡H�H�T D€HÔ)Ü‡H‚HˆR�ÔÜ	�"�|Õ#×	$Õ	$õ 	=Ø×.Ñ.¨sÓ3ˆßlo�3˜ s×,LÑ,LÈSÓ,QÐbfÔgÑhð  vBˆØ ×&Ñ& s¬M«OÄhÃjÔ_bÐcoÐquÓ_vØ4;¸AµJÐRYÐZ[ÕR\ð 'ó ^ˆ	÷ 
%ð ˆ%…Z×Ñ˜BŸG™GÑ#O¸Y¿_¹_Ô=NÓ#OÓOÐZaÐÔbÜÔÜ‹8€O÷ 
%×	$ús   Á0A;EÅE	c               ó   € V ^8„  d   QhRR/# rw  r)   )r*   s   "r+   r,   r,   $  s   € ÷ <ñ < ñ <r-   c                 óf   € ^ RI Hp  \        RR7      pVf   / # V P                  V\	        4       4      # )z`Published env of a sandbox-hosted screen (the caller saw the host-side marker written at start).ry  FrŒ  )rm  rz  rŽ  r3  rp  r™  s     r+   r}  r}  $  s.   € å.Ü
˜eÔ
$€CØ
‚{Øˆ	Ø×%Ñ% c¬=«?Ó;Ð;r-   c               ó   € V ^8„  d   QhRR/# r1   r)   )r*   s   "r+   r,   r,   -  s   € ÷  ñ  ˆdñ  r-   c                 óp  € ^ RI Hp  V P                  4       '       g3   \        P                  ! 4       P
                  \        P                  8X  dw   \        4       pVe   V P                  V\        4       4      MRpV P                  4       P                  RR7       R F$  p\        4       V,          P                  RR7       K&  	  V# \        4       '       g   R# \        4       pVP                  RRR7       \        VR,          4      ;_uu_ 4        \!        V4      uuRRR4       #   + '       g   i     R# ; i)	zqStop this profile's desktop; True when a running launcher (or the X server a dead one left behind)
was signalled.ry  NFTrÚ   rÆ  rÇ  )rÝ   rX  )rm  rz  r|  r	   r>  r?  rA  r“  rq  rp  r�  rå   r/   r8   r*  r  Ú_stop_locked)rz  rÝ   ÚstoppedrÒ   rÊ   s        r+   rq  rq  -  sâ   € õ /Ø× Ñ ×"Ò"¤i×&7Ò&7Ó&9×&?Ñ&?Ä9×CUÑCUÔ&Uô !Ó"ˆØ=@º_�,×#Ñ# C¬«Ô9ÐRWˆØ×ÑÓ×%Ñ%°Ð%Ô6Û'ˆDÜ‹[˜4Õ×'Ñ'°4Ð'Ö8ñ (àˆÜ×ÒÙÜ	‹€BØ‡H�H�T D€HÔ)Ü	�"�|Õ#×	$Õ	$Ü˜BÓ÷ 
%×	$×	$Ó	$ús   ÄD$Ä$D5	c               ó    € V ^8„  d   QhRRRR/# rÉ   r)   )r*   s   "r+   r,   r,   B  s   € ÷ 
ñ 
�Tð 
˜dñ 
r-   c                óÊ   € \        4       pVf'   \        V 4      pV R,          P                  RR7       V# \        WRR7       R F  pW,          P                  RR7       K  	  R# )NrÝ   TrÚ   g      @)rë   )rœ   rÝ   rX  )r¨   ré   rå   rä   )rÊ   rd   ÚreapedrÒ   s   &   r+   r  r  B  s\   € Ü
‹/€CØ
‚{Ü& rÓ*ˆØ	ˆe�×Ñ tÐÔ,Øˆä˜#¨#Õ.Û3ˆØ	�×Ñ dÐÖ+ñ 4ár-   )
r
   r   r   r   r   r   r   r   r   r   )r   r   r   r   r   úxfce4-terminalr   zx11-xserver-utilsr   r   r   zfonts-dejavu-core)r   r   r   r   r   r  r   ÚxsetrootÚxsetr   r   r   r   zdejavu-sans-fonts)r    r   r   r   r   r  r!   zxorg-xsetrootz	xorg-xsetr#   r%   r"   r$   z
ttf-dejavu)g       @r<   )XÚ__doc__Ú
__future__r   rò   ÚloggingrV   r>   r  rò  r5   r  Údataclassesr   Úpathlibr   Útypingr   r   Úhermes_constantsr   rm  r	   Ú	getLoggerrv   râ   Ú__file__Ú	with_namerô  r  r  r=   ÚBINARY_PACKAGESrM   r/   r8   rA   rH   rQ   rN   rZ   r\   r†   r�   r˜   r¨   r«   r±   rÀ   r²   rÄ   rÇ   ré   rä   r2  r=  Úhomer(  Úcontextmanagerr  r   r+  r9  rF  rM  rD  re  r4  ra  rh  ru  r3  r†  r‰  rL  r“  rl  r˜  rg   rŒ   r¢  rp  rB  rÍ  rŽ  rÉ  r}  rq  r  r)   r-   r+   Ú<module>r,     sÊ  ðñõ #ã Û Û 	Û Û Û Û 
Û Ý !Ý ß !å ,Ý 'à	×	Ò	˜8Ó	$€á�‹N×$Ñ$ ]Ó3€	ð   Ð €ˆlð@Ð ð 
ˆFÐ0°'¸7ÀMÐS`Ø˜ }Ð6FÐHZÐ\fØ�W˜j¨+°{ÀOÐU\Ð^iðkð
 
ˆFÐ)¨7°G¸]ÈMØ˜ mÐ5EÐGYÐ[hØÐ% z°:¸{ÈKÐY`Ðbiðkð ˆv�z 7¨G°]ÀMÐS^Ð`kØÐ.Ð0BÀFØ˜ j°/À;ÐP`ÐbiÐkwðyð€ð 
ò !ð 
ò !ð ò ð
€õ-õ,õEõõ1õ(8õ9ð ÷#ð #ó ð#õ,õõõaõ >ñ �6‹l€ÙÐ%Ó&€õõ	kõIõ#÷L$ñT �2—:‘:—>‘>Ð"3Ó4×NÐN¸¿	º	»ÀhÕ8NÓOÐRqÕq€ð ×Ñô4ó ð4õ	Kõ÷õ?õ:õ .ð Ð õõõ"õõ õ,Kõ;õ
ò&õ 0õ>õ2÷õB.õbð: 4÷ :õz:~õz9õõ*<õ ÷*
r-   