
    JjK                     F   U d dl Z d dl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lmZmZmZmZmZmZmZmZm Z  d dl!m"Z" d dl#m$Z$m%Z% d dl&m'Z'm(Z( d d	l)m*Z*m+Z+ d d
l,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z< d dl=m>Z>m?Z?m@Z@ d dlAmBZB e7rd dlCmDZDmEZE  eD             e-s eFd          	 d dlGZGd dlHZHd dlIZId dlJZJd dlKZKdZLn# eM$ r dZLY nw xY wdeNfdZOdeNfdZPd eO            z   ZQe3reQde3z   z  ZQ e(d          ZR eeR          fdee'         fdZSdedeBfdZT edd ed                    ZUeUV                    e"d  e/jW        d           D             dd!gd!g"           eUX                    eY          ded#eYfd$            ZZeU[                    d%          defd&            Z\ G d' d(e*          Z] G d) d*e*          Z^ G d+ d,e*          Z_ G d- d.e*          Z` G d/ d0e*          Za G d1 d2e*          Zb G d3 d4e*          Zce G d5 d6                      Zdi ZeefeNedf         egd7<   d8Zhi ZiefeNejeNekf         f         egd9<   d: Zld;eNdz  d<d=deNfd>Zmd;eNdz  d?eNfd@Znd dAlompZpmqZq dB ZrdCeNdedfdDZseUt                    dEddFdGdHI          dJ             ZueUt                    dKdL          dM             Zve1r+eUt                    dNd eeS          gO          dP             Zwe8r-eUt                    dQdRdSdT eeS          gU          dV             ZxeUt                    dWd eeS          gO           eeT          fdXed<eBfdY            ZyeUz                    dWd eeS          gO           eeT          fdXedead<eBfdZ            Z{eUt                    d[d\d]d^ eeS          gd_d`id_daidbc           edddef           eeT          fdXedgeNd<eBfdh            Z|eUt                    didjdkdl eeS          gd_dmid_dnid_daidoc           edpdqf           eddrdst           eddudst           eeT          fdXed?eNdvee}         dwee}         d<eBf
dx            Z~eUt                    dydzd{d| eeS          gd}d_daiic           edpd~f           eeT          fdXed?eNd<eBfd            ZeUt                    dd eeS          gO           edpdf           eeT          fd?eNd<eBfd            ZeUt                    dd eeS          gO           eeT          fd?eNd<eBfd            ZeUz                    dddd eeS          gd}d_daiic           eeT          fdXede_d<eBfd            ZeUz                    dd eeS          gO           eeT          fdead<eBfd            ZeU                    dd eeS          gO           edpdf           eeT          fd?eNd<eBfd            ZeUz                    dd eeS          gO           eeT          fdebd<eBfd            ZeUz                    dddd eeS          gd_dmid_did_daidc           eeT          fdXedecd<eBfd            ZeUt                    dddd eeS          gd_did_did_daidc           edpdf           edddf           eddf           eddf           eddf           eddf           edddsd           eeT          fdXedeNd?eNdededeeeN                  dede}d<eBfd            ZeUt                    dddd eeS          gd_did_daidbc           edpdf           edddf           eddf           eddd           edddsd           eeT          fdXedeNd?eNdeeeN                  deeN         de}d<eBfd            ZeUz                    ddddd eeS          gd}d_daiiæ           edpdĬf           edpdŬf           eeT          fdgeNded<eBfdǄ            Z G dȄ de*          ZeUz                    dd eeS          gO           eeT          fded<eBfd˄            ZeUt                    dddd eeS          gd}d_daiic          dЄ             ZeUz                    dddeQ eeS          gd}d_daiic           eddd d8           edddst          fdXede]deek         dee}         fdׄ            ZeUt                    dddd eeS          gd_did_daidbc           eddd d8           ed dd t           edddst          fdCeNdeek         de}dee}         fd            ZeUz                    dddd eeS          gd_did_did_daidc          dCeNde^fd            ZeU                    dddd eeS          gd_did_daidbc           eddf          fdCeNdefd            Zd dlmZmZ eUt                    dd eeS          gO          defd            Zdad ZeU                    dg dd eeS          g          de}d?eNdefd            Ze2rJd dlZd dlmZ d dl#m$Z$ 	 d dlZn# eM$ r dZY nw xY weLrdZn	 d dlmZ dZn# eM$ r dZY nw xY wi ZefeNeff         egd<   d;eNfdZeUz                    d eeS          gd           defd            ZdefdefdZeUt                    d eeS          gd           defd            ZeUt                    d eeS          gd           d;eNdefd            ZeU                    d eeS          gd           d;eNdefd            ZeU                    d          ded;eNfd	            Ze0r'd d
lmZ eU                     eeS                     dS dS (      N)version)	dataclassfield)Optional)	DependsFastAPIFileHTTPExceptionQueryRequest
UploadFile	WebSocketWebSocketDisconnect)CORSMiddleware)JSONResponseResponse)HTTPAuthorizationCredentials
HTTPBearer)	BaseModelField)API_KEYBINARY_FILE_MIME_PREFIXESCORS_ALLOWED_ORIGINSENABLE_NOTEBOOKSENABLE_SYSTEM_PROMPTENABLE_TERMINALEXECUTE_DESCRIPTIONEXECUTE_TIMEOUTLOG_DIRMAX_TERMINAL_SESSIONS
MULTI_USEROPEN_TERMINAL_INFOPROCESS_LOG_RETENTIONSESSION_CWD_TTLSYSTEM_PROMPTTERMINAL_TERM)
PipeRunnerProcessRunnercreate_runner)UserFS)check_environmentresolve_userza
[91m  OPEN_TERMINAL_API_KEY is required.
  Set via environment variable or --api-key flag.
[0mTFreturnc                     t           j                            dd          } t          sdt          j        dd           dnd}dt          j                     d	t          j                     d
t          j                     dt          j
                     | d|  dt          j                                        d          dS )z;Gather runtime system metadata for the OpenAPI description.SHELL/bin/sh
 as user 'USERunknown' zThis system is running   (z) on  with 	. Python r   z is available.)osenvirongetr!   getenvplatformsystemreleasemachinesocketgethostnamesysr   split)shell	user_parts     f/home/rurouni/.cache/uv/archive-v0/6mr0qdqUAO9GXgnL/lib/python3.11/site-packages/open_terminal/main.pyget_system_inforI   7   s    JNN7I..EDNV<RYvy99<<<<TVI	9(/"3"3 	9 	9h6F6H6H 	9 	9HL\L^L^ 	9 	9 ""	9$-	9 	95:	9 	9+##%%a(	9 	9 	9    c                     t           rt           S t          j                            dd          } t          sdt          j        dd           dnd}dt          j                     d	t          j                     d
t          j	                     dt          j                     d| d|  dt          j                                        d          d}t          r|dt           z  }|S )z2Build a default system prompt for LLM integration.r/   r0   r1   r2   r3   r4   r5   z&You have access to a computer running r6   r7   z) on host ""r8   r9   r   u@   is available.

Use your tools to directly interact with the system — run commands, read and write files, and search the filesystem. Prefer verifying the current state before making changes. When running commands, check the output to confirm success. If a command produces no output, that typically means it succeeded.

)r%   r:   r;   r<   r!   r=   r>   r?   r@   rA   rB   rC   rD   r   rE   r"   )rF   rG   prompts      rH   get_system_promptrO   B   s    JNN7I..EDNV<RYvy99<<<<TVI	N1B1B 	N 	NXEUEWEW 	N 	N[c[k[m[m 	N 	N&((	N 	N+4	N 	N<A	N 	N+##%%a(	N 	N 	N   .-+---MrJ   z@Run a shell command in the background and return a command ID.

