§
    ‰eîiœà  ã                   ó  — d 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
 ej        ¦   «         dk    ZddlmZmZ ddlmZmZ ddlmZmZmZmZ ddlmZ  ej        e¦  «        Z e¦   «         dz  Zd	Zd
ZdZ dZ!dZ"dZ#dZ$dZ%de&de'fd„Z(e G d„ d¦  «        ¦   «         Z) G d„ d¦  «        Z* e*¦   «         Z+ddl,m-Z-m.Z. ddddg d¢ddœddd œdd!d œd"d#d$d%œd"d&d œd"d'd$d%œd(œd)gd*œd+œZ/d,„ Z0 e-j1        dd-e/e0d.¬/¦  «         dS )0aø  
Process Registry -- In-memory registry for managed background processes.

Tracks processes spawned via terminal(background=true), providing:
  - Output buffering (rolling 200KB window)
  - Status polling and log retrieval
  - Blocking wait with interrupt support
  - Process killing
  - Crash recovery via JSON checkpoint file
  - Session-scoped tracking for gateway reset protection

Background processes execute THROUGH the environment interface -- nothing
runs on the host machine unless TERMINAL_ENV=local. For Docker, Singularity,
Modal, Daytona, and SSH backends, the command runs inside the sandbox.

Usage:
    from tools.process_registry import process_registry

    # Spawn a background process (called from terminal_tool)
    session = process_registry.spawn(env, "pytest -v", task_id="task_123")

    # Poll for status
    result = process_registry.poll(session.id)

    # Block until done
    result = process_registry.wait(session.id, timeout=300)

    # Kill it
    process_registry.kill(session.id)
é    NÚWindows)Ú_find_shellÚ_sanitize_subprocess_env)Ú	dataclassÚfield)ÚAnyÚDictÚListÚOptional)Úget_hermes_homezprocesses.jsoni@ i  é@   é   é   é
   é   ÚsecondsÚreturnc                 óÊ   — t          dt          | ¦  «        ¦  «        }|dk     r|› d�S t          |d¦  «        \  }}|dk     r|› d|› d�S t          |d¦  «        \  }}|› d|› d�S )Nr   é<   Úszm zh Úm)ÚmaxÚintÚdivmod)r   r   ÚminsÚsecsÚhourss        ú8/home/div/.hermes/hermes-agent/tools/process_registry.pyÚformat_uptime_shortr   M   s†   € ÝˆA�s�7‰|Œ|ÑÔ€AØˆ2‚v€vØˆwˆwˆwˆÝ˜˜2‘”�J€Dˆ$Øˆb‚y€yØÐ!Ð!˜$Ð!Ð!Ð!Ð!Ý˜˜rÑ"Ô"�K€Eˆ4ØÐÐ�tÐÐÐÐó    c                   ó8  — e Zd ZU dZeed<   eed<   dZeed<   dZeed<   dZe	e
         ed<   dZe	ej                 ed	<   dZeed
<   dZe	e         ed<   dZeed<   dZeed<   dZe	e
         ed<   dZeed<   eZe
ed<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   dZeed<   dZ e
ed<   dZ!eed<    e"e#¬¦  «        Z$e%e         ed<    e"dd¬ ¦  «        Z&e
ed!<    e"dd¬ ¦  «        Z'e
ed"<    e"dd¬ ¦  «        Z(eed#<    e"dd¬ ¦  «        Z)eed$<    e"dd¬ ¦  «        Z*eed%<    e"dd¬ ¦  «        Z+eed&<    e"dd¬ ¦  «        Z,e
ed'<    e"e-j.        ¬¦  «        Z/e-j.        ed(<    e"dd¬ ¦  «        Z0e	e-j1                 ed)<    e"dd¬ ¦  «        Z2eed*<   dS )+ÚProcessSessionz3A tracked background process with output buffering.ÚidÚcommandÚ Útask_idÚsession_keyNÚpidÚprocessÚenv_refÚcwdç        Ú
started_atFÚexitedÚ	exit_codeÚoutput_bufferÚmax_output_charsÚdetachedÚhostÚ	pid_scopeÚwatcher_platformÚwatcher_chat_idÚwatcher_user_idÚwatcher_user_nameÚwatcher_thread_idr   Úwatcher_intervalÚnotify_on_complete)Údefault_factoryÚwatch_patterns)ÚdefaultÚreprÚ_watch_hitsÚ_watch_suppressedÚ_watch_disabledÚ_watch_last_emit_atÚ_watch_cooldown_untilÚ_watch_strike_candidateÚ_watch_consecutive_strikesÚ_lockÚ_reader_threadÚ_pty)3Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚstrÚ__annotations__r&   r'   r(   r   r   r)   Ú
subprocessÚPopenr*   r   r+   r-   Úfloatr.   Úboolr/   r0   ÚMAX_OUTPUT_CHARSr1   r2   r4   r5   r6   r7   r8   r9   r:   r;   r   Úlistr=   r
   r@   rA   rB   rC   rD   rE   rF   Ú	threadingÚLockrG   rH   ÚThreadrI   © r    r   r"   r"   X   sì  € € € € € € à=Ð=Ø€G€G�GØ€L€L�LØ€GˆSÐÐÑØ€K�ÐÐÑØ€Cˆ�#ŒÐÐÑØ*.€GˆX�jÔ&Ô'Ð.Ð.Ñ.Ø€GˆSÐÐÑØ€Cˆ�#ŒÐÐÑØ€J�ÐÐÑØ€FˆDÐÐÑØ#€Iˆx˜Œ}Ð#Ð#Ñ#Ø€M�3ÐÐÑØ,Ð�cÐ,Ð,Ñ,Ø€HˆdÐÐÑØ€IˆsÐÐÑàÐ�cÐÐÑØ€O�SÐÐÑØ€O�SÐÐÑØÐ�sÐÐÑØÐ�sÐÐÑØÐ�cÐÐÑØ$Ð˜Ð$Ð$Ñ$à % °dÐ ;Ñ ;Ô ;€N�D˜”IÐ;Ð;Ñ;Ø�u Q¨UÐ3Ñ3Ô3€K�Ð3Ð3Ñ3Ø"˜U¨1°5Ð9Ñ9Ô9Ð�sÐ9Ð9Ñ9Ø!˜E¨%°eÐ<Ñ<Ô<€O�TÐ<Ð<Ñ<ð "' ¨s¸Ð!?Ñ!?Ô!?Ð˜Ð?Ð?Ñ?Ø#( 5°¸5Ð#AÑ#AÔ#AÐ˜5ÐAÐAÑAØ$) E°%¸eÐ$DÑ$DÔ$DÐ˜TÐDÐDÑDØ&+ e°A¸EÐ&BÑ&BÔ&BÐ ÐBÐBÑBØ!˜E°)´.ÐAÑAÔA€Eˆ9Œ>ÐAÐAÑAØ16°¸tÈ%Ð1PÑ1PÔ1P€N�H˜YÔ-Ô.ÐPÐPÑPØ�˜d¨Ð/Ñ/Ô/€Dˆ#Ð/Ð/Ñ/Ð/Ð/r    r"   c                   ó¤  — e Zd ZdZdZd„ Zededefd„¦   «         Zde	dedd	fd
„Z
dedefd„Zedee         defd„¦   «         Zdee	         dee	         fd„Zededd	fd„¦   «         Zededefd„¦   «         Z	 	 	 	 	 d<dedededededede	fd„Z	 	 	 	 d=dedededededede	fd„Zde	fd„Zde	ded ed!ed"ef
d#„Zde	fd$„Zde	fd%„Zd&edefd'„Zd&edee	         fd(„Zd&edefd)„Zd>d&ed,ed-edefd.„Zd?d&ededefd/„Z d&edefd0„Z!d&ed1edefd2„Z"d@d&ed1edefd3„Z#d&edefd4„Z$d?dede%fd5„Z&dedefd6„Z'dedefd7„Z(d?dedefd8„Z)d9„ Z*d:„ Z+defd;„Z,d	S )AÚProcessRegistrya$  
    In-memory registry of running and finished background processes.

    Thread-safe. Accessed from:
      - Executor threads (terminal_tool, process tool handlers)
      - Gateway asyncio loop (watcher tasks, session reset checks)
      - Cleanup thread (sandbox reaping coordination)
    )z'bash: cannot set terminal process groupz"bash: no job control in this shellzno job control in this shellz!cannot set terminal process groupz)tcsetattr: Inappropriate ioctl for devicec                 ó(  — i | _         i | _        t          j        ¦   «         | _        g | _        dd l}|                     ¦   «         | _        t          ¦   «         | _
        t          j        ¦   «         | _        d| _        d| _        d| _        d| _        d S )Nr   r,   )Ú_runningÚ	_finishedrV   rW   rG   Úpending_watchersÚqueueÚQueueÚcompletion_queueÚsetÚ_completion_consumedÚ_global_watch_lockÚ_global_watch_window_startÚ_global_watch_window_hitsÚ_global_watch_tripped_untilÚ$_global_watch_suppressed_during_trip)ÚselfÚ
_queue_mods     r   Ú__init__zProcessRegistry.__init__™   s‘   € Ø35ˆŒØ46ˆŒÝ”^Ñ%Ô%ˆŒ
ð 79ˆÔð 	#Ð"Ð"Ð"Ø2<×2BÒ2BÑ2DÔ2DˆÔõ *-©¬ˆÔ!õ
 #,¤.Ñ"2Ô"2ˆÔØ14ˆÔ'Ø./ˆÔ&Ø25ˆÔ(Ø9:ˆÔ1Ð1Ð1r    Útextr   c                 ó  ‡— |                       d¦  «        Š‰rat          ˆfd„t          j        D ¦   «         ¦  «        r<‰                     d¦  «         ‰r%t          ˆfd„t          j        D ¦   «         ¦  «        °<d                     ‰¦  «        S )z:Strip shell startup warnings from the beginning of output.Ú
