+
    jHàj¨M  ã                  óž  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	H
t
 ^ RIHt ^ RIHt ]P                  ! ]4      tRHt^],          tRt^],          tRItRtR	tRItRt]
! R
R7       ! R R4      4       t]
! R
R7       ! R R4      4       tR R ltRJR R lltR R ltR R lt RJR R llt!R R lt"RJRR/R R lllt#R]3R R  llt$RJR! R" llt%RJR# R$ llt&R% R& lt'R' R( lt(R) R* lt)RJR+ R, llt*R- R. lt+R/ R0 lt,R1 R2 lt-R3R4/R5 R6 llt.R7t/R8 R9 lt0RJR: R; llt1R< R= lt2R> R? lt3RJR@ RA llt4RBt5RJRC RD llt6RE]7/RF RG llt8R# )Ka  Low-disk prompt for ``sessions.auto_prune`` (off by default).

Auto-prune deletes history, so it is opt-in. Users who never decided still need to hear about it
when the disk holding ``state.db`` runs low: every surface asks once the disk is low, and the
question stops forever as soon as ``sessions.auto_prune`` is written to the user's config.yaml
(either answer). "Later" snoozes for :data:`SNOOZE_SECONDS`.

The hot-path check is two syscalls (``os.stat`` + ``shutil.disk_usage``, microseconds), so it can
run at every session start. Only when it fires does :func:`advise` open the database read-only to
estimate what a prune would actually free, so the prompt can say plainly when pruning will not
fix the disk (nothing old enough to delete, or the store is a small share of the full disk).
)ÚannotationsN)Ú	dataclass)ÚPath)ÚOptionalg      $@i€Q z.auto_prune_prompt.jsonz.auto_prune_estimate.jsonT)Úfrozenc                  óL   € ] tR t^-t$ R]R&   R]R&   R]R&   ]R R l4       tRtR# )	ÚDiskSnapshotÚintÚdb_bytesÚ
free_bytesÚtotal_bytesc               ó   € V ^8„  d   QhRR/# ©é   ÚreturnÚbool© )Úformats   "Ú=/home/ubuntu/.hermes/hermes-agent/hermes_cli/prune_advisor.pyÚ__annotate__ÚDiskSnapshot.__annotate__4   s   € ÷ Qñ Q�Tñ Qó    c                	óî   € V P                   ^ 8:  d   R# V P                  R,          V P                   ,          pV P                  \        8  ;'       g%    V\        8  ;'       d    V P                  \        8  # )é    Fg      Y@)r   r   ÚLOW_FREE_FLOORÚLOW_FREE_PERCENTÚLOW_FREE_HEADROOM)ÚselfÚfree_pcts   & r   ÚlowÚDiskSnapshot.low3   se   € à×Ñ˜qÔ ÙØ—?‘? UÕ*¨T×-=Ñ-=Õ=ˆØ�‰¤Ñ/÷ Qð QØÔ'Ñ'×OÐO¨D¯O©OÔ>OÑ,Oð	Qr   r   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__annotations__Úpropertyr   Ú__static_attributes__r   r   r   r   r   -   s&   ‡ àƒMØƒOØÓàôQó ôQr   r   c                  ó|   € ] tR t^<t$ R]R&   R]R&   R]R&   R]R&   R]R&   RtR	]R
&   RtR	]R&   ]R R l4       tRt	R# )ÚAdvicer   Údiskr	   Úretention_daysÚprunable_sessionsÚtotal_sessionsÚreclaim_bytesTr   Úestimate_okÚvacuum_after_prunec               ó   € V ^8„  d   QhRR/# r   r   )r   s   "r   r   ÚAdvice.__annotate__G   s   € ÷ ;ñ ;�tñ ;r   c                óV  € V P                   ^ 8X  d   R# \        V P                  P                  V P                  ,
          V P                  P
                  V P                  ,           V P                  P                  4      pV P                  \        8¬  ;'       g    VP                  '       * # )ztWhether a prune would free a meaningful amount: at least 1 GiB, or enough to lift the
disk back out of the low band.F)	r,   r   r*   r
   r.   r   r   ÚGIBr   )r   Úlifteds   & r   ÚhelpsÚAdvice.helpsF   sz   € ð ×!Ñ! QÔ&ÙÜ˜dŸi™i×0Ñ0°4×3EÑ3EÕEØ"Ÿi™i×2Ñ2°T×5GÑ5GÕGÈÏÉ×I^ÑI^ó`ˆà×!Ñ!¤SÑ(×:Ð:°·