rM   )
auto_errorcredentialsc                    K   t           sd S | rt          j        | j        t                     st	          dd          d S )N  Invalid API keystatus_codedetail)r   hmaccompare_digestrQ   r
   )rQ   s    rH   verify_api_keyrZ   e   sV         Gd1+2I7SS G4EFFFFG GrJ   requestc                     t           st                      S | j                            d          }|st                      S t	          |          \  }}t          ||          S )a  Build a :class:`UserFS` scoped to the requesting user.

    When multi-user mode is active and the ``X-User-Id`` header is present,
    returns a ``UserFS`` that routes all I/O through ``sudo -u``.
    Otherwise returns a plain ``UserFS`` using stdlib.
    z	x-user-id)usernamehome)r!   r*   headersr<   r,   )r[   user_idr]   r^   s       rH   get_filesystemra   n   s_      xxo!!+..G xx!'**NHd8$////rJ   zOpen TerminalzA remote terminal API.zopen-terminal)titledescriptionr   c                 6    g | ]}|                                 S  )strip).0os     rH   
<listcomp>ri      s     FFF17799FFFrJ   ,*)allow_originsallow_credentialsallow_methodsallow_headersexcc                 F   K   t          ddt          |          i          S )N  rW   )rV   content)r   str)r[   rp   s     rH   permission_error_handlerru      s$      C(CHH1EFFFFrJ   httpc                 
  K   ddl m} | j                                        }d |D             }t	          |          t	          |          k    r& ||                              d          | j        d<    ||            d{V S )z@Strip query parameters whose value is the literal string 'null'.r   )	urlencodec                 L    g | ]!\  }}|                                 d k    ||f"S )null)lower)rg   kvs      rH   ri   z/normalize_null_query_params.<locals>.<listcomp>   s2    DDD$!Q		V0C0C1v0C0C0CrJ   utf-8query_stringN)urllib.parserx   query_paramsmulti_itemslenencodescope)r[   	call_nextrx   
raw_paramscleaneds        rH   normalize_null_query_paramsr      s       '&&&&&%1133JDD*DDDG
7||s:&&(1	'(:(:(A(A'(J(Jn%7#########rJ   c                       e Zd ZU  edddddgi          Zeed<    edd	
          Zee         ed<    edd
          Z	ee
eef                  ed<   dS )ExecRequest.zUShell command to execute. Supports chaining (&&, ||, ;), pipes (|), and redirections.examplesz
echo hellozls -la && whoami)rc   json_schema_extracommandNzYWorking directory for the command. Defaults to the server's current directory if not set.rc   cwdzCExtra environment variables merged into the subprocess environment.env)__name__
__module____qualname__r   r   rt   __annotations__r   r   r   dictre   rJ   rH   r   r      s         5k%6H'IJ  GS   
 o  C#    %*EY% % %C$sCx.	!     rJ   r   c                   4    e Zd ZU  edd          Zeed<   dS )InputRequest.zJText to send to the process's stdin. Include newline characters as needed.r   inputN)r   r   r   r   r   rt   r   re   rJ   rH   r   r      sC         `  E3     rJ   r   c                   X    e Zd ZU  edd          Zeed<    edd          Zeed<   dS )WriteRequest.zTAbsolute or relative path to write to. Parent directories are created automatically.r   pathz"Text content to write to the file.rs   N)r   r   r   r   r   rt   r   rs   re   rJ   rH   r   r      sr         j  D#    58  GS     rJ   r   c                       e Zd ZU  edd          Zeed<    edd          Zeed<    eddd	
          Ze	e
         ed<    eddd	
          Ze	e
         ed<    edd          Zeed<   dS )ReplacementChunk.zAExact string to find. Must match precisely, including whitespace.r   targetz#Content to replace the target with.replacementNz8Narrow the search to lines at or after this (1-indexed).   rc   ge
start_linez9Narrow the search to lines at or before this (1-indexed).end_lineFzTIf true, replaces all occurrences. If false, errors when multiple matches are found.allow_multiple)r   r   r   r   r   rt   r   r   r   r   intr   r   boolre   rJ   rH   r   r      s        %W  FC    u9  K    !&N! ! !J   
 $eO  Hhsm   
 !5j  ND     rJ   r   c                   4    e Zd ZU  edd          Zeed<   dS )MkdirRequest.zGDirectory path to create. Parent directories are created automatically.r   r   N)r   r   r   r   r   rt   r   re   rJ   rH   r   r      sC         ]  D#     rJ   r   c                   X    e Zd ZU  edd          Zeed<    edd          Zeed<   dS )MoveRequest.z&Path to the file or directory to move.r   sourcez Destination path (new location).destinationN)r   r   r   r   r   rt   r   r   re   rJ   rH   r   r      sr         %<  FC    u6  K     rJ   r   c                   d    e Zd ZU  edd          Zeed<    edd          Zee	         ed<   dS )ReplaceRequest.zPath to the file to modify.r   r   z:List of find-and-replace operations to apply sequentially.replacementsN)
r   r   r   r   r   rt   r   r   listr   re   rJ   rH   r   r      sx         1  D#    ,15P, , ,L$'(     rJ   r   c                       e Zd ZU eed<   eed<   eed<   dZeed<   dZee	         ed<    e
dd	          Zeej                 ed
<    e
dd	          Zee         ed<    e
dd	          Zee         ed<   dS )BackgroundProcessidr   runnerrunningstatusN	exit_codeF)defaultreprlog_taskfinished_atlog_path)r   r   r   rt   r   r(   r   r   r   r   r   r   asyncioTaskr   floatr   re   rJ   rH   r   r      s         GGGLLLFC#Ix}###',uT'F'F'FHhw|$FFF#(5E#B#B#BK%BBB#eDu===Hhsm=====rJ   r   
_processesi,  _session_cwdsc                      t          j                     fdt                                          D             } | D ]
}t          |= dS )zERemove session cwd entries that haven't been accessed within the TTL.c                 <    g | ]\  }\  }}|z
  t           k    |S re   )r$   )rg   sid_tsnows       rH   ri   z(_expire_session_cwds.<locals>.<listcomp>  s/    [[[|sGQb?@Z@Zs@Z@Z@ZrJ   N)timer   items)expiredr   r   s     @rH   _expire_session_cwdsr     sW    
)++C[[[[}':':'<'<[[[G  # rJ   
session_idfsr*   c                     t                       | r8| t          v r/t          |          \  }}|t          j                    ft          | <   |S |j        S )zCReturn the tracked cwd for *session_id*, or ``fs.home`` as default.)r   r   r   r^   )r   r   r   r   s       rH   _get_session_cwdr   "  sO     jM11z*Q%($)++$6j!
7NrJ   r   c                 H    | r|t          j                     ft          | <   dS dS )z:Store a session's cwd.  No-op if *session_id* is ``None``.N)r   r   )r   r   s     rH   _set_session_cwdr   ,  s/     8%)49;;$7j!!!8 8rJ   )log_processread_logc                  N   t          j                     fdt                                          D             } | D ]h}t                              |          }|j        rE|j        r>|j        z
  t          k    r+	 t          j        |j                   X# t          $ r Y dw xY widS )zqRemove finished processes that have expired.

    Also deletes log files older than *LOG_RETENTION_SECONDS*.
    c                 N    g | ]!\  }}|j         r|j         z
  t          k    |"S re   )r   _EXPIRY_SECONDS)rg   
process_idbackground_processr   s      rH   ri   z$_cleanup_expired.<locals>.<listcomp>=  sL       *J*) $00?BB 	 CBBrJ   N)
r   r   r   popr   r   r#   r:   removeOSError)r   r   bpr   s      @rH   _cleanup_expiredr   7  s    
 )++C   .8.>.>.@.@  G   
^^J'' K		 bn$'<<<	"+&&&&    s   :B
B! B!r   c                 |    t                       t                              |           }|st          dd          |S )N  zProcess not foundrU   )r   r   r<   r
   )r   r   s     rH   _get_processr   Q  sC    #
