+
    lHàj‡Ž  ã                   ó   € R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHtH	t	H
t
 ^ RIHt ^ RIHtHtHtHt ^ RIHtHtHt ^ RIHt ^ RIHt ^ RIHt ^ R	IHt ^ R
IH t! ^ RIH"t# R R lt$RR/R R llt%R R lt&R R lt'R t(]PR                  R R l4       t*RRRR/R R llt+R t,R R  lt-R! R" lt.R# R$ lt/R% R& lt0R' R( lt1R) R* lt2R+ R, lt3R- R. lt4R/ R0 lt5R1 t6R2 t7R3 t8R4 t9R5 R6 lt:R7 R8 lt;R9 R: lt<R; R< lt=R= R> lt>RSR? lt?RTR@ lt@RA RB ltARURC RD lltBRE RF ltCRG RH ltDRI RJ ltERK RL ltFRM RN ltGRO RP ltHRQ RR ltIR# )Vuù   Browser session lifecycle: inactivity janitor, orphan reaper, per-session teardown, atexit cleanup.

Split out of ``tools/browser_tool.py``. Facade-owned state is read through ``_bt`` (``tools.browser_tool``, resolved per call) â€” no import cycle.
N)ÚdatetimeÚtimezoneÚUTC)ÚPath)ÚAnyÚDictÚOptionalÚTuple)Úget_hermes_homeÚreset_hermes_home_overrideÚset_hermes_home_override)Úorigin)Úbrowser_tool_cdp)Úbrowser_tool_cloud)Úbrowser_tool_session)Úbrowser_tool_install)Úbrowser_tool_real_profilec                óh   € V ^8„  d   QhR\         \        \        3,          R\        \        ,          /# )é   Úsession_infoÚreturn)ÚdictÚstrr   r   Úfloat)Úformats   "ÚA/home/ubuntu/.hermes/hermes-agent/tools/browser_tool_lifecycle.pyÚ__annotate__r      s&   € ÷ ñ ¬D´´c°­Nð ¼xÌ½ñ ó    c                óP  € V P                  R4      p\        V\        \        34      '       d"   \        V\        4      '       g   \        V4      # \        V\
        4      '       d   VP                  4       '       g   R# VP                  4       pVP                  R4      '       d	   VRR  R2p \        P                  ! V4      pTP                  f   TP                  \         R7      pTP#                  4       #   \         d$    \        P                  P                  R4        R# i ; i)zŸProvider-authoritative session expiry as epoch seconds; None when absent or
malformed (cloud providers may omit ``expires_at``; local browsers never have one).Ú
expires_atNz+00:00z7Ignoring invalid cloud browser session expiry timestamp)Útzinfo)ÚZÚzéÿÿÿÿ)ÚgetÚ
isinstanceÚintr   Úboolr   ÚstripÚendswithr   ÚfromisoformatÚ
ValueErrorÚ_btÚloggerÚwarningr    Úreplacer   Ú	timestamp)r   ÚvalueÚ
normalizedÚparseds   &   r   Ú_session_expiry_timestampr4      së   € ð ×Ñ˜\Ó*€EÜ�%œ#œu˜×&Ò&¬z¸%Ä×/FÒ/FÜ�U‹|ÐÜ�eœS×!Ò!¨¯©¯ªÙà—‘“€JØ×Ñ˜:×&Ò&Ø" 3 B˜Ð(¨Ð/ˆ
ðÜ×'Ò'¨
Ó3ˆð ‡}�}ÒØ—‘¤s�Ó+ˆØ×ÑÓÐøô ô Ü�
‰
×ÑÐTÔUÚðús   Â-C7 Ã7*D%Ä$D%Únowc                ót   € V ^8„  d   QhR\         \        \        3,          R\        \        ,          R\
        /# )r   r   r5   r   )r   r   r   r   r   r'   )r   s   "r   r   r   0   s0   € ÷ ?ñ ?Ü”sœC�x•.ð?Ü*2´5­/ð?ä	ñ?r   c               óf   € \        V 4      pVf   R# Vf   \        P                  ! 4       V8¬  # TV8¬  # )z?Whether a cached browser session crossed its provider deadline.F)r4   Útime)r   r5   r   s   &$ r   Ú_session_has_expiredr9   0   s6   € ô +¨<Ó8€JØÒÙØš;ŒD�IŠI‹K°JÑ>Ð>¨C°JÑ>Ð>r   c                ó(   € V ^8„  d   QhR\         RR/# )r   Úlabelr   N©r   )r   s   "r   r   r   :   s   € ÷ 4ñ 4œð 4 Dñ 4r   c                óˆ   €  V! 4        R#   \          d,   p\        P                  P                  RY4        Rp?R# Rp?ii ; i)uR   Run ``fn()``; log (debug) and swallow any exception â€” teardown must never abort.z%s failed: %sN)Ú	Exceptionr,   r-   Údebug)r;   ÚfnÚes   && r   Ú_best_effortrB   :   s3   € ð4Ù
ŽøÜô 4Ü�
‰
×Ñ˜¨%×3Ò3ûð4ús   ‚ ‹A– <¼Ac                ó   € V ^8„  d   QhRR/# ©r   r   N© )r   s   "r   r   r   B   s   € ÷ ñ ˜dñ r   c                  ó    € ^ RI Hp  V ! 4        R# )é    ©Ústop_all_lightpandaN)Útools.browser_lightpandarI   rH   s    r   Ú_stop_all_lightpandarK   B   s   € Ý<ÙÖr   c            	     ó:  €  \         P                  '       d   R# R\         n        \        R\        P
                  4       \         P                  '       dú   \         P                  P                  R\        \         P                  4      4        \        4        \         P                  ;_uu_ 4        \         P                  P                  4        \         P                  P                  4        \         P                  P                  4        \         P                   P                  4        \         P"                  P                  4        RRR4       \        R\$        4       \        R\&        4       R#   \         d     R# i ; i  \         d,   p \         P                  P                  RT 4        Rp ? ELRp ? ii ; i  + '       g   i     L}; i  \         P                  ;_uu_ 4        \         P                  P                  4        \         P                  P                  4        \         P                  P                  4        \         P                   P                  4        \         P"                  P                  4        RRR4       i   + '       g   i     i ; i; i)u¹   atexit: close this process's sessions, then sweep orphans left by crashed
