+
    jHàj   ã                  ó¨   a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIHt ]P                  ! ]	4      t
R R ltR R lt/ tR]R	&   R
 R ltR R ltR R ltR# )aq  Gateway housekeeping chores that keep the data disk healthy: stale media-cache cleanup and the
home-channel prompt for the low-disk auto-prune decision (see ``hermes_cli/prune_advisor.py``).

A headless gateway on a small VPS is where a disk fills up, and its owner may never open the CLI,
so the question goes to each served profile's home channel; Desktop and Ink TUI viewers of local
sessions get it as a notice. It is posted at most once per
snooze window per profile: posting records the snooze, and ``/autoprune on|off`` ends it for good.
Runs from the housekeeping thread; the send is scheduled onto the gateway loop.
)ÚannotationsN)ÚPathc               ó   € V ^8„  d   QhRR/# ©é   ÚreturnÚNone© )Úformats   "ÚB/home/ubuntu/.hermes/hermes-agent/gateway/run_housekeeping_disk.pyÚ__annotate__r      s   € ÷ Añ A 4ñ Aó    c            
     óæ   aa€ ^ RI Hp HpHpHpHp ^ RIHo ^ RIH	p ^ RI
Hp ^ RIHp ^ RIHo ^ RIHp RV3R	V3R
V 3RV3RV3RS3RV3RV3RV33	 F  w  ršWš3VV3R llpV! V	 R2V4       K  	  R# )z\Hourly media-cache prune (24h max age); spillover (None) keeps the session retention window.)Úcleanup_audio_cacheÚcleanup_document_cacheÚcleanup_image_cacheÚcleanup_screenshot_cacheÚcleanup_video_cache)Úcleanup_spillover_cache)Úcleanup_terminal_temp_cache)Úcleanup_bot_dm_cache)Úcleanup_bot_relay_artifacts)ÚMEDIA_CACHE_MAX_AGE_HOURS)Ú_housekeeping_choreÚImageÚDocumentÚAudioÚVideoÚ
ScreenshotÚ	SpilloverzTerminal tempzBot DMz	Bot relayc                ój   <€ T! VSJ d   R MSR7      pV'       d   \         P                  RW4       R # R # )N)Úmax_age_hoursz*%s cache cleanup: removed %d stale file(s))ÚloggerÚinfo)ÚnameÚfnÚremovedr   r   s   && €€r   Ú_oneÚ'housekeeping_media_caches.<locals>._one&   s/   ø€ Ù¨rÐ5LÓ/L¡tÐRkÔlˆGßÜ—‘ÐHÈ$ÖXñ r   z cache cleanupN)Úgateway.platforms.baser   r   r   r   r   Útools.tool_result_storager   Útools.environments.localr   Útools.bot_mode_dmr   Útools.bot_relayr   Úagent.provider_mediar   Úgateway.runr   )r   r   r   r   r   r   r   r   r   Ú
cache_nameÚ
cleanup_fnr'   r   r   s               @@r   Úhousekeeping_media_cachesr2      s¤   ù€ ÷õ õ BÝDÝ6Ý;Ý>Ý/ð 
Ð%Ð&¨Ð5KÐ(LØ	Ð%Ð&¨Ð2EÐ(FØ	Ð/Ð0°;Ð@WÐ2XØ	Ð5Ð6¸ÐCWÐ8XØ	Ð1Ð2ó#4Ñˆ
ð !÷ 	Yð 	Yñ 	˜z˜l¨.Ð9¸4Ö@ó#4r   c               ó   € V ^8„  d   QhRR/# r   r	   )r
   s   "r   r   r   -   s   € ÷ -ñ -°$ñ -r   c           	     óN  € V e   Vf   R# ^ RI Hp ^ RIHp ^ RIHp V P                  4        UUu0 uF  vrVVkK  	  pppRV! 4       /pTP                  \        V RR4      ;'       g    / 4       VP                  4        F�  w  rYWW9  g   VP                  \        V	4      4      f   K)  VP                  \        V	4      4      p
V
f   KI  V! \        WWš4      V\        RR7      pVf   Ki  VP                  ^<R7      '       g   Kƒ  VP!                  \        V	4      4       KŸ  	  R# u uppi )	a  One housekeeping tick: post the prompt to every served profile that has a home channel, a
low disk and no decision yet. Cheap when nothing is due (two syscalls + a YAML read per
profile); the database estimate runs only for a profile that can actually receive it.N)Úsafe_schedule_threadsafe©Úprune_advisor)Úget_routing_process_hermes_homeÚ_served_profile_homesz"Auto-prune prompt scheduling error)r"   Úlog_message)Útimeout)Úagent.async_utilsr5   Ú
hermes_clir7   Úhermes_constantsr8   Ú_served_home_channel_transportsÚupdateÚgetattrÚitemsÚ
should_askr   ÚadviseÚ_postr"   ÚresultÚsnooze)ÚrunnerÚloopr5   r7   r8   ÚprofileÚ_restÚ	reachableÚhomesÚhomeÚadviceÚfuts   &&          r   Úmaybe_post_auto_prune_promptrQ   -   sü   € ð ‚~˜šÙÝ:Ý(Ý@à06×0VÑ0VÔ0XÔYÑ0X˜_˜W“Ñ0X€IÑYØÑ8Ó:Ð;€EØ	‡L�L”˜Ð!8¸$Ó?×EÐEÀ2ÔFØŸ™ž‰ˆØÔ# }×'?Ñ'?ÄÀTÃ
Ó'KÒ'SÙØ×%Ñ%¤d¨4£jÓ1ˆØŠ>ÙÙ&¤u¨V¸dÓ'KÈTÔZ`Ø3WôYˆð Œ?˜sŸz™z°"˜z×5Ô5Ø× Ñ ¤ d£Ö,ó 'ùó Zs   °D!zdict[str, float]Ú_LOCAL_NOTIFIEDc               ó   € V ^8„  d   QhRR/# r   r	   )r
   s   "r   r   r   J   s   € ÷ -ñ -¸Tñ -r   c              ƒ  óŽ  "  € ^ RI p^ RIp^ RIHp ^ RIHp ^ RIHp ^ RIH	p V P                  P                  VP                  4      p\        VRR4      p	V	e   V	P                  VP                  8w  d   R#  V! V P                   V	4      p
