+
    lHàjo3  ã                   óÚ  a € R+ t0 t R t^ RIt^ RIt^ RIt^RIHtHt ]P                  ! ]	4      t
]! 4       t]P                  t]P                  tRt]P                   ! 4       tR R ltR R lt]! R4      ]R	 R
 l4       4       t]! R4      ]R R l4       4       t]! R4      ]R R l4       4       t]! R4      ]R R l4       4       t]P*                  ! 4       t] ^ k ]! 4       t] ^k R R ltR R ltR R lt]! R4      ]R R l4       4       t]! R4      ]R R l4       4       t]! R 4      ]R! R" l4       4       t]! R#4      ]R$ R% l4       4       t]! R&4      ]R' R( l4       4       tR) R* ltR# ),ui  Bot Desktop JSON-RPC handlers: the Desktop app's door to a profile's headless screen.

``display.status`` reports runtime + lease; ``display.start`` / ``display.stop`` manage the Xvnc/Xfce
process; ``display.observe`` mints a single-use ticket the renderer redeems on ``/api/display/ws``
(``hermes_cli.web_routers.display``) to stream raw RFB; ``display.lease.acquire`` / ``release`` are
Take over / Hand back. ``display.install`` runs the distro package install on the gateway host: sudo
privilege is asked for through the masked ``display.install.sudo`` serverâ†’client request (same ``_ask``
bridge as the terminal tool's sudo prompt), stdout streams as ``display.install.log`` and the run ends with
``display.install.done`` carrying a fresh status snapshot. Every handler is profile-scoped so a multiplexed gateway answers for the bot
the pane is looking at. Lease transitions fan out as the global ``display.lease`` event so every
connected client repaints (badge on the bot row, red border on the viewer, agent handoff prompt).

Bodies are rebound onto server.py's globals (method_ctx.bind_module) and reference them bare.
N)ÚHandlerRegistryÚbind_modulei´  c                ó$   € V ^8„  d   QhR\         /# ©é   Úreturn©Údict)Úformats   "Ú@/home/ubuntu/.hermes/hermes-agent/tui_gateway/methods_display.pyÚ__annotate__r      s   € ÷ oñ oœ4ñ oó    c                  ó²   € ^ RI Hp  ^ RIHpHp VP                  4       p/ VP                  4       CRVP                  VP                  4       4      RV ! 4       /C# )é    ©Úhermes_home_key©ÚleaseÚruntimer   Úprofile_key)	Úhermes_constantsr   Útools.bot_desktopr   r   ÚstatusÚas_dictÚpublic_viewÚget)r   Ú	_bd_leaseÚ_bd_runtimeÚsts       r   Ú_display_snapshotr      sG   € Ý0ßLØ	×	Ñ	Ó	€BØnˆb�j‰j‹lÐn˜G Y×%:Ñ%:¸9¿=¹=»?Ó%KÈ]Ñ\kÓ\mÑnÐnr   c                ó   € V ^8„  d   QhRR/# ©r   r   N© )r
   s   "r   r   r   &   s   € ÷ 	$ñ 	$ ñ 	$r   c                 ó¨   a€ \         P                  4       '       d   R# ^ RIHo R V3R llp SP	                  V 4       \         P                  4        R# )zHOnce per process: broadcast every lease change to all connected clients.N©r   c                ó(   € V ^8„  d   QhR\         RR/# )r   r   r   N©Ústr)r
   s   "r   r   Ú-_install_lease_listener.<locals>.__annotate__,   s   € ÷ vñ v¤ð v¨tñ vr   c           	      óF   <€ \        R RV RSP                  V4      /4       R# )zdisplay.leaser   r   N)Ú_broadcast_global_eventr   )r   r   r   s   &&€r   Ú