33 I4GHHHHrJ   z/healthhealth_checkzHealth checkz3Returns service status. No authentication required.)include_in_schemaoperation_idsummaryrc   c                     K   ddiS )Nr   okre   re   rJ   rH   healthr   ^  s       drJ   z/api/config)r   c                  4   K   dt           t          t          diS )z6Return server feature flags for client-side discovery.features)terminal	notebooksr?   )r   r   r   re   rJ   rH   
get_configr   n  s(       	')*
 
 rJ   z/system)r   dependenciesc                  &   K   dt                      iS )z+Return a system prompt for LLM integration.rN   )rO   re   rJ   rH   
get_systemr     s       +--..rJ   z/infoget_infozGet environment infoztReturn operator-provided information about this environment. Use this to understand the system you are working with.)r   r   rc   r   c                     K   dt           iS )Ninfo)r"   re   rJ   rH   r   r     s       *++rJ   z
/files/cwdhttp_requestc                 ^   K   | j                             d          }dt          ||          iS )Nx-session-idr   )r_   r<   r   )r   r   r   s      rH   get_cwdr     s4       %)).99J#J3344rJ   c                    K   | j                             d          }|                    |j                  }|j        s,|                    |           d {V st          dd          t          ||           d|iS )Nr   r   Directory not foundrU   r   )r_   r<   resolve_pathr   r]   isdirr
   r   )r   r[   r   r   r   s        rH   set_cwdr     s       %)).99J__W\**F; KRXXf%5%5555555 K4IJJJJZ(((6?rJ   z/files/list
list_fileszList directory contentszGReturn a structured listing of files and directories at the given path.rc   zDirectory not found.zInvalid or missing API key.)r   rS   )r   r   rc   r   	responses.zDirectory path to list.r   	directoryc                 (  K   | j                             d          }|rt          ||          nd }|                    ||          }|                    |           d {V st          dd          |                    |           d {V }||dS )Nr   r   r   r   rU   )direntries)r_   r<   r   r   r   r
   listdir)r   r  r   r   session_cwdr   r  s          rH   r   r     s        %)).99J6@J":r222dK__YK_88F&!!!!!!!! K4IJJJJJJv&&&&&&&&Gg...rJ   z/files/read	read_filezRead a filea  Read a file and return its contents. Supports text files and images (PNG, JPEG, WebP, etc.). For text files you can optionally request a specific line range. Images are returned as binary so you can view and analyze them directly. Use display_file to show a file to the user.zFile not found.zUnsupported binary file type.)r     rS   .zPath to the file to read.zSFirst line to return (1-indexed, inclusive). Defaults to the beginning of the file.r   r   zLLast line to return (1-indexed, inclusive). Defaults to the end of the file.r   r   c           
        K   | j                             d          }|rt          ||          nd }|                    ||          }|                    |           d {V st          dd          	 |                    |           d {V }|                    d          }	nd# t          t          f$ rO dd l
}
|                    |           d {V }|
                    |          \  }pd	dd
lm} |D ]\  }}}|r|k    s)|r|                                                    |          r{t#          j        ||           d {V }|                    d          }	|pddz
  }|pt'          |	          }|t'          |	          d                    |	||                   dc cY S t+          fdt,          D                       rt/          |          cY S t          dd dt'          |           d          w xY w|pddz
  }|pt'          |	          }|t'          |	          d                    |	||                   dS )Nr   r  r   File not foundrU   Tkeependsr   application/octet-stream)
EXTRACTORSr   r5   )r   total_linesrs   c              3   B   K   | ]}                     |          V  d S N)
startswith)rg   prefixmimes     rH   	<genexpr>zread_file.<locals>.<genexpr>  s/      OO6tv&&OOOOOOrJ   rs   
media_typer	  zUnsupported binary file type: r7   z bytes))r_   r<   r   r   isfiler
   	read_text
splitlinesUnicodeDecodeError
ValueError	mimetypesread
guess_typeopen_terminal.utils.documentsr  r{   endswithr   	to_threadr   joinanyr   r   )r   r   r   r   r   r   r  r   rs   linesr  rawr   r  ext_mime
ext_suffix	extractortextstartendr  s                       @rH   r  r    s     . %)).99J6@J":r222dK__T{_33F6"""""""" F4DEEEE#
V,,,,,,,,""D"11
+  
  
  
GGFOO######&&v..a11 	=<<<<</9 	 	+Hj) TX-- .%||~~66zBB . %.y&AAAAAAAA66#qA-,#e**"#&u::!wwuU3Y'788       OOOO5NOOOOO 	:CD999999 MDMMCHHMMM
 
 
 	
; 
D _1!E

 c%jjC5zz775s+,,  s   61B) )DH
02H
$&H
z/files/displaydisplay_filezDisplay a file to the useru   Open a file in the user's file viewer so they can see it. Use this when the user wants to view or look at a file. This does not return file content to you — use read_file if you need to read the content yourself.rS   z%Absolute path to the file to display.c                    K   | j                             d          }|rt          ||          nd}|                    ||          }|                    |           d{V }||dS )aW  Signal that a file should be displayed to the user.

    This endpoint does not serve file content itself. It returns the resolved
    path and whether the file exists. The consuming client is responsible for
    intercepting this response and presenting the file in its own UI (e.g.
    opening a preview pane, launching a viewer, etc.).
    r   Nr  )r   exists)r_   r<   r   r   r  )r   r   r   r   r  r   r0  s          rH   r.  r.    s~      , %)).99J6@J":r222dK__T{_33F99V$$$$$$$$Ff---rJ   z/files/viewzPath to the file to view.c                    K   |                     |           }|                    |           d{V st          dd          ddl}|                    |          \  }}|pd}|                    |           d{V }t          ||          S )zReturn raw file bytes with the appropriate Content-Type.

    Unlike read_file (which is designed for LLM consumption and restricts
    binary types), this endpoint serves any file as-is for UI previewing.
    Nr   r  rU   r   r  r  )r   r  r
   r  r   r  r   )r   r   r   r  r  r   r'  s          rH   	view_filer2  ;  s       __T""F6"""""""" F4DEEEE""6**GD!--D





CCD1111rJ   z/files/serve/{path:path}c                 :   K   t          d|  |           d{V S )uN   Path-based alias for view_file — enables relative URL resolution in iframes./r   r   N)r2  r5  s     rH   
serve_filer6  U  s3       
D