c              3   ó,   •K  — | ]}|‰d          v V — ŒdS )r   NrY   )Ú.0ÚnoiseÚliness     €r   ú	<genexpr>z5ProcessRegistry._clean_shell_noise.<locals>.<genexpr>¹   s,   øè è € ÐcÐc°%˜E U¨1¤XÐ-ÐcÐcÐcÐcÐcÐcr    r   )ÚsplitÚanyr[   Ú_SHELL_NOISE_SUBSTRINGSÚpopÚjoin)rm   rs   s    @r   Ú_clean_shell_noisez"ProcessRegistry._clean_shell_noiseµ   s—   ø€ ð —
’
˜4Ñ Ô ˆØð 	�ÐcÐcÐcÐc½?Ô;bÐcÑcÔcÑcÔcð 	Ø�IŠI�a‰LŒLˆLð ð 	�ÐcÐcÐcÐc½?Ô;bÐcÑcÔcÑcÔcð 	à�yŠy˜ÑÔÐr    ÚsessionÚnew_textNc                 ó  — |j         r|j        rdS |j        rdS g }d}|                     ¦   «         D ]=}|j         D ]3}||v r-|                     |                     ¦   «         ¦  «         |€|} nŒ4Œ>|sdS t          j        ¦   «         }d}|j        5  |j        ri||j        k     r^|xj	        t          |¦  «        z  c_	        |j        s7d|_        |xj        dz  c_        |j        t          k    rd|_        d|_        d}d}	nR|j        r|j        sd|_        d|_        ||_        |t           z   |_        |xj        dz  c_        |j	        }
d|_	        d}	ddd¦  «         n# 1 swxY w Y   |	rp|rl| j                             |j        |j        |j        d|j	        |j        |j        |j        |j        |j        d|j        › dt          › d	t           › d
�dœ¦  «         dS d                     |dd…         ¦  «        }t          |¦  «        dk    r|dd…         dz   }|                      |¦  «        sdS | j                             |j        |j        |j        d|||
|j        |j        |j        |j        |j        dœ¦  «         dS )uz  Scan new output for watch patterns and queue notifications.

        Called from reader threads with new_text being the freshly-read chunk.

        Per-session rate limit: at most ONE watch-match notification per
        WATCH_MIN_INTERVAL_SECONDS. Any match arriving inside the cooldown
        window is dropped and counts as ONE strike for that window. After
        WATCH_STRIKE_LIMIT consecutive strike windows, watch_patterns is
        disabled for this session and the session is promoted to
        notify_on_complete semantics â€” one notification when the process
        actually exits, no more mid-process spam.
        NFTé   r   Úwatch_disabledz$Watch patterns disabled for process u    â€” z7 consecutive rate-limit windows triggered (min spacing zms). Falling back to notify_on_complete semantics; you'll get exactly one notification when the process exits.)Ú
session_idr'   r$   ÚtypeÚ
suppressedÚplatformÚchat_idÚuser_idÚ	user_nameÚ	thread_idÚmessagero   é   iÐ  z
...(truncated)Úwatch_match)r€   r'   r$   r�   ÚpatternÚoutputr‚   rƒ   r„   r…   r†   r‡   )r=   rB   r.   Ú
splitlinesÚappendÚrstripÚtimerG   rD   rA   ÚlenrE   rF   ÚWATCH_STRIKE_LIMITr;   rC   ÚWATCH_MIN_INTERVAL_SECONDSr@   rb   Úputr#   r'   r$   r5   r6   r7   r8   r9   ry   Ú_global_watch_admit)rj   r{   r|   Úmatched_linesÚmatched_patternÚlineÚpatÚnowÚshould_disableÚreturn_earlyr‚   rŒ   s               r   Ú_check_watch_patternsz%ProcessRegistry._check_watch_patterns½   s�  € ð Ô%ð 	¨Ô)@ð 	ØˆFð
 Œ>ð 	ØˆFð ˆØˆØ×'Ò'Ñ)Ô)ð 	ð 	ˆDØÔ-ð ð �Ø˜$�;�;Ø!×(Ò(¨¯ª©¬Ñ7Ô7Ð7Ø&Ð.Ø*-˜Ø�Eð	 øð ð 	ØˆFåŒi‰kŒkˆØˆØŒ]ð %	%ð %	%ð
 Ô,ð  %°°wÔ7TÒ1TÐ1TØÐ)Ô)­S°Ñ-?Ô-?Ñ?Ð)Ô)ØÔ6ð 	.à6:�GÔ3ØÐ6Ô6¸!Ñ;Ð6Ô6ØÔ9Õ=OÒOÐOØ26˜Ô/ð 6:˜Ô2Ø)-˜Ø#��ð Ô1ð;à#Ô;ð;ð :;�GÔ6Ø27�Ô/ð /2�Ô+Ø03Õ6PÑ0P�Ô-ØÐ#Ô# qÑ(Ð#Ô#Ø$Ô6�
Ø,-�Ô)Ø$�ðK%	%ð %	%ð %	%ñ %	%ô %	%ð %	%ð %	%ð %	%ð %	%ð %	%ð %	%øøøð %	%ð %	%ð %	%ð %	%ðN ð 	Øð ð Ô%×)Ò)Ø")¤*Ø#*Ô#6Ø&œØ,Ø")Ô";Ø 'Ô 8Ø&Ô6Ø&Ô6Ø!(Ô!:Ø!(Ô!:ðL¸w¼zð Lð LÝ-ðLð Lå(BðLð Lð Lð+ð +ñ ô ð ð& ˆFð —’˜=¨¨"¨Ô-Ñ.Ô.ˆÝˆv‰;Œ;˜ÒÐØ˜E˜T˜E”]Ð%7Ñ7ˆFð ×'Ò'¨Ñ,Ô,ð 	ØˆFàÔ×!Ò!Ø!œ*Ø"Ô.Ø”Ø!Ø&ØØ$ØÔ0ØÔ.ØÔ.Ø Ô2Ø Ô2ð#
ð #
ñ 	ô 	ð 	ð 	ð 	s   ÂCEÅE#Å&E#rš   c                 óÂ  — | j         5  | j        rJ|| j        k    r?| j        }d| _        d| _        || _        d| _        |dk    rdddd|d|› d�ddddddœ}nd}nd}| j        r || j        k     r| xj        d	z  c_        d
}d}ni|| j        z
  t
          k    r|| _        d| _        | j        t          k    r$|t          z   | _        | xj        d	z  c_        |}d
}n| xj        d	z  c_        d}d}ddd¦  «         n# 1 swxY w Y   |�| j         	                    |¦  «         |�>| j         	                    dddddt          › dt
          › dt          › d�ddddddœ
¦  «         |S )a1  Return True if this watch_match event is allowed through the global breaker.

        Semantics:
        - If we're currently in a cooldown period, drop the event and count it.
        - Otherwise, slide the rolling window and check the global cap.
        - If the cap is exceeded, trip the breaker for WATCH_GLOBAL_COOLDOWN_SECONDS
          and emit ONE summary event so the agent/user sees "N notifications were
          suppressed" instead of getting them individually.
        - When the cooldown ends, emit a release summary and reset counters.
        r,   r   r%   Úwatch_overflow_releasedz%Watch-pattern notifications resumed. z1 match event(s) were suppressed during the flood.)r€   r'   r$   r�   r‚   rˆ   rƒ   r„   r…   r†   r‡   Nr~   FTÚwatch_overflow_trippedzWatch-pattern overflow: >z notifications in zCs across all processes. Suppressing further watch_match events for zs.)
r€   r'   r$   r�   rˆ   rƒ   r„   r…   r†   r‡   )
re   rh   ri   rf   rg   ÚWATCH_GLOBAL_WINDOW_SECONDSÚWATCH_GLOBAL_MAX_PER_WINDOWÚWATCH_GLOBAL_COOLDOWN_SECONDSrb   r”   )rj   rš   r‚   Úrelease_msgÚadmitÚtrip_nows         r   r•   z#ProcessRegistry._global_watch_admit;  sb  € ð Ô$ð 3	!ð 3	!àÔ/ð #°C¸4Ô;[Ò4[Ð4[Ø!ÔF�
Ø36�Ô0Ø<=�Ô9Ø25�Ô/Ø12�Ô.Ø ’>�>ð ')Ø')Ø#%Ø 9Ø&0ð]Ø)ð]ð ]ð ]ð %'Ø#%Ø#%Ø%'Ø%'ð#ð #�K�Kð" #'�K�Kà"�ð Ô/ð !°C¸$Ô:ZÒ4ZÐ4ZØÐ9Ô9¸QÑ>Ð9Ô9Ø�Ø��ð ˜Ô8Ñ8Õ<WÒWÐWØ69�DÔ3Ø56�DÔ2àÔ1Õ5PÒPÐPà7:Õ=ZÑ7Z�DÔ4ØÐ=Ô=ÀÑBÐ=Ô=Ø"�HØ!�E�EàÐ2Ô2°aÑ7Ð2Ô2Ø#�HØ �Eðg3	!ð 3	!ð 3	!ñ 3	!ô 3	!ð 3	!ð 3	!ð 3	!ð 3	!ð 3	!ð 3	!øøøð 3	!ð 3	!ð 3	!ð 3	!ðl Ð"ØÔ!×%Ò% kÑ2Ô2Ð2ØÐØÔ!×%Ò%Ø Ø!ØØ0ð9Õ0Kð 9ð 9Ý(Cð9ð 9õ 5ð9ð 9ð 9ð
 ØØØØð'ð 'ñ ô ð ð" ˆs   ˆC$C8Ã8C<Ã?C<r(   c                 ój   — | sdS 	 t          j        | d¦  «         dS # t          t          f$ r Y dS w xY w)z1Best-effort liveness check for host-visible PIDs.Fr   T)ÚosÚkillÚProcessLookupErrorÚPermissionError©r(   s    r   Ú_is_host_pid_alivez"ProcessRegistry._is_host_pid_alive’  sQ   € ð ð 	Ø�5ð	ÝŒG�C˜‰OŒOˆOØ�4øÝ"¥OÐ4ð 	ð 	ð 	Ø�5�5ð	øøøs   † �2±2c                 ó&  — |�|j         s|j        r|j        dk    r|S |                      |j        ¦  «        r|S |j        5  |j         r|cddd¦  «         S d|_         d|_        ddd¦  «         n# 1 swxY w Y   |                      |¦  «         |S )zJUpdate recovered host-PID sessions when the underlying process has exited.Nr3   T)r.   r2   r4   r­   r(   rG   r/   Ú_move_to_finished)rj   r{   s     r   Ú_refresh_detached_sessionz)ProcessRegistry._refresh_detached_session�  s  € àˆ?˜gœnˆ?°GÔ4Dˆ?ÈÔHYÐ]cÒHcÐHcØˆNà×"Ò" 7¤;Ñ/Ô/ð 	ØˆNàŒ]ð 	%ð 	%ØŒ~ð Øð	%ð 	%ð 	%ð 	%ñ 	%ô 	%ð 	%ð 	%ð "ˆGŒNð !%ˆGÔð	%ð 	%ð 	%ñ 	%ô 	%ð 	%ð 	%ð 	%ð 	%ð 	%ð 	%øøøð 	%ð 	%ð 	%ð 	%ð 	×Ò˜wÑ'Ô'Ð'Øˆs   Á	A1ÁA1Á1A5Á8A5c                 ó4  — t           r!t          j        | t          j        ¦  «         dS 	 t          j        t          j        | ¦  «        t          j        ¦  «         dS # t          t          t          f$ r# t          j        | t          j        ¦  «         Y dS w xY w)zKTerminate a host-visible PID without requiring the original process handle.N)