_on_changeÚ+_install_lease_listener.<locals>._on_change,   s#   ø€ Ü °-ÀÈgÐW`×WlÑWlÐmrÓWsÐ1tÖur   )Ú_lease_listener_installedÚis_setr   r   Ú	on_changeÚset)r+   r   s    @r   Ú_install_lease_listenerr1   &   s>   ø€ ä ×'Ñ'×)Ò)ÙÝ4÷vð và×Ñ˜
Ô#Ü×!Ñ!Ö#r   zdisplay.statusc                ó0   € V ^8„  d   QhR\         R\         /# ©r   Úparamsr   r   )r
   s   "r   r   r   4   s   € ÷ /ñ /”4ð /œDñ /r   c                 ó¤   € \        4         \        V \        4       4      #   \         d%   p\	        T \
        \        T4      4      u R p?# R p?ii ; i©N)r1   Ú_okr   Ú	ExceptionÚ_errÚ_DISPLAY_ERRr'   )Úridr4   Úes   && r   Ú_r=   2   sC   € ô Ôð/Ü�3Ô)Ó+Ó,Ð,øÜô /Ü�Cœ¤s¨1£vÓ.Õ.ûð/ús   Œ   A«A
ÁAÁ
Azdisplay.thumbnailc                ó0   € V ^8„  d   QhR\         R\         /# r3   r   )r
   s   "r   r   r   >   s   € ÷ /ñ /”4ð /œDñ /r   c                ó’  €  ^ RI Hp VP                  4       pVP                  VP                  8X  d   \        V RRRR/4      # ^ RIHp V! 4       pVP                  4       P                  VP                  8w  d   \        V RRRR/4      # \        V RV/4      #   \         d%   p\        T \        \        T4      4      u Rp?# Rp?ii ; i)uu  One JPEG grab of the bot's screen (``data_url``: null while stopped). Read-only: no lease change.
Suppressed while a human holds the lease â€” the frame may show what they are typing â€” and when
the lease moved DURING the grab: a takeover racing the framebuffer read means the frame may
already be the human's session, so it is dropped rather than shipped to every client.r$   Údata_urlNÚ
suppressedÚhuman_has_control)Úthumbnail_data_url)r   r   r   ÚholderÚHUMANr7   Útools.bot_desktop.thumbnailrC   Úepochr8   r9   r:   r'   )r;   r4   r   ÚbeforerC   r@   r<   s   &&     r   r=   r=   <   s«   € ð/Ý8Ø—‘“ˆØ�=‰=˜IŸO™OÔ+Ü�s˜Z¨¨|Ð=PÐQÓRÐRÝBÙ%Ó'ˆØ�=‰=‹?× Ñ  F§L¡LÔ0Ü�s˜Z¨¨|Ð=PÐQÓRÐRÜ�3˜ XÐ.Ó/Ð/øÜô /Ü�Cœ¤s¨1£vÓ.Õ.ûð/ús+   ‚A B ÁAB Â	B ÂCÂ"CÂ;CÃCzdisplay.startc                ó0   € V ^8„  d   QhR\         R\         /# r3   r   )r
   s   "r   r   r   S   s   € ÷ /ñ /”4ð /œDñ /r   c                 óÐ   € \        4        ^ RIHp  VP                  4        \	        V \        4       4      #   \         d%   p\        T \        \        T4      4      u Rp?# Rp?ii ; i)r   ©r   N)
r1   r   r   Ústartr7   r   r8   r9   r:   r'   )r;   r4   r   r<   s   &&  r   r=   r=   Q   sR   € ô ÔÝ8ð/Ø×ÑÔÜ�3Ô)Ó+Ó,Ð,øÜô /Ü�Cœ¤s¨1£vÓ.Õ.ûð/ús   ’#6 ¶A%ÁA ÁA%Á A%zdisplay.stopc                ó0   € V ^8„  d   QhR\         R\         /# r3   r   )r
   s   "r   r   r   _   s   € ÷ /ñ /”4ð /œDñ /r   c                óŠ  € ^ RI HpHp \        VP	                  R4      4      pVP                  V'       * R7      P                  VP                  8X  d   \        V \        RRR/R7      #  VP                  4       p\        V / \        4       CRV/C4      #   \         d%   p\        T \        \        T4      4      u R	p?# R	p?ii ; i)