r2222222222rJ   z/files/write
write_filezWrite a fileznWrite text content to a file. Creates parent directories automatically. Overwrites if the file already exists.c                   K   | j                             d          }|rt          ||          nd }|                    |j        |          }	 |                    ||j                   d {V  n<# t          t          j	        f$ r#}t          dt          |                    d }~ww xY w|t          |j                                                  dS )Nr   r    rU   r   size)r_   r<   r   r   r   writers   r   
subprocessCalledProcessErrorr
   rt   r   r   )r   r[   r   r   r  r   es          rH   r7  r7  _  s       %)).99J6@J":r222dK__W\{_;;F<hhvw//////////Z23 < < <CFF;;;;<C(>(>(@(@$A$ABBBs   !A0 0B)B$$B)z/files/mkdirc                    K   |                     | j                  }	 |                    |           d {V  n<# t          t          j        f$ r#}t          dt          |                    d }~ww xY wd|iS )Nr9  rU   r   )r   r   mkdirr   r=  r>  r
   rt   )r[   r   r   r?  s       rH   rA  rA  t  s       __W\**F<hhvZ23 < < <CFF;;;;<Fs   : A3A..A3z/files/deletezPath to delete.c                   K   |                     |           }|                    |           d {V st          dd          |                    |           d {V }	 |                    |           d {V  n<# t
          t          j        f$ r#}t          dt          |                    d }~ww xY w||rdnddS )Nr   zPath not foundrU   r9  r  file)r   type)	r   r0  r
   r   r   r   r=  r>  rt   )r   r   r   is_dirr?  s        rH   delete_entryrF    s       __T""F6"""""""" F4DEEEE88F########F<iiZ23 < < <CFF;;;;<6$EKKvFFFs    A< <B5B00B5z/files/movec                 r  K   |                     | j                  }|                     | j                  }|                    |           d {V st	          dd          t
          j                            |          }|                    |           d {V st	          dd          |                    |           d {V rt	          dd          	 |	                    ||           d {V  n<# t          t          j        f$ r#}t	          dt          |                    d }~ww xY w||dS )	Nr   zSource path not foundrU   r9  z&Destination parent directory not foundi  zDestination already exists)r   r   )r   r   r   r0  r
   r:   r   dirnamer   mover   r=  r>  rt   )r[   r   r   r   dest_parentr?  s         rH   
move_entryrK    so      __W^,,F//'"566K6"""""""" M4KLLLL'//+..K+&&&&&&&& ^4\]]]]YY{######## R4PQQQQ<ggfk**********Z23 < < <CFF;;;;<[999s   C8 8D1D,,D1z/files/replacereplace_file_contentzReplace content in a filezxFind and replace exact strings in a file. Supports multiple replacements in one call with optional line range narrowing.z+Target string not found or ambiguous match.)r   r9  rS   c                   K   | j                             d          }|rt          ||          nd }|                    |j        |          }|                    |           d {V st          dd          	 |                    |           d {V }n0# t          $ r#}t          dt          |                    d }~ww xY w|j
        D ]9}|j        s|j        rV|                    d          }	|j        pd	d	z
  }
|j        pt          |	          }d
                    |	|
|                   }n|}|                    |j                  }|dk    r!t          dd|j        d d                   |d	k    r|j        st          dd| d          |j        s|j        r?|                    |j        |j                  }|g|	|
|<   d
                    |	          }|                    |j        |j                  };	 |                    ||           d {V  n0# t          $ r#}t          dt          |                    d }~ww xY w|t          |                                          dS )Nr   r  r   r  rU   r9  Tr  r   r5   r   zTarget string not found: d   zFound z9 occurrences of target string but allow_multiple is falser:  )r_   r<   r   r   r   r  r
   r  r   rt   r   r   r   r  r   r$  countr   r   replacer   r<  r   )r   r[   r   r   r  r   rs   r?  chunkr&  r,  r-  search_regionrO  
new_regions                  rH   rL  rL    s      %)).99J6@J":r222dK__W\{_;;F6"""""""" F4DEEEE<V,,,,,,,, < < <CFF;;;;< % G G 	$u~ 	$&&&55E%*a/E..CJJCGGE%)$455MM#M##EL11A::I5<3EII    199U19````   
  	Gu~ 	G&..u|U=NOOJ *|E%)ggennGGooelE4EFFGG<hhvw'''''''''' < < <CFF;;;;< C(8(8$9$9:::s0   :B 
C B>>C	H& &
I0IIz/files/grepgrep_searchzSearch file contentszSearch for a text pattern across files in a directory. Returns structured matches with file paths, line numbers, and matching lines. Skips binary files.zSearch path not found.zInvalid regex pattern.z$Text or regex pattern to search for.zDirectory or file to search in.z(Use regex. Set false for literal search.z"Perform case-insensitive matching.zSGlob patterns to filter files (e.g. '*.py'). Files must match at least one pattern.zhIf true, return each matching line with line numbers. If false, return only the names of matching files.2   z$Maximum number of matches to return.i  )rc   r   lequeryregexcase_insensitiveincludematch_per_linemax_resultsc	                 d  K   | j                             d          }	|	rt          |	          nd }
                    ||
          t          j        j                                       d {V st          dd          |rt          j
        nd}|rB	 t          j        ||          nR# t          j        $ r}t          dd|           d }~ww xY wt          j        t          j        |          |          fd	}t          j        |           d {V \  }}|||d
S )Nr   r  r   zSearch path not foundrU   r   r9  zInvalid regex: c                     dt           dt          f
fd} g ddt           ffd}t          j                                      r |           nt          j                  D ]}\  }}	fd|D             |d d <   r n`t          |          D ]O} | |          st          j                            |          }	                    |          sD ||           P~fS )Nfilenamer-   c                 D     sdS t           fdD                       S )NTc              3   B   K   | ]}t          j         |          V  d S r  fnmatch)rg   globr_  s     rH   r  zNgrep_search.<locals>._search_sync.<locals>._matches_include.<locals>.<genexpr>   s/      KK4wx66KKKKKKrJ   )r%  )r_  rZ  s   `rH   _matches_includez;grep_search.<locals>._search_sync.<locals>._matches_include  s4     tKKKK7KKKKKKrJ   F	file_pathc           	         rd S 	 t          | ddd          5 }t          |d          D ]\  }}                    |          rrP                    | ||                    d          d           t                    k    rd d d d            d S l                    d	| i           t                    k    rd d d d            d S 	 d d d            d S # 1 swxY w Y   d S # t          t          t          f$ r Y d S w xY w)
Nrr~   strict)encodingerrorsr   z
)rC  liners   TrC  )	open	enumeratesearchappendrstripr   r  r  r   )	rf  fline_numberrl  r[  matchesr\  pattern	truncateds	       rH   _search_filez7grep_search.<locals>._search_sync.<locals>._search_file%  s    )S78LLL 'PQ-6q!__ ' ')T">>$// '- ' '090;37;;v3F3F%& %&!" !" !" $'w<<;#>#>04I$*' ' ' ' ' ' ' ' $? !(	/B C C C#&w<<;#>#>04I &%' ' ' ' ' ' ' '''' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' '& '
G<   sM   C- A/C 	C- .C C- C C-  C$$C- 'C$(C- -DDc                 z    g | ]7}                     t          j                            |                    5|8S re   is_path_allowedr:   r   r$  rg   ddirpathr   s     rH   ri   z5grep_search.<locals>._search_sync.<locals>.<listcomp>E  sM       ))"',,w*B*BCC  rJ   )	rt   r   r:   r   r  walksortedr$  rz  )re  rw  dirnames	filenamesr_  fullr}  rt  rv  r   rZ  r[  r\  ru  r   s         @@@rH   _search_syncz!grep_search.<locals>._search_sync  s   	Ls 	Lt 	L 	L 	L 	L 	L 	L
 		C 	 	 	 	 	 	 	 	 	 	6 7>>&!! 	'L    02 ' ',9    '    E &y 1 1 ' 'H++H55 ! 7<<::D--d33 !  L&&&&' 	!!rJ   )rW  r   rt  rv  )r_   r<   r   r   aiofilesr:   r   r0  r
   re
IGNORECASEcompileerrorescaper   r#  )r   rW  r   rX  rY  rZ  r[  r\  r   r   r  flagsrp   r  rt  rv  ru  r   s        ````       @@rH   rT  rT    s     B %)).99J6@J":r222dK__T{_33F!((00000000 M4KLLLL-4BMM1E 6	Qj..GGx 	Q 	Q 	QC8O#8O8OPPPP	Q *RYu--u557" 7" 7" 7" 7" 7" 7" 7" 7" 7"r  '0>>>>>>>>GY	  s   B2 2CCCz/files/globglob_searchzSearch files by namezSearch for files and subdirectories by name within a specified directory using glob patterns. Results will include the relative path, type, size, and modification time.zSearch directory not found.z)Glob pattern to search for (e.g. '*.py').zDirectory to search within.z-Glob patterns to exclude from search results.r%  z+Type filter: 'file', 'directory', or 'any'.z^(file|directory|any)$)rc   ru  ru  excluderD  c                 n  K   | j                             d          }|rt          |          nd }                    ||          t          j        j                                       d {V st          dd          fd}	t          j
        |	           d {V \  }
}|
|dS )Nr   r  r   zSearch directory not foundrU   c            	      "  	
 g } d}t          j                  D ]n\  }}|r ndfd|D             |d d <   g }dv r|                    d |D                        dv r|                    d |D                        t          |d           D ]\  	}|r nt           j                            	          }t           j                            |          