Ú_IS_WINDOWSr¨   r©   ÚsignalÚSIGTERMÚkillpgÚgetpgidÚOSErrorrª   r«   r¬   s    r   Ú_terminate_host_pidz#ProcessRegistry._terminate_host_pid°  sŒ   € õ ð 	ÝŒG�C�œÑ(Ô(Ð(ØˆFð	)ÝŒI•b”j ‘o”o¥v¤~Ñ6Ô6Ð6Ð6Ð6øÝÕ+­_Ð=ð 	)ð 	)ð 	)ÝŒG�C�œÑ(Ô(Ð(Ð(Ð(Ð(ð	)øøøs   ª1A Á6BÂBÚenvc                 óD  — t          | dd¦  «        }t          |¦  «        r	  |¦   «         }t          |t          ¦  «        r,|                     d¦  «        r|                     d¦  «        pdS n2# t          $ r%}t                               d|¦  «         Y d}~nd}~ww xY wdS )zEReturn the writable sandbox temp dir for env-backed background tasks.Úget_temp_dirNú/z*Could not resolve environment temp dir: %sz/tmp)	ÚgetattrÚcallableÚ
isinstancerN   Ú
startswithr�   Ú	ExceptionÚloggerÚdebug)r¹   r»   Útemp_dirÚexcs       r   Ú_env_temp_dirzProcessRegistry._env_temp_dir¾  sÂ   € õ ˜s N°DÑ9Ô9ˆÝ�LÑ!Ô!ð 	PðPØ'˜<™>œ>�Ý˜h­Ñ,Ô,ð 7°×1DÒ1DÀSÑ1IÔ1Ið 7Ø#Ÿ?š?¨3Ñ/Ô/Ð6°3Ð6øøÝð Pð Pð PÝ—’ÐIÈ3ÑOÔOÐOÐOÐOÐOÐOÐOøøøøðPøøøàˆvs   ¢A
A. Á.
BÁ8BÂBr%   Fr$   r+   r&   r'   Úenv_varsÚuse_ptyc                 óô  — t          dt          j        ¦   «         j        dd…         › �||||pt	          j        ¦   «         t          j        ¦   «         ¬¦  «        }|�ri	 t          rddlm	} nddl
m	} t          ¦   «         }	t          t          j        |¦  «        }
d|
d<   |                     |	d	d
|› �g|j        |
d¬¦  «        }|j        |_        ||_        t%          j        | j        |fdd|j        › �¬¦  «        }||_        |                     ¦   «          | j        5  |                      ¦   «          || j        |j        <   ddd¦  «         n# 1 swxY w Y   |                      ¦   «          |S # t8          $ r t:                               d¦  «         Y n1t>          $ r%}t:                               d|¦  «         Y d}~nd}~ww xY wt          ¦   «         }	t          t          j        |¦  «        }d|d<   tA          j!        |	d	d
|› �gd|j        |ddt@          j"        t@          j#        t@          j"        t          rdnt          j$        ¬¦
  «
        }||_%        |j        |_        t%          j        | j&        |fdd|j        › �¬¦  «        }||_        |                     ¦   «          | j        5  |                      ¦   «          || j        |j        <   ddd¦  «         n# 1 swxY w Y   |                      ¦   «          |S )aw  
        Spawn a background process locally.

        Only for TERMINAL_ENV=local. Other backends use spawn_via_env().

        Args:
            use_pty: If True, use a pseudo-terminal via ptyprocess for interactive
                     CLI tools (Codex, Claude Code, Python REPL). Falls back to
                     subprocess.Popen if ptyprocess is not installed.
        Úproc_Né   )r#   r$   r&   r'   r+   r-   r   )Ú
PtyProcessÚ1ÚPYTHONUNBUFFEREDz-liczset +m; )r   éx   )r+   r¹   Ú
dimensionsTzproc-pty-reader-©ÚtargetÚargsÚdaemonÚnamez3ptyprocess not installed, falling back to pipe modez0PTY spawn failed (%s), falling back to pipe modeúutf-8Úreplace)	rm   r+   r¹   ÚencodingÚerrorsÚstdoutÚstderrÚstdinÚ
preexec_fnzproc-reader-)'r"   ÚuuidÚuuid4Úhexr¨   Úgetcwdr�   r²   ÚwinptyrÌ   Ú
ptyprocessr   r   ÚenvironÚspawnr+   r(   rI   rV   rX   Ú_pty_reader_loopr#   rH   ÚstartrG   Ú_prune_if_neededr]   Ú_write_checkpointÚImportErrorrÂ   ÚwarningrÁ   rP   rQ   ÚPIPEÚSTDOUTÚsetsidr)   Ú_reader_loop)rj   r$   r+   r&   r'   rÇ   rÈ   r{   Ú_PtyProcessClsÚ
user_shellÚpty_envÚpty_procÚreaderÚeÚbg_envÚprocs                   r   Úspawn_localzProcessRegistry.spawn_localË  sÑ  € õ& !Ø.•t”z‘|”|Ô'¨¨¨Ô,Ð.Ð.ØØØ#ØÐ"•r”y‘{”{Ý”y‘{”{ð
ñ 
ô 
ˆð ñ (	Vð&VÝð HØCÐCÐCÐCÐCÐCÐCàGÐGÐGÐGÐGÐGÝ(™]œ]�
Ý2µ2´:¸xÑHÔH�Ø.1�Ð*Ñ+Ø)×/Ò/Ø Ð)=°GÐ)=Ð)=Ð>ØœØØ(ð	 0ñ ô �ð 'œl�”à'�”õ #Ô)ØÔ0Ø!˜ØØ8¨G¬JÐ8Ð8ð	ñ ô �ð *0�Ô&Ø—’‘”�à”Zð 8ð 8Ø×)Ò)Ñ+Ô+Ð+Ø07�D”M '¤*Ñ-ð8ð 8ð 8ñ 8ô 8ð 8ð 8ð 8ð 8ð 8ð 8øøøð 8ð 8ð 8ð 8ð ×&Ò&Ñ(Ô(Ð(Ø�øåð Vð Vð VÝ—’ÐTÑUÔUÐUÐUÐUÝð Vð Vð VÝ—’ÐQÐSTÑUÔUÐUÐUÐUÐUÐUÐUøøøøðVøøøõ !‘]”]ˆ
õ *­"¬*°hÑ?Ô?ˆØ%(ˆÐ!Ñ"ÝÔØ˜Ð!5¨GÐ!5Ð!5Ð6ØØ”ØØØÝ”?ÝÔ$Ý”/Ý*Ð9�t�tµ´	ð
ñ 
ô 
ˆð ˆŒØ”hˆŒõ Ô!ØÔ$Ø�ØØ, ¤
Ð,Ð,ð	
ñ 
ô 
ˆð "(ˆÔØ�Š‰ŒˆàŒZð 	0ð 	0Ø×!Ò!Ñ#Ô#Ð#Ø(/ˆDŒM˜'œ*Ñ%ð	0ð 	0ð 	0ñ 	0ô 	0ð 	0ð 	0ð 	0ð 	0ð 	0ð 	0øøøð 	0ð 	0ð 	0ð 	0ð 	×ÒÑ Ô Ð ØˆsU   ÁC E0 Ä$EÅE0 ÅEÅE0 ÅEÅE0 Å0$GÆ	GÆF?Æ?GÊ)$KËKË Kr   Útimeoutc                 óÎ  — t          dt          j        ¦   «         j        dd…         › �||||t	          j        ¦   «         |d¬¦  «        }|                      |¦  «        }|› d|j        › d�}	|› d|j        › d�}
|› d|j        › d	�}t          j        |¦  «        }t          j        |¦  «        }t          j        |	¦  «        }t          j        |
¦  «        }t          j        |¦  «        }d
|› d|› d|› d|› d|› d|› �}	 | 	                    ||¬¦  «        }| 
                    dd¦  «                             ¦   «         }|                     ¦   «         D ]@}|                     ¦   «         }|                     ¦   «         rt          |¦  «        |_         nŒAn/# t           $ r"}d|_        d|_        d|› �|_        Y d}~nd}~ww xY w|j        sEt)          j        | j        |||	|
|fdd|j        › �¬¦  «        }||_        |                     ¦   «          | j        5  |                      ¦   «          || j        |j        <   ddd¦  «         n# 1 swxY w Y   |                      ¦   «          |S )a#  
        Spawn a background process through a non-local environment backend.

        For Docker/Singularity/Modal/Daytona/SSH: runs the command inside the sandbox
        using the environment's execute() interface. We wrap the command to
        capture the in-sandbox PID and redirect output to a log file inside
        the sandbox, then poll the log via subsequent execute() calls.

        This is less capable than local spawn (no live stdout pipe, no stdin),
        but it ensures the command runs in the correct sandbox context.
        rÊ   NrË   Úsandbox)r#   r$   r&   r'   r+   r-   r*   r4   z/hermes_bg_z.logz.pidz.exitz	mkdir -p z && ( nohup bash -lc z > z$ 2>&1; rc=$?; printf '%s\n' "$rc" > z ) & echo $! > z && cat ©rù   rŒ   r%   TéÿÿÿÿzFailed to start: zproc-poller-rÑ   )r"   rÞ   rß   rà   r�   rÆ   r#   ÚshlexÚquoteÚexecuteÚgetÚstripr�   Úisdigitr   r(   rÁ   r.   r/   r0   rV   rX   Ú_env_poller_looprH   rç   rG   rè   r]   ré   )rj   r¹   r$   r+   r&   r'   rù   r{   rÄ   Úlog_pathÚpid_pathÚ	exit_pathÚquoted_commandÚquoted_temp_dirÚquoted_log_pathÚquoted_pid_pathÚquoted_exit_pathÚ