±
¬NÐ:r   r   N)
r!   r"   r#   r$   r%   r/   r0   r&   r6   r'   r   r   r   r)   r)   <   sG   ‡ à
ÓØÓØÓØÓØÓØ€K�ÓØ#Ð˜Ó#àô;ó ô;r   r)   c               ó    € V ^8„  d   QhRRRR/# ©r   ÚhomeúOptional[Path]r   r   r   )r   s   "r   r   r   Q   s   € ÷ ñ �ð  4ñ r   c                ó:   € V e   \        V 4      # ^ RIHp V! 4       # )N)Úget_hermes_home)r   Úhermes_constantsr=   )r:   r=   s   & r   Ú_homer?   Q   s   € ØÒÜ�D‹zÐÝ0ÙÓÐr   c               ó    € V ^8„  d   QhRRRR/# ©r   r:   r;   r   zOptional[DiskSnapshot]r   )r   s   "r   r   r   X   s   € ÷ 7ñ 7˜ð 7Ð2Hñ 7r   c                ó  € \        V 4      R,          p \        P                  ! V4      P                  p\        P
                  ! VP                  4      p\        Y#P                  TP                  4      #   \         d     R# i ; i)zZ``state.db`` size plus free/total bytes of its filesystem; None when either is unreadable.ústate.dbN)r?   ÚosÚstatÚst_sizeÚshutilÚ
disk_usageÚparentÚOSErrorr   ÚfreeÚtotal)r:   ÚdbÚsizeÚusages   &   r   Údisk_snapshotrP   X   sg   € ä	ˆt‹�zÕ	!€BðÜ�wŠw�r‹{×"Ñ"ˆÜ×!Ò! "§)¡)Ó,ˆô ˜Ÿj™j¨%¯+©+Ó6Ð6øô ô Úðús   ”A A4 Á4BÂBc               ó    € V ^8„  d   QhRRRR/# )r   r:   r;   r   zOptional[dict]r   )r   s   "r   r   r   c   s   € ÷ 
:ñ 
:˜nð 
:°ñ 
:r   c                óø   € ^ RI Hp  V! \        V 4      R,          RR7      P                  R4      p\        T\        4      '       d   T# / #   \         d$   p\
        P                  RTRR7        Rp?R# Rp?ii ; i)	a  *home*'s ``sessions:`` block as maintenance sees it (user file, ``${VAR}`` expansion, managed
overlay; no defaults merged) or None when the file cannot be read. Read through *home*'s own
config path, so gateway housekeeping gets each served profile's values, not the caller's.)Úload_user_config_effectiveúconfig.yamlT)Úfail_closedÚsessionsz(auto-prune advice: config unreadable: %s)Úexc_infoN)	Úhermes_cli.config_effectiverS   r?   ÚgetÚ	ExceptionÚloggerÚdebugÚ
isinstanceÚdict)r:   rS   rV   Úexcs   &   r   Ú_effective_sessionsr`   c   sp   € õ GðÙ-¬e°D«k¸MÕ.IÐW[Ô\×`Ñ`ÐakÓlˆô " (¬D×1Ò1ˆ8Ð9°rÐ9øô ô Ü�‰Ð?ÀÈtˆÔTÝûðús   ˆ)A ÁA9ÁA4Á4A9c               ó    € V ^8„  d   QhRRRR/# )r   rV   r^   r   r	   r   )r   s   "r   r   r   p   s   € ÷ %ñ %˜dð % sñ %r   c                ó€   €  \        V P                  R^Z4      4      pT^ 8¼  d   T# ^Z#   \        \        3 d     ^Z# i ; i)zYSame coercion maintenance applies (``int(...)``); an unusable value reads as the default.r+   )r	   rY   Ú	TypeErrorÚ
ValueError)rV   Údayss   & r   Ú_retention_daysrf   p   sI   € ðÜ�8—<‘<Ð 0°"Ó5Ó6ˆð ˜1”9ˆ4Ð$ "Ð$øô ”zÐ"ô Úðús   ‚( ¨=¼=c               ó    € V ^8„  d   QhRRRR/# ©r   r:   r;   r   r   r   )r   s   "r   r   r   y   s   € ÷ Añ A�Nð A¨dñ Ar   c                ó:   € \        V 4      pVRJ;'       d    RV9  # )z¿True while neither the user's config nor an administrator's managed layer sets
``sessions.auto_prune``. A managed value is already decided: asking would promise a choice the
user cannot make.NÚ
auto_prune)r`   )r:   rV   s   & r   Ú	undecidedrk   y   s&   € ô # 4Ó(€HØ˜4Ð×@Ð@ L¸Ñ$@Ð@r   c               ó    € V ^8„  d   QhRRRR/# r9   r   )r   s   "r   r   r   �   s   € ÷ &ñ &�~ð &¨$ñ &r   c                ó.   € \        V 4      \        ,          # ©N)r?   Ú_SNOOZE_FILE©r:   s   &r   Ú_snooze_pathrq   �   s   € Ü�‹;œÕ%Ð%r   Únowc               ó$   € V ^8„  d   QhRRRRRR/# )r   r:   r;   rr   zOptional[float]r   r   r   )r   s   "r   r   r   …   s!   € ÷ (ñ (�.ð (°ð (ÈDñ (r   c               ó  €  \        \        P                  ! \        V 4      P	                  R R7      4      P                  R^ 4      4      pT;'       g    \        P                  ! 4       T8  #   \        \        \        \        3 d     R# i ; i)ú	utf-8-sig©ÚencodingÚsnoozed_untilF)ÚfloatÚjsonÚloadsrq   Ú	read_textrY   rJ   rd   rc   ÚAttributeErrorÚtime)r:   rr   Úuntils   &$ r   Úsnoozedr€   …   st   € ðÜ”d—j’j¤¨dÓ!3×!=Ñ!=À{Ð!=Ó!SÓT×XÑXÐYhÐjkÓlÓmˆð ×Ð”4—9’9“; %Ñ'Ð'øô ”Z¤¬NÐ;ô Úðús   ‚AA, Á,BÂ
Bc               ó$   € V ^8„  d   QhRRRRRR/# )r   r:   r;   Úsecondsry   r   ÚNoner   )r   s   "r   r   r   �   s&   € ÷ Tñ T�ð T°ð TÈDñ Tr   c                ón   € ^ RI Hp V! \        V 4      R\        P                  ! 4       V,           /4       R# )r   ©Úatomic_json_writerx   N)Úutilsr†   rq   r~   )r:   r‚   r†   s   && r   Úsnoozerˆ   �   s$   € Ý'Ù”l 4Ó(¨?¼D¿IºI»KÈ'Õ<QÐ*RÖSr   c               ó    € V ^8„  d   QhRRRR/# rA   r   )r   s   "r   r   r   ’   s   € ÷ ñ �^ð Ð/Eñ r   c                ó”   € \        V 4      pVe   VP                  '       g   R# \        V 4      '       d   \        V 4      '       d   R# V# )zµThe cheap gate every surface runs at session start: the snapshot when the disk is low and
the user has neither decided nor snoozed, else None. Two syscalls plus one small YAML read.N)rP   r   rk   r€   )r:   Úsnaps   & r   Ú
should_askrŒ   ’   s7   € ô ˜Ó€DØ‚|˜4Ÿ8Ÿ8˜8ÙÜ�T�?Š?œg dŸmšmÙØ€Kr   c               ó    € V ^8„  d   QhRRRR/# )r   r:   r;   r   zOptional[Advice]r   )r   s   "r   r   r   �   s   € ÷ -ñ -�ð -Ð+;ñ -r   c                ó¦  € \        V 4      pVf   R# \        V 4      ;'       g    / p\        V4      p^ ;p;p;rgRp ^ RIHp	 V	! \        V 4      R,          RR7      p
 V