t          j        	          st          j        
          strt          	
fd	D                       r	 t          j	        |          }| 
                    
||j        |j        d
           t          |           k    rd} n# t          $ r Y w xY wp| |fS )NFc                 z    g | ]7}                     t          j                            |                    5|8S re   ry  r{  s     rH   ri   z3glob_search.<locals>._glob_sync.<locals>.<listcomp>  sM       %%bgll7A&>&>??  rJ   )r%  r  c                     g | ]}|d fS )r  re   )rg   r|  s     rH   ri   z3glob_search.<locals>._glob_sync.<locals>.<listcomp>  s    CCCQK 0CCCrJ   )r%  rC  c                     g | ]}|d fS )rC  re   )rg   rr  s     rH   ri   z3glob_search.<locals>._glob_sync.<locals>.<listcomp>  s    ???F???rJ   c                     | d         S )Nr   re   )xs    rH   <lambda>z1glob_search.<locals>._glob_sync.<locals>.<lambda>  s
    !A$ rJ   )keyc              3   l   K   | ].}t          j         |          pt          j         |          V  /d S r  rb  )rg   exclnamerel_paths     rH   r  z2glob_search.<locals>._glob_sync.<locals>.<genexpr>  sT       # # OD$//R7?8T3R3R# # # # # #rJ   )r   rD  r;  modifiedT)r:   r~  extendr  r   r$  relpathrc  r%  statrp  st_sizest_mtimer   r   )rt  rv  r  r  r  
entry_type	full_path	file_statr}  r  r  r  r   r\  ru  r   rD  s           @@@rH   
_glob_synczglob_search.<locals>._glob_sync  s@   	,.GFOO 3	 3	(GXy     #  HQQQK
 G+++CC(CCCDDD&&??Y???@@@$*7$G$G$G # # j EGLL$77	7??9f== tW55 gog? ?    s # # # # # '# # #       "	 2 2INN$,$.$-$5(1(:	    7||{22$(	 3    D 	!!s   +AE;;
FF)ru  r   rt  rv  )r_   r<   r   r   r  r:   r   r   r
   r   r#  )r   ru  r   r  rD  r\  r   r   r  r  rt  rv  r   s    ` ````     @rH   r  r  ^  s     8 %)).99J6@J":r222dK__T{_33F!''//////// R4PQQQQ9" 9" 9" 9" 9" 9" 9" 9" 9" 9"v  '0<<<<<<<<GY	  rJ   z/files/uploadupload_filezUpload a filez:Save a file to the specified path via multipart form data.)r   r   r   rc   r   r   z#Destination directory for the file.zThe file to upload.rC  c                 v  K   |                                  d {V }t          j                            |j        pd          }|                    |           } t          j                            t          j                            | |                    }	 |                    |            d {V  |	                    ||           d {V  n[# t          $ r#}t          dt          |                    d }~wt          $ r#}t          dt          |                    d }~ww xY w|t          |          dS )Nuploadrr   rU   r9  r:  )r  r:   r   basenamer_  r   normpathr$  rA  write_bytesPermissionErrorr
   rt   r   r   )r  rC  r   rs   r_  r   r?  s          rH   r  r    sF     $ IIKKGw 9::H	**I7BGLLH==>>D<hhy!!!!!!!!!nnT7++++++++++ < < <CFF;;;; < < <CFF;;;;<#g,,///s$   7C 
D&C66D&D!!D&c                   @    e Zd ZU  edd          Zee         ed<   dS )ArchiveRequest.z>List of file or directory paths to include in the ZIP archive.r   pathsN)r   r   r   r   r  r   rt   r   re   rJ   rH   r  r    sG         uT  E49     rJ   r  z/files/archivec                 <  	K   ddl ddl	| j        st          dd          g | j        D ][}                    |          }                    |           d{V st          dd|                               |           \t                    dk    r;t          j	        
                    d                             d	                    pd
}nd}dt          f	fd}t          j        |           d{V }t          |ddd| di          S )z:Bundle files and/or directories into a single ZIP archive.r   Nr9  zNo paths providedrU   r   zPath not found: r   /\archivedownloadr-   c                    	                                  }                     | dj                  5 }D ]g}t          j                            |          r4|                    |t          j                            |                     Vt          j                            |          rt          j                            |	                    d                    pd}t          j
        |          D ]\  	}}	
fd|D             |d d <   |D ]}t          j                            	|          }
                    |          s8t          j                            |t          j                            ||                    }|                    ||           i	 d d d            n# 1 swxY w Y   |                                 S )Nwr  r  c                 z    g | ]7}                     t          j                            |                    5|8S re   ry  r{  s     rH   ri   z5archive_paths.<locals>._build_zip.<locals>.<listcomp>  sM     ' ' '"#!11"',,w2J2JKK'' ' 'rJ   )BytesIOZipFileZIP_DEFLATEDr:   r   r  r<  r  r   rq  r~  r$  rz  r  getvalue)bufzfr   rH  r  r  fnamer  arcnamer}  r   ioresolvedzipfiles            @rH   
_build_zipz!archive_paths.<locals>._build_zip  s   jjll__S#w';<< 	4" 4 47>>&)) 4HHVRW%5%5f%=%=>>>>W]]6** 4 g..v}}U/C/CDDMG8: 4 449' ' ' ' ''/' ' ' &/ 4 4E#%7<<#?#?D#%#5#5d#;#; ) (&(gll 'v)F)F' 'G HHT7333344	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4& ||~~s   E,F,,F03F0zapplication/zipzContent-Dispositionzattachment; filename="z.zip")rs   r  r_   )r  r  r  r
   r   r0  rp  r   r:   r   r  rq  bytesr   r#  r   )