bg_commandÚresultrŒ   r˜   rõ   rô   s                          r   Úspawn_via_envzProcessRegistry.spawn_via_env;  s.  € õ( !Ø.•t”z‘|”|Ô'¨¨¨Ô,Ð.Ð.ØØØ#ØÝ”y‘{”{ØØð	
ñ 	
ô 	
ˆð ×%Ò% cÑ*Ô*ˆØÐ;Ð;¨7¬:Ð;Ð;Ð;ˆØÐ;Ð;¨7¬:Ð;Ð;Ð;ˆØÐ=Ð=¨G¬JÐ=Ð=Ð=ˆ	Ýœ WÑ-Ô-ˆÝœ+ hÑ/Ô/ˆÝœ+ hÑ/Ô/ˆÝœ+ hÑ/Ô/ˆÝ œ; yÑ1Ô1ÐðD˜ð Dð DØ .ðDð DØ3BðDð Dà/?ðDð Dð )ðDð Dð 3BðDð Dð 	ð	<Ø—[’[ °W�[Ñ=Ô=ˆFØ—Z’Z ¨"Ñ-Ô-×3Ò3Ñ5Ô5ˆFà×)Ò)Ñ+Ô+ð ð �Ø—z’z‘|”|�Ø—<’<‘>”>ð Ý"% d¡)¤)�G”KØ�Eðøøõ ð 	<ð 	<ð 	<Ø!ˆGŒNØ "ˆGÔØ$;¸Ð$;Ð$;ˆGÔ!Ð!Ð!Ð!Ð!Ð!øøøøð	<øøøð
 Œ~ð 		åÔ%ØÔ,Ø˜s H¨h¸	ÐBØØ0 G¤JÐ0Ð0ð	ñ ô ˆFð &,ˆGÔ"Ø�LŠL‰NŒNˆNàŒZð 	0ð 	0Ø×!Ò!Ñ#Ô#Ð#Ø(/ˆDŒM˜'œ*Ñ%ð	0ð 	0ð 	0ñ 	0ô 	0ð 	0ð 	0ð 	0ð 	0ð 	0ð 	0øøøð 	0ð 	0ð 	0ð 	0ð 	×ÒÑ Ô Ð Øˆs+   Ã?BF Æ
G ÆF;Æ;G È$IÉI
ÉI
c                 óÞ  — d}	 	 |j         j                             d¦  «        }|sn–|r|                      |¦  «        }d}|j        5  |xj        |z  c_        t          |j        ¦  «        |j        k    r|j        |j         d…         |_        ddd¦  «         n# 1 swxY w Y   |                      ||¦  «         Œ¸n2# t          $ r%}t                               d|¦  «         Y d}~nd}~ww xY w	 |j                              d¬¦  «         n2# t          $ r%}t                               d|¦  «         Y d}~nd}~ww xY wd|_        |j         j        |_        |                      |¦  «         dS # 	 |j                              d¬¦  «         n2# t          $ r%}t                               d|¦  «         Y d}~nd}~ww xY wd|_        |j         j        |_        |                      |¦  «         w xY w)	z:Background thread: read stdout from a local Popen process.Té   FNzProcess stdout reader ended: %sé   rü   z$Process wait timed out or failed: %s)r)   rÚ   Úreadrz   rG   r0   r‘   r1   r�   rÁ   rÂ   rÃ   Úwaitr.   Ú
returncoder/   r¯   )rj   r{   Úfirst_chunkÚchunkrõ   s        r   rï   zProcessRegistry._reader_loop�  s¡  € àˆð	,ð;ØœÔ.×3Ò3°DÑ9Ô9�Øð ØØð (Ø ×3Ò3°EÑ:Ô:�EØ"'�KØ”]ð bð bØÐ)Ô)¨UÑ2Ð)Ô)Ý˜7Ô0Ñ1Ô1°GÔ4LÒLÐLØ07Ô0EÀwÔG_ÐF_ÐF`ÐF`Ô0a˜Ô-ðbð bð bñ bô bð bð bð bð bð bð bøøøð bð bð bð bð ×*Ò*¨7°EÑ:Ô:Ð:ð;ð øõ ð 	?ð 	?ð 	?Ý�LŠLÐ:¸AÑ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>øøøøð	?øøøðHØ”×$Ò$¨QÐ$Ñ/Ô/Ð/Ð/øÝð Hð Hð HÝ—’ÐCÀQÑGÔGÐGÐGÐGÐGÐGÐGøøøøðHøøøà!ˆGŒNØ '¤Ô :ˆGÔØ×"Ò" 7Ñ+Ô+Ð+Ð+Ð+øðHØ”×$Ò$¨QÐ$Ñ/Ô/Ð/Ð/øÝð Hð Hð HÝ—’ÐCÀQÑGÔGÐGÐGÐGÐGÐGÐGøøøøðHøøøà!ˆGŒNØ '¤Ô :ˆGÔØ×"Ò" 7Ñ+Ô+Ð+Ð+øøøs—   „AB> ÁABÂB> ÂBÂB> Â"BÂ#B> Â=E. Â>
C-ÃC(Ã#E. Ã(C-Ã-E. Ã1D Ä
D<ÄD7Ä7D<Å.G,Å0FÆG,Æ
F;ÆF6Æ1G,Æ6F;Æ;1G,r  r  r  c                 óN  — t          j        |¦  «        }t          j        |¦  «        }t          j        |¦  «        }d}	|j        �s^t          j        d¦  «         	 |                     d|› d�d¬¦  «        }
|
                     dd¦  «        }|r£t          |¦  «        |	k    r
||	d	…         nd}t          |¦  «        }	|j        5  ||_	        t          |j	        ¦  «        |j
        k    r|j	        |j
         d	…         |_	        d	d	d	¦  «         n# 1 swxY w Y   |r|                      ||¦  «         |                     d
|› d�d¬¦  «        }|                     dd¦  «                             ¦   «         }|rï|                     ¦   «         d                              ¦   «         dk    r¿|                     d|› d�d¬¦  «        }|                     dd¦  «                             ¦   «         }	 t          |                     ¦   «         d                              ¦   «         ¦  «        |_        n# t           t"          f$ r
 d|_        Y nw xY wd|_        |                      |¦  «         d	S n4# t&          $ r' d|_        d|_        |                      |¦  «         Y d	S w xY w|j        �¯\d	S d	S )zBBackground thread: poll a sandbox log file for non-local backends.r   é   zcat ú 2>/dev/nullr   rü   rŒ   r%   Nzkill -0 "$(cat z# 2>/dev/null)" 2>/dev/null; echo $?r  rý   Ú0T)rþ   rÿ   r.   r�   Úsleepr   r  r‘   rG   r0   r1   r�   r  r�   r   r/   Ú
ValueErrorÚ
IndexErrorr¯   rÁ   )rj   r{   r¹   r  r  r  r
  r  r  Úprev_output_lenr  Ú
new_outputÚdeltaÚcheckÚcheck_outputÚexit_resultÚexit_strs                    r   r  z ProcessRegistry._env_poller_loop©  s>  € õ  œ+ hÑ/Ô/ˆÝœ+ hÑ/Ô/ˆÝ œ; yÑ1Ô1ÐØˆØ”.ñ +	ÝŒJ�q‰MŒMˆMð)àŸšÐ%I¨OÐ%IÐ%IÐ%IÐSU˜ÑVÔV�Ø#ŸZšZ¨°"Ñ5Ô5�
Øð 	Cå<?À
¹O¼OÈoÒ<]Ð<]˜J Ð'7Ð'7Ô8Ð8Ðce�EÝ&)¨*¡o¤o�OØ œð fð fØ0:˜Ô-Ý˜wÔ4Ñ5Ô5¸Ô8PÒPÐPØ4;Ô4IÈ7ÔKcÐJcÐJdÐJdÔ4e˜GÔ1ðfð fð fñ fô fð fð fð fð fð fð føøøð fð fð fð fð ð CØ×2Ò2°7¸EÑBÔBÐBð ŸšØ\ Ð\Ð\Ð\Øð $ñ ô �ð  %Ÿyšy¨°2Ñ6Ô6×<Ò<Ñ>Ô>�Øð  L×$;Ò$;Ñ$=Ô$=¸bÔ$A×$GÒ$GÑ$IÔ$IÈSÒ$PÐ$Pà"%§+¢+Ø=Ð/Ð=Ð=Ð=Ø !ð #.ñ #ô #�Kð  +Ÿš¨x¸Ñ<Ô<×BÒBÑDÔD�Hð/Ý,/°×0CÒ0CÑ0EÔ0EÀbÔ0I×0OÒ0OÑ0QÔ0QÑ,RÔ,R˜Ô)Ð)øÝ&­
Ð3ð /ð /ð /Ø,.˜Ô)Ð)Ð)ð/øøøà%)�G”NØ×*Ò*¨7Ñ3Ô3Ð3Ø�Føøåð ð ð à!%�”Ø$&�Ô!Ø×&Ò& wÑ/Ô/Ð/Ø��ðøøøðM ”.ñ +	ð +	ð +	ð +	ð +	s\   ÁA(I' Ã?DÄI' ÄDÄI' ÄDÄCI' Ç+>H* È)I' È*IÉI' ÉIÉI' É'-JÊJc                 óŒ  — |j         }	 |                     ¦   «         rò	 |                     d¦  «        }|rªt          |t          ¦  «        r|n|                     dd¬¦  «        }|j        5  |xj        |z  c_        t          |j        ¦  «        |j	        k    r|j        |j	         d…         |_        ddd¦  «         n# 1 swxY w Y   |  
                    ||¦  «         n# t          $ r Y n#t          $ r Y nw xY w|                     ¦   «         °òn2# t          $ r%}t                               d|¦  «         Y d}~nd}~ww xY w	 |                     ¦   «          n2# t          $ r%}t                               d|¦  «         Y d}~nd}~ww xY wd|_        t#          |d	¦  «        r|j        nd
|_        |                      |¦  «         dS )z2Background thread: read output from a PTY process.r  rÖ   r×   )rÙ   NzPTY stdout reader ended: %sz PTY wait timed out or failed: %sTÚ
exitstatusrý   )rI   Úisaliver  r¿   rN   ÚdecoderG   r0   r‘   r1   r�   ÚEOFErrorrÁ   rÂ   rÃ   r  r.   Úhasattrr'  r/   r¯   )rj   r{   Úptyr  rm   rõ   s         r   ræ   z ProcessRegistry._pty_reader_loopÞ  s^  € àŒlˆð	;Ø—+’+‘-”-ð ðØŸHšH T™NœN�EØð Bå(2°5½#Ñ(>Ô(>Ðk˜u˜uÀEÇLÂLÐQXÐajÀLÑDkÔDk˜Ø$œ]ð jð jØ#Ð1Ô1°TÑ9Ð1Ô1Ý" 7Ô#8Ñ9Ô9¸GÔ<TÒTÐTØ8?Ô8MÈwÔOgÐNgÐNhÐNhÔ8i Ô 5ðjð jð jñ jô jð jð jð jð jð jð jøøøð jð jð jð jð ×2Ò2°7¸DÑAÔAÐAøøÝð ð ð Ø�EÝ ð ð ð Ø�Eðøøøð —+’+‘-”-ð øøõ ð 	;ð 	;ð 	;Ý�LŠLÐ6¸Ñ:Ô:Ð:Ð:Ð:Ð:Ð:Ð:øøøøð	;øøøð	@Ø�HŠH‰JŒJˆJˆJøÝð 	@ð 	@ð 	@Ý�LŠLÐ;¸QÑ?Ô?Ð?Ð?Ð?Ð?Ð?Ð?øøøøð	@øøøàˆŒÝ.5°c¸<Ñ.HÔ.HÐP˜CœN˜NÈbˆÔØ×Ò˜wÑ'Ô'Ð'Ð'Ð's„   ‰D žAC  Á*AB>Â2C  Â>CÃC  ÃCÃC  ÃD Ã 
C8Ã*D Ã,	C8Ã5D Ã7C8Ã8D Ä
D?ÄD:Ä:D?ÅE Å
FÅ"FÆFc                 ó”  — | j         5  | j                             |j        d¦  «        du}|| j        |j        <   ddd¦  «         n# 1 swxY w Y   |                      ¦   «          |r_|j        rZddlm} |j	        r ||j	        dd…         ¦  «        nd}| j
                             d|j        |j        |j        |dœ¦  «         dS dS dS )uú   Move a session from running to finished.

        Idempotent: if the session was already moved (e.g. kill_process raced
        with the reader thread), the second call is a no-op â€” no duplicate
        completion notification is enqueued.
        Nr   ©Ú
