+
    lHàj&+  ã                  ó²  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	H
t
Ht ^ RIHt ]P                  ! ]4      tRRRR/R R	 lltR
 R ltR R ltR R ltRRRR/R R lltR R ltRRRRRR/R R lltRRRRR]P0                  /R R lltRRRRRRRR/R  R! lltR"t/ tR#]R$&   ]P<                  ! 4       t ! R% R&4      t R'R(RR/R) R* llt!R# )+a¡  A long-lived process INSIDE a terminal backend with both stdio pipes open.

``BaseEnvironment.execute`` is request/response: it captures output and returns. The desktop that
follows the terminal backend needs three things that are not: the RFB byte stream between the
Desktop pane and the sandbox's Xvnc, cua-driver's MCP-over-stdio server, and agent-browser
invocations whose daemon must outlive the call. All three are "spawn argv in the sandbox, keep
stdin/stdout as pipes". Each spawn-per-call backend has a local argv prefix that gives exactly that
(``docker exec -i``, ``ssh``); this module is the one place that knows them.

SDK backends (modal, daytona, vercel) have no argv prefix: ``exec_prefix`` returns None there and
the desktop stays on the gateway host (or refuses, per ``bot_desktop.placement``). Plugin backends
that declare ``supports_streams`` supply the prefix from their environment's own ``exec_prefix()``.
)ÚannotationsN)ÚOptionalÚSequence)ÚBaseEnvironmentÚuserÚinteractiveTc               ó(   € V ^8„  d   QhRRRRRRRR/# ©	é   Úenvr   r   úOptional[str]r   ÚboolÚreturnúOptional[list[str]]© )Úformats   "Ú?/home/ubuntu/.hermes/hermes-agent/tools/environments/streams.pyÚ__annotate__r      s0   € ÷ Hñ H�_ð H¨}ð HÐRVð HÐbuñ Hó    c               óL  € ^ RI Hp ^ RIHp \	        W4      '       d[   \        V RR4      pV'       g   R# V P                  R.pV'       d   VP                  R4       V'       d   VRV.,          pWe.,           # \	        W4      '       d   V P                  4       # \        WVR7      # )	zùLocal argv that runs its remainder inside ``env``, or None for backends without one.

``user`` selects the sandbox-side account (docker only; ssh runs as the configured login).
``interactive`` keeps stdin open (``docker exec -i``); ssh always does.
)ÚDockerEnvironment©ÚSSHEnvironmentÚ_container_idNÚexecz-iz-u©r   r   )
Útools.environments.dockerr   Útools.environments.sshr   Ú
isinstanceÚgetattrÚ_docker_exeÚappendÚ_build_ssh_commandÚ_plugin_exec_prefix)r   r   r   r   r   Ú	containerÚargvs   &$$    r   Úexec_prefixr&      s‰   € õ <Ý5ä�#×)Ò)Ü˜C °$Ó7ˆ	ßÙØ—‘ Ð(ˆßØ�K‰K˜ÔßØ�T˜4�LÕ ˆDØ�kÕ!Ð!Ü�#×&Ò&Ø×%Ñ%Ó'Ð'Ü˜s¸;ÔGÐGr   c               ó(   € V ^8„  d   QhRRRRRRRR/# r	   r   )r   s   "r   r   r   4   s*   € ÷ *ñ *˜_ð *°}ð *ÐSWð *Ð\oñ *r   c               óÚ  € \        V RR4      p\        V4      '       g   R#  V! WR7      pT'       g   R# \        T\        \        34      '       g@   \        P	                  R\        T 4      P                  \        T4      P                  4       R# T Uu. uF  p\        T4      NK  	  up#   \         d0    \        P	                  R\        T 4      P                  RR7        R# i ; iu upi )z`A plugin environment's own ``exec_prefix()`` (``TerminalEnvironmentProvider.supports_streams``).r&   Nr   zA%s.exec_prefix() failed; treating the backend as unable to streamT)Úexc_infoz`%s.exec_prefix() returned %s, not a list of argv words; treating the backend as unable to stream)r   ÚcallableÚ	ExceptionÚloggerÚwarningÚtypeÚ__name__r   ÚlistÚtupleÚstr)r   r   r   ÚhookÚprefixÚparts   &$$   r   r#   r#   4   sÆ   € ä�3˜ tÓ,€DÜ�D�>Š>ÙðÙ˜4Ô9ˆ÷
 ÙÜ�fœt¤U˜m×,Ò,ä�‰ð #Ü$(¨£I×$6Ñ$6¼¸V»×8MÑ8Mô	OáÙ"(Ó)¡&˜$ŒC�ŽI¡&Ñ)Ð)øô ô Ü�‰ÐZÜ˜C“y×)Ñ)°Dð 	ô 	:âðüò *s   ¢	B+ ÂC(Â+6C%Ã$C%c               ó    € V ^8„  d   QhRRRR/# )r
   r   r   r   r2   r   )r   s   "r   r   r   I   s   € ÷ Eñ E˜/ð E¨cñ Er   c                ób   € \        V RR4      p\        V4      '       d   \        V! 4       4      # R# )zg``env.get_temp_dir()``, or ``/tmp`` for a plugin environment that doesn't subclass ``BaseEnvironment``.Úget_temp_dirNz/tmp)r   r*   r2   )r   r8   s   & r   Úsandbox_temp_dirr9   I   s,   € ä˜3 °Ó5€LÜ"*¨<×"8Ò"8Œ3‰|‹~ÓÐD¸fÐDr   c               ó    € V ^8„  d   QhRRRR/# ©r
   r   r   r   r   r   )r   s   "r   r   r   O   s   € ÷ :ñ :˜/ð :¨dñ :r   c                ó    € \        V R R7      RJ# )T)r   N)r&   )r   s   &r   Úsupports_streamsr=   O   s   € Ü�s¨Ô-°TÐ9Ð9r   r   Úshell_joinedFc          
     ó,   € V ^8„  d   QhRRRRRRRRRR	/# )