r[   r   pr   archive_namer  datar  r  r  s
    `     @@@rH   archive_pathsr    s      IIINNN= I4GHHHHH]    ##YYv&&&&&&&& 	PC8N18N8NOOOO 8}}w''(:(:5(A(ABBOi!         . ":........D$!#OL#O#O#O
   rJ   z/executelist_processeszList running commandszXReturns a list of all tracked background processes, including running, done, and killed.c                  h   K   t                       d t                                          D             S )Nc                 P    g | ]#}|j         |j        |j        |j        |j        d $S )r   r   r   r   r   r  )rg   r   s     rH   ri   z"list_processes.<locals>.<listcomp>>  sO     	 	 	  %')1(/+5*3	
 	
	 	 	rJ   )r   r   valuesre   rJ   rH   r  r  2  sC       	 	 #-"3"3"5"5	 	 	 	rJ   run_commandzExecute a commandzSeconds to wait for the command to finish before returning. If the command completes in time, output is included inline. Null to return immediately.zeReturn only the last N output entries. Useful to limit response size when only recent output matters.waittailc           	        K   t          |           }| j                            d          }|rt          ||          nd }|j        r|                    |j        |          n|p|j        }|j        ri t          j	        |j        nd }t          |j        |||j                   d {V }	t          j        d          t          j                    j        d d         z   }
t          j                            t(          d|
 d          }t+          |
|j        |	|          }t-          j        t1          |                    |_        |t4          |
<   |t6          rt6          }|J	 t-          j        t-          j        |j                  |	           d {V  n# t,          j        $ r Y nw xY wt?          |j         d
|           d {V \  }}}|
|j        |j!        |j"        ||||j         dS )Nr   r  )run_as_userz%Y%m%d-%H%M%S-   	processesz.jsonl)r   r   r   r   timeoutr   offsetr  r   r   r   r   outputrv  next_offsetr   )#ra   r_   r<   r   r   r   r^   r   r:   r;   r)   r   r]   r   strftimeuuiduuid4hexr   r$  r   r   r   create_taskr   r   r   r   wait_forshieldTimeoutErrorr   r   r   r   )r   r[   r  r  r   r   r  r   subprocess_envr   r   r   r   r  r  rv  s                   rH   executer  J  si     2 
	%	%B%)).99J6@J":r222dK;B;
d"//'+;/
7
7
7[Mc\^\cC6=kK2
2gk22tN n"+        F /004:<<3CBQB3GGJw||G[Z2G2G2GHHH*wv   #*"5kBT6U6U"V"V/Jz||	"1:;;T           # 	 	 	D	 ,4#AD, , , & & & & & &"FK
 ?$+'1"&/	 	 	s   &3F F,+F,z/execute/{process_id}/statusget_process_statuszGet command status and outputzxReturns new output since the last poll, process status, and exit code. Output is drained on read to keep memory bounded.zProcess not found.z{Seconds to wait for the process to finish before returning. Returns early if the process exits. Null to return immediately.zdNumber of output entries to skip. Use next_offset from the previous response to get only new output.r  c           	      |  K   t          |           }|t          rt          }|U|j        dk    rJ	 t          j        t          j        |j                  |           d {V  n# t          j        $ r Y nw xY wt          |j	        ||           d {V \  }}}|j
        |j        |j        |j        ||||j	        dS )Nr   r  r  r  )r   r   r   r   r  r  r   r  r   r   r   r   r   )r   r  r  r  r   r  r  rv  s           rH   
get_statusr    s/     < &j11||.5BB	"1:;;T           # 	 	 	D	 ,4#F, , , & & & & & &"FK
 !#%-$+'1"&/	 	 	s   3A$ $A65A6z/execute/{process_id}/inputsend_process_inputzSend input to a running commandzHWrite text to the process's stdin. Include newline characters as needed.z.Process has already exited or stdin is closed.bodyc                   K   t          |           }|j        dk    rt          dd          |j                            d                              d          }	 |j                            |                                           t          |j        t                    r|j        
                                 d {V  n,# t          t          t          f$ r t          dd          w xY wdd	iS )
Nr   r9  zProcess has already exitedrU   raw_unicode_escapeunicode_escapezProcess stdin is closedr   r   )r   r   r
   r   r   decoder   write_input
isinstancer'   drain_inputBrokenPipeErrorConnectionResetErrorr   )r   r  r   r+  s       rH   
send_inputr    s
      &j11 I--4PQQQQ :12299:JKKDO!--dkkmm<<<(/<< 	:$+7799999999917; O O O4MNNNNO ds   A%C )C+z/execute/{process_id}kill_processzKill a running commandzfTerminate the process. Sends SIGTERM by default for graceful shutdown. Use force=true to send SIGKILL.z Send SIGKILL instead of SIGTERM.forcec                   K   t          |           }|j        dk    ra|j                            |           |j                                         d {V }|j                                         d|_        ||_        t          | = ddiS )Nr   )r  killedr   )r   r   r   killr  closer   r   )r   r  r   r   s       rH   r  r    s       &j11 I--!&&U&333,388::::::::	!'')))$,!'0$:hrJ   )detect_listening_portsget_descendant_pidsz/portsc                   K   t          j        t                     d{V }	 t          |           }n# t          $ r dg icY S w xY w|j        rEddl}	 |                    |j                  j        fd|D             }nS# t          $ r g }Y nEw xY wt          j                    }t          j        t          |           d{V fd|D             }|D ]}|                    dd           d|iS )zReturn TCP ports currently listening on localhost.

    In multi-user mode, only shows ports owned by the requesting user.
    In single-user mode, shows ports owned by descendant processes.
    Nportsr   c                 F    g | ]}|                     d           k    |S )uidr<   )rg   r  user_uids     rH   ri   zlist_ports.<locals>.<listcomp>!  s-    JJJqu1I1I1I1I1IrJ   c                 B    g | ]}|                     d           v |S )pidr  )rg   r  descendant_pidss     rH   ri   zlist_ports.<locals>.<listcomp>'  s-    MMM1QUU5\\_-L-LQ-L-L-LrJ   r  )r   r#  r  ra   	Exceptionr]   pwdgetpwnampw_uidKeyErrorr:   getpidr  r   )r[   	all_portsr   r  own_pidr  r  r  s         @@rH   
list_portsr    s\      '(>????????IG$$    }
 
{ N


	||BK007HJJJJIJJJII 	 	 	III	 )++ ' 12Ew O OOOOOOOMMMM	MMM	   	eTYs!   5 AA-B BBc                     K   t           0dd l} |                     |                     dd          d          a t           S )Nr   g     r@g      @)connectF)r  follow_redirects)_port_proxy_clienthttpxAsyncClientTimeout)r  s    rH   _get_port_proxy_clientr  4  sN      !"..MM%M55" / 
 
 rJ   z/proxy/{port}/{path:path})GETPOSTPUTPATCHDELETEHEADOPTIONS)methodsr   r   portc                   K   | dk     s| dk    rt          dd          d|  d| }|j        r|d|j         z  }t          |j                  }d	D ]}|                    |d
           |                                 d
{V }dd
l}t                       d
{V }	 |                    |j	        |||pd
           d
{V }	n?# |j
        $ r t          dd|            |j        $ r t          dd|            w xY wt          |	j                  }
dD ]}|
                    |d
           t          |	j        |	j        |
          S )z3Reverse-proxy a request to localhost:{port}/{path}.r   i  i  z Port must be between 1 and 65535rU   zhttp://localhost:r4  ?)hosttransfer-encoding
connectionauthorizationNr   )methodurlr_   rs   i  zConnection refused: localhost:i  z Timeout connecting to localhost:)r   r!  zcontent-encodingzcontent-length)rs   rV   r_   )r
   r   r   r_   r   r  r  r  r[   r#  ConnectErrorTimeoutExceptionr   rs   rV   )r  r   r[   
target_urlr_   hr  r  clientupstreamresponse_headerss              rH   
port_proxyr,  ?  s      axx4%<<4VWWWW2T22D22J 10'.000
 7?##GI  AtDLLL)++++++++F
>LD	 ( 
 
 
 
 
 
 
 
  
 
 
:D::
 
 
 	
 ! 
 
 
<d<<
 
 
 	

 H,--V & &Q%%%% (    s   &C <D)datetime)r   pty)
PtyProcesswinpty_terminal_sessionsc                    t                               | d          }|dS |                    d          }|dk    r	 t          j        |d                    n# t
          $ r Y nw xY w|d         }|                                	 t          j        |j        t          j
                   n# t          t          f$ r Y nw xY w	 |                    d           dS # t          j        $ rU 	 t          j        |j        t          j                   n# t          t          f$ r Y nw xY w|                                 Y dS w xY wdS |dk    r2|d	         }|                                r|                                 dS dS dS )
am  Clean up a terminal session's resources.

        For PTY sessions the shell is spawned with ``start_new_session=True``,
        giving it a dedicated process group.  We signal the *entire* group so
        that background jobs started inside the terminal (e.g. ``sleep 999 &``)
        are also reaped, and always call ``process.wait()`` to avoid zombies.
        Nbackendr.  	master_fdprocess   r  r0  pty_process)r1  r   r<   r:   r  r   pollkillpgr  signalSIGTERMProcessLookupErrorr  r  r=  TimeoutExpiredSIGKILLisalive	terminate)r   sessionr3  r5  pty_procs        rH   _cleanup_sessionrC    s    %((T::?F++i((e-....    i(G||~~%Igk6>::::*O<   D#LLL+++++!0 # # #	'+v~>>>>.@   LLNNNNNN# &%    }-H!! %""$$$$$ ! % %sY   A 
A%$A%$B* *B>=B>C D>*$DD>D# D>"D##D>=D>z/api/terminals)r   r   c                   K   t           t          ddid          S t           dk    r$d t                                          D             }n#d t                                          D             }|D ]}t	          |           t          t                    t          k    rt          dd	t           d
id          S t          t          j	                              dd         }t           dk    r-	 t          j                    \  }}n## t          $ r t          ddid          cY S w xY w	 t          j        |t          j        t#          j        ddddd                     t'          |           }| j                            d|          }|rt-          ||          nd}|j        rddd|j         dg}|p|j        }	n6t2          j                            dd          g}|pt3          j                    }	t2          j                                        }
|
                    dt<                     t?          j         |||||	|
d          }n7# tB          $ r* t3          j"        |           t3          j"        |            w xY wt3          j"        |           t          j        |t          j#                  }t          j        |t          j$        |t2          j%        z             d||tM          j'                    (                                dz   |j)        dt          |<   nt2          j                            dd          }t2          j                                        }
|
                    dt<                     tU          j+        |gt3          j                    |
d !          }d"|tM          j'                    (                                dz   |j)        d#t          |<   t          |         }||d$         |d%         d&S )'z0Create a new terminal session and return its ID.Nr  z@PTY not available on this platform (install pywinpty on Windows)i  rV   r.  c                 L    g | ]!\  }}|d                                           |"S r5  r8  rg   r   ss      rH   ri   z#create_terminal.<locals>.<listcomp>  s1    dddFCAiLDUDUDWDWDcCDcDcDcrJ   c                 L    g | ]!\  }}|d                                           |"S )r7  r?  rI  s      rH   ri   z#create_terminal.<locals>.<listcomp>  s2    cccFC-HXH`H`HbHbcCcccrJ   z%Maximum number of terminal sessions (z	) reachedi     u=   Out of PTY devices — too many active terminals or processesHHHH   P   r   r   scriptz-qczsudo -i -u z	/dev/nullr/   r0   TERMT)stdinstdoutstderrr   r   start_new_sessionZ)r3  r4  r5  
created_atr  COMSPECzcmd.exe)rO  rP  )r   r   
dimensionsr0  )r3  r7  rX  r  rX  r  r   rX  r  ),_TERMINAL_BACKENDr   r1  r   rC  r   r    rt   _uuidr  r.  openptyr   fcntlioctltermios
TIOCSWINSZstructpackra   r_   r<   r   r]   r^   r:   r;   getcwdcopy
setdefaultr&   r=  Popenr  r  F_GETFLF_SETFL
O_NONBLOCK	_datetimeutcnow	isoformatr  _WinPtyProcessspawn)r[   deadr   r   r4  slave_fdr   r  	shell_cmdr   	spawn_envr5  r  rF   rB  rA  s                   rH   create_terminalru    s)      $\]    %%dd&8&>&>&@&@dddDDcc&8&>&>&@&@cccD 	" 	"CS!!!!!""&;;;bBWbbbc   
 ''+
%%&)kmm#	88   #]^ #     "Hg&8&+fbRTVWYZ:[:[\\\#G,, %_00LL
BLV.z2>>>RV; 	5 %3bk33#!I
 &0CC!#!C!C DI%4CJOO--	$$V];;;$*"##!&*      """### HX K	5=99EK	5=%"-2GHHH !&"'.00::<<sB{. .z** JNN9i88E
))I  777%+IKK#	  H $''.00::<<sB|	. .z* %Z0!,/5>
 
 	
s   1D D('D(,DI
 
4I>rA  c                     | d         dk    r| d                                          du S | d                                         S )z7Check if a terminal session's process is still running.r3  r.  r5  Nr7  )r8  r?  )rA  s    rH   _session_is_aliverw  *  sE    9&&9%**,,44=)11333rJ   c                   K   g }g }t                                           D ]O\  }}t          |          s|                    |           *|                    ||d         |d         d           P|D ]}t	          |           |S )zList active terminal sessions.rX  r  r[  )r1  r   rw  rp  rC  )r[   result	to_remover   rA  s        rH   list_terminalsr{  2  s       	.4466 	 	LC$W--   %%%MM%l3u~     
  	" 	"CS!!!!rJ   z/api/terminals/{session_id}c                    K   t                               |           }|t          ddid          S t          |          s"t	          |            t          ddid          S | |d         |d         dS )	z"Get info about a terminal session.Nr  Session not foundr   rE  rX  r  r[  )r1  r<   r   rw  rC  )r   r[   rA  s      rH   get_terminalr~  E  s       %((44?*= >CPPPP )) 	QZ(((*= >CPPPP!,/5>
 
 	
rJ   c                 d   K   | t           vrt          ddid          S t          |            ddiS )z#Kill and remove a terminal session.r  r}  r   rE  r   deleted)r1  r   rC  )r   r[   s     rH   delete_terminalr  U  sF       ///*= >CPPPP$$$)$$rJ   wsc                 :   K   t                               |          }|                     dd           d{V  dS t          |          s.t	          |                                dd           d{V  dS                                   d{V  t          r	 t          j         	                                d           d{V }t          j        |          }|                    d          d	k    s.t          j        |                    d
d          t                    s                     dd           d{V  dS nE# t          j        t          j        t           f$ r!                      dd           d{V  Y dS w xY w|d         }t          j                    t          j                    |dk    r=|d         |d         fdfddt&          ffd}dt(          dt(          ffd}n3|d         fdfddt&          ffd}dt(          dt(          ffd} fd}t          j         |                      }		 	                                   d{V }|d         d!k    rnd"|v r,|d"         r$                    d||d"                    d{V  nd#|v r|d#         r	 t          j        |d#                   }|                    d          d$k    r8|                    dd%          }
|                    dd&          } |||
           n# t          j        t0          f$ r Y nw xY wn# t2          $ r Y nw xY w                                 |	                                 	 |	 d{V  n# t          j        t           f$ r Y nw xY wt	          |           dS #                                  |	                                 	 |	 d{V  n# t          j        t           f$ r Y nw xY wt	          |           w xY w)'a:  Attach to an existing terminal session via WebSocket.

        Authentication is via **first-message auth**: after connecting, the client
        must send a JSON text frame as its first message::

            {"type": "auth", "token": "<api_key>"}

        The server validates the token and closes the connection if invalid.
        After authentication, the client sends keystrokes as **binary** frames
        and receives PTY output as binary frames.

        To resize, send a **text** JSON frame::

            {"type": "resize", "cols": 120, "rows": 40}
        Ni  r}  )codereasonzSession has endedg      $@r  rD  authtokenr5   i  rT   zAuth timeout or invalid payloadr3  r.  r4  r5  c                                                       sa	 t          j        gg g d          \  } }}| rt          j        d          S n# t
          t          f$ r Y dS w xY w                                 adS )z7Read from PTY using select() so we don't block forever.g?   rJ   )is_set_selectselectr:   r  r   r  )rlistr   r4  
stop_events     rH   _blocking_readz#ws_terminal.<locals>._blocking_read  s    $++-- ##&-ni["b#&N&Nq!  <#%79d#;#;;<#Z0 # # #"ss# %++-- # ss   2A A A c                  0                                      d u S r  rH  rG  s   rH   _check_alivez!ws_terminal.<locals>._check_alive  s    ||~~--rJ   r  c                 2    t          j        |            d S r  )r:   r<  )r  r4  s    rH   _write_dataz ws_terminal.<locals>._write_data  s    D)))))rJ   rowscolsc                 t    t          j        t          j        t	          j        d| |dd                     d S )NrN  r   )r_  r`  ra  rb  rc  rd  )r  r  r4  s     rH   
_do_resizezws_terminal.<locals>._do_resize  s?    &KdAq99    rJ   r7  c                      	                      d          } | r|                     d          ndS # t          $ r Y dS t          $ r Y dS w xY w)zRead from WinPTY process.r  rP  rk  rJ   )r  r   EOFErrorr  r  rB  s    rH   r  z#ws_terminal.<locals>._blocking_read  sr    #==..D<@I4;;i;888cI   33    33s   .2 
A	AAc                  ,                                      S r  rL  )rB  s   rH   r  z!ws_terminal.<locals>._check_alive  s    '')))rJ   c                 Z                         |                     d                     d S )NrP  r  )r<  r  r  s    rH   r  z ws_terminal.<locals>._write_data  s)    t{{){<<=====rJ   c                 4                         | |           d S r  )
setwinsize)r  r  rB  s     rH   r  zws_terminal.<locals>._do_resize  s    ##D$/////rJ   c                  @  K   	                                  s                    d           d{V } | s!                                 rnM             snBS	                     |            d{V  n# t          $ r Y nw xY w                                 dS # w xY w)z Forward PTY output -> WebSocket.N)r  run_in_executor
send_bytesr  )r  r  r  loopr  r  s    rH   _pty_readerz ws_terminal.<locals>._pty_reader  s      $++-- !%!5!5dN!K!KKKKKKKD !%,,.. "!+|~~ "!  mmD1111111111$    %++--  s0   AB A5 4B 5
B?B BB BTzwebsocket.disconnectr  r+  resizerP  rO  )r1  r<   r  rw  rC  acceptr   r   r  receive_textjsonloadsrX   rY   r  JSONDecodeErrorr  get_event_loopEventr  r   r  receiver  r  r   setcancelCancelledError)r  r   rA  msgpayloadr3  r  r  r  reader_taskr  r  r  r  r  r4  r5  rB  r  s   `           @@@@@@@rH   ws_terminalr  ^  s     " %((44?((-@(AAAAAAAAAF )) 	Z(((((-@(AAAAAAAAAFiikk  		#,R__->->MMMMMMMMM*S//;;v&&&008KGKKX_acLdLdfm8n8n0((5F(GGGGGGGGGF 1 ($*>	J   hhD1RhSSSSSSSSS )$%'']__
 e,Ii(G	 	 	 	 	 	. . . . .*% * * * * * * C        }-H    * * * * *>% > > > > > >0 0C 0 0 0 0 0 0
	 	 	 	 	 	 	 	 	$ )++--88	)JJLL((((((v;"888^^G^..t[#g,OOOOOOOOOOs]]s6{]"&*S["9"9";;v..(::#*;;vr#:#:D#*;;vr#:#:D&JtT222 0(;     # 	 	 	D	 NN   !!!!!!!!!*I6    Z((((( NN   !!!!!!!!!*I6    Z((((s   %B&E >FFA$M A+L. -M .MM MM N; 
MN; MN; N N'&N';)P%O.-P.PPPP)create_notebooks_router)r   rX   importlib.metadatar   _pkg_versionrc  r  r  aiofiles.osr:   r>   r  shutilr:  rB   rD   r   r  dataclassesr   r   typingr   fastapir   r   r	   r
   r   r   r   r   r   fastapi.middleware.corsr   fastapi.responsesr   r   fastapi.securityr   r   pydanticr   r   open_terminal.envr   r   r   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   open_terminal.utils.runnerr'   r(   r)   open_terminal.utils.fsr*   "open_terminal.utils.user_isolationr+   r,   
SystemExitr_  r.  rc  r=  ra  _PTY_AVAILABLEImportErrorrt   rI   rO   _EXECUTE_DESCRIPTIONbearer_schemerZ   ra   appadd_middlewarerE   exception_handlerr  ru   
middlewarer   r   r   r   r   r   r   r   r   r   r   r   r   r   tupler   r   r   r   open_terminal.utils.logr   r   r   r   r<   r   r   r   r   r   postr   r   r   r  r.  r2  r6  r7  rA  deleterF  rK  rL  r   r   rT  r  r  r  r  r  r  r  r  r  open_terminal.utils.portr  r  r  r  r  	api_router,  r]  r-  rl  r  r  r\  r0  r/  ro  r1  rC  ru  rw  r{  r~  r  	websocketr  open_terminal.utils.notebooksr  include_routerre   rJ   rH   <module>r     s     6 6 6 6 6 6        				  				    



   ( ( ( ( ( ( ( (       u u u u u u u u u u u u u u u u u u u u u u 2 2 2 2 2 2 4 4 4 4 4 4 4 4 E E E E E E E E % % % % % % % % |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | O O O O O O O O O O ) ) ) ) ) ) RRRRRRRR 
*	  	LLLJJJMMMNNNNN   NNN    3    4 Io   9F%888
e,,, ;B'-:P:PG G67G G G G0G 0 0 0 0 0  g
(L))  
   FF&@&:&@&E&EFFF%%     ''GG G/ G G G ('G $w $ $ $ $     )        9       9       y   2    9       )       Y   " > > > > > > > > ,.
D''( - - - /1tCsEz**+ 0 0 0  t  c    8t 83 8 8 8 8 : 9 9 9 9 9 9 9
  4S %6     E 	      	   	   	/WWgn--.   
/ / 
/
  
,WW& Kgn--.   , , , '.))* 	   ((5 555 5 5 
5 '.))* 
   ((
 


 	
 
 
 

 %Y'.))*34:;  	 
 
 U3,EFFF((/ /// 	/ / /
 
/  f'.))*./<=:;  	   c'BCCC %otu! ! ! $ehmn   ((< <<
< < sm< 	< < < <~ ( i'.))*m:; 	 	 	 c'NOOO((. ..
. 	. . .	 	.& '.))* 	   c'BCCC((2 2
22 2 2 
2* '.))* 	  
 .5W^-D-D 3 33 3F 3 3 3 
3
  A'.))*m:; 
 	 	 QXPWXfPgPg C C7 C\ Cv C C C	 	C '.))* 
  
 5<GN4K4K   6    
 '.))*    c'8999((G G
GG G G 
G '.))* 
  
 9@8O8O : :k :v : : : 
:* '' K'.))*./JK:;  
   ]d\cdr\s\s -; -;W -;~ -;SY -; -; -; -;` " k'.))*5656:;  	   s(NOOOc'HIII%*TUUU"U?   $)5i$ $ $ !5~   u