P                  VR/ RR7      w  r¼\        V
P                  RV R2V4      ;'       g    R4      w  rEV'       d˜   \        V
4      pV
P                  R	V R
V R2V4      ;'       g    R^ ,          p\        WP                  4      pVf?   V
P                  R	V R2. 4      ;'       g    R^ ,          p\        WVP                  R7       \        Wv4      pV
P                  4        T'       d$   \-        TP                  T,          T,          4      M^ p\/        Y\-        T4      \-        T4      Yø\1        TP3                  RR4      4      4      pT'       d6   \        T RTRTP4                  RTP6                  RTP                  RT/R7       T#   T
P                  4        i ; i  \        P                   \"        \$        \&        3 d#   p\(        P+                  RT4       Rp Rp?LýRp?ii ; i)z¹:func:`should_ask` plus the reclaim estimate. Opens state.db read-only (a second or two on
a multi-GB store), so callers run it only after the cheap gate fires or off the prompt thread.NT)Ú	SessionDBrC   )Údb_pathÚ	read_only)Úwhole_lineagesz.SELECT (SELECT COUNT(*) FROM sessions s WHERE z"), (SELECT COUNT(*) FROM sessions)zSELECT COALESCE(SUM(zO), 0) FROM messages m WHERE m.session_id IN (SELECT s.id FROM sessions s WHERE Ú)z), 0) FROM messages m)r   Útotal_at_db_bytesz3auto-prune advice: reclaim estimate unavailable: %sFr0   r+   ÚprunablerL   r
   r.   )Úadvice)r   r   )r   )rŒ   r`   rf   Úhermes_stater�   r?   Ú_prune_whereÚtupleÚ	_read_oneÚ_row_bytes_sqlÚ_cached_total_bytesr
   Ú_store_estimateÚmaxÚcloseÚsqlite3ÚErrorrJ   ÚRuntimeErrorrd   r[   r\   r	   r)   r   rY   r,   r-   )r:   r‹   rV   Ú	retentionr•   rL   Úprunable_bytesr   r/   r�   rM   ÚwhereÚparamsÚ	row_bytesr_   Úreclaimr–   s   &                r   Úadviser©   �   sQ  € ô �dÓ€DØ‚|Ùô # 4Ó(×.Ð.¨B€HÜ Ó)€IØ67Ð7€HÐ7ˆuÐ7�~Ø€KðÝ*Ùœu T›{¨ZÕ7À4ÔHˆð	ØŸO™O¨I°t¸RÐPT˜OÓU‰MˆEÜ# B§L¡LØ@ÀÀÐGiÐjØó%÷ %"ð %"à!ó#‰OˆH÷ ô +¨2Ó.�	Ø"$§,¡,Ø*¨9¨+ð 6:Ø:?¸ÀðCØDJó#L÷ #Tð #TàOSÐUVõ"X�ô 2°$¿¹ÓF�ØÒ&Ø#%§<¡<Ø.¨y¨kÐ9NÐOÐQSó$U÷ $]ð $]ØX\Ð^_õ#a�Kä# DÐUY×UbÑUbÕcÜ! +Ó>�à�H‰HŒJ÷ DOŒc�$—-‘- .Õ0°;Õ>Ô?ÐTU€GÜ�D¤S¨£]´C¸³JÀÜ˜Ÿ™Ð&:¸DÓAÓBóD€FçÜ˜Ð&6¸	À:Èv×OgÑOgØ&-¨v×/DÑ/DÀjÐRV×R_ÑR_Ø&5°wð&@õ 	Að €Møð �H‰H�JûÜ�M‰Mœ7¤L´*Ð=ô Ü�‰ÐJÈCÔPØ�ûðús<   ¼ H	 ÁA4G4 Ã?G4 Ä,G4 Ä>H	 Ç4HÈH	 È	%IÈ.IÉIc               ó    € V ^8„  d   QhRRRR/# )r   r:   r;   r   r^   r   )r   s   "r   r   r   Í   s   € ÷ 2ñ 2˜ð 2¨Dñ 2r   c                óÞ   €  \         P                  ! \        V 4      \        ,          P	                  R R7      4      p\        T\        4      '       d   T# / #   \
        \        3 d    / u # i ; i)ru   rv   )	rz   r{   r?   Ú_ESTIMATE_FILEr|   rJ   rd   r]   r^   )r:   Údatas   & r   Ú_read_estimater®   Í   s`   € ðÜ�zŠzœ5 ›;¬Õ7×BÑBÈKÐBÓXÓYˆô ˜d¤D×)Ò)ˆ4Ð1¨rÐ1øô ”ZÐ ô ØŠ	ðús   ‚:A ÁA,Á+A,c               ó    € V ^8„  d   QhRRRR/# )r   r:   r;   r   rƒ   r   )r   s   "r   r   r   Õ   s   € ÷ Hñ H˜.ð H°tñ Hr   c                ó4  € ^ RI Hp \        V 4      p\        P                  ! 4       pVP	                  4        F  w  rVWcV&   WCV R2&   K  	   V! \        V 4      \        ,          V4       R#   \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)zšMerge *fields* (each stamped with the time) into the estimate sidecar; a full disk that