strip_ansié0øÿÿr%   Ú
completion)r�   r€   r$   r/   rŒ   )rG   r]   rx   r#   r^   ré   r;   Útools.ansi_stripr/  r0   rb   r”   r$   r/   )rj   r{   Úwas_runningr/  Úoutput_tails        r   r¯   z!ProcessRegistry._move_to_finishedý  sI  € ð ŒZð 	1ð 	1Øœ-×+Ò+¨G¬J¸Ñ=Ô=ÀTÐIˆKØ)0ˆDŒN˜7œ:Ñ&ð	1ð 	1ð 	1ñ 	1ô 	1ð 	1ð 	1ð 	1ð 	1ð 	1ð 	1øøøð 	1ð 	1ð 	1ð 	1ð 	×ÒÑ Ô Ð ð
 ð 		˜7Ô5ð 		Ø3Ð3Ð3Ð3Ð3Ð3ØGNÔG\Ðd˜*˜* WÔ%:¸5¸6¸6Ô%BÑCÔCÐCÐbdˆKØÔ!×%Ò%Ø$Ø%œjØ"œ?Ø$Ô.Ø%ð'ð 'ñ ô ð ð ð ð		ð 		ð 		ð 		s   ˆ2AÁA
ÁA
r€   c                 ó   — || j         v S )zJCheck if a completion notification was already consumed via wait/poll/log.)rd   )rj   r€   s     r   Úis_completion_consumedz&ProcessRegistry.is_completion_consumed  s   € à˜TÔ6Ð6Ð6r    c                 óÒ   — | j         5  | j                             |¦  «        p| j                             |¦  «        }ddd¦  «         n# 1 swxY w Y   |                      |¦  «        S )z*Get a session by ID (running or finished).N)rG   r]   r  r^   r°   )rj   r€   r{   s      r   r  zProcessRegistry.get  s®   € àŒZð 	Vð 	VØ”m×'Ò'¨
Ñ3Ô3ÐU°t´~×7IÒ7IÈ*Ñ7UÔ7UˆGð	Vð 	Vð 	Vñ 	Vô 	Vð 	Vð 	Vð 	Vð 	Vð 	Vð 	Vøøøð 	Vð 	Vð 	Vð 	Và×-Ò-¨gÑ6Ô6Ð6s   ˆ5A	Á	AÁAc                 óÖ  — ddl m} |                      |¦  «        }|€dd|› �dœS |j        5  |j        r ||j        dd…         ¦  «        nd}ddd¦  «         n# 1 swxY w Y   |j        |j        |j        rd	nd
|j        t          t          j
        ¦   «         |j        z
  ¦  «        |dœ}|j        r$|j        |d<   | j                             |¦  «         |j        r
d|d<   d|d<   |S )z9Check status and get new output for a background process.r   r.  NÚ	not_foundúNo process with ID ©ÚstatusÚerroréüÿÿr%   r.   Úrunning)r€   r$   r<  r(   Úuptime_secondsÚoutput_previewr/   Tr2   z=Process recovered after restart -- output history unavailableÚnote)r2  r/  r  rG   r0   r#   r$   r.   r(   r   r�   r-   r/   rd   Úaddr2   )rj   r€   r/  r{   rA  r  s         r   ÚpollzProcessRegistry.poll#  ss  € à/Ð/Ð/Ð/Ð/Ð/à—(’(˜:Ñ&Ô&ˆØˆ?Ø)Ð4VÈ*Ð4VÐ4VÐWÐWÐWàŒ]ð 	hð 	hØJQÔJ_Ðg˜Z˜Z¨Ô(=¸e¸f¸fÔ(EÑFÔFÐFÐegˆNð	hð 	hð 	hñ 	hô 	hð 	hð 	hð 	hð 	hð 	hð 	høøøð 	hð 	hð 	hð 	hð "œ*Ø”Ø")¤.Ð?�h�h°iØ”;Ý!¥$¤)¡+¤+°Ô0BÑ"BÑCÔCØ,ð
ð 
ˆð Œ>ð 	6Ø")Ô"3ˆF�;ÑØÔ%×)Ò)¨*Ñ5Ô5Ð5ØÔð 	]Ø!%ˆF�:ÑØ\ˆF�6‰NØˆs   ­"AÁAÁ"Ar   éÈ   ÚoffsetÚlimitc                 óò  — ddl m} |                      |¦  «        }|€dd|› �dœS |j        5   ||j        ¦  «        }ddd¦  «         n# 1 swxY w Y   |                     ¦   «         }t          |¦  «        }|dk    r|dk    r|| d…         }	n||||z   …         }	|j        |j        rdndd	 	                    |	¦  «        |t          |	¦  «        › d
�dœ}
|j        r| j
                             |¦  «         |
S )z;Read the full output log with optional pagination by lines.r   r.  Nr9  r:  r;  r.   r?  ro   z lines)r€   r<  rŒ   Útotal_linesÚshowing)r2  r/  r  rG   r0   r�   r‘   r#   r.   ry   rd   rC  )rj   r€   rF  rG  r/  r{   Úfull_outputrs   rI  Úselectedr  s              r   Úread_logzProcessRegistry.read_log>  sr  € à/Ð/Ð/Ð/Ð/Ð/à—(’(˜:Ñ&Ô&ˆØˆ?Ø)Ð4VÈ*Ð4VÐ4VÐWÐWÐWàŒ]ð 	<ð 	<Ø$˜* WÔ%:Ñ;Ô;ˆKð	<ð 	<ð 	<ñ 	<ô 	<ð 	<ð 	<ð 	<ð 	<ð 	<ð 	<øøøð 	<ð 	<ð 	<ð 	<ð ×&Ò&Ñ(Ô(ˆÝ˜%‘j”jˆð �QŠ;ˆ;˜5 1š9˜9Ø˜e˜V˜W˜W”~ˆHˆHà˜V F¨U¡NÐ2Ô3ˆHð "œ*Ø")¤.Ð?�h�h°iØ—i’i Ñ)Ô)Ø&Ý˜h™-œ-Ð/Ð/Ð/ð
ð 
ˆð Œ>ð 	6ØÔ%×)Ò)¨*Ñ5Ô5Ð5Øˆs   ­A
Á
AÁAc                 ó8  — ddl m} ddlm} 	 t	          t          j        dd¦  «        ¦  «        }n# t          t          f$ r d}Y nw xY w|}|}d}|r||k    r|}	d|› d	|› d
�}n|p|}	|  	                    |¦  «        }
|
€dd|› �dœS t          j        ¦   «         |	z   }t          j        ¦   «         |k     rº|                      |
¦  «        }
|
j        rD| j                             |¦  «         d|
j         ||
j        dd…         ¦  «        dœ}|r||d<   |S  |¦   «         r%d ||
j        dd…         ¦  «        ddœ}|r||d<   |S t          j        d¦  «         t          j        ¦   «         |k     °ºd ||
j        dd…         ¦  «        dœ}|r||d<   n	d|	› d�|d<   |S )aY  
        Block until a process exits, timeout, or interrupt.

        Args:
            session_id: The process to wait for.
            timeout: Max seconds to block. Falls back to TERMINAL_TIMEOUT config.

        Returns:
            dict with status ("exited", "timeout", "interrupted", "not_found")
            and output snapshot.
        r   r.  )Úis_interruptedÚTERMINAL_TIMEOUTÚ180é´   NzRequested wait of z%s was clamped to configured limit of r   r9  r:  r;  r.   r0  )r<  r/   rŒ   Útimeout_noteÚinterruptedr>  z+User sent a new message -- wait interrupted)r<  rŒ   rB  r~   rù   )r<  rŒ   zWaited zs, process still running)r2  r/  Útools.interruptrO  r   r¨   Úgetenvr  Ú	TypeErrorr  r�   Ú	monotonicr°   r.   rd   rC  r/   r0   r  )rj   r€   rù   r/  Ú_is_interruptedÚdefault_timeoutÚmax_timeoutÚrequested_timeoutrS  Úeffective_timeoutr{   Údeadliner  s                r   r  zProcessRegistry.wait]  su  € ð 	0Ð/Ð/Ð/Ð/Ð/ØEÐEÐEÐEÐEÐEð	"Ý!¥"¤)Ð,>ÀÑ"FÔ"FÑGÔGˆOˆOøÝ�IÐ&ð 	"ð 	"ð 	"Ø!ˆOˆOˆOð	"øøøà%ˆØ#ÐØˆàð 	AÐ!2°[Ò!@Ð!@Ø +Ðð9Ð%6ð 9ð 9Ø*5ð9ð 9ð 9ð ˆLð
 !2Ð @°[Ðà—(’(˜:Ñ&Ô&ˆØˆ?Ø)Ð4VÈ*Ð4VÐ4VÐWÐWÐWå”>Ñ#Ô#Ð&7Ñ7ˆåŒnÑÔ Ò)Ð)Ø×4Ò4°WÑ=Ô=ˆGØŒ~ð 	ØÔ)×-Ò-¨jÑ9Ô9Ð9à&Ø!(Ô!2Ø(˜j¨Ô)>¸u¸v¸vÔ)FÑGÔGðð �ð
  ð :Ø-9�F˜>Ñ*Ø�àˆÑ Ô ð à+Ø(˜j¨Ô)>¸u¸v¸vÔ)FÑGÔGØIðð �ð
  ð :Ø-9�F˜>Ñ*Ø�åŒJ�q‰MŒMˆMõ/ ŒnÑÔ Ò)Ð)ð4  Ø �j Ô!6°u°v°vÔ!>Ñ?Ô?ð
ð 
ˆð ð 	[Ø%1ˆF�>Ñ"Ð"à%ZÐ/@Ð%ZÐ%ZÐ%ZˆF�>Ñ"Øˆs   Ž"1 ±AÁAc                 óÌ  — |                       |¦  «        }|€dd|› �dœS |j        r
d|j        dœS 	 |j        rZ	 |j                             d¬¦  «         �n¥# t
          $ r/ |j        r$t          j        |j        t          j
        ¦  «         Y �nmw xY w|j        r�	 t          r|j                             ¦   «          n;t          j        t          j        |j        j        ¦  «        t          j
        ¦  «         �n# t          t           f$ r |j                             ¦   «          Y n×w xY w|j        r-|j        r&|j                             d	|j        › d