>1   (('c ccc c 	c
 c d3i c c  !c& 	'c c c cL " {'.))*:;:;  	 
 
 5*UVVVc'DEEE#(5I$ $ $  %A(  
 u
>1   ((X XXX X d3i 	X 3-X X 	X X X
 
Xz L'.))*m:; 
 
 
 U3,QRRRt.   ((0 00
0
 	0 0 0
 
0.    Y    '.))* 
   ((6 666 6 6 
6| !#j'.))*m:; 	 	 	 	 	 $'.))*m:; 
 	 	 "E k	    %{  8 888 5/8 3-8 8 8	 	8v "%+ K'.))*12:;  	 
 
 "E R	   %	z  
  %{  , ,,
5/, , 3-, , ,
 
,^ !%-Z'.))*12MN:;  
   L    & $x'.))*12:;   
 
 %+MNNN         
 
 & Q P P P P P P P'.))* 	  
  g          
  H     HHH'.))*	   -3 -c -G - - - -h  v)............          %!	%;;;;;; ( 	% 	% 	% $	% +-S$Y,,,(%S (% (% (% (%V 	XXggn.E.E-FZ_X``h
w h
 h
 h
 a`h
V44 4D 4 4 4 4 	WWWW^-D-D,EY^W__g    `_$ 	WW*''.:Q:Q9RfkWll
s 
W 
 
 
 ml
 	ZZ-WW^=T=T<UinZoo%# % % % % po% 	]]011P)i P)S P) P) P) 21P)n  @EEEEEE..~>>?????@ @s6   C3 3C=<C=?k kkk   k*)k*