zªStopping kills the screen under whoever is on it, so it obeys the same rule as a bare
display.lease.release: refused while a human holds unless the caller says ``force``.r   Úforce©Úunless_humanz=a human holds this screen; pass force: true to stop it anywayÚcodeÚviewer_mismatch©ÚdataÚstoppedN)r   r   r   Úboolr   ÚreleaserD   rE   r9   r:   Ústopr7   r   r8   r'   )r;   r4   r   r   rO   rV   r<   s   &&     r   r=   r=   ]   s°   € ÷
 MÜ�—‘˜GÓ$Ó%€Eð ×Ñ¨%¤iÐÓ0×7Ñ7¸9¿?¹?ÔJÜ�CœÐ'fØ Ð"3Ð4ô6ð 	6ð/Ø×"Ñ"Ó$ˆÜ�3ÐCÔ,Ó.ÐC°	¸7ÑCÓDÐDøÜô /Ü�Cœ¤s¨1£vÓ.Õ.ûð/ús   Á))B ÂCÂB=Â7CÂ=Cc                ó:   € V ^8„  d   QhR\         \        ,          /# r   )r0   r'   )r
   s   "r   r   r   x   s   € ÷ &ñ &¤S¬¥Xñ &r   c                  ó~   €  \         P                  \        4       \        4       4      #   \         d
    \
        u # i ; ir6   )Ú_minted_viewer_idsÚ
setdefaultÚcurrent_transportr0   Ú	TypeErrorÚ_unweakable_minted_idsr"   r   r   Ú_minted_for_this_connectionra   x   s5   € ð&Ü!×,Ñ,Ô->Ó-@Ä#Ã%ÓHÐHøÜô &Ü%Ò%ð&ús   ‚%( ¨<»<c                ó0   € V ^8„  d   QhR\         R\         /# )r   Ú	requestedr   r&   )r
   s   "r   r   r      s   € ÷ 	ñ 	œsð 	¤sñ 	r   c                óv   € ^ RI p\        4       pW9   d   V # VP                  ^4      pVP                  V4       V# )z´Server-minted viewer identity. ``requested`` is honoured only when THIS connection minted it
earlier; anything else (including a holder id read off display.status) gets a fresh id.N)Úsecretsra   Útoken_urlsafeÚadd)rc   re   ÚmineÚ	viewer_ids   &   r   Ú_mint_viewer_idrj      s=   € ó Ü&Ó(€DØÔØÐØ×%Ñ% bÓ)€IØ‡H�HˆYÔØÐr   c                ó$   € V ^8„  d   QhR\         /# )r   ri   r&   )r
   s   "r   r   r   ‹   s   € ÷ 2ñ 2¤sñ 2r   c                óN   € V\        4       9   d   R# \        V \        RRR/R7      # )u  The error for a viewer id this connection never minted, or None. acquire/release take the id
as a capability, so one a caller invented or read off the wire must be refused â€” otherwise the
minting only shapes the honest path and a made-up id still evicts or releases the human.NzHviewer_id was not minted for this connection; call display.observe firstrR   rS   rT   )ra   r9   r:   )r;   ri   s   &&r   Ú_foreign_viewer_idrm   ‹   s0   € ð Ô/Ó1Ô1ÙÜ�”\Ð#mØÐ/Ð0ô2ð 2r   zdisplay.observec                ó0   € V ^8„  d   QhR\         R\         /# r3   r   )r
   s   "r   r   r   —   s   € ÷ /ñ /”4ð /œDñ /r   c           	     óì  € ^ RI Hp ^ RIHp ^ RIHp  VP                  4       f(   VP                  4       '       g   \        V \        R4      # \        \        VP                  R4      ;'       g    R4      P                  4       4      pV! RV 2R	R
