
    xj"                       U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlZddlmZmZ ddlmZ d-d
Zd.dZe G d d                      Zi Zded<    ej                    Zd/dZd0dZd1dZd2dZd3dZ d4dZ!d5d6d&Z"d7d(Z#d8d)Z$d9d*Z%d:d+Z&d/d,Z' ej(        e'           dS );a8  Embedded workspace terminal support for Hermes Web UI.

The terminal is intentionally independent from the agent execution path.  It
starts a shell with an explicit cwd/env per process and never mutates
process-global os.environ, which avoids expanding the session-env race tracked
in the agent execution layer.
    )annotationsN)	dataclassfield)PathfdintreturnNonec                    t          j         | t           j                  }t          j         | t           j        |t          j        z             d S N)fcntlF_GETFLF_SETFLos
O_NONBLOCK)r   flagss     //Users/bertmahoney/hermes-webui/api/terminal.py_set_nonblockingr      s8    KEM**E	KEM52=#899999    rowscolsbytesc                    t          dt          t          | pd          d                    } t          dt          t          |pd          d                    }t          j        d| |dd          S )N      P         HHHHr   )maxminr   structpack)r   r   s     r   _winsizer$   !   s`    q#c$*"oor**++Dr3s4:2,,--D;vtT1a000r   c                      e Zd ZU ded<   ded<   ded<   ded<   dZded	<   d
Zded<    ed           Zded<    eej	                  Z
ded<   dZded<   ddZddZdS )TerminalSessionstr
session_id	workspacezsubprocess.Popenprocr   	master_fdr   r   r   r   c                 ,    t          j        d          S )Ni  )maxsize)queueQueue r   r   <lambda>zTerminalSession.<lambda>/   s    D8Q8Q8Q r   )default_factoryzqueue.Queueoutputzthreading.EventclosedNzthreading.Thread | Nonereaderr	   boolc                l    | j                                          o| j                                        d u S r   )r4   is_setr*   poll)selfs    r   is_alivezTerminalSession.is_alive3   s/    ;%%'''DDINN,<,<,DDr   eventpayloaddictr
   c                4   	 | j                             ||f           d S # t          j        $ rh 	 | j                                          n# t          j        $ r Y nw xY w	 | j                             ||f           Y d S # t          j        $ r Y Y d S w xY ww xY wr   )r3   
put_nowaitr.   Full
get_nowaitEmpty)r:   r<   r=   s      r   
put_outputzTerminalSession.put_output6   s    	K""E7#344444z 		 		 		&&((((;   &&w'7888888:   		sJ     BA
	B
ABAB A??BBBB)r	   r6   )r<   r'   r=   r>   r	   r
   )__name__
__module____qualname____annotations__r   r   r   r3   	threadingEventr4   r5   r;   rD   r0   r   r   r&   r&   '   s         OOONNNNNNDNNNNDNNNN%0Q0QRRRFRRRR#eIODDDFDDDD&*F****E E E E     r   r&   zdict[str, TerminalSession]
_TERMINALSc                     	 ddl } |                     d          }|                    dt          j                   dS # t
          $ r Y dS w xY w)z@Ask Linux to terminate the PTY shell when the WebUI parent dies.r   N   )ctypesCDLLprctlsignalSIGTERM	Exception)rN   libcs     r   _terminal_shell_preexec_fnrU   I   sa    	{{4  

1fn%%%%%    		s   9= 
A
Adatar'   c                ,    |                      |          S )z>Decode PTY bytes without stripping terminal control sequences.)decode)decoderrV   s     r   _decode_terminal_outputrZ   W   s    >>$r   c                 
   t           j                            d          pd} | r#t          |                                           r| S t          j        d          p)t          j        d          pt          j        d          pdS )NSHELL zshbashshz/bin/sh)r   environgetr   existsshutilwhich)shells    r   _shell_pathrg   \   st    JNN7##)rE e##%% <Y&,v"6"6Y&,t:L:LYPYYr   rf   	list[str]c                @    t          |           j        }|dv r| dgS | gS )N>   r`   r^   r_   z-i)r   name)rf   rj   s     r   _shell_argvrk   c   s-    ;;D$$$t}7Nr   termc                     t          j        d          d          }	 | j                                        s| j                                        n	 t          j        | j        gg g d          \  }}}n# t          t          f$ r Y nw xY w|sp	 t          j        | j        d          }n7# t          $ r*}|j        t          j        t          j        fv rY d }~nO d }~ww xY w|snCt          ||          }|r|                     dd|i           | j                                        n<# t"          $ r/}|                     ddt%          |          i           Y d }~nd }~ww xY w| j                                         | j                                        }|                     d	d
|i           d S # | j                                         | j                                        }|                     d	d
|i           w xY w)Nutf-8replaceg      ?i    r3   textterminal_errorerrorterminal_closed	exit_code)codecsgetincrementaldecoderr4   r8   r*   r9   selectr+   OSError
ValueErrorr   readerrnoEIOEBADFrZ   rD   rS   r'   set)rl   rY   ready_rV   excrp   codes           r   _reader_loopr   j   s1   3f*733I>>G@+$$&& 	:y~~+$mT^,<b"dKKq!!Z(    wt~t44   9EK 888EEEE  *7D99D :64.999' +$$&& 	:(  ? ? ?(7CHH*=>>>>>>>>? 	y~~)K+>????? 	y~~)K+>????s   3D) !A5 4D) 5B	D) B		D) B+ *D) +
C5CD) CCA	D) (F1 )
E"3%EF1 E""F1 1AG=c                B   t          dt          t          |p| j        pd          d                    | _        t          dt          t          |p| j        pd          d                    | _        	 t          j        | j        t          j	        t          | j        | j                             n# t          $ r Y nw xY w	 | j                                        +t          j        | j        j        t"          j                   d S d S # t          t&          f$ r Y d S w xY w)Nr   r   r   r   r   )r    r!   r   r   r   r   ioctlr+   termios
TIOCSWINSZr$   rx   r*   r9   r   killpgpidrQ   SIGWINCHProcessLookupError)rl   r   r   s      r   	_set_sizer      s   As3t6ty6B77<<==DIBC 7	 7R88#>>??DIDNG$6DI8V8VWWWW   9>>#IdimV_55555 $#'(   s%   4=B2 2
B?>B?AD	 	DDr   r   Fr(   r)   r   restartr6   c                   t          | pd                                          }|st          d          t          t          |                                                                                    }t          |                                          st          d          t          5  t          	                    |          }|r@|
                                r,|s*|j        |k    rt          |||           |cddd           S |rt          |           t          j                    \  }}	h dfdt          j                                        D             }
|
                    ddt          |          t          |          |d	d
           t'                      }t)          j        t-          |          ||
|	|	|	dt.          d	  	        }t          j        |	           t3          |           t5          ||||||          }t          |||           t7          j        t:          |fd          |_        |j                                         |t          |<   |cddd           S # 1 swxY w Y   dS )z:Start or return the embedded terminal for a WebUI session.r]   zsession_id is requiredzworkspace is not a directoryN>   TZHOMELANGPATHTEMPUSERr\   LC_ALLTMPDIRLOGNAMELANGUAGELC_CTYPELC_MESSAGESXDG_DATA_HOMEXDG_CONFIG_HOMEXDG_RUNTIME_DIRc                $    i | ]\  }}|v 	||S r0   r0   ).0kv_SAFE_ENV_KEYSs      r   
<dictcomp>z"start_terminal.<locals>.<dictcomp>   s)    JJJ1a>6I6Iq!6I6I6Ir   zxterm-256color	truecolor1)TERM	COLORTERMCOLUMNSLINESPWDHERMES_WEBUI_TERMINALT)cwdenvstdinstdoutstderr	close_fds
preexec_fnstart_new_session)r(   r)   r*   r+   r   r   )targetargsdaemon) r'   stripry   r   
expanduserresolveis_dir_LOCKrK   rb   r;   r)   r   close_terminalr   openptyra   itemsupdaterg   
subprocessPopenrk   rU   closer   r&   rI   Threadr   r5   start)r(   r)   r   r   r   sidr   currentr+   slave_fdr   rf   r*   rl   r   s                 @r   start_terminalr      s   
jB


%
%
'
'C 31222
d9oo((**2244
5
5C99 97888	 6 6..%% 	w'')) 	' 	g>OSV>V>VgtT***	6 6 6 6 6 6 6 6
  	 3 jll	8
 
 

 KJJJ
 0 0 2 2JJJ

((t99T), 		
 		
 		
 1"

 

 

 	###
 
 
 	$d###&l$QUVVV
3m6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6s   -AI.
EI..I25I2TerminalSession | Nonec                    t           5  t                              t          | pd                    }|r"|                                r|cd d d            S |cd d d            S # 1 swxY w Y   d S )Nr]   )r   rK   rb   r'   r;   )r(   rl   s     r   get_terminalr      s    	  ~~c*"23344 	DMMOO 	        	                 s   AA$A$$A(+A(c                    t          |           }|r|                                st          d          t          j        |j        t          |pd                              dd                     d S )Nterminal not runningr]   rn   ro   )errors)r   r;   KeyErrorr   writer+   r'   encode)r(   rV   rl   s      r   write_terminalr      sl    
##D /t}} /-...HT^S__33GI3NNOOOOOr   c                h    t          |           }|st          d          t          |||           d S )Nr   )r   r   r   )r(   r   r   rl   s       r   resize_terminalr      s>    
##D /-...dD$r   c                   t          | pd          }t          5  t                              |d           }d d d            n# 1 swxY w Y   |sdS |j                                         	 |j                                        	 t          j	        |j        j
        t          j                   n# t          $ r Y nw xY w	 |j                            d           n# t          j        $ rw 	 t          j	        |j        j
        t          j                   n# t          $ r Y nw xY w	 |j                            d           n# t          j        t          f$ r Y nw xY wY nw xY w	 t          j        |j                   n?# t(          $ r Y n3w xY w# 	 t          j        |j                   w # t(          $ r Y w w xY wxY wdS )Nr]   Fg      ?)timeoutg      ?T)r'   r   rK   popr4   r~   r*   r9   r   r   r   rQ   SIGHUPr   waitr   TimeoutExpiredSIGKILLr   r+   rx   )r(   r   rl   s      r   r   r      s:   
jB

C	 ) )~~c4(() ) ) ) ) ) ) ) ) ) ) ) ) ) ) uKOO9>>#	$)-7777%   
	s++++,   IdimV^<<<<)   DINN3N////"13EF   D	HT^$$$$ 	 	 	D		HT^$$$$ 	 	 	D	4s   AAA*F )B. -F .
B;8F :B;;F ?C F E!+)DE!
D"E!!D""E!&EE!EE!EE!F  E!!F %E? ?
FFF;F+*F;+
F85F;7F88F;c                     t           5  t          t                    } ddd           n# 1 swxY w Y   | D ]}t          |           dS )zCBest-effort reap of embedded shells during graceful WebUI shutdown.N)r   listrK   r   )session_idsr(   s     r   close_all_terminalsr     s    	 ' ':&&' ' ' ' ' ' ' ' ' ' ' ' ' ' '! # #
z""""# #s   )--)r   r   r	   r
   )r   r   r   r   r	   r   )r	   r
   )rV   r   r	   r'   )r	   r'   )rf   r'   r	   rh   )rl   r&   r	   r
   )rl   r&   r   r   r   r   r	   r
   )r   r   F)r(   r'   r)   r   r   r   r   r   r   r6   r	   r&   )r(   r'   r	   r   )r(   r'   rV   r'   r	   r
   )r(   r'   r   r   r   r   r	   r
   )r(   r'   r	   r6   ))__doc__
__future__r   r{   atexitru   r   r   r.   rw   rd   rQ   r"   r   r   rI   dataclassesr   r   pathlibr   r   r$   r&   rK   rH   RLockr   rU   rZ   rg   rk   r   r   r   r   r   r   r   r   registerr0   r   r   <module>r      si     # " " " " "     				               ( ( ( ( ( ( ( (      : : : :
1 1 1 1        : *,
 + + + +	          
Z Z Z Z   @ @ @ @>   ? ? ? ? ?D   P P P P          @# # # # # $ $ $ $ $r   