T
e   T
P"                  R	9  d   R# \%        T P&                  P(                  4      P*                  pTP-                  T\.        4      '       g   R# TP                  4       \.        \1        T4      &   TP3                  TP4                  T4      G Rj  x€L
 pTRJ;'       dS    TP7                  T4      RJ;'       d8    TP8                  P;                  TP                  TP=                  T4      RR7      pT'       g"   \.        P?                  \1        T4      R4       R# R#   T d     R# i ; i L›5i)
zùDesktop / Ink TUI sessions (``AuthorityConnection.resume``): one sticky ``notification.show``
per profile per snooze window while the disk is low and auto-prune is undecided. The classic
CLI asks at its own startup, so its sessions are skipped here.N©ÚPlatform)Úpolicy_for_sourcer6   )ÚRuntimeStoreErrorÚsourceznotification.show©Ú
event_type>   ÚguiÚtui) ÚasyncioÚtimeÚgateway.configrV   Úgateway.session_policyrW   r=   r7   Úhermes_state_runtimerX   ÚsessionsÚgetÚ
session_idrA   ÚplatformÚLOCALrH   rY   r   ÚdbÚdb_pathÚparentÚ
notice_duerR   ÚstrÚ	to_threadrD   rC   Úevent_streamÚpublishÚnotice_payloadÚpop)Ú	authorityÚrefr^   r_   rV   rW   r7   rX   ÚliverY   ÚpolicyrN   rO   Ú	delivereds   &&            r   Úpublish_local_auto_prune_noticerw   J   sƒ  é € ó ÛÝ'Ý8Ý(Ý6à×Ñ×!Ñ! #§.¡.Ó1€DÜ�T˜8 TÓ*€FØ‚~˜Ÿ™¨H¯N©NÔ:ÙðÙ" 9×#3Ñ#3°VÓ<ˆð ‚~˜Ÿ™¨nÔ<ÙÜ�	—‘×$Ñ$Ó%×,Ñ,€DØ×#Ñ# D¬/×:Ò:ÙØ!%§¡£„O”C˜“IÑØ×$Ñ$ ]×%9Ñ%9¸4Ó@×@€Fà˜tÐ#÷ Oð O¨×(@Ñ(@ÀÓ(FÈdÐ(R÷ Oð OØ×&Ñ&×.Ñ.¨s¯~©~¸}×?[Ñ?[Ð\bÓ?cØ:Mð /ó Oð ÷ Ü×ÑœC ›I tÖ,ñ øð ô Úðúñ AùsI   ‚A4GÁ7F5 Â
BGÄ'GÄ(GÄ7GÅ?GÆ#GÆ5G Æ<GÆ?G Ç Gc               ó   € V ^8„  d   QhRR/# r   r	   )r
   s   "r   r   r   l   s   € ÷ 