hermes processes â€” every clean exit reaps accumulated orphans, not only
processes that used the browser tool.NTz#Real-profile chrome cleanup on exitz2Emergency cleanup: closing %s active session(s)...zEmergency cleanup error: %szLightpanda cleanup on exitzOrphan reap on exit)r,   Ú_cleanup_doner>   rB   Ú_real_profileÚ_terminate_real_profile_chromeÚ_active_sessionsr-   ÚinfoÚlenÚcleanup_all_browsersÚerrorÚ_cleanup_lockÚclearÚ_session_last_activityÚ_session_owner_homesÚ_cleanup_failuresÚ_recording_sessionsrK   Ú_reap_orphaned_browser_sessions)rA   s    r   Ú_emergency_cleanup_all_sessionsr\   G   s¬  € ðÜ××ÐÙØ ŒÔô Ð6¼×8dÑ8dÔeÜ
××ÐÜ�
‰
�‰ÐLÌcÔRU×RfÑRfÓNgÔhð
	0Ü Ô"ô ×"×"Ó"Ü×$Ñ$×*Ñ*Ô,Ü×*Ñ*×0Ñ0Ô2Ü×(Ñ(×.Ñ.Ô0Ü×%Ñ%×+Ñ+Ô-Ü×'Ñ'×-Ñ-Ô/÷ #ô Ð-Ô/CÔDô Ð&Ô(GÖHøô5 ô ò 	ðûô ô 	?Ü�J‰J×ÑÐ:¸A×>Ò>ûð	?ú÷ #×"û”×"×"Ó"Ü×$Ñ$×*Ñ*Ô,Ü×*Ñ*×0Ñ0Ô2Ü×(Ñ(×.Ñ.Ô0Ü×%Ñ%×+Ñ+Ô-Ü×'Ñ'×-Ñ-Ô/÷ #×"×"Ð"ýsf   ‚E0 šE0 Â
F Â/BF;Å0E?Å>E?ÆF8Æ F3Æ-G Æ3F8Æ8G Æ;G	ÇJÇ'BJ	É>	JÊJÊJc                ó$   € V ^8„  d   QhR\         /# ©r   Útask_idr<   )r   s   "r   r   r   m   s   € ÷ /ñ /¤#ñ /r   c              #  óX  "  € \         P                  P                  V 4      pVf   Rx € R# ^ RIHpHpHp ^ RIHp \        V4      p V! \        V4      4       V! V! \        V4      4      VR7      p Rx € V! V4        \        V4       R#   T! T4       i ; i  \        T4       i ; i5i)a  Run under the Hermes home + secret scope owning ``task_id``'s session (no-op if unrecorded).

The janitor thread is process-global, so each teardown must re-enter its OWN
profile's scope rather than inherit the spawning profile's; never falls
through to ``os.environ``.
N)Úbuild_profile_secret_scopeÚreset_secret_scopeÚset_secret_scope)Úhydrate_profile_secret_sources)Úprofile_home)r,   rX   r$   Úagent.secret_scopera   rb   rc   Úhermes_cli.env_loaderrd   r   r   r   )r_   Ú
owner_homera   rb   rc   rd   Ú
home_tokenÚsecret_tokens   &       r   Ú_session_owner_scoperk   l   s’   é € ô ×)Ñ)×-Ñ-¨gÓ6€JØÒÛÙçcÑcÝDä)¨*Ó5€Jð/Ù&¤t¨JÓ'7Ô8Ù'Ñ(BÄ4È
ÓCSÓ(TÐcmÔnˆð	-Ûá˜|Õ,ä" :Ö.øñ ˜|Õ,ûä" :Õ.üs6   ‚AB*Á*B Á3B Á7B Â B*Â
BÂB ÂB'Â'B*ÚactivityTÚsessionFc                ó@   € V ^8„  d   QhR\         R\        R\        RR/# )r   r_   rl   rm   r   N©r   r'   )r   s   "r   r   r   ˆ   s)   € ÷ 1ñ 1¤cð 1¼ð 1Ìdð 1Ð_cñ 1r   c               ó�  € \         P                  ;_uu_ 4        V'       d!   \         P                  P                  V R4       V'       d!   \         P                  P                  V R4       \         P
                  P                  V R4       \         P                  P                  V R4       RRR4       R#   + '       g   i     R# ; i)zRDrop the janitor's bookkeeping (and optionally the session entry) for ``task_id``.N)r,   rU   rP   ÚpoprW   rX   rY   )r_   rl   rm   s   &$$r   Ú_forget_session_trackingrr   ˆ   s{   € ä	×	×	Ó	ßÜ× Ñ ×$Ñ$ W¨dÔ3ßÜ×&Ñ&×*Ñ*¨7°DÔ9Ü× Ñ ×$Ñ$ W¨dÔ3Ü×Ñ×!Ñ! '¨4Ô0÷ 
×	×	Ò	ús   ™0B4Á
A B4Â4C	c            	     óP  € \         P                   ! 4       p \        P                  ;_uu_ 4        \        \        P                  P                  4       4       UUu. uF$  w  rW,
          \        P                  8”  g   K"  VNK&  	  pppRRR4       X FÉ  p\        V4      ;_uu_ 4        \        V4      '       d   \        V4        RRR4       K>   RRR4       \        V \        P                  P                  W4      ,
          4      p\        P                  P                  RW4        \        V4      ;_uu_ 4        \        V4       RRR4       \        V4       KË  	  R# u uppi   + '       g   i     Lç; i  + '       g   i     L±; i  + '       g   i     LM; i  \          Ed|   p\        P                  ;_uu_ 4        \        P"                  P                  T^ 4      ^,           ;p\        P"                  T&   RRR4       M  + '       g   i     M; iX\        P$                  8  d8   \        P                  P'                  RY\        P$                  T4        Rp?EKÕ  \        P                  P)                  RYaT4        \        T4      ;_uu_ 4        \+        T4       RRR4       MK  + '       g   i     M;; i  \          d+   p\        P                  P)                  RY4        Rp?MRp?ii ; i\        TRR7        Rp?EK~    \        TRR7       i ; iRp?ii ; i)a'  Close sessions inactive longer than the timeout (cleanup thread).

Each teardown runs under its owner profile's scope. A session whose cleanup
keeps failing is force-reaped after MAX_INACTIVITY_CLEANUP_FAILURES attempts;
only a successful cleanup clears its failure count.

See #100738, #86402.
Nz<Cleaning up inactive session for task: %s (inactive for %ss)z9Error cleaning up inactive session %s (attempt %d/%d): %szJBrowser cleanup failed %d times for inactive session %s; force-reaping: %sz+Force-reap of browser session %s failed: %sF)rl   )r8   r,   rU   ÚlistrW   ÚitemsÚ"BROWSER_SESSION_INACTIVITY_TIMEOUTrk   Ú_human_holds_shared_browserÚ_update_session_activityr&   r$   r-   rQ   Úcleanup_browserrr   r>   rY   ÚMAX_INACTIVITY_CLEANUP_FAILURESr.   rT   Ú_force_reap_browser_session)Úcurrent_timer_   Ú	last_timeÚsessions_to_cleanupÚelapsedrA   ÚfailuresÚreap_excs           r   Ú"_cleanup_inactive_browser_sessionsr‚   “   s@  € ô —9’9“;€Lä	×	×	Ó	ÜAEÄc×F`ÑF`×FfÑFfÓFhÔAiô eÑAiÑ+=¨7Ø".Õ":¼S×=cÑ=cÑ"c÷  '˜wÑAiÐñ e÷ 
ó 'ˆÜ! '×*Õ*Ü*¨7×3Ò3ä(¨Ô1Ø÷	 +Ñ*Ø3÷ +ô
 �l¤S×%?Ñ%?×%CÑ%CÀGÓ%ZÕZÓ[ˆÜ�
‰
�‰ÐVÐX_Ôið	BÜ% g×.Õ.Ü Ô(÷ /ä$ WÖ-ó 'ùóe÷ 
×	ú÷
 +×*ú÷ /×.ûô õ 	BÜ×"×"Ó"Ü<?×<QÑ<Q×<UÑ<UÐV]Ð_`Ó<aÐdeÕ<eÐe�œ3×0Ñ0°Ñ9÷ #×"×"Ð"úàœ#×=Ñ=Ô=Ü—
‘
×"Ñ"Ð#^Ø&´#×2UÑ2UÐWXôZæÜ�J‰J×Ñð -Ø.6ÀôDðBÜ)¨'×2Õ2Ü/°Ô8÷ 3×2×2Ð2ûäô cÜ—
‘
× Ñ Ð!NÐPW×bÑbûðcúô )¨¸5×AÔAøÔ(¨¸5ÖAþð	BúsÞ   ®+E%ÁE
Á=E
ÂE%Â&E8Ä'FÄ:FÅFÅE%Å%E5	Å8FÆFÆFÆL%Æ*L Ç;H	Ç=	L ÈHÈAL É%!L ÊKÊJ/	Ê&KÊ.LÊ/J?Ê:KÊ>LÊ?KËK7Ë K2Ë-LË2K7Ë7LË:L ÌLÌL Ì L%c                ó0   € V ^8„  d   QhR\         R\        /# )r   r_   r   ro   )r   s   "r   r   r   À   s   € ÷ =ñ =¬ð =´ñ =r   c                óè   € \         P                  ;_uu_ 4        \         P                  P                  V 4      pRRR4       X'       g   R# \        P
                  ! V4      #   + '       g   i     L0; i)zXLease check for the janitor, under the owner's profile scope (the lease is per profile).NF)r,   rU   rP   r$   Ú_sessionÚhuman_holds_shared_browser©r_   r   s   & r   rw   rw   À   sI   € ä	×	×	Ó	Ü×+Ñ+×/Ñ/°Ó8ˆ÷ 
çÙÜ×.Ò.¨|Ó<Ð<÷	 
×	ús   ™ A!Á!A1	c                ó4   € V ^8„  d   QhR\         R\         RR/# )r   Ú
socket_dirÚsession_namer   Nr<   )r   s   "r   r   r   É   s&   € ÷ 	Yñ 	Y¤ð 	Y´Cð 	Y¸Dñ 	Yr   c                ó~  €  \         P                  P                  W R24      p\        VRRR7      ;_uu_ 4       pVP	                  \        \         P                  ! 4       4      4       RRR4       R#   + '       g   i     R# ; i  \         d,   p\        P                  P                  RY4        Rp?R# Rp?ii ; i)zÖRecord this hermes PID in ``<socket_dir>/<session>.owner_pid`` so the orphan
reaper can tell live-owner daemons from crashed-owner ones. Best-effort: an
OSError falls back to the legacy ``tracked_names`` heuristic.ú
.owner_pidÚwzutf-8©ÚencodingNz)Could not write owner_pid file for %s: %s)ÚosÚpathÚjoinÚopenÚwriter   ÚgetpidÚOSErrorr,   r-   r?   )r‰   rŠ   r‘   ÚfÚexcs   &&   r   Ú_write_owner_pidr™   É   s�   € ðYÜ�w‰w�|‰|˜J¨.¸
Ð(CÓDˆÜ�$˜ g×.Õ.°!Ø�G‰G”CœŸ	š	›Ó$Ô%÷ /×.×.Ò.ûäô YÜ�
‰
×ÑÐDÀl×XÒXûðYús4   ‚8B º.A2Á(B Á2B	Á=B ÂB ÂB<Â B7Â7B<c                ó<   € V ^8„  d   QhR\         R\         R\        /# )r   Útokenr‘   r   ro   )r   s   "r   r   r   Õ   s&   € ÷ Kñ Kœsð K¬#ð K´$ñ Kr   c                óT  € \         P                  P                  V4      P                  4       pV P	                  R4      '       d!   RV 9   d   V P                  R^4      ^,          MT p\        V4      ;'       d1    \         P                  P                  V4      P                  4       V8H  # )zKTrue when ``token`` (or its ``--flag=VALUE`` value) names exactly ``path``.Ú-Ú=)r�   r‘   ÚnormpathÚlowerÚ
startswithÚsplitr'   )r›   r‘   ÚwantÚ	candidates   &&  r   Ú_argv_token_is_pathr¥   Õ   s|   € ä�7‰7×Ñ˜DÓ!×'Ñ'Ó)€DØ*/×*:Ñ*:¸3×*?Ò*?ÀCÈ5ÄL�—‘˜C Ó# AÖ&ÐV[€IÜ�	‹?×JÐJœrŸw™w×/Ñ/°	Ó:×@Ñ@ÓBÀdÑJÐJr   c                óH   € V ^8„  d   QhR\         R\        R\        R\        /# )r   Ú
daemon_pidr‰   rŠ   r   ©r&   r   r'   )r   s   "r   r   r   Ü   s*   € ÷ ,ñ ,´ð ,Äð ,Ü25ð,Ü:>ñ,r   c                óö  a aa€ R V V3R llp ^ RI p TP                  S 4      pTP                  4       ;'       g    RP	                  4       p\        TP                  4       ;'       g    . 4      pRP                  T4      P	                  4       pR	T9  d   R	T9  d
   T! R
T4      # \        ;QJ d    T3R lT 4       F  '       g   K   RM	  RM! T3R lT 4       4      p
T
'       g~    TP                  4       ;'       g    / P                  RR4      p\        T4      ;'       d@    \        P                   P#                  T4      \        P                   P#                  S4      8H  p
T
'       g
   T! RS4      # R#   \         d    T! R4      u # i ; i  TP                   d     R# TP                  \        3 d   p	T! RT	4      u Rp	?	# Rp	?	ii ; i  TP                  TP                  \        3 d    Rp
 L’i ; i)u˜  Confirm a live PID is genuinely *this* session's agent-browser daemon (fail-closed).

The ``.pid`` file sits in a world-writable temp dir: a planted or recycled PID
would turn the tree-kill into an arbitrary-process DoS. Both must pass:
(1) identity â€” ``agent-browser`` in name/cmdline; (2) binding â€” the socket dir in
the cmdline or ``AGENT_BROWSER_SOCKET_DIR`` in its environ (the real spoof defense).
c                ó0   € V ^8„  d   QhR\         R\        /# )r   Úreasonr   ro   )r   s   "r   r   Ú5_verify_reapable_browser_daemon.<locals>.__annotate__å   s   € ÷ ñ ”sð ¤dñ r   c                 ó^   <€ \         P                  P                  ! R V ,           SS.VO5!   R# )z5Refusing to reap browser daemon PID %d (session %s): F)r,   r-   r.   )r«   Úargsr§   rŠ   s   &*€€r   ÚrefuseÚ/_verify_reapable_browser_daemon.<locals>.refuseå   s.   ø€ Ü�
‰
×ÒÐRÐU[Õ[Ø% |ð	<Ø6:ô	<ár   Nz,psutil unavailable for identity verificationÚ Ú Fz$could not read process identity (%s)zagent-browserz&not an agent-browser process (name=%r)c              3   ó<   <"  € T F  p\        VS4      x € K  	  R # 5i©N)r¥   )Ú.0Útokr‰   s   & €r   Ú	<genexpr>Ú2_verify_reapable_browser_daemon.<locals>.<genexpr>ÿ   s   øé € ÐEÁ¸Ô# C¨×4Ð4Ãùs   ƒTÚAGENT_BROWSER_SOCKET_DIRzNnot bound to session socket dir %s (possible recycled PID or planted pid file))ÚpsutilÚImportErrorÚProcessÚnamer    rt   Úcmdliner’   ÚNoSuchProcessÚAccessDeniedr–   ÚanyÚenvironr$   r'   r�   r‘   rŸ   )r§   r‰   rŠ   r¯   rº   Úprocr½   Úargvr¾   r˜   ÚboundÚenv_dirs   fff         r   Ú_verify_reapable_browser_daemonrÇ   Ü   s®  ú€ ÷ñ ð
FÛðCØ�~‰~˜jÓ)ˆØ—	‘	“×!Ð!˜r×(Ñ(Ó*ˆÜ�D—L‘L“N×(Ð( bÓ)ˆØ—(‘(˜4“.×&Ñ&Ó(ˆð ˜dÔ" ¸gÔ'EÙÐ>ÀÓEÐE÷
 ‹CÔEÁÓE�C�CŠCÔEÁÓEÓE€Eßð	Ø—|‘|“~×+Ð+¨×0Ñ0Ð1KÈRÓPˆGÜ˜“M×_Ð_¤b§g¡g×&6Ñ&6°wÓ&?Ä2Ç7Á7×CSÑCSÐT^ÓC_Ñ&_ˆE÷ ÙÐfÐhrÓsÐsÙøô9 ô FÙÐDÓEÒEðFûð ×Ñô ÚØ×Ñ¤Ð)ô CÙÐ<¸cÓBÕBûðCûð ×#Ñ# V×%9Ñ%9¼7ÐCô 	ØŠEð	úsd   �E8 ”'F ¼,F Á)&F Ã)G Ä $G Ä%A G Å8FÆFÆGÆ%GÆ:GÆ;G	ÇGÇ	GÇ$G8Ç7G8c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   r‰   r   )r   r   r   )r   s   "r   r   r     s   € ÷ *ñ *¬ð *´¼%µñ *r   c                óÈ  €  \         P                  P                  V 4      p \         P                  ! T 4      ;_uu_ 4       pT F'  p \        YP                  4       P                  4      pK)  	  RRR4       \        R\        P                  ! 4       T,
          4      #   \         d     R# i ; i  \         d     Ky  i ; i  + '       g   i     LZ; i  \         d     Lji ; i)uõ   Seconds since anything in ``socket_dir`` was last written; None if unknown (fail safe).
Every command rewrites ``_stdout_<cmd>`` there â€” a restart-proof activity marker â€” and
rewriting doesn't touch the dir mtime, so entries are scanned too.Nç        )	r�   r‘   Úgetmtimer–   ÚscandirÚmaxÚstatÚst_mtimer8   )r‰   ÚlatestÚentriesÚentrys   &   r   Ú_socket_dir_idle_secondsrÓ     s¸   € ðÜ—‘×!Ñ! *Ó-ˆðÜ�ZŠZ˜
×#Ô# wÛ �ðÜ  ¯©«×)>Ñ)>Ó?’Fñ !÷ $ô ˆs”D—I’I“K &Õ(Ó)Ð)øô ô Úðûô ô Úðú÷	 $×#ûô ô Ùðúsd   ‚B ¢C Á C Á#B.Á*C Á.C ÂB+Â*B+Â.B=	Â9C Â<B=	Â=C Ã C	ÃC ÃC ÃC!Ã C!c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r   r‘   r   )r   r   r&   )r   s   "r   r   r   !  s   € ÷ ñ œð ¤¬#¥ñ r   c                ó˜   €  \        \        V 4      P                  RR7      P                  4       4      #   \        \
        3 d     R# i ; i)z8Integer PID from ``path``; None when missing or corrupt.ú	utf-8-sigrŽ   N)r&   r   Ú	read_textr(   r+   r–   )r‘   s   &r   Ú_read_pid_filerØ   !  sD   € ðÜ”4˜“:×'Ñ'°Ð'Ó=×CÑCÓEÓFÐFøÜœÐ ô Úðús   ‚14 ´A	ÁA	c          	      óŠ   € V ^8„  d   QhR\         R\         R\        \        \        ,          \        \        ,          3,          /# ©r   r‰   rŠ   r   )r   Útupler   r&   r'   )r   s   "r   r   r   )  s6   € ÷ -ñ -¤ð -´Cð -¼EÄ(Ì3Å-ÔQYÔZ^ÕQ_ÐB_Õ<`ñ -r   c                ó‚   € \        \        P                  P                  W R24      4      pVf   R# ^ RIHp W#! V4      3# )z`Read ``<session>.owner_pid`` and report ``(pid, alive)``; ``(None, None)`` when missing/corrupt.rŒ   ©Ú_pid_exists)NN)rØ   r�   r‘   r’   Úgateway.statusrÞ   )r‰   rŠ   Ú	owner_pidrÞ   s   &&  r   Ú_owner_pid_aliverá   )  s?   € äœrŸw™wŸ|™|¨J¸.È
Ð8SÓTÓU€IØÒØÐå*Ø�k )Ó,Ð,Ð,r   c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r   r§   rŠ   r   r¨   )r   s   "r   r   r   3  s!   € ÷ ñ ¬3ð ¼cð Ì4ñ r   c                ón   € ^ RI Hp ^ RIHp V! V 4      pVf   V! RW4       R# VP	                  W4       R# )z¶Tree-kill ``daemon_pid`` if it has a start-time fingerprint (so a PID swapped
between check and kill is refused); False (logged via ``log``) when no fingerprint.
Raises on OS errors.)Úget_process_start_time)ÚProcessRegistryzXRefusing to reap browser daemon PID %d (session %s): no start-time fingerprint availableFT)rß   rä   Útools.process_registryrå   Ú_terminate_host_pid)r§   rŠ   Úlogrä   rå   Údaemon_starts   &&&   r   Ú_terminate_verified_daemonrê   3  s<   € õ 6Ý6Ù)¨*Ó5€LØÒÙÐfØô	&áØ×'Ñ'¨
ÔAÙr   c                óH   € V ^8„  d   QhR\         R\         R\        R\        /# )r   r‰   rŠ   Útracked_namesr   )r   Úsetr'   )r   s   "r   r   r   B  s)   € ÷ 3ñ 3¤ð 3´Cð 3Ìð 3ÔPTñ 3r   c                óÎ  € \        W4      w  r4VRJ di   W9   d   R# \        V 4      pVe   V\        P                  8  d   R# \        P                  P                  RW\        V4      \        P                  4       MVf	   W9   d   R# \        P                  P                  W R24      p\        P                  P                  V4      '       gA   \        V 4      pVe   V\        P                  8  d   R# \        P                  ! V RR7       R# \        V4      p^ RIHp Ve   V! V4      '       g   \        P                  ! V RR7       R# \!        WpV4      '       g   R# Rp	 \#        Wq\        P                  P
                  4      '       g   R# \        P                  P%                  RWq4       Rp	\        P                  ! V RR7       V	#   \&        \(        \*        3 d     L2i ; i)uø  Reap one ``agent-browser-<session>`` dir if orphaned; True when a daemon was killed.