r
   r4   úSequence[str]r%   r   úOptional[dict]r>   r   r   z	list[str]r   )r   s   "r   r   r   S   s1   € ÷ +ñ +˜ð +¨]ð +ÀNð +Ø"ð+Ø/8ñ+r   c               óú   € RP                  R T;'       g    / P                  4        4       4      pV RRP                  R V 4       4       2pV'       d   . V O\        P                   ! RRV.4      N# . V ORNRNVN# )aA  ``prefix`` + a ``bash -c`` that exports ``env`` and execs ``argv``.

The script is built once, then delivered the way the client needs it: argv-preserving clients (docker,
apptainer) get ``["bash", "-c", script]``; ``shell_joined`` clients (OpenSSH joins the words after the host
with spaces and the remote login shell splits them again) get the whole ``bash -c '<script>'`` as ONE
quoted word, or the remote side runs ``bash -c export`` and hands the rest to the login shell
(``SSHEnvironment.run_bash`` quotes for the same reason). Prefer :func:`remote_command`, which knows.Ú c              3  ó`   "  € T F$  w  rR V R\         P                  ! V4       R2x € K&  	  R# 5i)zexport Ú=Ú;N©ÚshlexÚquote)Ú.0ÚkÚvs   &  r   Ú	<genexpr>Úremote_argv.<locals>.<genexpr>\   s,   é € ÐWÑCV¹4¸1˜   1¤U§[¢[°£^Ð$4°AÕ6ÓCVùs   ‚,.z exec c              3  óN   "  € T F  p\         P                  ! V4      x € K  	  R # 5i)NrG   )rJ   Úas   & r   rM   rN   ]   s   é € Ð'EÁ¸1¬¯ª°A¯¨Ãùs   ‚#%Úbashú-c)ÚjoinÚitemsrH   )r4   r%   r   r>   ÚexportsÚscripts   &&$$  r   Úremote_argvrW   S   s„   € ð �h‰hÑWÀCÇIÀIÈ2×CTÑCTÔCVÓWÓW€GØˆy˜˜sŸx™xÑ'EÁÓ'EÓEÐFÐG€FßØ<�Ð<œŸš V¨T°6Ð$:Ó;Ð<Ð<Ø*ˆVÐ*�VÐ*˜TÐ* 6Ð*Ð*r   c               ó    € V ^8„  d   QhRRRR/# r;   r   )r   s   "r   r   r   c   s   € ÷ +ñ +�oð +¨$ñ +r   c                ó$   € ^ RI Hp \        W4      # )é    r   )r   r   r   )r   r   s   & r   r>   r>   c   s   € Ý5Ü�cÓ*Ð*r   Ú	child_envc               ó0   € V ^8„  d   QhRRRRRRRRR	R
RR/# )r
   r   r   r%   r@   r[   rA   r   r   r   r   r   r   r   )r   s   "r   r   r   h   sA   € ÷ Tñ T˜ð T¨}ð TÈNð TØ&ðTØ<@ðTØL_ñTr   c               óV   € \        WVR7      pVf   R# \        WQV\        V 4      R7      # )z™Full local argv running ``argv`` inside ``env`` with ``child_env`` exported, quoted for that backend's
client; None for a backend without an exec prefix.r   N)r   r>   )r&   rW   r>   )r   r%   r[   r   r   r4   s   &&$$$ r   Úremote_commandr^   h   s,   € ô ˜°[ÔA€FØ‚~ÙÜ�v¨ÄÈcÓARÔSÐSr   Ústderrc          
     ó,   € V ^8„  d   QhRRRRRRRRR	R
/# )r
   r   r   r%   r@   r[   rA   r   r   r   zsubprocess.Popenr   )r   s   "r   r   r   r   s8   € ÷ _ñ _�_ð _¨Mð _Èð _Ø#ð_ØJZñ_r   c               óÖ   € \        WW#RR7      pVf"   \        \        V 4      P                   R24      h\        P
                  ! V\        P                  \        P                  VRR7      # )z†Spawn ``argv`` inside ``env`` with stdin and stdout as pipes (bytes). Raises ``RuntimeError`` for a
backend that cannot host a stream.T©r[   r   r   z& cannot host a long-lived stdio stream)ÚstdinÚstdoutr_   Ú	close_fds)r^   ÚRuntimeErrorr.   r/   Ú
subprocessÚPopenÚPIPE)r   r%   r[   r   r_   Úcommands   &&$$$ r   Úopen_streamrk   r   s_   € ô ˜S°)ÐTXÔY€GØ‚Üœd 3›i×0Ñ0Ð1Ð1WÐXÓYÐYÜ×ÒØ”z—‘¬z¯©ÀvÐY]ô_ð _r   Útimeoutg      >@rc   c               ó4   € 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[   rA   r   r   rl   Úfloatrc   zOptional[bytes]r   zsubprocess.CompletedProcessr   )r   s   "r   r   r   }   sJ   € ÷ Qñ Q�ð Q }ð QÀNð QÐanð QØðQØ)8ðQØD_ñQr   c               ó    € \        WW#VRJR7      pVf"   \        \        V 4      P                   R24      h\        P
                  ! WeRVRR7      # )zbOne short command inside ``env`` with captured bytes output (probes: ``command -v``, ``cat env``).Nrb   z cannot exec argvTF)ÚinputÚcapture_outputrl   Úcheck)r^   rf   r.   r/   rg   Úrun)r   r%   r[   r   rl   rc   rj   s   &&$$$$ r   Úrun_inrt   }   sX   € ô ˜S°)ÐTYÐaeÐTeÔf€GØ‚Üœd 3›i×0Ñ0Ð1Ð1BÐCÓDÐDÜ�>Š>Ø¨T¸7È%ôQð Qr   a;  import os,socket,sys,threading
s=socket.create_connection((sys.argv[1],int(sys.argv[2])))
def up():
  while True:
    d=os.read(0,65536)
    if not d: break
    s.sendall(d)
  s.shutdown(socket.SHUT_WR)
threading.Thread(target=up,daemon=True).start()
while True:
  d=s.recv(65536)
  if not d: break
  os.write(1,d)
z'dict[tuple[int, str, int], PortForward]Ú	_forwardsc                  óJ   € ] tR t^¢tRtR R ltR R ltR R ltR R	 ltR
t	R# )ÚPortForwardzfLocal ``127.0.0.1:<local_port>`` whose connections land on ``remote_host:remote_port`` inside ``env``.c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r
   r   r   Úremote_hostr2   Úremote_portÚintr   r   r   )r   s   "r   r   ÚPortForward.__annotate__¥   s/   € ÷ pñ p˜Oð p¸#ð pÈCð pÐZgñ pr   c               	ód  € WW43w  V n         V n        V n        V n        \        P                  ! \        P
                  \        P                  4      V n        V P                  P                  \        P                  \        P                  ^4       V P                  P                  R4       V P                  P                  ^4       V P                  P                  4       ^,          V n        RV n        \         P"                  ! V P$                  RV P                   2RR7      P'                  4        R# )é   Fzport-forward-T)ÚtargetÚnameÚdaemonN)ú	127.0.0.1rZ   )r   ry   rz   r   ÚsocketÚAF_INETÚSOCK_STREAMÚ_serverÚ
setsockoptÚ
SOL_SOCKETÚSO_REUSEADDRÚbindÚlistenÚgetsocknameÚ
local_portÚ_closedÚ	threadingÚThreadÚ_accept_loopÚstart)Úselfr   ry   rz   r   s   &&&&$r   Ú__init__ÚPortForward.__init__¥   sÑ   € ØBEÐT_ÐBeÑ?ˆŒ�$Ô" DÔ$4°d´iÜ—}’}¤V§^¡^´V×5GÑ5GÓHˆŒØ�‰×Ñ¤× 1Ñ 1´6×3FÑ3FÈÔJØ�‰×ÑÐ*Ô+Ø�‰×Ñ˜BÔØ#Ÿ|™|×7Ñ7Ó9¸!Õ<ˆŒØˆŒÜ×Ò × 1Ñ 1¸-ÈÏÉÐGXÐ8YÐbfÔg×mÑmÖor   c               ó   € V ^8„  d   QhRR/# ©r
   r   ÚNoner   )r   s   "r   r   r|   ¯   s   € ÷ Tñ T˜dñ Tr   c                	óð   € V P                   '       gR    V P                  P                  4       w  r\        P
                  ! T P                  T3RR7      P                  4        Kc  R #   \         d     R # i ; i)NT)r   Úargsr�   )rŽ   r†   ÚacceptÚOSErrorr�   r�   Ú_server’   )r“   ÚconnÚ_s   &  r   r‘   ÚPortForward._accept_loop¯   s`   € Ø—,—,�,ðØŸ,™,×-Ñ-Ó/‘�ô ×Ò D§K¡K°t°gÀdÔK×QÑQÖSñ øô ô Úðús   ”A& Á&A5Á4A5c               ó    € V ^8„  d   QhRRRR/# )r
   rž   zsocket.socketr   r˜   r   )r   s   "r   r   r|   ·   s   € ÷ %ñ %˜=ð %¨Tñ %r   c           
     	ó$  aa€  \        V P                  R R\        V P                  \	        V P
                  4      .V P                  R7      oR TT3R llp\        P                  ! TRR7      P                  4          \        SP                  R4      '       d   SP                  P                  R	4      MSP                  P                  R	4      pT'       g   MSP!                  T4       Ko   SP                  4        SP%                  4        R#   \         d    SP                  4         R# i ; i  \"         d     LRi ; i  SP%                  4        i ; i   SP                  4        SP%                  4        i   SP%                  4        i ; i; i)