�d¬¦  «         nŸ|j        r“|j        dk    rˆ|j        r�|                      |j        ¦  «        sL|j        5  d|_        d|_        ddd¦  «         n# 1 swxY w Y   |                      |¦  «         d|j        dœS |                      |j        ¦  «         ndddœS d|_        d|_        |                      |¦  «         |                      ¦   «          d|j        dœS # t
          $ r}dt7          |¦  «        dœcY d}~S d}~ww xY w)zKill a background process.Nr9  r:  r;  Úalready_exited)r<  r/   T)Úforcezkill r  r  rü   r3   r=  zkRecovered process cannot be killed after restart because its original runtime handle is no longer availableiñÿÿÿÚkilled)r<  r€   )r  r.   r/   rI   Ú	terminaterÁ   r(   r¨   r©   r³   r´   r)   r²   rµ   r¶   rª   r«   r*   r   r2   r4   r­   rG   r¯   r¸   ré   r#   rN   ©rj   r€   r{   rõ   s       r   Úkill_processzProcessRegistry.kill_process¦  s  € à—(’(˜:Ñ&Ô&ˆØˆ?Ø)Ð4VÈ*Ð4VÐ4VÐWÐWÐWàŒ>ð 	à*Ø$Ô.ðð ð ð-	8ØŒ|ð %ð=Ø”L×*Ò*°Ð*Ñ6Ô6Ð6Ñ6øÝ ð =ð =ð =Ø”{ð =Ýœ ¤­V¬^Ñ<Ô<Ð<øùð=øøøð ”ð ð+Ý"ð SØœ×1Ò1Ñ3Ô3Ð3Ð3åœ	¥"¤*¨W¬_Ô-@Ñ"AÔ"AÅ6Ä>ÑRÔRÐRùøÝ*­OÐ<ð +ð +ð +Ø”O×(Ò(Ñ*Ô*Ð*Ð*Ð*ð+øøøà”ð  W¤[ð à”×'Ò'Ð(I°´Ð(IÐ(IÐ(IÐSTÐ'ÑUÔUÐUÐUØÔ!ð  gÔ&7¸6Ò&AÐ&AÀgÄkÐ&AØ×.Ò.¨w¬{Ñ;Ô;ð Ø œð 1ð 1Ø)-˜œØ,0˜Ô)ð1ð 1ð 1ñ 1ô 1ð 1ð 1ð 1ð 1ð 1ð 1øøøð 1ð 1ð 1ð 1ð ×*Ò*¨7Ñ3Ô3Ð3à"2Ø%,Ô%6ðð ð ð ×(Ò(¨¬Ñ5Ô5Ð5Ð5ð &ðMðð ð ð "ˆGŒNØ #ˆGÔØ×"Ò" 7Ñ+Ô+Ð+Ø×"Ò"Ñ$Ô$Ð$Ø&°g´jÐAÐAÐAøÝð 	8ð 	8ð 	8Ø%µ°A±´Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7øøøøð	8øøøs—   ²H= ºA ÁH= Á5BÂH= ÂBÂ
H= ÂAC9 Ã7H= Ã9*D&Ä#H= Ä%D&Ä&A1H= ÆF2Æ&H= Æ2F6Æ6H= Æ9F6Æ:!H= ÇH= Ç<A H= È=
I#ÉIÉI#ÉI#Údatac                 ó¬  — |                       |¦  «        }|€dd|› �dœS |j        rdddœS t          |d¦  «        r‰|j        r‚	 t	          |t
          ¦  «        r|                     d¦  «        n|}|j                             |¦  «         d	t          |¦  «        d
œS # t          $ r}dt          |¦  «        dœcY d}~S d}~ww xY w|j
        r|j
        j        sdddœS 	 |j
        j                             |¦  «         |j
        j                             ¦   «          d	t          |¦  «        d
œS # t          $ r}dt          |¦  «        dœcY d}~S d}~ww xY w)zASend raw data to a running process's stdin (no newline appended).Nr9  r:  r;  r`  úProcess has already finishedrI   rÖ   Úok)r<  Úbytes_writtenr=  ú?Process stdin not available (non-local backend or stdin closed))r  r.   r+  rI   r¿   rN   ÚencodeÚwriter‘   rÁ   r)   rÜ   Úflush)rj   r€   rf  r{   Úpty_datarõ   s         r   Úwrite_stdinzProcessRegistry.write_stdinâ  s°  € à—(’(˜:Ñ&Ô&ˆØˆ?Ø)Ð4VÈ*Ð4VÐ4VÐWÐWÐWØŒ>ð 	YØ.Ð9WÐXÐXÐXõ �7˜FÑ#Ô#ð 	<¨¬ð 	<ð<Ý3=¸dÅCÑ3HÔ3HÐR˜4Ÿ;š; wÑ/Ô/Ð/Èd�Ø”×"Ò" 8Ñ,Ô,Ð,Ø"&½¸T¹¼ÐCÐCÐCøÝð <ð <ð <Ø")µC¸±F´FÐ;Ð;Ð;Ð;Ð;Ð;Ð;Ð;øøøøð<øøøð Œð 	s g¤oÔ&;ð 	sØ%Ð0qÐrÐrÐrð	8ØŒOÔ!×'Ò'¨Ñ-Ô-Ð-ØŒOÔ!×'Ò'Ñ)Ô)Ð)Ø"µS¸±Y´YÐ?Ð?Ð?øÝð 	8ð 	8ð 	8Ø%µ°A±´Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7øøøøð	8øøøs>   ÁAB Â
CÂ&B=Â7CÂ=CÃAD- Ä-
EÄ7EÅEÅEc                 ó4   — |                       ||dz   ¦  «        S )zGSend data + newline to a running process's stdin (like pressing Enter).ro   )rp  )rj   r€   rf  s      r   Úsubmit_stdinzProcessRegistry.submit_stdiný  s   € à×Ò 
¨D°4©KÑ8Ô8Ð8r    c                 óà  — |                       |¦  «        }|€dd|› �dœS |j        rdddœS t          |d¦  «        rO|j        rH	 |j                             ¦   «          dd	d
œS # t
          $ r}dt          |¦  «        dœcY d}~S d}~ww xY w|j        r|j        j        sdddœS 	 |j        j         	                    ¦   «          ddd
œS # t
          $ r}dt          |¦  «        dœcY d}~S d}~ww xY w)zGClose a running process's stdin / send EOF without killing the process.Nr9  r:  r;  r`  rh  rI   ri  zEOF sent)r<  rˆ   r=  rk  zstdin closed)
r  r.   r+  rI   ÚsendeofrÁ   rN   r)   rÜ   Úcloserd  s       r   Úclose_stdinzProcessRegistry.close_stdin  sb  € à—(’(˜:Ñ&Ô&ˆØˆ?Ø)Ð4VÈ*Ð4VÐ4VÐWÐWÐWØŒ>ð 	YØ.Ð9WÐXÐXÐXå�7˜FÑ#Ô#ð 	<¨¬ð 	<ð<Ø”×$Ò$Ñ&Ô&Ð&Ø"&°:Ð>Ð>Ð>øÝð <ð <ð <Ø")µC¸±F´FÐ;Ð;Ð;Ð;Ð;Ð;Ð;Ð;øøøøð<øøøð Œð 	s g¤oÔ&;ð 	sØ%Ð0qÐrÐrÐrð	8ØŒOÔ!×'Ò'Ñ)Ô)Ð)Ø"¨~Ð>Ð>Ð>øÝð 	8ð 	8ð 	8Ø%µ°A±´Ð7Ð7Ð7Ð7Ð7Ð7Ð7Ð7øøøøð	8øøøs<   ÁA" Á"
BÁ,BÁ=BÂBÂ$"C Ã
C-ÃC(Ã"C-Ã(C-c                 ó¼  ‡ ‡— ‰ j         5  t          ‰ j                             ¦   «         ¦  «        t          ‰ j                             ¦   «         ¦  «        z   }ddd¦  «         n# 1 swxY w Y   ˆ fd„|D ¦   «         }‰rˆfd„|D ¦   «         }g }|D ]Ê}|j        |j        dd…         |j        |j        t          j
        dt          j        |j        ¦  «        ¦  «        t          t          j	        ¦   «         |j        z
  ¦  «        |j        rdnd|j        r|j        dd…         nd	d
œ}|j        r
|j        |d<   |j        rd|d<   |                     |¦  «         ŒË|S )z1List all running and recently-finished processes.Nc                 ó:   •— g | ]}‰                      |¦  «        ‘ŒS rY   )r°   )rq   r   rj   s     €r   ú
<listcomp>z1ProcessRegistry.list_sessions.<locals>.<listcomp>  s'   ø€ ÐPÐPÐP¸a˜×6Ò6°qÑ9Ô9ÐPÐPÐPr    c                 ó*   •— g | ]}|j         ‰k    ¯|‘ŒS rY   ©r&   ©rq   r   r&   s     €r   ry  z1ProcessRegistry.list_sessions.<locals>.<listcomp>   s%   ø€ ÐLÐLÐL !°q´yÀGÒ7KÐ7K˜AÐ7KÐ7KÐ7Kr    rE  z%Y-%m-%dT%H:%M:%Sr.   r?  i8ÿÿÿr%   )r€   r$   r+   r(   r-   r@  r<  rA  r/   Tr2   )rG   rU   r]   Úvaluesr^   r#   r$   r+   r(   r�   ÚstrftimeÚ	localtimer-   r   r.   r0   r/   r2   rŽ   )rj   r&   Úall_sessionsr  r   Úentrys   ``    r   Úlist_sessionszProcessRegistry.list_sessions  sÇ  øø€ àŒZð 	Xð 	XÝ ¤× 4Ò 4Ñ 6Ô 6Ñ7Ô7½$¸t¼~×?TÒ?TÑ?VÔ?VÑ:WÔ:WÑWˆLð	Xð 	Xð 	Xñ 	Xô 	Xð 	Xð 	Xð 	Xð 	Xð 	Xð 	Xøøøð 	Xð 	Xð 	Xð 	Xð QÐPÐPÐPÀ<ÐPÑPÔPˆàð 	MØLÐLÐLÐL |ÐLÑLÔLˆLàˆØð 	!ð 	!ˆAàœdØœ9 T c Tœ?Ø”uØ”uÝ"œmÐ,?ÅÄÐPQÔP\ÑA]ÔA]Ñ^Ô^Ý"%¥d¤i¡k¤k°A´LÑ&@Ñ"AÔ"AØ&'¤hÐ=˜(˜(°IØ<=¼OÐ"S !¤/°$°%°%Ô"8Ð"8ÐQSð	ð 	ˆEð Œxð 1Ø%&¤[��kÑ"ØŒzð )Ø$(��jÑ!Ø�MŠM˜%Ñ Ô Ð Ð Øˆs   ŠAA$Á$A(Á+A(c                 óh  ‡— | j         5  t          | j                             ¦   «         ¦  «        }ddd¦  «         n# 1 swxY w Y   |D ]}|                      |¦  «         Œ| j         5  t          ˆfd„| j                             ¦   «         D ¦   «         ¦  «        cddd¦  «         S # 1 swxY w Y   dS )z<Check if there are active (running) processes for a task_id.Nc              3   ó>   •K  — | ]}|j         ‰k    o|j         V — Œd S ©N©r&   r.   r|  s     €r   rt   z7ProcessRegistry.has_active_processes.<locals>.<genexpr>@  sG   øè è € ð ð àð ”	˜WÒ$Ð5¨Q¬X¨ðð ð ð ð ð r    ©rG   rU   r]   r}  r°   rv   )rj   r&   Úsessionsr{   s    `  r   Úhas_active_processesz$ProcessRegistry.has_active_processes7  óP  ø€ àŒZð 	4ð 	4Ý˜DœM×0Ò0Ñ2Ô2Ñ3Ô3ˆHð	4ð 	4ð 	4ñ 	4ô 	4ð 	4ð 	4ð 	4ð 	4ð 	4ð 	4øøøð 	4ð 	4ð 	4ð 	4ð  ð 	4ð 	4ˆGØ×*Ò*¨7Ñ3Ô3Ð3Ð3àŒZð 	ð 	Ýð ð ð ð àœ×-Ò-Ñ/Ô/ðñ ô ñ ô ð	ð 	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	ó!   ‰'<¼A ÁA Á(2B'Â'B+Â.B+c                 óh  ‡— | j         5  t          | j                             ¦   «         ¦  «        }ddd¦  «         n# 1 swxY w Y   |D ]}|                      |¦  «         Œ| j         5  t          ˆfd„| j                             ¦   «         D ¦   «         ¦  «        cddd¦  «         S # 1 swxY w Y   dS )z>Check if there are active processes for a gateway session key.Nc              3   ó>   •K  — | ]}|j         ‰k    o|j         V — Œd S r…  )r'   r.   )rq   r   r'   s     €r   rt   z9ProcessRegistry.has_active_for_session.<locals>.<genexpr>N  sG   øè è € ð ð àð ” Ò,Ð=°Q´X°ðð ð ð ð ð r    r‡  )rj   r'   rˆ  r{   s    `  r   Úhas_active_for_sessionz&ProcessRegistry.has_active_for_sessionE  rŠ  r‹  c                 ó
  ‡— | j         5  ˆfd„| j                             ¦   «         D ¦   «         }ddd¦  «         n# 1 swxY w Y   d}|D ]8}|                      |j        ¦  «        }|                     d¦  «        dv r|dz  }Œ9|S )zQKill all running processes, optionally filtered by task_id. Returns count killed.c                 ó<   •— g | ]}‰�|j         ‰k    ¯|j        °|‘ŒS r…  r†  r|  s     €r   ry  z,ProcessRegistry.kill_all.<locals>.<listcomp>V  s;   ø€ ð ð ð ØØ�O q¤y°GÒ';Ð';ÀQÄXÐ';ð Ø';Ð';Ð';r    Nr   r<  )rb  r`  r~   )rG   r]   r}  re  r#   r  )rj   r&   Útargetsrb  r{   r  s    `    r   Úkill_allzProcessRegistry.kill_allS  sè   ø€ àŒZð 	ð 	ðð ð ð Øœ=×/Ò/Ñ1Ô1ðñ ô ˆGð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð ˆØð 	ð 	ˆGØ×&Ò& w¤zÑ2Ô2ˆFØ�zŠz˜(Ñ#Ô#Ð'CÐCÐCØ˜!‘�øØˆs   ‰&;»?Á?c                 óV  ‡ ‡— t          j         ¦   «         Šˆfd„‰ j                             ¦   «         D ¦   «         }|D ]$}‰ j        |= ‰ j                             |¦  «         Œ%t          ‰ j        ¦  «        t          ‰ j        ¦  «        z   }|t          k    rB‰ j        r;t          ‰ j        ˆ fd„¬¦  «        }‰ j        |= ‰ j                             |¦  «         ‰ j         	                    ¦   «         ‰ j         	                    ¦   «         z  }‰ j        |z
  }|r‰ xj        |z  c_        dS dS )zGRemove oldest finished sessions if over MAX_PROCESSES. Must hold _lock.c                 ó@   •— g | ]\  }}‰|j         z
  t          k    ¯|‘ŒS rY   )r-   ÚFINISHED_TTL_SECONDS)rq   Úsidr   rš   s      €r   ry  z4ProcessRegistry._prune_if_needed.<locals>.<listcomp>h  s:   ø€ ð 