A live ``owner_pid`` means another hermes process owns it â€” leave it UNLESS untracked
here and idle past ``BROWSER_ORPHAN_GRACE_SECONDS`` (owner-alive alone made leaked
daemons immortal); no owner_pid (legacy) falls back to this process's tracking. A
pidless dir is only stale after the grace period (deleting it immediately races the
creator's first stdout open). The PID is identity-verified before any tree-kill.
TFu}   Browser session %s has a live owner (PID %s) but is untracked and idle for %ds (grace %ds) â€” treating as leaked and reapingú.pid©Úignore_errorsrÝ   z2Reaped orphaned browser daemon PID %d (session %s))rá   rÓ   r,   ÚBROWSER_ORPHAN_GRACE_SECONDSr-   r.   r&   r�   r‘   r’   ÚisfileÚshutilÚrmtreerØ   rß   rÞ   rÇ   rê   rQ   ÚProcessLookupErrorÚPermissionErrorr–   )
r‰   rŠ   rì   rà   Úowner_aliveÚidle_sÚpid_filer§   rÞ   Úreapeds
   &&&       r   Ú_reap_socket_dirrü   B  sƒ  € ô .¨jÓGÑ€IØ�dÓØÔ(ÙÜ)¨*Ó5ˆØŠ>˜V¤c×&FÑ&FÔFÙÜ�
‰
×ÑðNà¤S¨£[Ü×,Ñ,õ		.ð
 
Ò	 Ô!>Ùä�w‰w�|‰|˜J¨.¸Ð(=Ó>€HÜ�7‰7�>‰>˜(×#Ò#Ü)¨*Ó5ˆØŠ>˜V¤c×&FÑ&FÔFÙÜ�Š�j°Õ5Ùä Ó)€JÝ*ØÒ¡¨Z×!8Ò!8Ü�Š�j°Õ5Ùä*¨:À<×PÒPÙð €FðÜ)¨*ÄCÇJÁJ×DVÑDV×WÒWÙÜ�
‰
�‰ÐLÈjÔgØˆô ‡M‚M�*¨DÕ1Ø€Møô ¤´Ð9ô Ùðús   Å#*G Æ"G ÇG$Ç#G$c                 ó~  € ^ RI p R p\        RV4       \        P                  ! 4       p. pRRRR\        P                   23 F7  pW0P                  \
        P                  P                  W$4      4      ,          pK9  	  V'       g   R# \        P                  ;_uu_ 4        \        P                  P                  4        Uu0 uF,  qUP                  R4      '       g   K  VP                  R4      kK.  	  ppRRR4       XP                  \        P                  4       ^ pV FX  p\
        P                  P                  V4      P                  R4      p	V	'       g   K;  \        W‰V4      '       g   KO  V^,          pKZ  	  V'       d#   \        P                   P#                  R	V4       R# R# u upi   + '       g   i     LÀ; i)
zÛKill agent-browser daemons whose owning hermes process is gone (an unclean exit loses
``_active_sessions`` but node + Chromium keep running). Scans the tmp dir for
``agent-browser-*`` socket dirs; safe from any context.Nc                  ó    € ^ RI Hp  V ! 4        R# )rG   ©Úreap_orphaned_lightpandaN)rJ   r   rÿ   s    r   Ú_reap_lpÚ1_reap_orphaned_browser_sessions.<locals>._reap_lp€  s   € ÝEÙ Ö"r   zLightpanda orphan reapzagent-browser-h_*zagent-browser-cdp_*zagent-browser-hermes_*úagent-browser-rŠ   z:Reaped %d orphaned browser session(s) from previous run(s))ÚglobrB   r,   Ú_socket_safe_tmpdirÚ_REAL_PROFILE_SESSIONr�   r‘   r’   rU   rP   Úvaluesr$   ÚaddÚbasenameÚremoveprefixrü   r-   rQ   )
r  r  ÚtmpdirÚsocket_dirsÚprefixrQ   rì   rû   r‰   rŠ   s
             r   r[   r[   x  sU  € ó ò#ô Ð)¨8Ô4ä×$Ò$Ó&€FØ€Kà&Ð(=Ð?WØ#¤C×$=Ñ$=Ð#>Ð?óAˆà—y‘y¤§¡§¡¨fÓ!=Ó>Õ>ŠñA÷ Ùä	×	×	Ó	Ü>A×>RÑ>R×>YÑ>YÔ>[ÓxÑ>[°d×_gÑ_gÐhv×_wÔ1˜Ÿ™ .Ö1Ñ>[ˆÐx÷ 
ð
 ×Ñ”c×/Ñ/Ô0à€FÛ!ˆ
Ü—w‘w×'Ñ'¨
Ó3×@Ñ@ÐAQÓRˆß‰<Ô,¨ZÀ}×UÔUØ�a�KŠFñ "÷
 Ü�
‰
�‰ÐTÐV\Ö]ñ ùò y÷ 
×	ús$   Â!F,Ã F'ÃF'Ã2F,Æ'F,Æ,F<	c                 óH  € \        ^\        \        P                  ^,          4      4      p ^ p\        P                  '       dp   W,          ^ 8X  d    \        4        V^,          p \        4        \        ^4       F2  p\        P                  '       g    Ki  \        P                  ! ^4       K4  	  K…  R#   \         d+   p\        P                  P                  RT4        Rp?L‰Rp?ii ; i  \         d+   p\        P                  P                  RT4        Rp?L­Rp?ii ; i)z�Every 30s: close sessions idle past BROWSER_SESSION_INACTIVITY_TIMEOUT; reap
orphans on startup AND every BROWSER_ORPHAN_REAP_INTERVAL seconds.zOrphan reap error: %sNzCleanup thread error: %s)rÍ   Úroundr,   ÚBROWSER_ORPHAN_REAP_INTERVALÚ_cleanup_runningr[   r>   r-   r.   r‚   Úranger8   Úsleep)Úreap_every_cyclesÚcyclerA   Ú_s       r   Ú_browser_cleanup_thread_workerr  Ÿ  sà   € ô ˜Aœu¤S×%EÑ%EÈÕ%JÓKÓLÐØ€Eä
×
×
Ð
ØÕ$¨Ô)ð?Ü/Ô1ð 	��
ˆð	>Ü.Ô0ô �r–ˆAÜ×'×'Ð'ÚÜ�JŠJ�qŽMó ñ øô ô ?Ü—
‘
×"Ñ"Ð#:¸A×>Ñ>ûð?ûô ô 	>Ü�J‰J×ÑÐ9¸1×=Ñ=ûð	>ús0   Á
B4 Á%
C, Â4C)Â? C$Ã$C)Ã,D!Ã7 DÄD!c                 óÖ  € \         P                  ;_uu_ 4        \         P                  e%   \         P                  P                  4       '       g~   R\         n        \
        P                  ! \        RRR7      \         n        \         P                  P                  4        \         P                  P                  R\         P                  4       RRR4       R#   + '       g   i     R# ; i)z;Start the background cleanup thread if not already running.NTzbrowser-cleanup)ÚtargetÚdaemonr½   z0Started inactivity cleanup thread (timeout: %ss))r,   rU   Ú_cleanup_threadÚis_aliver  Ú	threadingÚThreadr  Ústartr-   rQ   rv   rE   r   r   Ú_start_browser_cleanup_threadr   ¸  sŽ   € ä	×	×	Ó	Ü×ÑÒ&¬c×.AÑ.A×.JÑ.J×.LÒ.LØ#'ŒCÔ Ü"+×"2Ò"2Ô:XÐaeØ8Iô#KŒCÔä×Ñ×%Ñ%Ô'Ü�J‰J�O‰OÐNÔPS×PvÑPvÔw÷ 