\        V! 4       4      RV/R7      p\        V RVRRRV/\        4       C4      #   \          d%   p\        T \        \        T4      4      u Rp?# Rp?ii ; i)a  Mint a single-use, 30 s ticket for ``/api/display/ws``. The ticket carries the profile home so
the bridge dials THIS profile's RFB socket, and a server-minted viewer id (returned to the caller,
who passes it to ``display.lease.acquire`` / ``release``) so the lease can name the holder.)Úget_hermes_home)Úmint_ticketrK   NzCthis profile's Bot Desktop is not running; call display.start firstri   Ú zdisplay:zbot-desktopÚhermes_home)Úuser_idÚproviderÚextraÚticketÚpathz/api/display/ws)r   rp   Ú$hermes_cli.dashboard_auth.ws_ticketsrq   r   r   Úrfb_socket_pathÚsandbox_screen_runningr9   r:   rj   r'   r   Ústripr7   r   r8   )r;   r4   rp   rq   r   ri   rw   r<   s   &&      r   r=   r=   •   sã   € õ 1Ý@Ý8ð
/à×&Ñ&Ó(Ò0¸×9[Ñ9[×9]Ò9]Ü˜œ\Ð+pÓqÐqÜ#¤C¨¯
©
°;Ó(?×(EÐ(EÀ2Ó$F×$LÑ$LÓ$NÓOˆ	Ù x°	¨{Ð%;ÀmØ$1´3±Ó7HÓ3IÈ;ÐXaÐ#bôdˆä�3˜ 6¨6Ð3DÀkÐS\ð 0Ü,Ó.ð0ó 1ð 	1øäô /Ü�Cœ¤s¨1£vÓ.Õ.ûð/ús/   ”'C ¼C Á!C Á/AC ÃC3ÃC.Ã(C3Ã.C3zdisplay.switchSandboxImagec                ó0   € V ^8„  d   QhR\         R\         /# r3   r   )r
   s   "r   r   r   ­   s   € ÷ 	Dñ 	D”4ð 	DœDñ 	Dr   c           	     óÀ   € ^ RI HpHp V! 4       pVf   \        V \        R4      # V! V\        VP                  RR4      4      R7      p\        V RV/\        4       C4      # )a  The Screen pane's answer to the pending default-image switch: ``approve`` true pins the new
image (the container is recreated on the next terminal call), false pins the current one. Both
end the offer. Refused when nothing is pending, so a stale pane cannot rewrite the config.)ÚdecideÚpendingz3no sandbox image switch is pending for this profileÚapproveT)r�   Údocker_image)	Úhermes_cli.sandbox_image_switchr   r€   r9   r:   rW   r   r7   r   )r;   r4   r   r€   ÚswÚimages   &&    r   r=   r=   «   s[   € ÷ @Ù	‹€BØ	‚zÜ�CœÐ'\Ó]Ð]Ù�2œt F§J¡J¨y¸$Ó$?Ó@ÔA€EÜˆs�^ UÐBÔ.?Ó.AÐBÓCÐCr   zdisplay.installc                ó0   € V ^8„  d   QhR\         R\         /# r3   r   )r
   s   "r   r   r   »   s   € ÷ ,mñ ,m”4ð ,mœDñ ,mr   c           	     ó¸  aa	a
a€ ^ RI Hp ^ RIHo	Hp VP                  4       '       g   \        V \        R4      # VP                  4       '       d   \        V \        R4      # VP                  4       f   \        V \        R4      # V! 4       oR V3R lloR	 V3R
 llo
^ RI
pVP                  4       pR VV	V
V3R llp S	P                  4        \        P                   ! TP"                  T3RS 2RR7      P%                  4        \'        T RRRTP                  4       RS/4      #   S	P                   d%   p\        T \        \        T4      4      u Rp?# Rp?ii ; i)z¬Start the package install in the background; the renderer follows ``display.install.log`` /
``display.install.done``. Refused while one is already running for this profile.r   )Úinstallr   z,Bot Desktop runs on Linux gateway hosts onlyzÄthis profile's screen lives inside the terminal backend's sandbox; give that sandbox an image with the desktop stack (nousresearch/hermes-sandbox:desktop) instead of installing on the gateway hostNz@no supported package manager (apt-get, dnf, pacman) on this hostc                ó$   € V ^8„  d   QhR\         /# r   r&   )r
   s   "r   r   Ú_.<locals>.__annotate__Ê   s   € ÷ [ñ [œ3ñ [r   c                  ó&   <€ \        R RRS /RR7      # )zdisplay.install.sudorr   r   i,  )Útimeout)Ú_ask)r   s   €r   Ú_ask_passwordÚ_.<locals>._ask_passwordÊ   s   ø€ ô Ð*¨B°ÀÐ0LÐVYÔZÐZr   c                ó(   € V ^8„  d   QhR\         RR/# )r   Útextr   Nr&   )r
   s   "r   r   rŠ   Ð   s   € ÷ cñ c”Cð c˜Dñ cr   c                 ó(   <€ \        R RSRV /4       R# )zdisplay.install.logr   ÚlineN)r*   )r‘   r   s   &€r   Ú_lineÚ_.<locals>._lineÐ   s   ø€ ÜÐ 5¸À{ÐTZÐ\`Ð7aÖbr   c                ó   € V ^8„  d   QhRR/# r!   r"   )r
   s   "r   r   rŠ   Ù   s   € ÷ Yñ Y�$ñ Yr   c            
      ó°   <€  SP                  SSR R7      p \        RRSRV R\        4       /4       R#   \         d   pS! RT 24       ^p  Rp?L9Rp?ii ; i)T)Úask_passwordÚon_lineÚclaimedzinstall failed: Nzdisplay.install.doner   rR   r   )Úinstall_packagesr8   r*   r   )rR   r<   rŽ   Ú_bd_installr”   r   s     €€€€r   Ú_runÚ_.<locals>._runÙ   so   ø€ ð	Ø×/Ñ/¸]ÐTYÐcgÐ/ÓhˆDô 	 Ð 6¸ÈÐU[Ð]aØ9AÔCTÓCVð9Xö 	Yøô ô 	ÙÐ$ Q CÐ(Ô)Ø�Dûð	ús   ƒ3 ³A¾AÁAzbot-desktop-install:T)ÚtargetÚargsÚnameÚdaemonÚstartedÚcommandr   )r   r   r   rˆ   r   Úis_supported_hostr9   r:   Ú