ð 
ð 
Ù�C˜Ø�a”lÑ"Õ&:Ò:Ð:ð Ø:Ð:Ð:r    c                 ó(   •— ‰j         |          j        S r…  )r^   r-   )r–  rj   s    €r   ú<lambda>z2ProcessRegistry._prune_if_needed.<locals>.<lambda>s  s   ø€ ¸D¼NÈ3Ô<OÔ<Z€ r    )ÚkeyN)
r�   r^   Úitemsrd   Údiscardr‘   r]   ÚMAX_PROCESSESÚminÚkeys)rj   Úexpiredr–  ÚtotalÚ	oldest_idÚtrackedÚstalerš   s   `      @r   rè   z ProcessRegistry._prune_if_neededd  sN  øø€ õ Œi‰kŒkˆð
ð 
ð 
ð 
Ø"œn×2Ò2Ñ4Ô4ð
ñ 
ô 
ˆð ð 	3ð 	3ˆCØ”˜sÐ#ØÔ%×-Ò-¨cÑ2Ô2Ð2Ð2õ �D”MÑ"Ô"¥S¨¬Ñ%8Ô%8Ñ8ˆØ•MÒ!Ð! d¤nÐ!Ý˜DœNÐ0ZÐ0ZÐ0ZÐ0ZÐ[Ñ[Ô[ˆIØ”˜yÐ)ØÔ%×-Ò-¨iÑ8Ô8Ð8ð
 ”-×$Ò$Ñ&Ô&¨¬×)<Ò)<Ñ)>Ô)>Ñ>ˆØÔ)¨GÑ3ˆØð 	/ØÐ%Ô%¨Ñ.Ð%Ô%Ð%Ð%ð	/ð 	/r    c                 óT  — 	 | j         5  g }| j                             ¦   «         D ]ž}|j        s•|                     i d|j        “d|j        “d|j        “d|j        “d|j	        “d|j
        “d|j        “d|j        “d	|j        “d
|j        “d|j        “d|j        “d|j        “d|j        “d|j        “d|j        “¦  «         ŒŸ	 ddd¦  «         n# 1 swxY w Y   ddlm}  |t.          |¦  «         dS # t0          $ r(}t2                               d|d¬¦  «         Y d}~dS d}~ww xY w)z=Write running process metadata to checkpoint file atomically.r€   r$   r(   r4   r+   r-   r&   r'   r5   r6   r7   r8   r9   r:   r;   r=   Nr   )Úatomic_json_writez#Failed to write checkpoint file: %sT)Úexc_info)rG   r]   r}  r.   rŽ   r#   r$   r(   r4   r+   r-   r&   r'   r5   r6   r7   r8   r9   r:   r;   r=   Úutilsr¥  ÚCHECKPOINT_PATHrÁ   rÂ   rÃ   )rj   Úentriesr   r¥  rõ   s        r   ré   z!ProcessRegistry._write_checkpoint�  s  € ð	RØ”ð ð Ø�Øœ×-Ò-Ñ/Ô/ð ð �AØœ8ð ØŸšð (Ø(¨!¬$ð(à% q¤yð(ð " 1¤5ð(ð (¨¬ð	(ð
 " 1¤5ð(ð )¨!¬,ð(ð & q¤yð(ð *¨1¬=ð(ð /°Ô0Bð(ð .¨qÔ/@ð(ð .¨qÔ/@ð(ð 0°Ô1Dð(ð 0°Ô1Dð(ð /°Ô0Bð(ð 1°!Ô2Fð(ð  -¨aÔ.>ð!(ñ ô ð øððð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð0 0Ð/Ð/Ð/Ð/Ð/ØÐ�o¨wÑ7Ô7Ð7Ð7Ð7øÝð 	Rð 	Rð 	RÝ�LŠLÐ>ÀÈDˆLÑQÔQÐQÐQÐQÐQÐQÐQÐQøøøøð	Røøøs;   ‚C5 ‰B;CÃC5 ÃCÃC5 ÃCÃC5 Ã5
D'Ã?D"Ä"D'c                 ó   — t                                ¦   «         sdS 	 t          j        t                                d¬¦  «        ¦  «        }n# t
          $ r Y dS w xY wd}|D �]˜}|                     d¦  «        }|sŒ|                     dd¦  «        }|dk    r:t                               d|                     dd	¦  «        d
d…         ||¦  «         Œq|  	                    |¦  «        }|�rt          d!i d|d         “d|                     dd	¦  «        “d|                     dd¦  «        “d|                     dd¦  «        “d|“d|“d|                     d¦  «        “d|                     dt          j        ¦   «         ¦  «        “dd“d|                     dd¦  «        “d|                     dd¦  «        “d|                     dd¦  «        “d|                     dd¦  «        “d|                     dd¦  «        “d|                     dd¦  «        “d|                     dd¦  «        “d|                     dg ¦  «        “Ž}| j        5  || j        |j        <   d
d
d
¦  «         n# 1 swxY w Y   |dz  }t                               d|j        d
d…         |¦  «         |j        dk    rQ| j                             |j        |j        |j        |j        |j        |j        |j        |j        |j        d œ	¦  «         �Œš|                      ¦   «          |S )"z†
        On gateway startup, probe PIDs from checkpoint file.

        Returns the number of processes recovered as detached.
        r   rÖ   )rØ   r(   r4   r3   z=Skipping recovery for non-host process: %s (pid=%s, scope=%s)r$   ÚunknownNr   r#   r€   r&   r%   r'   r+   r-   r2   Tr5   r6   r7   r8   r9   r:   r;   Fr=   r~   z'Recovered detached process: %s (pid=%d))	r€   Úcheck_intervalr'   rƒ   r„   r…   r†   r‡   r;   rY   )r¨  ÚexistsÚjsonÚloadsÚ	read_textrÁ   r  rÂ   Úinfor­   r"   r�   rG   r]   r#   r$   r:   r_   rŽ   r'   r5   r6   r7   r8   r9   r;   ré   )rj   r©  Ú	recoveredr�  r(   r4   Úaliver{   s           r   Úrecover_from_checkpointz'ProcessRegistry.recover_from_checkpoint¡  så  € õ ×%Ò%Ñ'Ô'ð 	Ø�1ð	Ý”j¥×!:Ò!:ÀGÐ!:Ñ!LÔ!LÑMÔMˆGˆGøÝð 	ð 	ð 	Ø�1�1ð	øøøð ˆ	Øð :	ñ :	ˆEØ—)’)˜EÑ"Ô"ˆCØð ØàŸ	š	 +¨vÑ6Ô6ˆIØ˜FÒ"Ð"õ —’ØSØ—I’I˜i¨Ñ3Ô3°C°R°CÔ8ØØñ	ô ð ð ð ×+Ò+¨CÑ0Ô0ˆEàñ %Ý(ð ð ð Ø˜\Ô*Ð*ðà!ŸIšI i°Ñ;Ô;Ð;ðð "ŸIšI i°Ñ4Ô4Ð4ðð !&§	¢	¨-¸Ñ <Ô <Ð <ð	ð
 ˜ðð (˜iðð Ÿ	š	 %Ñ(Ô(Ð(ðð  %Ÿyšy¨µt´y±{´{ÑCÔCÐCðð "˜Tðð &+§Y¢YÐ/AÀ2Ñ%FÔ%FÐ%Fðð %*§I¢IÐ.?ÀÑ$DÔ$DÐ$Dðð %*§I¢IÐ.?ÀÑ$DÔ$DÐ$Dðð ',§i¢iÐ0CÀRÑ&HÔ&HÐ&Hðð ',§i¢iÐ0CÀRÑ&HÔ&HÐ&Hðð &+§Y¢YÐ/AÀ1Ñ%EÔ%EÐ%Eðð  (-§y¢yÐ1EÀuÑ'MÔ'MÐ'Mð!ð" $)§9¢9Ð-=¸rÑ#BÔ#BÐ#Bð#�ð& ”Zð 8ð 8Ø07�D”M '¤*Ñ-ð8ð 8ð 8ñ 8ô 8ð 8ð 8ð 8ð 8ð 8ð 8øøøð 8ð 8ð 8ð 8à˜Q‘�	Ý—’ÐEÀwÄÐWZÐXZÐWZÔG[Ð]`ÑaÔaÐað Ô+¨aÒ/Ð/ØÔ)×0Ò0Ø&-¤jØ*1Ô*BØ'.Ô':Ø$+Ô$<Ø#*Ô#:Ø#*Ô#:Ø%,Ô%>Ø%,Ô%>Ø.5Ô.Hð