cannot take the write just means the next estimate measures again.r…   Ú_atz*auto-prune advice: estimate not cached: %sN)
r‡   r†   r®   r~   Úitemsr?   r¬   rJ   r[   r\   )r:   Úfieldsr†   r­   rr   ÚkeyÚvaluer_   s   &,      r   r�   r�   Õ   s€   € õ (Ü˜$Ó€DÜ
�)Š)‹+€CØ—l‘l–n‰
ˆØˆS‰	Ø�ˆu�Cˆ[Óñ %ðHÙœ% ›+¬Õ6¸Ö=øÜô HÜ�‰ÐAÀ3×GÒGûðHús   ÁA+ Á+BÁ6BÂBc               ó$   € V ^8„  d   QhRRRRRR/# )r   r:   r;   r
   r	   r   zOptional[int]r   )r   s   "r   r   r   ä   s!   € ÷ 	(ñ 	(˜nð 	(¸ð 	(Àñ 	(r   c                óX  € \        V 4      p \        VR,          4      \        VR,          4      \        VR,          4      rTp\        P                  ! 4       T,
          \        8”  g   T^ 8:  g   T^ 8:  d   R# \        Y1,          T,          4      #   \        \        \
        3 d     R# i ; i)zXThe week-old all-rows byte total scaled to the current file size, or None to re-measure.r   Útotal_bytes_atr”   N)r®   r	   ry   ÚKeyErrorrc   rd   r~   ÚTOTAL_BYTES_TTL)r:   r
   r­   rL   ÚatÚbases   &&    r   rœ   rœ   ä   s�   € ä˜$Ó€DðÜ˜d =Õ1Ó2´E¸$Ð?OÕ:PÓ4QÔSVÐW[Ð\oÕWpÓSq�4ˆô ‡y‚yƒ{�RÕœ/Ô)¨T°Q¬Y¸%À1¼*ÙÜˆuÕ $Õ&Ó'Ð'øô	 ”i¤Ð,ô Úðús   �5B ÂB)Â(B)c               ó    € V ^8„  d   QhRRRR/# )r   r:   r;   r   ztuple[Optional[Advice], bool]r   )r   s   "r   r   r   ð   s   € ÷ ñ ˜ð Ð2Oñ r   c                óâ  € \        V 4      pVf   R