in_sandboxÚinstall_commandÚcontextvarsÚcopy_contextÚclaimÚInstallBusyr'   Ú	threadingÚThreadÚrunrL   r7   )r;   r4   r   r   r¨   Úctxr�   r<   rŽ   rœ   r”   r   s   &&      @@@@r   r=   r=   ¹   sA  û€ õ
 1ßPØ×(Ñ(×*Ò*Ü�CœÐ'UÓVÐVØ×Ñ×ÒÜ�Cœð (Só Tð 	Tð ×"Ñ"Ó$Ò,Ü�CœÐ'iÓjÐjÙ!Ó#€K÷[ð [÷cð có Ø
×
"Ñ
"Ó
$€C÷Yó Yð/Ø×ÑÔô ×Ò˜CŸG™G¨4¨'Ð:NÈ{ÈmÐ8\ÐeiÔj×pÑpÔrÜˆs�Y  i°×1LÑ1LÓ1NÐP]Ð_jÐkÓlÐløð ×"Ñ"ô /Ü�Cœ¤s¨1£vÓ.Õ.ûð/ús   Â>D$ Ä$EÄ5EÅEÅEzdisplay.lease.acquirec                ó0   € V ^8„  d   QhR\         R\         /# r3   r   )r
   s   "r   r   r   ì   s   € ÷ =ñ =”4ð =œDñ =r   c                 ój  € ^ RI Hp \        VP                  R4      ;'       g    R4      P	                  4       pV'       g   \        V \        R4      # \        W4      ;pe   V# TP                  T\        VP                  R4      ;'       g    R4      R7      p\        V RVP                  V4      /4      # )r   r$   ri   rr   zviewer_id requiredÚreason)r²   r   )r   r   r'   r   r|   r9   r:   rm   Úacquirer7   r   ©r;   r4   r   ri   Úrefusedr   s   &&    r   r=   r=   ê   s›   € õ 5Ü�F—J‘J˜{Ó+×1Ð1¨rÓ2×8Ñ8Ó:€IßÜ�CœÐ';Ó<Ð<Ü% cÓ5Ð5ˆÒBØˆØ×Ñ˜i´°F·J±J¸xÓ4H×4NÐ4NÈBÓ0OÐÓP€EÜˆs�W˜i×3Ñ3°EÓ:Ð;Ó<Ð<r   zdisplay.lease.releasec                ó0   € V ^8„  d   QhR\         R\         /# r3   r   )r
   s   "r   r   r   ù   s   € ÷ =ñ =”4ð =œDñ =r   c                 óä  € ^ RI Hp \        VP                  R4      ;'       g    R4      P	                  4       ;'       g    RpVe)   VP                  R4      '       g   \        W4      ;pe   V# TP                  Y3RJ ;'       d    VP                  R4      '       * R7      pVf1   VP                  VP                  8X  d   \        V \        RRR	/R
7      # \        V RVP                  V4      /4      # )r   r$   ri   rr   NrO   rP   zJviewer_id required to release another viewer's lease (or pass force: true)rR   rS   rT   r   )r   r   r'   r   r|   rm   rX   rD   rE   r9   r:   r7   r   r´   s   &&    r   r=   r=   ÷   sÞ   € õ 5Ü�F—J‘J˜{Ó+×1Ð1¨rÓ2×8Ñ8Ó:×BÐB¸d€Ið Ò V§Z¡Z°×%8Ò%8ÔI[Ð\_ÓIkÐ>k¸gÒ=xØˆà×Ñ˜iÀ4Ð6G×6cÐ6cÐPV×PZÑPZÐ[bÓPcÔLcÐÓd€EØÒ˜UŸ\™\¨Y¯_©_Ô<Ü�CœÐ'sØ Ð"3Ð4ô6ð 	6äˆs�W˜i×3Ñ3°EÓ:Ð;Ó<Ð<r   c                ó   € V ^8„  d   QhRR/# r!   r"   )r
   s   "r   r   r     s   € ÷ 0ñ 0˜ñ 0r   c                 ó2   € \        \        4       V RR7       R# )r=   )ÚskipN)r=   )r   Úglobals)Úservers   &r   Úregisterr½     s   € Ü”“	˜6¨×/r   c                óÊ   € V ^8„  d   Qh/ ^ \         9   d0   \        P                  \        \        \
        ,          3,          ;R&   ^\         9   d   \        \
        ,          ;R&   # )r   r\   r`   )Ú__conditional_annotations__ÚweakrefÚWeakKeyDictionaryÚobjectr0   r'   )r
   s   "r   r   r      sM   € ÷ ñ ÷b ^Ò ]”G×-Ñ-¬f´c¼#µhÐ.>Õ?Ñ ]ñc÷h )Ò (œœC�Ñ (òir   )r¿   Ú__doc__Úloggingr¬   rÀ   Ú
method_ctxr   r   Ú	getLoggerÚ__name__ÚloggerÚ	_registryÚmethodÚprofile_scopedÚ_profile_scopedr:   ÚEventr-   r   r1   r=   rÁ   r\   r0   r`   ra   rj   rm   r½   r   )r¿   s   @r   Ú<module>rÎ      sÐ  øðöó Û Û ç 4à	×	Ò	˜8Ó	$€ÙÓ€	Ø	×	Ñ	€Ø×*Ñ*€à€Ø%ŸOšOÓ-Ð õoõ	$ñ ÐÓØô/ó ó ð/ñ ÐÓØô/ó ó ð/ñ& ˆÓØô/ó ó ð/ñ ˆÓØô/ó ó ð/ð& CJ×B[ÒB[ÓB]Ð Ó ]ñ $'£5Ð Ó (õ&õ	õ2ñ ÐÓØô/ó ó ð/ñ( Ð$Ó%Øô	Dó ó &ð	Dñ ÐÓØô,mó ó ð,mñ^ ÐÓ Øô=ó ó !ð=ñ ÐÓ Øô=ó ó !ð=÷0r   