Úpython3rR   ©r   Nc               ó   € V ^8„  d   QhRR/# r—   r   )r   s   "r   r   Ú(PortForward._serve.<locals>.__annotate__¿   s   € ÷ 	ñ 	˜4ñ 	r   c                 ó˜  <€   SP                  R4      p V '       g   M7SP                  P                  V 4       SP                  P                  4        KR   SP                  P                  4        R#   \        \
        3 d     L0i ; i  \         d     R# i ; i   SP                  P                  4        i   \         d     i i ; i; i)Té   N)Úrecvrc   ÚwriteÚflushrœ   Ú
ValueErrorÚclose)Údatarž   Úprocs    €€r   Ú	to_remoteÚ%PortForward._serve.<locals>.to_remote¿   s©   ø€ ðØØŸ9™9 UÓ+�DßØØ—J‘J×$Ñ$ TÔ*Ø—J‘J×$Ñ$Ö&ðØ—J‘J×$Ñ$Ö&øô	 œZÐ(ô Ùðûô
 ô ÚðûðØ—J‘J×$Ñ$Õ&øÜô Ùðýsc   ƒA2 �B ž7A2 ÁB	 Á2BÂB ÂBÂB Â	BÂBÂC	ÂB8Â7C	Â8CÃC	ÃCÃC	T)r   r�   Úread1r¨   )rk   r   Ú