2ð 
2ñ 
ô 
ð 
ùð 	×ÒÑ Ô Ð àÐs#   �-A Á
AÁAÉI#É#I'	É*I'	)Nr%   r%   NF)Nr%   r%   r   )r   rE  r…  )r%   )-rJ   rK   rL   rM   rw   rl   ÚstaticmethodrN   rz   r"   r�   rR   rS   r•   r   r   r­   r°   r¸   r   rÆ   Údictrø   r  rï   r  ræ   r¯   r6  r  rD  rM  r  re  rp  rr  rv  rU   r‚  r‰  rŽ  r’  rè   ré   r´  rY   r    r   r[   r[   ‡   sB  € € € € € ðð ðÐð;ð ;ð ;ð8 ð  ð  ¨ð  ð  ð  ñ „\ð ð|¨^ð |Àsð |Ètð |ð |ð |ð |ð|U uð U°ð Uð Uð Uð Uðn ð ¨¤ð °$ð ð ð ñ „\ðð°¸.Ô1Ið ÈhÐWeÔNfð ð ð ð ð& ð	) ð 	)¨ð 	)ð 	)ð 	)ñ „\ð	)ð ð
˜3ð 
 3ð 
ð 
ð 
ñ „\ð
ð ØØØØðnð nàðnð ðnð ð	nð
 ðnð ðnð ðnð 
ðnð nð nð nðh ØØØðNð NàðNð ðNð ð	Nð
 ðNð ðNð ðNð 
ðNð Nð Nð Nðd, Nð ,ð ,ð ,ð ,ð83Ø%ð3Ø,/ð3Ø;>ð3ØJMð3ØZ]ð3ð 3ð 3ð 3ðj(¨ð (ð (ð (ð (ð>¨ð ð ð ð ð87°ð 7¸ð 7ð 7ð 7ð 7ð7˜cð 7 h¨~Ô&>ð 7ð 7ð 7ð 7ð˜sð  tð ð ð ð ð6ð  3ð °ð Àð Èdð ð ð ð ð>Gð G˜sð G¨Sð G¸Dð Gð Gð Gð GðR:8 sð :8¨tð :8ð :8ð :8ð :8ðx8 cð 8°ð 8¸ð 8ð 8ð 8ð 8ð69ð 9 sð 9°#ð 9¸tð 9ð 9ð 9ð 9ð8 cð 8¨dð 8ð 8ð 8ð 8ð.ð  Sð °Dð ð ð ð ð>¨Cð °Dð ð ð ð ð°#ð ¸$ð ð ð ð ðð  ð ¨sð ð ð ð ð"/ð /ð /ð:Rð Rð Rð@M¨ð Mð Mð Mð Mð Mð Mr    r[   )ÚregistryÚ
tool_errorr)   af  Manage background processes started with terminal(background=true). Actions: 'list' (show all), 'poll' (check status + new output), 'log' (full output with pagination), 'wait' (block until done or timeout), 'kill' (terminate), 'write' (send raw stdin data without newline), 'submit' (send data + Enter, for answering prompts), 'close' (close stdin/send EOF).ÚobjectÚstring)rU   rD  Úlogr  r©   rm  Úsubmitru  z)Action to perform on background processes)r�   ÚenumÚdescriptionz]Process session ID (from terminal background output). Required for all actions except 'list'.)r�   r¾  z@Text to send to process stdin (for 'write' and 'submit' actions)ÚintegerzJMax seconds to block for 'wait' action. Returns partial output on timeout.r~   )r�   r¾  Úminimumz6Line offset for 'log' action (default: last 200 lines)z$Max lines to return for 'log' action)Úactionr€   rf  rù   rF  rG  rÁ  )r�   Ú
propertiesÚrequired)rÕ   r¾  Ú
parametersc                 ór  — |                      d¦  «        }|                       dd¦  «        }|                       d¦  «        �#t          |                       dd¦  «        ¦  «        nd}|dk    r1t          j        dt                               |¬¦  «        id¬	¦  «        S |d
v �r|st          d|› �¦  «        S |dk    r.t          j        t                               |¦  «        d¬	¦  «        S |dk    rYt          j        t                               ||                       dd¦  «        |                       dd¦  «        ¬¦  «        d¬	¦  «        S |dk    rCt          j        t           	                    ||                       d¦  «        ¬¦  «        d¬	¦  «        S |dk    r.t          j        t           
                    |¦  «        d¬	¦  «        S |dk    rPt          j        t                               |t          |                       dd¦  «        ¦  «        ¦  «        d¬	¦  «        S |dk    rPt          j        t                               |t          |                       dd¦  «        ¦  «        ¦  «        d¬	¦  «        S |dk    r.t          j        t                               |¦  «        d¬	¦  «        S t          d|› d�¦  «        S )Nr&   rÁ  r%   r€   rU   Ú	processesr{  F)Úensure_ascii)rD  r»  r  r©   rm  r¼  ru  zsession_id is required for rD  r»  rF  r   rG  rE  )rF  rG  r  rù   rü   r©   rm  rf  r¼  ru  zUnknown process action: z8. Use: list, poll, log, wait, kill, write, submit, close)r  rN   r®  ÚdumpsÚprocess_registryr‚  r¸  rD  rM  r  re  rp  rr  rv  )rÓ   Úkwr&   rÁ  r€   s        r   Ú_handle_processrË  '  s¢  € Ø�fŠf�YÑÔ€GØ�XŠX�h Ñ#Ô#€Fà48·H²H¸\Ñ4JÔ4JÐ4V•�T—X’X˜l¨BÑ/Ô/Ñ0Ô0Ð0Ð\^€Jà�ÒÐÝŒz˜;Õ(8×(FÒ(FÈwÐ(FÑ(WÔ(WÐXÐglÐmÑmÔmÐmØ	ÐNÐ	NÑ	NØð 	FÝÐD¸FÐDÐDÑEÔEÐEØ�VÒÐÝ”:Õ.×3Ò3°JÑ?Ô?ÈeÐTÑTÔTÐTØ�uŠ_ˆ_Ý”:Õ.×7Ò7Ø 4§8¢8¨H°aÑ#8Ô#8ÀÇÂÈÐRUÑ@VÔ@Vð 8ñ Xô XØfkðmñ mô mð mà�vÒÐÝ”:Õ.×3Ò3°JÈÏÊÐQZÑH[ÔH[Ð3Ñ\Ô\ÐkpÐqÑqÔqÐqØ�vÒÐÝ”:Õ.×;Ò;¸JÑGÔGÐV[Ð\Ñ\Ô\Ð\Ø�wÒÐÝ”:Õ.×:Ò:¸:ÅsÈ4Ï8Ê8ÐTZÐ\^ÑK_ÔK_ÑG`ÔG`ÑaÔaÐpuÐvÑvÔvÐvØ�xÒÐÝ”:Õ.×;Ò;¸JÍÈDÏHÊHÐU[Ð]_ÑL`ÔL`ÑHaÔHaÑbÔbÐqvÐwÑwÔwÐwØ�wÒÐÝ”:Õ.×:Ò:¸:ÑFÔFÐUZÐ[Ñ[Ô[Ð[ÝÐq°ÐqÐqÐqÑrÔrÐrr    Úterminalu   âš™ï¸�)rÕ   ÚtoolsetÚschemaÚhandlerÚemoji)2rM   r®  Úloggingr¨   rƒ   rþ   r³   rP   rV   r�   rÞ   Úsystemr²   Útools.environments.localr   r   Údataclassesr   r   Útypingr   r	   r
   r   Úhermes_cli.configr   Ú	getLoggerrJ   rÂ   r¨  rT   r•  rœ  r“   r’   r¢   r¡   r£   r   rN   r   r"   r[   rÉ  Útools.registryr·  r¸  ÚPROCESS_SCHEMArË  ÚregisterrY   r    r   ú<module>rÛ     sõ  ððð ð> €€€Ø €€€Ø 	€	€	€	Ø €€€Ø €€€Ø €€€Ø Ð Ð Ð Ø Ð Ð Ð Ø €€€Ø €€€àˆhŒoÑÔ 9Ò,€Ø JÐ JÐ JÐ JÐ JÐ JÐ JÐ JØ (Ð (Ð (Ð (Ð (Ð (Ð (Ð (Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,à -Ð -Ð -Ð -Ð -Ð -à	ˆÔ	˜8Ñ	$Ô	$€ð "�/Ñ#Ô#Ð&6Ñ6€ð Ð ØÐ Ø€ð  Ð ØÐ ð !Ð Ø Ð Ø "Ð ð ð ¨ð ð ð ð ð ð+0ð +0ð +0ð +0ð +0ñ +0ô +0ñ „ð+0ð\gð gð gð gð gñ gô gð gðV# #�?Ñ$Ô$Ð ð 0Ð /Ð /Ð /Ð /Ð /Ð /Ð /ð ð	_ð ð !Ø[Ð[Ð[ØJðð ð !Ø~ðð ð
 !Øaðð ð
 "ØkØðð ð "ØWðð ð
 "ØEØðð ð/
ð 
ð: �Jð? ð  ð*ð *€ðZsð sð sð: €Ô Ø	ØØØØ
ðñ ô ð ð ð r    