×	×	Ò	ús   ™6CÁA=CÃC(	c                 óÄ   €  R\         n        \         P                  p T e    T P	                  ^R7       R# R#   \         d     R# i ; i  \
        \        3 d     R# i ; i)z#Stop the background cleanup thread.FN©Útimeout)r,   r  r  r>   r’   Ú
SystemExitÚKeyboardInterrupt)Úthreads    r   Ú_stop_browser_cleanup_threadr'  Ã  si   € ðØ$ŒÔÜ×$Ñ$ˆð
 Òð	Ø�K‰K ˆKÖ"ñ	 øô	 ô ò 	ðûô Ô-Ð.ô 	Úð	ús    ‚8 ¢A
 ¸AÁAÁ
AÁAc                ó$   € V ^8„  d   QhR\         /# r^   r<   )r   s   "r   r   r   Õ  s   € ÷ Mñ M¤cñ Mr   c           	     ó  € \         P                  ;_uu_ 4        \        P                  ! 4       \         P                  V &   \         P                  P                  V \        \        4       4      4       RRR4       R#   + '       g   i     R# ; i)z³Touch the activity timestamp and record the owning Hermes home on first sight (the
janitor tears down under the owner's scope). Does NOT reset ``_cleanup_failures``.

See #86402.
N)r,   rU   r8   rW   rX   Ú
setdefaultr   r
   )r_   s   &r   rx   rx   Õ  sS   € ô 
×	×	Ó	Ü.2¯iªi«kŒ×"Ñ" 7Ñ+Ü× Ñ ×+Ñ+¨G´S¼Ó9JÓ5KÔL÷ 
×	×	Ò	ús   ™AA;Á;B	c                ó<   € V ^8„  d   QhR\         P                  RR/# ©r   rÃ   r   N©Ú
subprocessÚPopen)r   s   "r   r   r   à  s    € ÷ (ñ (œZ×-Ñ-ð (°$ñ (r   c                ór   €  ^ RI Hp V! V P                  4       R#   \         d    \	        T 4        R# i ; i)uq  Best-effort kill of *proc* and every descendant; never raises.

``Popen.kill()`` only signals the direct child; npm/npx helpers and the detached
daemon grandchild keep a capture pipe open so ``communicate()`` never sees EOF, so
the whole tree must go (no grace: the caller already burned its timeout). Delegates
to :func:`agent.deadline.kill_process_tree`, falling back to the legacy kill.