# \        V 4      ;'       g    / p\        V4      p\        V 4      pVP	                  R4      p \        V\        4      '       d   \        VR,          4      V8X  g   R# \        P                  ! 4       \        VR,          4      ,
          \        8„  p\        VR,          4      VP                  ,          \        \        VR,          4      ^4      ,          p\        W\        VR,          4      \        VR,          4      \        WqP                  4      R\        VP	                  R	R4      4      4      V3#   \         \"        \$        3 d    Ru # i ; i)a=  ``(advice, stale)`` from the last stored estimate for the same retention, scaled to the
live file and disk; ``(None, True)`` when nothing usable is stored. No DB read. A stale one
(over :data:`CLI_ADVICE_TTL`) still answers: refusing it would let a user who launches less
often than the TTL miss the question forever.r–   r+   TÚ	advice_atr.   r
   r•   rL   r0   )NF)NT)rŒ   r`   rf   r®   rY   r]   r^   r	   r~   ry   ÚCLI_ADVICE_TTLr
   rž   r)   Úminr   r¹   rc   rd   )r:   r‹   rV   r£   ÚstoredÚestÚstaler¨   s   &       r   Úcached_advicerÅ   ð   s5  € ô
 �dÓ€DØ‚|ØÐÜ" 4Ó(×.Ð.¨B€HÜ Ó)€IÜ˜DÓ!€FØ
�*‰*�XÓ
€CðÜ˜3¤×%Ò%¬#¨cÐ2BÕ.CÓ*DÈ	Ô*QØÐÜ—	’	“œe F¨;Õ$7Ó8Õ8¼>ÑIˆÜ�c˜/Õ*Ó+¨d¯m©mÕ;¼sÄ3ÀsÈ:ÅÓCWÐYZÓ?[Õ[ˆÜ�d¤s¨3¨z­?Ó';¼SÀÀWÅÓ=NÔPSÐT[×]jÑ]jÓPkØœD §¡Ð.BÀDÓ!IÓJóLØMRðSð 	Søä”i¤Ð,ô ØÒðús   Á.E Á>CE ÅE.Å-E.c               ó   € V ^8„  d   QhRR/# )r   r   Ústrr   )r   s   "r   r   r     s   € ÷ Zñ Z˜#ñ Zr   c                óî   € V P                  R. 4       Uu. uF3  p\        V^,          4      P                  4       R9   g   K*  V^,          NK5  	  ppRP                  R V 4       4      ;'       g    R# u upi )z¥Stored size of one ``messages`` row: the byte length of every text/blob column (read from
the live schema, so a column added later is counted without touching this).zPRAGMA table_info(messages)z + c              3  ó.   "  € T F  pR V R2x € K  	  R# 5i)zCOALESCE(LENGTH(CAST(m."z" AS BLOB)), 0)Nr   )Ú.0Úcs   & r   Ú	<genexpr>Ú!_row_bytes_sql.<locals>.<genexpr>  s   é € ÐRÉTÈÐ0°°°?ÕCËTùs   ‚Ú0>   Ú ÚBLOBÚTEXT)Ú	_read_allrÇ   ÚupperÚjoin)rM   ÚrÚcolss   &  r   r›   r›     sp   € ð Ÿ,™,Ð'DÀbÔIó :ÑI�QÜ�1�Q•4‹y�‰Ó Ð$8Ñ8ô ˆAˆa�DˆDÑI€Dð :à�:‰:ÑRÉTÓRÓR×YÐYÐVYÐYùò:s   •'A2ÁA2c               ó    € V ^8„  d   QhRRRR/# ©r   Únr	   r   rÇ   r   )r   s   "r   r   r     s   € ÷ Rñ Rˆ3ð R�3ñ Rr   c                óh   € V \         8¼  d   V \         ,          R R2# \        V ^ 4      R,          R R2# )zRHuman size: GB at or above 1 GiB, MB below (a 26 MB store must not read "0.0 GB").z.1fz GBz.0fz MBi   )r4   rž   ©rÙ   s   &r   Ú_gbrÜ     s5   € à"#¤s¤(ˆa”#�g�cˆ]˜#ÐÐQ´3°q¸!³9¸yÕ3HÈÐ2MÈSÐ0QÐQr   c               ó    € V ^8„  d   QhRRRR/# rØ   r   )r   s   "r   r   r     s   € ÷ 4ñ 4�ð 4˜ñ 4r   c                ó8   € V  R 2V ^8X  d	   R,           # R,           # )z sessionrÏ   Úsr   rÛ   s   &r   Ú	_sessionsrà     s!   € ØˆS�ˆ> 1¨¤6˜RÕ3Ð3¨sÕ3Ð3r   Úcommand_prefixÚ/c               ó$   € V ^8„  d   QhRRRRRR/# )r   r–   r)   rá   rÇ   r   z	list[str]r   )r   s   "r   r   r     s!   € ÷ ñ ˜ð °Cð À)ñ r   c          
     ó¬  € V P                   pR\        VP                  4       R\        VP                  4       R\        VP                  4       R2RV P
                   R2.pV P                  '       g   VP                  R4       MýV P                  ^ 8X  dQ   V P                  '       d'   R\        V P                  4       R	V P
                   R
2MRpVP                  RV R24       MœV P                  '       g@   VP                  R\        V P                  4       R\        V P                  4       R24       MKVP                  R\        V P                  4       RV P                   R\        V P                  4       R24       V P                  '       d$   V P                  '       d   VP                  R4       TpVP                  V RV RV R24       V# )zXPlain-text prompt shared by every surface (no markup); the last line names the commands.zLow disk space: ú	 free of z'. Your session history (state.db) uses Ú.zOAuto-prune is off. Turning it on deletes ended sessions inactive for more than z6 days, once a day (pinned and open sessions are kept).z@Could not read state.db to estimate how much pruning would free.znone of your z is older than z daysz%there is no session history to deletez!Pruning will not help right now: z&. Something else is filling this disk.z Pruning would remove only about z of history (z+), which will not fix this disk on its own.zPruning would remove about z of z).zŠDeleted history frees space inside state.db; to give it back to the disk, run `hermes sessions optimize` with other Hermes windows closed.zautoprune on to enable, z6autoprune off to keep everything (never asked again), z)autoprune later to be reminded in a week.)r*   rÜ   r   r   r
   r+   r/   Úappendr,   r-   rà   r6   r.   )r–   rá   ÚdÚlinesÚheldÚps   &$    r   Úadvice_linesrì     sÛ  € à�‰€Aà
œ3˜qŸ|™|Ó,Ð-¨Y´s¸1¿=¹=Ó7IÐ6Jð K0Ü03°A·J±J³Ð/@Àð	Cà
YØ× Ñ Ð
!Ð!Wð	Yð€Eð ××ÐØ�‰ÐWÕXØ	×	!Ñ	! QÔ	&à×(×(Ð(ð  ¤	¨&×*?Ñ*?Ó @ÐAÀÐQW×QfÑQfÐPgÐglÑmØ.Uð 	à�‰Ð8¸¸Ð>dÐeÕfØ�\�\ˆ\Ø�‰Ð7¼¸F×<PÑ<PÓ8QÐ7Rð SÜ" 6×#;Ñ#;Ó<Ð=Ð=hðjõ 	kð 	�‰Ð2´3°v×7KÑ7KÓ3LÐ2Mð NØ×1Ñ1Ð2°$´yÀ×AVÑAVÓ7WÐ6XÐXZð\ô 	]à××Ð˜f×6×6Ð6ð 	�‰ð Tô 	Uà€AØ	‡L�L�A�3Ð.¨q¨cÐ1gØ�3Ð?ðAô Bà€Lr   úsessions.auto_prunec               ó    € V ^8„  d   QhRRRR/# )r   r–   r)   r   r^   r   )r   s   "r   r   r   ;  s   € ÷ 1ñ 1˜6ð 1 dñ 1r   c                ó¨   € V P                   pRR\        VP                  4       R2RRP                  \	        V 4      4      RRRR	R
RR\
        R\
        /# )z¶``notification.show`` payload for TUI/Desktop: a short status-line ``text`` plus the full
question in ``detail`` (Desktop's expandable toast body; Ink prints it into the transcript).Útextu   âš  Low disk (u!    free) Â· /autoprune on|off|laterÚdetailÚ
ÚlevelÚwarnÚkindÚstickyÚttl_msNr´   Úid)r*   rÜ   r   rÔ   rì   Ú
NOTICE_KEY)r–   rè   s   & r   Únotice_payloadrú   ;  s[   € ð 	�‰€AØ�n¤S¨¯©Ó%6Ð$7Ð7XÐYØ�d—i‘i¤¨VÓ 4Ó5°wÀÈÐPXÐZbÐdhØ”:˜t¤Zð1ð 1r   c               ó    € V ^8„  d   QhRRRR/# rh   r   )r   s   "r   r   r   D  s   € ÷ 0ñ 0�>ð 0¨Tñ 0r   c                óH   € \        V 4      '       * ;'       g    \        V 4      # )z�True once the question is settled for now (a saved on/off, or a live ``later`` snooze):
the only state in which a shown notice may be withdrawn.)rk   r€   rp   s   &r   Úansweredrý   D  s   € ô ˜‹Ô×/Ð/¤'¨$£-Ð/r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r:   r;   Úshownr^   r   r   r   )r   s   "r   r   r   J  s&   € ÷ @ñ @�^ð @¨Dð @°Tñ @r   c                óÄ   € \        V 4      f   R# VP                  \        \        V 4      4      4      pVRJ ;'       g$    \        P                  ! 4       V,
          \
        8¬  # )z¯Per-process dedup that re-arms: a home already noticed is due again once the gate passes
and a full snooze window has gone by since (so ``later`` really asks again in a week).NF)rŒ   rY   rÇ   r?   r~   ÚSNOOZE_SECONDS)r:   rÿ   Úlasts   && r   Ú
notice_duer  J  sK   € ô �$ÓÒÙØ�9‰9”Sœ˜t›Ó%Ó&€DØ�4ˆ<×?Ð?œ4Ÿ9š9›;¨Õ-´Ñ?Ð?r   c               ó   € V ^8„  d   QhRR/# r   r   )r   s   "r   r   r   S  s   € ÷ ?ñ ?�ñ ?r   c                 ó0   € ^ RI Hp  V P                  R4      # )zTTrue when an administrator pins ``sessions.auto_prune`` (the user cannot change it).©Úmanaged_scoperí   )Ú
hermes_clir  Úis_key_managedr  s    r   Úmanagedr
  S  s   € å(Ø×'Ñ'Ð(=Ó>Ð>r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úenabler   r:   r;   r   r   )r   s   "r   r   r   Y  s&   € ÷ Uñ U�4ð U˜~ð U¸ñ Ur   c                ó  € ^ RI p^ RIHp ^ RIHp \        4       '       d   R# \        V4      R,          p V! VP                  4       V! VR\        V 4      4        \        T4      P                  RR	7       \        \!        T4      ;'       g    / P#                  R
4      4      \        T 4      8H  #   \        \        TP                  3 d"   p\        P                  RT4        Rp?R# Rp?ii ; i  \         d     L†i ; i)z´Persist the user's answer as an explicit ``sessions.auto_prune``; ends the prompt for good.
False when the save failed or did not take effect (an administrator-managed value wins).N)Úmkdir_under_hermes_home)Úatomic_roundtrip_yaml_updateFrT   rí   z&Could not save sessions.auto_prune: %sT)Ú
missing_okrj   )Úhermes_yamlr>   r  r‡   r  r
  r?   rI   r   rJ   rd   Ú	YAMLErrorr[   Úwarningrq   Úunlinkr`   rY   )r  r:   Úyamlr  r  Úpathr_   s   &&     r   Údecider  Y  sÓ   € ó Ý8Ý2Ü‡y‚yÙÜ�‹;˜Õ&€DðÙ §¡Ô,Ù$ TÐ+@Ä$ÀvÃ,ÔOðÜ�TÓ×!Ñ!¨TÐ!Ô2ô Ô$ TÓ*×0Ð0¨b×5Ñ5°lÓCÓDÌÈVËÑTÐTøô ”Z §¡Ð0ô Ü�‰Ð?ÀÔEÝûðûô
 ô Ùðús)   ¶%B0 ÁC0 Â0C-ÃC(Ã(C-Ã0C>Ã=C>zQCould not save sessions.auto_prune; check disk space and config.yaml permissions.c               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚargsrÇ   r:   r;   r   r   )r   s   "r   r   r   r  s!   € ÷ 2ñ 2�cð 2 ð 2¸3ñ 2r   c           	     óâ  € T ;'       g    RP                  4       P                  4       p\        V4      ;'       g    / pVP                  R4      '       d   RMRpVR9   d   \	        4       '       d   RV R2# VR9   d   \        RV4      '       d   R# \        # VR9   d   \        R	V4      '       d   R
# \        # VR9   d   \        V4       R# \	        4       '       d   RM
RV9  d   RMRp\        V4      pV'       d\   R\        VP                  4       R\        VP                  4       R\        VP                  4       VP                  '       d   RMR R2MRpRV RV R\        V4       RV R2	# )um   ``/autoprune [on|off|later|status]`` â€” the one handler behind the CLI, TUI, Desktop and
messaging surfaces.rÏ   rj   ÚonÚoffzAuto-prune is z7, set by your administrator; it cannot be changed here.TzUAuto-prune is on: ended sessions inactive past retention_days are deleted once a day.Fz`Auto-prune is off and you will not be asked again. `hermes sessions prune` still works any time.z6OK, I'll ask again in a week if the disk is still low.zset by your administratorÚdefaultzyour settingz
 state.db z; rå   z (low)ræ   z (z), retention z days.z# Usage: /autoprune on | off | later>   Únor  r  ÚyesÚlaterr  rˆ   Údisable>   r  r  r  >   r  r  r!  >   r   rˆ   )ÚstripÚlowerr`   rY   r
  r  Ú_SAVE_FAILEDrˆ   rP   rÜ   r
   r   r   r   rf   )r  r:   ÚargrV   ÚstateÚchosenr‹   r*   s   &&      r   Úrun_commandr(  r  s~  € ð �:ˆ:�2×
Ñ
Ó
×
$Ñ
$Ó
&€CÜ" 4Ó(×.Ð.¨B€HØ—L‘L ×.Ò.‰D°E€EØ
ÐPÔPÔU\×U^ÒU^Ø ˜wÐ&]Ð^Ð^Ø
Ð%Ô%ä˜$ ×%Ò%ð hð 	9Ü+7ð	9à
Ð&Ô&ä˜% ×&Ò&ð sð 	:Ü,8ð	:à
Ð!Ô!ÜˆtŒÙGÜ-4¯YªYÑ)Ø'¨xÔ7‰i¸^ð ä˜Ó€Dç37ð œ˜TŸ]™]Ó+Ð,¨B¬s°4·?±?Ó/CÐ.DÀIÌcÐRV×RbÑRbÓNcÐMdØŸ8Ÿ8˜8‰x¨Ð,¨Añ/Ø=?ð 	à˜U˜G 2 f X¨]¼?È8Ó;TÐ:UÐU[Ð\`Ð[að b1ð 1ð 2r   Úaskc               ó   € V ^8„  d   QhRR/# )r   r   zOptional[bool]r   )r   s   "r   r   r   Œ  s   € ÷  ñ  ¨~ñ  r   c                ó†  € \        4       f   R# \        4       w  r#V'       d#   ^ RIHp V! \        RR7      P                  4        Vf   R# V ! R4       V ! R\        V4      ^ ,          ,           4       \        V4      ^R  F  pV ! RV 24       K  	   V! R4      pTP                  4       P                  4       pTR9   dN   TP                  R	4      p\        T4      '       g   T ! R\         24       R# T ! T'       d	   R
4       T# R4       T# \        4        T ! R4       R#   \        \        3 d    \        4         R# i ; i)zsClassic-CLI startup offer (TTY only). Returns the decision, or None when nothing was asked
or the user chose later.N)Úspawn_context_threadzauto-prune-estimate)ÚnamerÏ   u   â˜¤ z  z`  Enable auto-prune? [y = enable / n = never prune, don't ask again / Enter = remind me later]: Úyu     âœ“ sessions.auto_prune: trueu;     âœ“ sessions.auto_prune: false. You won't be asked again.z/  Later. /autoprune on|off decides it any time.éÿÿÿÿ>   rÙ   r.  r  r  )rŒ   rÅ   Úagent.memory_providerr,  r©   Ústartrì   ÚKeyboardInterruptÚEOFErrorÚprintr"  r#  Ú
startswithr  r$  rˆ   )Úcprintr)  r–   rÄ   r,  ÚlineÚanswerr  s   $$      r   Úoffer_interactiver9  Œ  s)  € ô ƒ|ÒÙÜ!“O�M€Fßå>ÙœVÐ*?Ô@×FÑFÔHØ‚~ÙÙ
ˆ2„JÙ
ˆ6”L Ó(¨Õ+Õ+Ô,Ü˜VÓ$ Q rÓ*ˆÙ��D�6ˆ{Öñ +ðÙÐwÓxˆð �\‰\‹^×!Ñ!Ó#€FØÐ(Ô(Ø×"Ñ" 3Ó'ˆÜ�f�~Š~Ù�Rœ�~Ð&Ô'ÙÙ·FÐ0ô 	Nàˆð Mô	NàˆÜ
„HÙ
Ð<Ô=Ùøô œxÐ(ô ÜŒÚðús   ÂD! Ä!E Ä?E i   @i€:	 rn   )9Ú__doc__Ú
__future__r   rz   ÚloggingrD   rG   r    r~   Údataclassesr   Úpathlibr   Útypingr   Ú	getLoggerr!   r[   r4   r   r   r   r  ro   r¬   rº   rÀ   r   r)   r?   rP   r`   rf   rk   rq   r€   rˆ   rŒ   r©   r®   r�   rœ   rÅ   r›   rÜ   rà   rì   rù   rú   rý   r  r
  r  r$  r(  Úinputr9  r   r   r   Ú<module>rB     so  ðñõ #ã Û Û 	Û Û Û Ý !Ý Ý à	×	Ò	˜8Ó	$€à€à�S•€ØÐ Ø˜•HÐ Ø€Ø(€ð -€Ø€ð €ñ �$Ô÷Qð Qó ðQñ �$Ô÷;ð ;ó ð;õ(÷7õ
:õ%÷Aõ&ñ(À4÷ (ð (ð #'¸÷ T÷
÷-õ`2õHõ	(÷õ.ZõRõ
4ð¸#÷ ð@ #€
õ1÷0õ@õ?÷Uð, c€÷2ð4  U÷  ñ  r   