_TCP_RELAYry   r2   rz   r   r+   r­   r�   r�   r’   Úhasattrrd   r²   ÚreadÚsendallrœ   Úkill)r“   rž   r°   r®   r¯   s   &f  @r   r�   ÚPortForward._serve·   s,  ù€ ð	Ü˜tŸx™x¨)°T¼:Àt×GWÑGWÔY\Ð]a×]mÑ]mÓYnÐ)oØ$(§I¡Iô/ˆD÷	ñ 	ô  	×Ò 	°$Ô7×=Ñ=Ô?ð	ØÜ3:¸4¿;¹;È×3PÒ3P�t—{‘{×(Ñ(¨Ô/ÐVZ×VaÑVa×VfÑVfÐglÓVm�ßØØ—‘˜TÖ"ðØ—
‘
”à—	‘	–øôC ô 	Ø�J‰JŒLÚð	ûô6 ô 	Ùð	ûð —	‘	•ûðØ—
‘
”à—	‘	•ø�—	‘	•ýsg   „AD Á=AD1 ÃE ÃD1 Ã-E ÄD.Ä-D.Ä1D?Ä<E Ä>D?Ä?E ÅEÅFÅE:Å)FÅ:FÆFc               ó   € V ^8„  d   QhRR/# r—   r   )r   s   "r   r   r|   Þ   s   € ÷ ñ �tñ r   c                	ón   € R V n          V P                  P                  4        R#   \         d     R# i ; i)TN)rŽ   r†   r­   rœ   )r“   s   &r   r­   ÚPortForward.closeÞ   s0   € ØˆŒð	Ø�L‰L×ÑÖ øÜô 	Úð	ús   ‰% ¥4³4)rŽ   r†   r   r�   ry   rz   r   N)
r/   Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r”   r‘   r�   r­   Ú__static_attributes__r   r   r   rw   rw   ¢   s!   † ÙpõpõTõ%÷Nñ r   rw   ry   r‚   c          
     ó,   € V ^8„  d   QhRRRRRRRRR	R/# )
r
   r   r   rz   r{   ry   r2   r   r   r   r   )r   s   "r   r   r   æ   s1   € ÷ 	ñ 	�oð 	°Cð 	Èð 	Ø$ð	Ø03ñ	r   c          	     óH  € \        V 4      V\        V4      3p\        ;_uu_ 4        \        P	                  V4      pVe   VP
                  '       d!   \        W\        V4      VR7      ;p\        V&   RRR4       VP                  #   + '       g   i     XP                  # ; i)z»Local port on 127.0.0.1 that reaches ``remote_host:remote_port`` inside ``env``; one listener per
(env, host, port) is kept for the process lifetime (daemon threads, nothing to clean up).Nr¤   )Úidr{   Ú_forwards_lockru   ÚgetrŽ   rw   r�   )r   rz   ry   r   ÚkeyÚfwds   &&$$  r   Úforward_portrÈ   æ   s{   € ô ˆc‹7�K¤ [Ó!1Ð
2€Cß	ŽÜ�m‰m˜CÓ ˆØŠ;˜#Ÿ+Ÿ+˜+Ü#.¨sÄÀ[ÓAQÐX\Ô#]Ð]ˆC”)˜C‘.÷ 
ð �>‰>Ð÷	 
Žð �>‰>Ðús   ¦+BÁ BÂB!	)"Ú__conditional_annotations__r¿   Ú
__future__r   ÚloggingrH   rƒ   rg   r�   Útypingr   r   Útools.environments.baser   Ú	getLoggerr/   r,   r&   r#   r9   r=   rW   r>   r^   ÚDEVNULLrk   rt   r³   ru   Ú__annotations__ÚLockrÄ   rw   rÈ   )rÉ   s   @r   Ú<module>rÒ      s1  øðôõ #ã Û Û Û Û ß %å 3à	×	Ò	˜8Ó	$€ðH¸tð HÐY]÷ Hõ0*õ*Eõ:ð+ÐUYð +Ø%*÷+õ +ð
TÐ]að TØ)-ðTØCG÷Tð_ÐZ^ð _Ø&*ð_Ø3=×3EÑ3E÷_ðQÐUYð QÐquð QØ ðQØ;?÷Qð$ð ð  68€	Ð2Ó 7Ø—’Ó!€÷Añ AðH	È{ð 	Ø'+÷	ñ 	r   