``Popen.kill()`` only signals the direct child PID. npm/npx routinely fork further processes
(registry-fetch helpers, npm's own lifecycle runner, agent-browser's own detached daemon grandchild)
that can survive a plain ``kill()`` of the top-level PID and keep a ``capture_output``-style pipe open,
hanging the caller's ``communicate()`` past the nominal timeout â€” the same orphaned-pipe hazard already
hit in production on POSIX (see ``tools/process_registry.py``'s ``_reader_loop``, issue 68915: a
backgrounded grandchild inheriting a pipe's write end kept it from ever reaching EOF). That hazard is
cross-platform, not Windows-specific; what *is* Windows-specific is the lack of a remedy other than
killing the tree â€” anonymous pipes there don't support overlapped I/O, so there's no ``select()``-style
non-blocking read to poll around a stuck grandchild the way POSIX can. Killing the whole process
group/tree the child was launched into reaches those descendants on both platforms. See #68915.
)Úkill_process_treeN)Úagent.deadliner1  Úpidr>   Ú_legacy_kill_process_tree)rÃ   Ú_deadline_kill_trees   & r   Ú_kill_process_treer6  à  s-   € ð&(ÝKá˜DŸH™HÖ%øÜô (Ü! $×'ð(ús   ‚ œ6µ6c                ó<   € V ^8„  d   QhR\         P                  RR/# r,  r-  )r   s   "r   r   r   û  s    € ÷ 8ñ 8¤J×$4Ñ$4ð 8¸ñ 8r   c                ó&  € \         P                  R8X  dD    \        P                  ! RR\	        V P
                  4      RR.RR\        P                  R7       R	# \        \         R
R	4      pVf    V P                  4        R	#  \         P                  ! V P
                  4      p. pVeQ   W P
                  8X  dA   \        P                  \        \        R\        P                  4      3 F  p V! W$4       K  	  M0 ^ R	IpVP#                  V P
                  4      P%                  RR7      p V P                  4        V F>  p\&        P(                  ! \        4      ;_uu_ 4        VP                  4        R	R	R	4       K@  	  R	#   \         d     R	# i ; i  \         d     R	# i ; i  \        \        3 d    R	p ELi ; i  \        \        \        3 d      K¯  i ; i  \         d    . p LÂi ; i  \         d     LÂi ; i  + '       g   i     KÕ  ; i)a'  Local tree-kill (fallback when agent.deadline is unavailable; tests pin
the signal sequence). A child leading its own group gets SIGTERM then
SIGKILL via killpg; a shared-group child can never be killpg'd (that is OUR
group), so it and its psutil-snapshotted descendants are killed
individually.ÚntÚtaskkillz/PIDz/Tz/FFT)ÚcheckÚcapture_outputÚstdinNÚkillpgÚSIGKILL)Ú	recursive)r�   r½   r.  Úrunr   r3  ÚDEVNULLr>   ÚgetattrÚkillÚgetpgidrö   r–   ÚsignalÚSIGTERMr÷   rº   r¼   ÚchildrenÚ
contextlibÚsuppress)rÃ   r>  ÚpgidÚdescendantsÚsigrº   Úchilds   &      r   r4  r4  û  sÅ  € ô 
‡w�w�$„ð	Ü�NŠN˜J¨´°D·H±H³¸tÀTÐJØ!&°tÄ:×CUÑCUõWñ 	ô ”R˜ 4Ó(€FØ‚~ð	Ø�I‰IŒKñ 	ðÜ�zŠz˜$Ÿ(™(Ó#ˆð €KØÒ˜D§H¡HÔ,Ü—N‘N¤G¬F°I¼v¿~¹~Ó$NÓOˆCðÙ�tÖ!ò Pð	Ûà Ÿ.™.¨¯©Ó2×;Ñ;ÀdÐ;ÓKˆKðØ�	‰	Œó ˆÜ× Ò ¤×+Õ+Ø�J‰JŒL÷ ,Ñ+ó øôY ô 	ØÙð	ûô ô 	ØÙð	ûô
 ¤Ð(ô Ø‹ðûô '¬¼ÐAô Ûðûô ô 	ØŠKð	ûô ô Ùðú÷ ,×+Ð+úsx   —A E? Á/F Â F# Ã+F=Ã9/G Ä)G. Å G?Å?FÆFÆF ÆF Æ#F:Æ9F:Æ=GÇGÇG+Ç*G+Ç.G<Ç;G<Ç?Hc                ó0   € V ^8„  d   QhR\         R\        /# )r   r3  r   )r&   r'   )r   s   "r   r   r   6  s   € ÷ $ñ $”Sð $œTñ $r   c                ó0   € V ^ 8:  d   R# ^ RI Hp V! V 4      # )z[Best-effort 'is this PID alive' (cross-platform via gateway.status; zombies count as dead).FrÝ   )rß   rÞ   )r3  Ú_gateway_pid_existss   & r   rÞ   rÞ   6  s   € à
ˆa„xÙÝAÙ˜sÓ#Ð#r   c          
      óL   € V ^8„  d   QhR\         R\        R\        R\        RR/# )r   Ú	directoryÚpatternÚmax_age_hoursr;   r   N)r   r   r   )r   s   "r   r   r   >  s8   € ÷ Wñ W¤$ð W´ð WÄUð WÔSVð WÐ[_ñ Wr   c                óæ  €  \         P                   ! 4       VR,          ,
          pV P                  V4       F5  p VP                  4       P                  V8  d   VP	                  4        K5  K7  	  R#   \
         d-   p\        P                  P                  RY5T4        Rp?Km  Rp?ii ; i  \
         d;   p\        P                  P                  RTP                  4       T4        Rp?R# Rp?ii ; i)zNDelete ``directory/pattern`` files older than ``max_age_hours``; never raises.é  zFailed to clean old %s %s: %sNz#%s cleanup error (non-critical): %s)
r8   r  rÎ   rÏ   Úunlinkr>   r,   r-   r?   Ú
capitalize)rS  rT  rU  r;   Úcutoffr—   rA   s   &&&&   r   Ú_unlink_older_thanr[  >  s»   € ð	WÜ—’“ °Õ 4Õ5ˆØ—‘ Ö(ˆAðOØ—6‘6“8×$Ñ$ vÔ-Ø—H‘H–Jñ .ó )øô ô OÜ—
‘
× Ñ Ð!@À%ÈA×NÒNûðOûäô WÜ�
‰
×ÑÐ>À×@PÑ@PÓ@RÐTU×VÒVûðWús@   ‚7B+ º/A1Á)B+ Á1B(Á<!B#ÂB+ Â#B(Â(B+ Â+C0Â6/C+Ã+C0c                óä   € \        V 4      p\        P                  ! 4       pV\        P                  P	                  VR4      ,
          R8  d   R# V\        P                  V&   \        V RVR4       R# )zHPrune old browser screenshots; throttled to once per hour per directory.rÊ   rW  Nzbrowser_screenshot_*.pngÚ
screenshot)r   r8   r,   Ú_last_screenshot_cleanup_by_dirr$   r[  )Úscreenshots_dirrU  Úkeyr5   s   &&  r   Ú_cleanup_old_screenshotsra  L  sZ   € ä
ˆoÓ
€CÜ
�)Š)‹+€CØ
ŒS×0Ñ0×4Ñ4°S¸#Ó>Õ>ÀÔEÙØ/2„C×'Ñ'¨Ñ,Ü�Ð(BÀMÐS_Ö`r   c                óè   €  \        4       R,          pTP                  4       '       d   \        TRT R4       R# R#   \         d,   p\        P                  P	                  RT4        Rp?R# Rp?ii ; i)zPrune old browser recordings.Úbrowser_recordingsz*Recording cleanup error (non-critical): %sNzsession_*.webmÚ	recording)r
   r>   r,   r-   r?   Úexistsr[  )rU  Úrecordings_dirrA   s   &  r   Ú_cleanup_old_recordingsrg  V  sd   € ðÜ(Ó*Ð-AÕAˆð ×Ñ×ÒÜ˜>Ð+;¸]ÈKÖXñ øô ô Ü�
‰
×ÑÐEÀqÔIÝûðús   ‚; »A1Á A,Á,A1c                ó(   € V ^8„  d   QhR\         RR/# ©r   r_   r   Nr<   )r   s   "r   r   r   a  s   € ÷ =ñ =¤sð =¨tñ =r   c                óÊ   € \         P                  ! V 4      pW8X  g%   \         P                  P                  V4      V 8X  d#   \         P                  P	                  VR4       R# R# )zåDrop stale last-active ownership after cleaning ``task_id``: a bare task always, a
sidecar only if it was still the recorded owner (a later click must not resurrect a
cleaned sidecar while a primary-session binding is preserved).N)r,   Ú_bare_task_id_for_session_keyÚ_last_active_session_keyr$   rq   )r_   Úbare_task_ids   & r   Ú_drop_last_active_bindingrn  a  sO   € ô ×4Ò4°WÓ=€LØÔ¤#×">Ñ">×"BÑ"BÀ<Ó"PÐT[Ô"[Ü×$Ñ$×(Ñ(¨°tÖ<ñ #\r   c                ó>   € V ^8„  d   QhR\         \        ,          RR/# ri  )r   r   )r   s   "r   r   r   j  s   € ÷ 'ñ 'œX¤c�]ð '°dñ 'r   c                ój  € V f   Rp V .pV  \         P                   2p\         P                  ;_uu_ 4        \         P                  ! V 4      '       g'   V\         P                  9   d   VP                  V4       RRR4       V F  p\        V4       K  	  \        V 4       R#   + '       g   i     L1; i)zšClean up browser session(s) for a task: a bare task id reaps BOTH the primary
session and any hybrid local sidecar; a ``::local`` key reaps only that one.NÚdefault)r,   Ú_LOCAL_SUFFIXrU   Ú_is_local_sidecar_keyrP   ÚappendÚ_cleanup_single_browser_sessionrn  )r_   Úsession_keysÚsidecar_keyÚsession_keys   &   r   ry   ry   j  sŒ   € ð ‚Øˆà�9€LØ�Iœc×/Ñ/Ð0Ð1€KÜ	×	×	Ó	Ü×(Ò(¨×1Ò1°kÄS×EYÑEYÔ6YØ×Ñ Ô,÷ 
ó $ˆÜ'¨Ö4ñ $ä˜gÖ&÷ 
×	ús   ¶AB"Â"B2	c                ó<   € V ^8„  d   QhR\         R\         R\        /# rÚ   ro   )r   s   "r   r   r   z  s!   € ÷ ñ ¤cð ¼ð Äñ r   c                ój  aa€ \         P                  P                  V S R24      p\         P                  P                  V4      '       g   R#  \	        \        V4      P                  RR7      P                  4       4      o\        SV S4      '       g$   \        P                  P                  RSS4       R# \        SSVV3R l4      '       g   R# \        P                  P                  RSS4       R#   \        \        \        \         3 d%    \        P                  P                  R	S4        R# i ; i)
zuTree-kill the daemon in ``<socket_dir>/<session>.pid`` if verifiably ours; True when
a kill was issued. Never raises.rï   FrÖ   rŽ   z?Skipped daemon kill for %s: pid %s failed identity verificationc                  óF   <€ \         P                  P                  R SS4      # )z@Skipped daemon kill for %s: no start-time fingerprint for pid %s)r,   r-   r?   )Ú_ar§   rŠ   s   *€€r   Ú<lambda>Ú'_kill_verified_daemon.<locals>.<lambda>…  s"   ø€ ÔPS×PZÑPZ×P`ÑP`ØRÐT`ÐblôQnr   zKilled daemon pid %s for %sTz?Could not kill daemon pid for %s (already dead or inaccessible))r�   r‘   r’   ró   r&   r   r×   r(   rÇ   r,   r-   r?   rê   rö   r+   r÷   r–   )r‰   rŠ   rú   r§   s   &f @r   Ú_kill_verified_daemonr  z  só   ù€ ô �w‰w�|‰|˜J¨<¨.¸Ð(=Ó>€HÜ�7‰7�>‰>˜(×#Ò#ÙðÜœ˜h›×1Ñ1¸;Ð1ÓG×MÑMÓOÓPˆ
Ü.¨z¸:À|×TÒTÜ�J‰J×ÑÐ^Ð`lÐnxÔyÙÜ)¨*°lõ En÷ oò oáÜ�
‰
×ÑÐ6¸
ÀLÔQÙøÜ¤
¬O¼WÐEô Ü�
‰
×ÑÐZÐ\hÔiÚðús   ÁA&C3 Â6C3 Ã!C3 Ã3;D2Ä1D2c                óV   € V ^8„  d   QhR\         R\        \         \        3,          RR/# ©r   r_   r   r   N©r   r   r   )r   s   "r   r   r   �  s)   € ÷ 	4ñ 	4¬ð 	4¼4ÄÄSÀ½>ð 	4Èdñ 	4r   c                ó6   € \        V RR7       \        W4       R# )u¦  Untrack ``task_id``, close its cloud provider session, kill its daemon â€” the
unconditional tail of a teardown, and the whole of the janitor's force-reap path.

The unconditional tail of ``_cleanup_single_browser_session``; also the whole of the janitor's
force-reap path (#100738), which skips the polite agent-browser/Camofox ``close`` that kept failing but
must still release the cloud session and the local Chromium.
T)rm   N)rr   Ú_release_session_backendr‡   s   &&r   Ú_release_session_resourcesr…  �  s   € ô ˜W¨dÕ3Ü˜WÖ3r   c                óV   € V ^8„  d   QhR\         R\        \         \        3,          RR/# r�  r‚  )r   s   "r   r   r   ›  s)   € ÷ :ñ :¤cð :¼¼cÄ3¸h½ð :ÈDñ :r   c                ó8  € VP                  RR4      pV'       d,   \        P                  ! 4       pVe    VP                  V4       VP                  RR4      pV'       dƒ   \        P                  P                  \
        P                  ! 4       RV 24      p\        P                  P                  V4      '       d&   \        We4       \        P                  ! VRR	7       R# R# R#   \         d+   p\
        P                  P                  RT4        Rp?LÎRp?ii ; i)
z®Close ``session_info``'s cloud provider session and kill its daemon, by object: no shared
session map is read or written (an unpublished session releases through this alone).Úbb_session_idÚunknownNz)Could not close cloud browser session: %srŠ   r±   r  Trð   )r$   Ú_cloudÚ_get_cloud_providerÚclose_sessionr>   r,   r-   r.   r�   r‘   r’   r  re  r  rô   rõ   )r_   r   rˆ  ÚproviderrA   rŠ   r‰   s   &&     r   r„  r„  ›  sÜ   € ð !×$Ñ$ _°iÓ@€MßÜ×-Ò-Ó/ˆØÒðSØ×&Ñ& }Ô5ð  ×#Ñ# N°BÓ7€LßÜ—W‘W—\‘\¤#×"9Ò"9Ó";¸~ÈlÈ^Ð=\Ó]ˆ
Ü�7‰7�>‰>˜*×%Ò%Ü! *Ô;Ü�MŠM˜*°D×9ñ &ñ øô	 ô SÜ—
‘
×"Ñ"Ð#NÐPQ×RÑRûðSús   µC$ Ã$DÃ/ DÄDc                ó(   € V ^8„  d   QhR\         RR/# ri  r<   )r   s   "r   r   r   ¯  s   € ÷ 'ñ '¬ð '°ñ 'r   c                ó’  € \         P                  ! V 4       \        P                  ;_uu_ 4        \        P                  P                  V 4      p\        P                  P                  V R4       \        P                  P                  V 4       RRR4       X'       d   \        W4       \        V 4       R#   + '       g   i     L0; i)z™Janitor last resort: skip the failing ``close`` round-trips, release resources directly.

Janitor last resort after repeated cleanup failures (#100738).
N)Ú_cdpÚ_stop_cdp_supervisorr,   rU   rP   r$   rW   rq   rZ   Údiscardr…  rn  r‡   s   & r   r{   r{   ¯  s�   € ô
 	×Ò˜gÔ&Ü	×	×	Ó	Ü×+Ñ+×/Ñ/°Ó8ˆÜ×"Ñ"×&Ñ& w°Ô5Ü×Ñ×'Ñ'¨Ô0÷ 
÷ Ü" 7Ô9Ü˜gÖ&÷ 
×	ús   ¯AB6Â6C	c                ó(   € V ^8„  d   QhR\         RR/# ri  r<   )r   s   "r   r   r   ¾  s   € ÷ -Fñ -F¬Sð -F°Tñ -Fr   c                óž  a € \         P                  ! S 4       \        P                  ! 4       '       d   V 3R lp\	        RS  2V4       \        P
                  P                  RS 4       \        P
                  P                  R\        \        P                  P                  4       4      4       \        P                  ;_uu_ 4        \        P                  P                  S 4      pRRR4       X'       g#   \        P
                  P                  RS 4       R# \        P
                  P                  RS VP                  RR	4      4       \        P                  ! S 4       VP                  R
4      ;'       g    / P                  R4      '       d!    ^ RIHp V! VP                  RR4      4       Mm\#        V4      '       d"   \        P
                  P                  RS 4       M; \$        P&                  ! S R. ^
R7       \        P
                  P                  RS 4       \)        S V4       \        P
                  P                  RS 4       R#   + '       g   i     ELm; i  \         d,   p\        P
                  P!                  RS T4        Rp?LsRp?ii ; i  \         d,   p\        P
                  P!                  RS T4        Rp?L¬Rp?ii ; i)z7Reap a single browser session by its exact session key.c                  óH   <€ ^ RI Hp Hp V! S4      '       g   V ! S4       R# R# )rG   )Úcamofox_closeÚcamofox_soft_cleanupN)Útools.browser_camofoxr–  r—  )r–  r—  r_   s     €r   Ú_camofox_cleanupÚ9_cleanup_single_browser_session.<locals>._camofox_cleanupÅ  s   ø€ ßQÙ'¨×0Ò0Ù˜gÖ&ñ 1r   zCamofox cleanup for task z&cleanup_browser called for task_id: %szActive sessions: %sNz'No active session found for task_id: %sz+Found session for task %s: bb_session_id=%srˆ  r‰  ÚfeaturesÚ
lightpanda)Ústop_lightpandarŠ   r±   z&lightpanda stop failed for task %s: %sz3Skipping agent-browser close for expired session %sÚcloser"  z1agent-browser close command completed for task %sz*agent-browser close failed for task %s: %sz$Removed task %s from active sessions)r�  r‘  r,   Ú_is_camofox_moderB   r-   r?   rt   rP   ÚkeysrU   r$   Ú_maybe_stop_recordingrJ   r�  r>   r.   r9   r…   Ú_run_browser_commandr…  )r_   r™  r   r�  rA   s   f    r   ru  ru  ¾  s  ø€ ä×Ò˜gÔ&ô ×Ò×Òõ	'ô 	Ð0°°	Ð:Ð<LÔMä‡J�J×ÑÐ=¸wÔGÜ‡J�J×ÑÐ*¬D´×1EÑ1E×1JÑ1JÓ1LÓ,MÔNô 
×	×	Ó	Ü×+Ñ+×/Ñ/°Ó8ˆ÷ 
÷ Ü�
‰
×ÑÐBÀGÔLÙä‡J�J×ÑÐBÀGÈ\×M]ÑM]Ð^mÐoxÓMyÔzÜ×Ò˜gÔ&ð 	×Ñ˜Ó$×*Ð*¨×/Ñ/°×=Ò=ð	UÝ@Ù˜L×,Ñ,¨^¸RÓ@ÕAô 
˜l×	+Ò	+Ü�
‰
×ÑÐNÐPWÕXð	YÜ×)Ò)¨'°7¸BÈÕKÜ�J‰J×ÑÐPÐRYÔZô ˜w¨Ô5Ü‡J�J×ÑÐ;¸WÖE÷9 
×	Ð	ûô  ô 	UÜ�J‰J×ÑÐGÈÐRS×TÑTûð	Uûô ô 	YÜ�J‰J×ÑÐKÈWÐVW×XÑXûð	Yús<   Ã I	ÆI Ç!:J É	I	ÉJÉ(!JÊJÊKÊ!!KËKc                ó(   € V ^8„  d   QhR\         RR/# )r   Úhome_keyr   Nr<   )r   s   "r   r   r   î  s   € ÷ 4ñ 4¤sð 4¨tñ 4r   c           	     ón  a € \         P                  ;_uu_ 4        \         P                  P                  4        UUu. uF  w  rVP	                  R4      S 8X  g   K  VNK!  	  pppRRR4       X F  p\        V4       \        V4       K  	  V 3R lp\        RV4       V 3R lp\        RV4       R FS  p\        P                  ! \        \        4      ;_uu_ 4        \        \         V4      P                  S R4       RRR4       KU  	  R# u uppi   + '       g   i     L´; i  + '       g   i     Kƒ  ; i)zÀClose one profile home's browser sessions, CDP supervisors and harness daemons, and drop its
cached config slots (``/browser connect`` on a multiplexed gateway). Other profiles' browsers stay.r¤  Nc                  ó6   <€ ^ RI Hp  V P                  S4       R# )rG   ©ÚSUPERVISOR_REGISTRYN)Útools.browser_supervisorr¨  Ú	stop_home)r¨  r¤  s    €r   Ú_stop_supervisorsÚ3cleanup_profile_browsers.<locals>._stop_supervisors÷  s   ø€ Ý@Ø×%Ñ% hÖ/r   zCDP supervisor stopc                  ó$   <€ ^ RI Hp  V ! S4       R# ©rG   ©Ústop_harness_daemonsN©Útools.browser_use_clir°  )r°  r¤  s    €r   Ú_stop_harnessÚ/cleanup_profile_browsers.<locals>._stop_harnessü  s   ø€ Ý>Ù˜XÖ&r   úBrowser Use harness daemon stop)Ú_cached_command_timeoutÚ_cached_snapshot_threshold)r,   rU   rP   ru   r$   ru  rn  rB   rI  rJ  ÚAttributeErrorÚ	TypeErrorrC  rq   )r¤  ÚtaskrQ   Útask_idsr_   r«  r³  Úcaches   f       r   Úcleanup_profile_browsersr½  î  sè   ø€ ô 
×	×	Ó	Ü+.×+?Ñ+?×+EÑ+EÔ+GÔlÑ+G™Z˜TÈ4Ï8É8ÐT^ÓK_ÐckÑKk—D�DÑ+GˆÑl÷ 
ãˆÜ'¨Ô0Ü! 'Ö*ñ õ0ô Ð&Ð(9Ô:õ'ô Ð2°MÔBÛJˆÜ× Ò ¤´×;Õ;Ü”C˜Ó×#Ñ# H¨dÔ3÷ <Ñ;ó Kùó m÷ 
×	ú÷  <×;Ð;ús.   š"D¼D

ÁD

Á!DÃ!D#Ä
DÄD 	Ä#D4c                ó   € V ^8„  d   QhRR/# rD   rE   )r   s   "r   r   r     s   € ÷ "ñ "˜dñ "r   c                 óþ  € \         P                  ;_uu_ 4        \        \         P                  P	                  4       4      p RRR4       X  F  p\        V4       K  	   ^ RIHp VP                  4        R p\        RV4       \        P                  P                  4        R\         n        R F'  w  rE\        \         VR4       \        \         VR4       K)  	  R#   + '       g   i     L¢; i  \         d     L‡i ; i)zIClean up all active browser sessions (shutdown) and reset cached lookups.Nr§  c                  ó    € ^ RI Hp  V ! 4        R# r®  r±  r¯  s    r   r³  Ú+cleanup_all_browsers.<locals>._stop_harness  s   € Ý>ÙÖr   rµ  F))Ú_command_timeout_resolvedr¶  )Ú_snapshot_threshold_resolvedr·  )Ú_browser_engine_resolvedÚ_cached_browser_engine)r,   rU   rt   rP   r   ry   r©  r¨  Ústop_allr>   rB   Ú_installÚ_discover_homebrew_node_dirsÚcache_clearÚ_chromium_autoinstall_attemptedÚsetattr)r»  r_   r¨  r³  Úflagr¼  s         r   rS   rS     sÂ   € ä	×	×	Ó	Üœ×,Ñ,×1Ñ1Ó3Ó4ˆ÷ 
ãˆÜ˜Ö ñ ðÝ@Ø×$Ñ$Ô&òô Ð2°MÔBä×)Ñ)×5Ñ5Ô7Ø*/„CÔ'ó‰ˆô
 	”�T˜5Ô!Ü”�U˜DÖ!ó÷) 
×	ûô ô Ùðús   ™(CÁC. ÃC+	Ã.C<Ã;C<)é   )éH   r´   )JÚ__doc__rI  r�   rô   rF  r.  r  r8   r   r   r   Úpathlibr   Útypingr   r   r   r	   Úhermes_constantsr
   r   r   Útools.browser_tool_originr   r,   Útoolsr   r�  r   rŠ  r   r…   r   rÇ  r   rN   r4   r9   rB   rK   r\   Úcontextmanagerrk   rr   r‚   rw   r™   r¥   rÇ   rÓ   rØ   rá   rê   rü   r[   r  r   r'  rx   r6  r4  rÞ   r[  ra  rg  rn  ry   r  r…  r„  r{   ru  r½  rS   rE   r   r   Ú<module>rÖ     s?  ðñó
 Û 	Û Û Û Û Û ß ,Ñ ,Ý ß -Ó -ç bÑ bÝ 3Ý *Ý .Ý 2Ý 2Ý <õð,?Ø<@÷?õ4õò
"IðJ ×Ñô/ó ð/ð61¸tð 1ÐUZ÷ 1ò*BõZ=õ	YõKõ,õ^*õ,õ-õõ3òl$^òNò2xòõ$Mõ(õ68õv$õWôaôYõ=÷'õ õ*	4õ:õ('õ-Fõ`4÷."r   