hñ 
h°Tñ 
hr   c                ó,  € ^ RI Hp ^ RIHp ^ RIHp \        VRR4      VP                  8w  d   R# V! V 4      pVe&   VP                  P                  VP                  4      MRpVe-   VP                  P                  VP                  RV/RR7       R# R# )	zXAfter /autoprune is answered on a local session, drop its sticky notice for that viewer.rU   )Úactive_authority)Ú
NOTICE_KEYrf   NÚkeyznotification.clearrZ   )r`   rV   Úgateway.session_authoritiesrz   Úhermes_cli.prune_advisorr{   rA   rg   rc   rd   Úchat_idrn   ro   )rH   rY   rV   rz   r{   rr   rt   s   &&     r   Úclear_local_auto_prune_noticer€   l   s   € å'Ý<Ý3Üˆv�z 4Ó(¨H¯N©NÔ:ÙÙ  Ó(€IØ5>Ò5Jˆ9×Ñ×!Ñ! &§.¡.Ô1ÐPT€DØÒØ×Ñ×!Ñ! &§.¡.°5¸*Ð2EÐRfÐ!Ögñ r   c               ó   € V ^8„  d   QhRR/# )r   r   Úboolr	   )r
   s   "r   r   r   y   s   € ÷ ñ °$ñ r   c              ƒ  ón  a a"  € ^ RI Hp ^ RIHp ^ RIHp RpVe   V! \        V4      4      M\        P                  ! 4       pT;_uu_4       GRj  x€L
  \        S P                  4       4       F�  w  ršr¼pW‘8w  d   K  VP                  '       d   \        VP                  RR4      MRpRR	P                  V! W>R
7      4      ,           p. oW¬Wß3V V3R llpV! VV
R7      G Rj  x€L
  T;'       g    \        S4      pK�  	  RRR4      GRj  x€L
  V#  LÀ L1 L
  + GRj  x€L 
 '       g   i     T# ; i5i)zOSend to the profile's home channels; True when at least one send was delivered.)Ú_async_profile_runtime_scope)Úpresent_notification)Úadvice_linesFNÚtyped_command_prefixÚ/u   âš  Ú
)Úcommand_prefixc           	   “  óh   <"  € SP                  SP                  WW#R 4      G Rj  x€L
 4       R#  L
5i)z&Auto-prune prompt failed for %s:%s: %sN)ÚappendÚ_send_home_channel_message)rf   Úhome_chÚ	transportÚmessagerH   Úsents   &&&&€€r   Ú_sendÚ_post.<locals>._send‰   s5   øé € Ø—‘ &×"CÑ"CØ yÐ;có#e÷ eö fñ eùs   ƒ"2¥0¦2)rf   )r/   r„   Úgateway.warning_notificationsr…   r~   r†   r   Ú
contextlibÚnullcontextÚlistr?   ÚadapterrA   ÚjoinÚany)rH   rJ   rN   rO   r„   r…   r†   rv   ÚscopeÚtarget_profilerf   Ú_cfgrŽ   r�   Úprefixr�   r’   r‘   s   f&&&             @r   rE   rE   y   s  ùé € å8ÝBÝ5à€IØ8?Ò8KÑ(¬¨d«Ô4ÔQ[×QgÒQgÓQi€Eß�uŠuÜBFÀv×GmÑGmÓGoÖBpÑ>ˆN d°YØÔ(ÙØPY×Pa×PaÐPa”W˜Y×.Ñ.Ð0FÈÔLÐgjˆFØ˜tŸy™y©°fÔ)TÓUÕUˆGØ!ˆDà%-È)÷ fð fñ ' u°xÔ@×@Ð@Ø!×.Ð.¤S¨£YŠIñ Cq÷ �uð Ðñ ñ A÷ �u�u‰uð Ðüsm   „AD5ÁDÁD5Á:DÂADÃ"D
Ã#DÃ0DÄ D5ÄDÄD5ÄDÄD5ÄD2	ÄD!Ä
D2	Ä*D2	Ä,	D5)Ú__conditional_annotations__Ú__doc__Ú
__future__r   r•   ÚloggingÚpathlibr   Ú	getLoggerÚ__name__r"   r2   rQ   rR   Ú__annotations__rw   r€   rE   )rŸ   s   @r   Ú<module>r§      sR   øðôõ #ã Û Ý à	×	Ò	˜8Ó	$€õAõ2-ð4 %'€Ð!Ó &õ-õD
h÷r   