+
    „WÝj*©  ã                  ó.  a € 0 t $ 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
t
^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIHtHtHtHtHtHt ^ RIHtHt ^ RIHtHt ]P@                  ! R4      t!R t"]PF                  ! 4       t$/ t%R	]&R
&   . t'R]&R&   RQt(R R lt)R R lt*R R lt+R R lt,R R lt-R R lt.R R lt/R t0^t1^t2^t3^t4Rt5^t6^ t7^°t8Rs9Rt:R t;R R  lt<R! t=R" R# lt>R$ R% lt?R& R' lt@R(tAR)tB^tCRRtDRStE^dtF ! R* R+]G4      tHR, R- ltIR. R/ ltJR0 R1 ltKR2 R3 ltLR4 R5 ltMR6 R7 ltNR8 R9 ltORTR: ltPR; R< ltQR=^dR>R?/R@ RA lltRR=^dR>R?/RB RC lltS]P¨                  RURD RE ll4       tURFR?/RG RH lltVRI RJ ltWRK RL ltXRM RN ltYRO RP ltZR# )VaÐ  state.db file-level health helpers, split out of ``hermes_state.py``.

Header probes (application_id / zeroed-file detection), deleted-WAL-sidecar
holder scans, quarantine of zeroed databases, ``collect_state_db_stats`` and
holder-process classification.  Helpers that hermes_state itself imports and
calls (``_connect_tracked_db`` & co) are looked up lazily from ``hermes_state`` at
call time, so tests that monkeypatch ``hermes_state.<name>`` keep intercepting.
)ÚannotationsN)ÚPath)ÚAnyÚCallableÚDictÚListÚOptionalÚTuple)Úcanonical_sqlite_pathÚread_only_db_uri)ÚFTS_REBUILD_DEFERRAL_KEYÚstat_db_file_identityÚhermes_statec                 ó  € Rp \         P                  P                  R8w  d   \        V 4      h ^ RIpVP
                  R,          pVP                  3Vn        RVn        V#   \        \        \        3 d   p\        T 4      ThRp?ii ; i)aÁ  Bind a non-finalizing reference before opening a writable SQLite handle.

A Python container is cleared during interpreter shutdown. An unmatched
CPython C reference keeps the exact connection alive through that cleanup,
so SQLite cannot checkpoint its lost WAL generation from a finalizer. This
deliberately retains the connection and its descriptors until process exit;
it does not make already-unlinked WAL data durable after the last fd closes.
z®Writable SessionDB on a Python without sqlite3 setconfig (< 3.12) requires CPython with ctypes support to retain a quarantined SQLite connection through interpreter shutdown.ÚcpythonNÚ	Py_IncRef)ÚsysÚimplementationÚnameÚRuntimeErrorÚctypesÚ	pythonapiÚ	py_objectÚargtypesÚrestypeÚImportErrorÚAttributeErrorÚOSError)Úmessager   ÚretainÚexcs       ÚGC:\Users\johnn\AppData\Local\hermes\hermes-agent\hermes_state_dbfile.pyÚ_prepare_connection_retirementr"   $   sŒ   € ð	að ô ×Ñ×Ñ )Ô+Ü˜7Ó#Ð#ð-Ûð ×!Ñ! +Õ.ˆØ!×+Ñ+Ð-ˆŒØˆŒð €Møô œ¬Ð1ô -Ü˜7Ó#¨Ð,ûð-ús   ®0A  Á BÁ6BÂBzdict[str, tuple[int, int, int]]Ú_HEADER_PROBE_FDSú	list[int]Ú_RETIRED_HEADER_PROBE_FDSc               ó(   € V ^8„  d   QhRRRRRRRR/# )é   Údb_pathr   ÚoffsetÚintÚlengthÚreturnúOptional[bytes]© )Úformats   "r!   Ú__annotate__r0   M   s(   € ÷ "ñ "˜Tð "¨3ð "¸ð "Àñ "ó    c           	     ó>  € ^ RI Hp V'       dt   \        P                  ! \        4      ;_uu_ 4        V P                  R4      ;_uu_ 4       pVP                  V4       VP                  V4      uuRRR4       uuRRR4       # \        V 4      p \        P                  ! V 4      p\        ;_uu_ 4        \        P                  T4      pTe_   T^,          T^,          3TP                  TP                  38w  d2   \         P#                  \        P%                  T4      ^ ,          4       RpTf_    \        P
                  ! T \        P&                  4      p \        P(                  ! T4      p	Y‰P                  T	P                  3;p\        T&   \        P                  ! \        4      ;_uu_ 4        \        P*                  ! T^ ,          Y!4      uuRRR4       uuRRR4       #   + '       g   i     M; iRRR4       R#   + '       g   i     R# ; i  \         d     R# i ; i  \         d     RRR4       R# i ; i  \         d"    \         P#                  T4        RRR4       R# i ; i  + '       g   i     M; i RRR4       R#   + '       g   i     R# ; i)zÝLock-safe raw read of a possibly-live SQLite database: POSIX preads from a cached,
never-closed fd (rebound when the path names a new inode); Windows reads plainly, since
advisory-lock cancellation is a POSIX-only hazard.©Ú_IS_WINDOWSÚrbN)r   r4   Ú
contextlibÚsuppressr   ÚopenÚseekÚreadÚstrÚosÚstatÚ_HEADER_PROBE_LOCKr#   ÚgetÚst_devÚst_inor%   ÚappendÚpopÚO_RDONLYÚfstatÚpread)
r(   r)   r+   r4   ÚhandleÚkeyÚstÚcachedÚfdÚfsts
   &&&       r!   Ú_pread_db_rangerM   M   sî  € õ )ßÜ× Ò ¤×)Õ)¨7¯<©<¸×+=Ô+=ÀØ�K‰K˜ÔØ—;‘;˜vÓ&÷ ,>Ñ+=×)Ò)ô ˆg‹,€CðÜ�WŠW�WÓˆ÷ 
Ö	Ü"×&Ñ& sÓ+ˆØÒ 6¨!¥9¨f°Q­iÐ"8¸R¿Y¹YÈÏ	É	Ð<RÔ"Rä%×,Ñ,Ô->×-BÑ-BÀ3Ó-GÈÕ-JÔKØˆFØŠ>ðÜ—W’W˜W¤b§k¡kÓ2�ðÜ—h’h˜r“l�ð 02·:±:¸s¿z¹zÐ.JÐJˆFÔ& sÑ+Ü× Ò ¤×)Õ)Ü—8’8˜F 1�I vÓ6÷ *Ñ)÷# 
Ò	÷ ,>×+=ú×)ñ ÷ *Ö)ñ ûô ô Úðûô ô Ø÷ 
Ñ	ðûô ô Ü)×0Ñ0°Ô4Ø÷ 
Ñ	ðú÷ *×)úÐ)÷# 
ñ& ÷' 
Ö	ñ& ús�   ±G>Á"G!	Á-
G>ÂH Â2A<JÄ/%H$ÅH>Å+AJÆ.I-	Ç
JÇ!G1Ç,G>Ç>H	ÈH!È H!È$H;È/JÈ:H;È;JÈ> I*ÉJÉ)I*É*JÉ-I=É8JÊJ	c               ó$   € V ^8„  d   QhRRRRRR/# )r'   r(   r   r+   r*   r,   r-   r.   )r/   s   "r!   r0   r0   r   s!   € ÷ /ñ /˜dð /¨Cð /°Oñ /r1   c                ó   € \        V ^ V4      # )z[Lock-safe raw header read of a possibly-live SQLite database (see :func:`_pread_db_range`).©rM   )r(   r+   s   &&r!   Ú_pread_db_headerrQ   r   s   € ä˜7 A vÓ.Ð.r1   c               ó    € V ^8„  d   QhRRRR/# ©r'   r(   r   r,   úOptional[int]r.   )r/   s   "r!   r0   r0   w   s   € ÷ Tñ T¨ð T°-ñ Tr1   c                óÐ   € ^ RI Hp V^,           p\        W4      pVe   \        V4      V8  g   VR,          R8w  d   R# \	        \
        P                  ! RW1V 4      ^ ,          4      # )zRapplication_id from the SQLite header, via the lock-safe :func:`_pread_db_header`.©Ú_STATE_DB_APPLICATION_ID_OFFSETNºNé   Nó   SQLite format 3 ú>I)Úhermes_state_errorsrW   rQ   Úlenr*   ÚstructÚunpack)r(   rW   ÚendÚheaders   &   r!   Ú_read_sqlite_application_idrb   w   sY   € åCØ
)¨AÕ
-€CÜ˜gÓ+€FØ‚~œ˜V› sÔ*¨f°S­kÐ=SÔ.SÙÜŒv�}Š}˜T 6È#Ð#NÓOÐPQÕRÓSÐSr1   c               ó    € V ^8„  d   QhRRRR/# )r'   r(   r   r,   údict[str, tuple]r.   )r/   s   "r!   r0   r0   �   s   € ÷ Tñ T¨4ð TÐ4Dñ Tr1   c           
     óê   € \         P                  ! V 4      pR Uu/ uF  q"\        \        W,           4      4      bK  	  ppVP	                  4        UUu/ uF  w  r$Vf   K  W$bK  	  upp# u upi u uppi )z<Snapshot ``(st_dev, st_ino)`` for existing WAL/SHM sidecars.©ú-walú-shm)r<   ÚfspathÚ_stat_db_file_identityr   Úitems)r(   ÚbaseÚsuffixÚidentsÚidents   &    r!   Ú_stat_sqlite_sidecar_identityrp   �   sb   € ä�9Š9�WÓ€DÙP`ÓaÑP`ÀfÔ,¬T°$µ-Ó-@ÓAÒAÑP`€FÐaØ/5¯|©|¬~ÔS©~™m˜fÀŒMˆFŠM©~ÒSÐSùò bùÛSs   ›#A*ÁA/Á A/c               ó   € V ^8„  d   QhRR/# )r'   r,   zdict[str, str]r.   )r/   s   "r!   r0   r0   ˆ   s   € ÷ ñ ¨nñ r1   c                ón  € \         P                  P                  \         P                  ! V 4      4      pVR,           VR,           3pV Uu/ uF  p\	        V4      VbK  	  pp\         P                  P                  \         P                  P                  \         P                  P                  V4      4      \         P                  P                  V4      4      \         P                  P                  V4      3pV F3  pR F*  pVP                  \	        Wg,           4      Wg,           4       K,  	  K5  	  V# u upi )zªMap each sidecar's canonical (/proc-comparable) form to its literal, still-named path,
so a canonical match can be re-``stat``'d for identity rather than trusted as text.rg   rh   rf   )
r<   ÚpathÚabspathri   r
   ÚjoinÚrealpathÚdirnameÚbasenameÚ
setdefault)r(   Úliteral_baseÚliteralrs   ÚwatchedÚresolved_basesrl   rm   s   &       r!   Ú_watched_sqlite_sidecar_pathsr~   ˆ   sê   € ô —7‘7—?‘?¤2§9¢9¨WÓ#5Ó6€LØ˜fÕ$ l°VÕ&;Ð<€GÙ=DÓE¹W°TÔ$ TÓ*¨DÒ0¹W€GÐEô 	�‰�‰”R—W‘W×%Ñ%¤b§g¡g§o¡o°lÓ&CÓDÜ—W‘W×%Ñ% lÓ3ó	5ä
�‰×Ñ˜Ó&ð€Nó
 ˆÛ&ˆFØ×ÑÔ4°Tµ]ÓCÀTÅ]ÖSó 'ñ ð €Nùò Fs   Á
D2c               ó$   € V ^8„  d   QhRRRRRR/# )r'   Úidentityztuple[int, int]Úwatched_pathr;   r,   Úboolr.   )r/   s   "r!   r0   r0   Ÿ   s'   € ÷ Bñ B¨/ð BÈð BÐQUñ Br1   c                óˆ   €  \         P                  ! V4      pYP                  TP                  38g  #   \         d     R# i ; i)z·The shared verdict: does ``(st_dev, st_ino)`` name a generation the watched path no longer
holds?  See :func:`_fd_is_truly_unlinked` for why the test is identity and never link count.T)r<   r=   r   r@   rA   )r€   r�   Úwatched_stats   && r!   Ú_identity_is_truly_unlinkedr…   Ÿ   sE   € ðÜ—w’w˜|Ó,ˆð ×+Ñ+¨\×-@Ñ-@ÐAÑAÐAøô ô Úðús   ‚2 ²AÁ Ac               ó$   € V ^8„  d   QhRRRRRR/# )r'   Úfd_pathr;   r�   r,   r‚   r.   )r/   s   "r!   r0   r0   ©   s&   € ÷ Wñ W 3ð W°cð W¸dñ Wr1   c                ó  €  \         P                  ! V 4      p\        TP                  TP                  3T4      #   \         dA   pTP                  \        P                  \        P
                  39   d    Rp?R#  Rp?R# Rp?ii ; i)uY  Confirm a `` (deleted)`` /proc fd target really names an orphaned generation, not the
CURRENT watched sidecar.

The suffix alone is not proof: on OpenZFS a live, still-linked file whose dentry was
unhashed is reported as deleted while it is still the very same inode the watched path
names. Conversely ``st_nlink == 0`` is not proof of the opposite â€” a stale generation can
keep a surviving hard link (a backup, an operator copy) after the watched path itself is
removed or replaced, leaving ``st_nlink >= 1`` on a truly orphaned inode. So compare
identity, not link count: only an exact ``(st_dev, st_ino)`` match between the fd and the
CURRENT watched path proves they are the same live file. A mismatch, or a watched path
that cannot be stat'd at all, means the fd holds a generation the watched path no longer
names â€” the guard keeps failing closed.NFT)	r<   r=   r   ÚerrnoÚENOENTÚESRCHr…   r@   rA   )r‡   r�   Úfd_statr    s   &&  r!   Ú_fd_is_truly_unlinkedr�   ©   sd   € ðÜ—'’'˜'Ó"ˆô '¨¯©¸¿¹Ð'GÈÓVÐVøô ô ð �9‰9œŸ™¤u§{¡{Ð3Ô3ÝÝûðús   ‚: ºBÁ/B Â Bc            	   #  ó¼  "  € \         P                  ! R4       F—  p V P                  4       '       g   K  RV  R2p \         P                  ! V4      pT FY  p\        P
                  ! \        4      ;_uu_ 4        T RT 2p\        T 4      \         P                  ! T4      T3x € RRR4       K[  	  K™  	  R#   \         d     K«  i ; i  + '       g   i     K†  ; i5i)zVYield ``(pid, readlink target, fd path)`` for every readable ``/proc/<pid>/fd`` entry.z/procz/proc/z/fdÚ/N)r<   ÚlistdirÚisdigitr   r6   r7   r*   Úreadlink)Úpid_strÚfd_dirÚfdsrK   r‡   s        r!   Ú_iter_proc_fd_targetsr–   Â   s·   é € ä—:’:˜gÖ&ˆØ�‰× Ò ÙØ˜'˜ #Ð&ˆð	Ü—*’*˜VÓ$ˆCó ˆBÜ×$Ò$¤W×-Õ-Ø#˜H A b TÐ*�Ü˜'“l¤B§K¢K°Ó$8¸'ÐAÒA÷ .Ñ-ó ó 'øô ô 	Úð	ú÷ .×-Ð-üs@   ‚8C»B6Á'CÁ8,C	Â$CÂ6CÃCÃCÃCÃCÃ	Ci°  ç      @c                 óŒ  € \         p V e   V # ^ RIpVP                  RRR7      p VP                  V P                  n        VP                  VP                  VP                  VP                  3V P                  n        VP                  V P                  n        VP                  VP                  VP                  VP                  VP                  3V P                  n        VP                  V P                  n        VP                  VP                  VP                  VP                  VP                  3V P                  n        V s V # )zîlibproc's fd-enumeration entry points, loaded once per process.

macOS exports these from libSystem, so this process's own handle resolves them; a failure
here propagates to the caller's ``except Exception`` and keeps the guard fail-open.NT)Ú	use_errno)Ú_DARWIN_LIBPROCr   ÚCDLLÚc_intÚproc_listpidsr   Úc_uint32Úc_void_pr   Úproc_pidinfoÚc_uint64Úproc_pidfdinfo)Úlibr   s     r!   Ú_darwin_libprocr¤   ó   sò   € ô €CØ
‚Øˆ
Ûà
�+‰+�d dˆ+Ó
+€CØ &§¡€C×ÑÔØ"(§/¡/°6·?±?ÀFÇOÁOÐU[×UdÑUdÐ!e€C×ÑÔØ%Ÿ|™|€C×ÑÔØ!'§¡¨v¯|©|¸V¿_¹_ÈfÏoÉoÐ_e×_kÑ_kÐ l€C×ÑÔØ!'§¡€C×ÑÔØ#)§<¡<°·±¸v¿|¹|ÈVÏ_É_Ð^d×^jÑ^jÐ"k€C×ÑÔØ€OØ€Jr1   c               ó   € V ^8„  d   QhRR/# )r'   r,   r$   r.   )r/   s   "r!   r0   r0   	  s   € ÷ ñ ˜Yñ r1   c                ó&  € ^ RI pRp VP                  V4      pV P                  \        ^ W24      pV^ 8:  d   . # WB8  dE   \        P
                  ! RV^,           R2VP                  4       Uu. uF  qU^ 8”  g   K  VNK  	  up# V^,          pK‡  u upi )zZEvery pid ``proc_listpids`` will name (the kernel silently omits ones we may not inspect).NÚ<Úii €  )r   Úcreate_string_bufferr�   Ú_DARWIN_ALL_PIDSr^   Úunpack_fromÚraw)r£   r   ÚsizeÚbufferÚusedÚpids   &     r!   Ú_darwin_all_pidsr±   	  s�   € ãà€DØ
Ø×,Ñ,¨TÓ2ˆØ× Ñ Ô!1°1°fÓCˆØ�1Œ9ØˆIØŒ;Ü#)×#5Ò#5¸¸$À!½)¸ÀAÐ6FÈÏ
É
Ô#SÓ_Ñ#S˜CÐ]^ÑW^—C�CÑ#SÑ_Ð_Ø��	Šùò `s   Á-BÁ:Bc            	   #  ó  "  € ^ RI p \        4       p\        V4       EF]  pRp V P                  V4      pVP	                  V\
        ^ WC4      pV^ 8:  d   MWS8  d   MV^,          pKD  \        ^ V\        ,
          ^,           \        4       Fì  p\        P                  ! RVP                  V4      ^ ,          pV P                  \        4      pVP                  W'\        V\        4      ^ 8:  d   Kd  VP                  p	\        P                  ! RV	\        4      ^ ,          \        P                  ! RV	\        4      ^ ,          3p
V	\         R P#                  R^4      ^ ,          P%                  RR4      pW'Wº3x € Kî  	  EK`  	  R# 5i)	a`  Yield ``(pid, fd, last pathname, (st_dev, st_ino))`` for every vnode fd libproc reports.

The pathname and the identity both stay readable after the path is unlinked, which is what
makes an orphaned WAL generation visible at all on macOS.  Processes that cannot be inspected
(gone, or not ours) and descriptors that are not vnodes are skipped silently.Ni   z<iz<Iz<Qó    zutf-8Úreplace)r   r¤   r±   r©   r    Ú_DARWIN_PIDLISTFDSÚrangeÚ_DARWIN_PROC_FD_INFO_SIZEr^   r«   r¬   Ú_DARWIN_FD_RECORD_SIZEr¢   Ú_DARWIN_PIDFDVNODEPATHINFOÚ_DARWIN_FD_DEV_OFFSETÚ_DARWIN_FD_INO_OFFSETÚ_DARWIN_FD_PATH_OFFSETÚsplitÚdecode)r   r£   r°   r­   Úlistingr¯   r)   rK   Úrecordr¬   r€   Útargets               r!   Ú_iter_darwin_fd_targetsrÂ     sX  é € ó ä
Ó
€CÜ ×$ˆØˆØØ×1Ñ1°$Ó7ˆGØ×#Ñ# CÔ);¸QÀÓNˆDØ�qŒyØØŒ{ØØ�A�IŠDô ˜A˜tÔ&?Õ?À!ÕCÔE^Ö_ˆFÜ×#Ò# D¨'¯+©+°vÓ>¸qÕAˆBØ×0Ñ0Ô1GÓHˆFØ×!Ñ! #Ô+EÀvÜ"8ó:Ø=>ô?áØ—*‘*ˆCÜ×*Ò*¨4°Ô6KÓLÈQÕOÜ×*Ò*¨4°Ô6KÓLÈQÕOðQˆHàÔ/Ð0Ð1×7Ñ7¸ÀÓCÀAÕF×MÑMÈgÐW`ÓaˆFØ˜6Ð+Ô+ô `ó %ùs   ‚E>F c               ó   € V ^8„  d   QhRR/# ©r'   r,   úlist[tuple[int, str]]r.   )r/   s   "r!   r0   r0   :  s   € ÷ &ñ &Ð-Bñ &r1   c                ó6  aaa€ \         P                  P                  \         P                  P                  \         P                  ! V 4      4      4      pVR,           VR,           3 Uu/ uF  q"P                  4       VbK  	  upo. o. oR VVV3R llp\        P                  ! VRR7      pVP                  4        VP                  \        4       VP                  4       '       d   \        P                  R\        V 4       . # S'       d
   S^ ,          hS# u upi )a¨  The macOS leg of :func:`iter_deleted_sqlite_sidecar_holders`: libproc enumeration matched
against the watched sidecar paths, judged by identity.

The watched side is resolved with ``os.path.realpath`` because libproc reports the kernel's
path for the vnode, while ``os.path.abspath`` does not resolve symlinks -- a textual compare
of the two silently misses every sidecar under a symlinked prefix (on macOS ``/var`` itself).rg   rh   c               ó   € V ^8„  d   QhRR/# ©r'   r,   ÚNoner.   )r/   s   "r!   r0   Ú2_iter_darwin_sidecar_holders.<locals>.__annotate__H  s   € ÷ ñ �4ñ r1   c                 ó  <€  \        4        FP  w  rr#SP                  VP                  4       4      pVf   K+  \        W44      '       g   K>  SP	                  W34       KR  	  R #   \
         d   pSP	                  T4        R p?R # R p?ii ; i©N)rÂ   r?   Úcasefoldr…   rB   ÚBaseException)	r°   Ú_fdrÁ   r€   r{   r    ÚerrorsÚholdersr|   s	         €€€r!   Ú_scanÚ+_iter_darwin_sidecar_holders.<locals>._scanH  sp   ø€ ð	Ü.EÖ.GÑ*�˜&Ø!Ÿ+™+ f§o¡oÓ&7Ó8�ØÔ&Ô+FÀx×+YÔ+YØ—N‘N C =Ö1ó /Høô ô 	Ø�M‰M˜#×Òûð	ús"   ƒ0A# ¸A# ÁA# Á#B
Á.BÂB
T)rÁ   ÚdaemonzJdeleted-WAL holder scan timed out after %.1fs for %s; continuing fail-open)r<   rs   rv   rt   ri   rÍ   Ú	threadingÚThreadÚstartru   Ú_DARWIN_FD_SCAN_TIMEOUT_SECONDSÚis_aliveÚloggerÚwarning)r(   rl   rs   rÒ   ÚworkerrÐ   rÑ   r|   s   &    @@@r!   Ú_iter_darwin_sidecar_holdersrÝ   :  sÛ   ú€ ô �7‰7×ÑœBŸG™GŸO™O¬B¯IªI°gÓ,>Ó?Ó@€Dð 37¸µ-ÀÈÅÑ1OÓPÑ1O¨�}‰}‹ Ò$Ñ1OÑP€GØ%'€GØ"$€F÷ò ô ×Ò U°4Ô8€FØ
‡L�L„NØ
‡K�KÔ/Ô0Ø‡�×ÒÜ�‰ØXÜ+Øô	
ð
 ˆ	ßØ�Q�iˆØ€Nùò9 Qs   Á(Dc               ó   € V ^8„  d   QhRR/# rÄ   r.   )r/   s   "r!   r0   r0   c  s   € ÷ ñ Ð4Iñ r1   c                óô  € \         P                  R8X  d   . # . p \         P                  R8X  d   \        V 4      pV# \         P                  P                  R4      '       dh   \	        V 4      p\        4        FN  w  r4p\        V4      pRV9   g   K  Wb9   g   K"  \        WRV,          4      '       g   K<  VP                  W434       KP  	  V#   \         d"   p\        P                  RY4        Rp?T# Rp?ii ; i)a   Return processes holding an unlinked ``state.db-wal`` / ``-shm`` sidecar for *db_path*.

Linux enumerates ``/proc/<pid>/fd`` (using the `` (deleted)`` suffix as a cheap pre-filter);
macOS enumerates descriptors through libproc, because a retired generation there keeps its
last pathname and no suffix marks it.  Either way the verdict is the same identity comparison:
the fd must name a watched sidecar path while its ``(st_dev, st_ino)`` no longer matches what
that path holds.  Windows returns ``[]`` -- it cannot unlink a held sidecar, so no retired
generation can exist; any other platform returns ``[]`` as before.

Includes this process: on the open/write refuse path the in-process writer holding the orphan
inode must not mint a replacement WAL (``_foreign_state_db_holders`` skips this PID).Úwin32ÚdarwinÚlinuxz
 (deleted)z)deleted-WAL holder scan failed for %s: %sN)r   ÚplatformrÝ   Ú
startswithr~   r–   r
   r�   rB   Ú	ExceptionrÚ   Údebug)r(   rÑ   r|   r°   rÁ   r‡   Ú	canonicalr    s   &       r!   Ú#iter_deleted_sqlite_sidecar_holdersrè   c  sØ   € ô ‡|�|�wÔØˆ	Ø%'€GðPÜ�<‰<˜8Ô#Ü2°7Ó;ˆGð €Nô �\‰\×$Ñ$ W×-Ò-Ü3°GÓ<ˆGÜ(=Ö(?Ñ$�˜WÜ1°&Ó9�	Ø  FÖ*¨yÖ/CÜ1°'À9Õ;M×NÔNØ—N‘N C =Ö1ñ	 )@ð €Nøô ô PÜ�‰Ð@À'×OÐOØ€NûðPús4   › C ½$C Á"*C ÂC ÂC Â3C ÃC7ÃC2Ã2C7c               ó   € V ^8„  d   QhRR/# rÈ   r.   )r/   s   "r!   r0   r0   �  s   € ÷ Añ A¨dñ Ar1   c                óz   € ^ RI Hp ^ RIHp \	        V 4      '       g   R# \
        P                  V4       V! V4      h)z¢Raise if any process holds a deleted WAL/SHM generation for *db_path*; called
*before* ``sqlite3.connect`` so a second opener cannot mint a replacement WAL inode.)ÚDeletedWalGenerationError)Ú_DELETED_WAL_GENERATION_MSGN)r   rë   r\   rì   rè   rÚ   Úerror)r(   rë   rì   s   &  r!   Úrefuse_deleted_wal_generationrî   �  s1   € õ 7Ý?Ü.¨w×7Ò7ÙÜ
‡L�LÐ,Ô-Ù
#Ð$?Ó
@Ð@r1   z.retired-wal-zmanifest.jsonc                  ó   € ] tR tRtRtRtR# )ÚRetiredGenerationCaptureErrori¢  zNThe retired WAL generation could not be captured durably; nothing was mutated.r.   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__static_attributes__r.   r1   r!   rð   rð   ¢  s   † ÝXr1   rð   c               ó    € V ^8„  d   QhRRRR/# )r'   rs   r   r,   rÉ   r.   )r/   s   "r!   r0   r0   ¦  s   € ÷ 
ñ 
�dð 
˜tñ 
r1   c                ó   € ^ RI Hp V'       d   R# \        P                  ! V \        P                  4      p \        P
                  ! V4       \        P                  ! V4       R#   \        P                  ! T4       i ; i)z±fsync a file or directory we own. Never used on the live database: opening and closing a
descriptor on a file SQLite has locked would cancel this process's POSIX advisory locks.r3   N)r   r4   r<   r8   rD   ÚfsyncÚclose)rs   r4   rK   s   &  r!   Ú_fsync_pathrû   ¦  sH   € õ )ßÙÜ	�Š�”r—{‘{Ó	#€BðÜ
�Š�Œä
�Š�ŽøŒ�Š��ús   ·A% Á%A=c               ó   € V ^8„  d   QhRR/# )r'   r,   rT   r.   )r/   s   "r!   r0   r0   ³  s   € ÷ ñ ¨mñ r1   c                ó”  € V '       g   R# \        V 4      pR Fˆ  p \        P                  ! V4      pT Fg  pTP	                  4       '       g   K   \        P
                  ! \        T4      4      pTP                  TP                  3T8X  g   KZ  \        T4      u u # 	   R# 	  R#   \         d     Kœ  i ; i  \         d     K’  i ; i)zÉThis process's open descriptor for the inode ``(st_dev, st_ino)``, or None.

Exact-generation qualified: pathnames are never consulted. The descriptor stays owned by
SQLite; callers only pread from it.N)z/proc/self/fdz/dev/fd)	Útupler<   r�   r   r‘   rE   r*   r@   rA   )r€   Úwantedr”   Únamesr   rI   s   &     r!   Ú_own_descriptor_for_identityr  ³  s³   € ÷
 ÙÜ�8‹_€FÛ.ˆð	Ü—J’J˜vÓ&ˆEó ˆDØ—<‘<—>’>ÙðÜ—X’Xœc $›iÓ(�ð —	‘	˜2Ÿ9™9Ð%¨Ö/Ü˜4“yÔ ñ ò ñ /ñ øô ô 	Úð	ûô ô Úðús#   œB&ÁB8Â&B5Â4B5Â8CÃCc               ó(   € V ^8„  d   QhRRRRRRRR/# )	r'   r:   z%Callable[[int, int], Optional[bytes]]Údestr   r­   r*   r,   údict[str, Any]r.   )r/   s   "r!   r0   r0   Í  s1   € ÷ Nñ NÐ;ð NÀ4ð NÐRUð NÐZhñ Nr1   c          
     ó   € \         P                  ! 4       pVP                  VP                  R,           4      p^ p \	        VR4      ;_uu_ 4       pWR8  d]   V ! V\        \        W%,
          4      4      pV'       g   M6VP                  V4       VP                  V4       V\        V4      ,          pKb  VP                  4        \        P                  ! VP                  4       4       RRR4       YR8w  d2   TP                  RR7       \!        RTP                   RT RT R	24      h\        P"                  ! YA4       R
TP                  RTRTP%                  4       /#   + '       g   i     L}; i  \         d    TP                  RR7       h i ; i)a  Stream ``size`` bytes via ``read(offset, length)`` into ``dest`` (temp file, fsync, rename).

A short read raises ``RetiredGenerationCaptureError``: a truncated copy with a valid-looking
manifest would let the caller settle the handle while the unlinked inode still dies at exit.z.partÚwbNT)Ú
missing_okzshort read copying ú: ú of uZ    bytes â€” the retired generation is NOT fully captured; the handle stays open for a retryÚfileÚbytesÚsha256)Úhashlibr  Ú	with_namer   r8   ÚminÚ_CAPTURE_CHUNK_BYTESÚwriteÚupdater]   Úflushr<   rù   Úfilenorå   Úunlinkrð   r´   Ú	hexdigest)r:   r  r­   ÚdigestÚpartr)   ÚoutÚchunks   &&$     r!   Ú_copy_ranger  Í  sE  € ô
 �^Š^Ó€FØ�>‰>˜$Ÿ)™) gÕ-Ó.€DØ€FðÜ�$˜×Ô Ø”-Ù˜V¤SÔ)=¸t½}Ó%MÓN�ßØØ—	‘	˜%Ô Ø—‘˜eÔ$Øœ#˜e›*Õ$’Ø�I‰IŒKÜ�HŠH�S—Z‘Z“\Ô"÷ ð „~Ø�‰˜tˆÔ$Ü+Ø! $§)¡) ¨B¨v¨h°d¸4¸&ð AGð Gó
ð 	
ô ‡J‚JˆtÔØ�D—I‘I˜w¨°¸&×:JÑ:JÓ:LÐMÐM÷) ×ûô ô Ø�‰˜tˆÔ$Øðús*   »E. ÁBEÃ&E. ÅE+	Å&E. Å+E. Å.Fc               ó(   € V ^8„  d   QhRRRRRRRR/# )r'   rK   r*   r  r   r­   r,   r  r.   )r/   s   "r!   r0   r0   í  s.   € ÷ ]ñ ]˜ð ] Dð ]°3ð ]¸>ñ ]r1   c               ó&   a € \        V 3R lWR7      # )zIpread ``fd`` (a descriptor SQLite owns; never closed here) into ``dest``.c                ó2   <€ \         P                  ! SW4      # rÌ   )r<   rF   )r)   r+   rK   s   &&€r!   Ú<lambda>Ú"_copy_descriptor.<locals>.<lambda>ï  s   ø€ ¬b¯hªh°r¸6Ô.Jr1   ©r­   ©r  )rK   r  r­   s   f&$r!   Ú_copy_descriptorr#  í  s   ø€ äÔJÈDÔ\Ð\r1   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r'   r(   r   r  r­   r*   r,   r  r.   )r/   s   "r!   r0   r0   ò  s.   € ÷ iñ i˜dð i¨$ð i¸ð iÀñ ir1   c               ó&   a € \        V 3R lWR7      # )zZCopy the live main file through the lock-safe cached descriptor (see ``_pread_db_range``).c                ó   <€ \        SW4      # rÌ   rP   )r)   r+   r(   s   &&€r!   r  Ú"_copy_main_image.<locals>.<lambda>ô  s   ø€ ¬o¸gÀvÔ.Vr1   r!  r"  )r(   r  r­   s   f&$r!   Ú_copy_main_imager(  ò  s   ø€ äÔVÐX\ÔhÐhr1   c               ó    € V ^8„  d   QhRRRR/# )r'   ra   r  r,   r  r.   )r/   s   "r!   r0   r0   ÷  s   € ÷ bñ b ð b¨>ñ br1   c                ó‚  € \        V 4      \        8  g   V R ,          R8w  d   RR/# \        P                  ! RV R,          4      ^ ,          p^ RIHp R^R^R	^<R
VR^\/pVP                  4        UUu/ uF-  w  rEV\        P                  ! RWV^,            4      ^ ,          bK/  	  pppRRRV^8X  d   R/VC# T/VC# u uppi )rX   rZ   ÚvalidFz>H:rY   é   NrV   Úchange_counterÚ
page_countÚuser_versionÚapplication_idÚversion_valid_forr[   TÚ	page_sizei   )r]   Ú_SQLITE_HEADER_BYTESr^   r_   r\   rW   rk   )ra   Úraw_page_sizerW   Úfieldsr   ÚoffÚparseds   &      r!   Ú_parse_sqlite_headerr8  ÷  sÒ   € Ü
ˆ6ƒ{Ô)Ô)¨V°C­[Ð<RÔ-RØ˜ÐÐÜ—M’M $¨¨u­Ó6°qÕ9€MÝCØ  L°"°nÀbØÐ ?ÐATÐVXðZ€FàQW×Q]ÑQ]ÔQ_Ô`ÑQ_ÁIÀDˆd”F—M’M $¨°3¸µ7Ð(;Ó<¸QÕ?Ò?ÑQ_€FÑ`Ø�T˜;°À!Ô1C¨ÐaÐZ`ÐaÐaÈÐaÐZ`ÐaÐaùó as   Á13B;c               ó$   € V ^8„  d   QhRRRRRR/# )r'   Úsidecar_identityrd   Útriggerr;   r,   r   r.   )r/   s   "r!   r0   r0     s)   € ÷ Vñ VØ"2ðVØ=@ðVà	ñVr1   c               ó 
  € \        V 4      p \        VP                  R4      ;'       g    R-4      pV'       g   \        RV  R24      h\	        V4      pVf   \        RV RV  24      h \
        P                  ! V4      P                  pT P                   \         \        P                  ! R	\        P                  ! 4       4       R
\
        P                  ! 4        2pT P                  T4      p^ p	TP!                  4       '       g7   TP                  TP                  R,           4      P!                  4       '       d"   T	^,          p	T P                  T R
T	 24      pKm  TP                  TP                  R,           4      p
 T
P#                  RRR7       R\$        R\'        T 4      RTR\
        P                  ! 4       R\        P                  ! R\        P                  ! 4       4      R\(        P*                  P-                  4       ^ ,          R\.        P0                  RR\3        T4      /\5        YJT P                  R,           ,          TR7      CRRR\7        T 4      P9                  4        UUu/ uF  w  r¼T\3        T4      bK  	  uppRR/p\        TP                  R4      ;'       g    R-4      pT'       d   \	        T4      MRpTe   \:        P<                  ! \        4      ;_uu_ 4        R\3        T4      /\5        YúT P                  R,           ,          \
        P                  ! T4      P                  R7      CTR&   RRR4       \?        T ^ \@        4      pTf   \        RT  24      h\
        PB                  ! T 4      P                  pR\3        \E        T 4      ;'       g    R-4      ;'       g    RR TR!\G        T4      /pT\H        8:  d2   TPJ                  ! R-R"R#/\M        Y
T P                  ,          TR7      B  M\Y P                  R$,           ,          pTPO                  T4       \Q        T4       TPK                  R%TP                  \S        T4      R&7       TTR'&   ^ R(I*H+p T! T
\X        ,          TRR)7       \Q        T
4       \
        PZ                  ! Y¨4       \Q        TP\                  4       T#   \         d   p\        RT  RT 24      ThRp?ii ; iu uppi   + '       g   i     EL§; i  \         d    \^        P`                  ! T
RR*7       h \         d3   p\^        P`                  ! T
RR*7       \        R+T  R,T
 RT 24      ThRp?ii ; i).a—  Durably capture the lost WAL generation this process still holds open; return the artifact dir.

The artifact sits next to the database as ``<name>.retired-wal-<utc ts>-<pid>/`` and holds the
retired ``<name>-wal`` (and ``-shm`` when still ours), the main image (or its header past the size
cap) and ``manifest.json`` with identities, sizes, digests and the sidecar generation found at the
path at capture time. Nothing is merged: whether those frames belong on top of the main file is
the operator's decision. Raises :class:`RetiredGenerationCaptureError` when the exact generation
cannot be located or written; no descriptor is ever closed, moved or truncated.
rg   z(no recorded WAL generation identity for z"; refusing to guess it by pathnameNz3this process no longer holds the retired WAL inode r	  zcannot stat the retired WAL of r  ú%Y%m%d-%H%M%SÚ-z.partialTF©ÚparentsÚexist_okÚversionÚdatabaser;  r°   Úcaptured_atz%Y-%m-%dT%H:%M:%SZÚpythonÚsqliteÚwalr€   r!  ÚshmÚpath_generation_at_captureÚnotezçFrames in the captured WAL were committed by the retired generation. Whether they belong on top of the main file now at the path is an operator decision; inspect the copied image with `hermes sessions recover --inspect-only` first.rh   z%cannot read the main image header of r­   ra   ÚmodeÚcopiedz.headerÚheader_only)rK  r
  r  Úmain)Úatomic_json_write)Ú	sort_keys)Úignore_errorsz.could not write the retired WAL generation of z under r.   )1r   rþ   r?   rð   r  r<   rE   Úst_sizer   r   ÚRETIRED_GENERATION_DIR_SUFFIXÚtimeÚstrftimeÚgmtimeÚgetpidr  ÚexistsÚmkdirÚ#RETIRED_GENERATION_MANIFEST_VERSIONr;   r   rB  r½   Úsqlite3Úsqlite_versionÚlistr#  rp   rk   r6   r7   rM   r3  r=   rj   r8  Ú'RETIRED_GENERATION_MAIN_IMAGE_MAX_BYTESr  r(  Úwrite_bytesrû   r]   ÚutilsrO  ÚRETIRED_GENERATION_MANIFESTr´   ÚparentÚshutilÚrmtree)r(   r:  r;  Úwal_identityÚwal_fdÚwal_sizer    ÚstemÚfinalÚnÚstagingrm   ro   ÚmanifestÚshm_identityÚshm_fdra   Ú	main_sizerN  Úheader_filerO  s   &$$                  r!   Úcapture_retired_wal_generationrq    s«  € ô �7‹m€GÜÐ)×-Ñ-¨fÓ5×;Ð;¸Ó<€LßÜ+Ø6°w°iÐ?aÐbódð 	dä)¨,Ó7€FØ‚~Ü+ØAÀ,ÀÈtÐT[ÐS\Ð]ó_ð 	_ðiÜ—8’8˜FÓ#×+Ñ+ˆð �l‰lˆ^Ô9Ð:¼4¿=º=ÈÔZ^×ZeÒZeÓZgÓ;hÐ:iÐijÔkm×ktÒktÓkvÐjwÐx€DØ×Ñ˜dÓ#€EØ	€AØ
�,‰,�.Š.˜EŸO™O¨E¯J©J¸Õ,CÓD×KÑK×MÒMØ	ˆQ�ˆØ×!Ñ! T F¨!¨A¨3 -Ó0ŠØ�o‰o˜eŸj™j¨:Õ5Ó6€Gð4hØ�‰˜d¨UˆÔ3àÔ:Øœ˜G›Ø�wØ”2—9’9“;Øœ4Ÿ=š=Ð)=¼t¿{º{»}ÓMØ”c—k‘k×'Ñ'Ó)¨!Õ,Ø”g×,Ñ,Ø�J¤ \Ó 2ð bÜ& v¸'¿,¹,ÈÕ:OÕ/PÐW_Ô`ðbà�4à(Ü9VÐW^Ó9_×9eÑ9eÔ9gô+iÙ9g©¨�œ˜U›Ò#Ñ9gò+iàð ]ð$
ˆô$ Ð-×1Ñ1°&Ó9×?Ð?¸RÓ@ˆß?KÔ-¨lÔ;ÐQUˆØÒÜ×$Ò$¤W×-Õ-Ø#-¬t°LÓ/Að #_ÔEUØ w§|¡|°fÕ'<Õ=ÄBÇHÂHÈVÓDT×D\ÑD\ôF^ð #_�˜‘÷ .ô ! ¨!Ô-AÓBˆØŠ>Ü/Ð2WÐX_ÐW`Ð0aÓbÐbÜ—G’G˜GÓ$×,Ñ,ˆ	Ø *¬DÔ1GÈÓ1P×1VÐ1VÐTVÓ,W×,_Ð,_Ð[_Ø &¨	°8Ô=QÐRXÓ=Yð [ˆàÔ?Ô?Ø�KŠKÑk˜XÐkÔ)9¸'ÈWÏ\É\ÕCYÐ`iÔ)jÓkà!§\¡\°IÕ%=Õ>ˆKØ×#Ñ# FÔ+Ü˜Ô$Ø�K‰K˜]°×1AÑ1AÌÈVËˆKÔUØˆ�Ñå+Ù˜'Ô$?Õ?ÀÐUYÕZÜ�GÔÜ
�
Š
�7Ô"Ü�E—L‘LÔ!ð €Løô ô iÜ+Ð.MÈgÈYÐVXÐY\ÐX]Ð,^Ó_ÐehÐhûðiüó0+i÷ .×-Ð-ûô. )ô Ü�Š�g¨TÕ2ØÜô hÜ�Š�g¨TÕ2Ü+Ø<¸W¸IÀWÈWÈIÐUWÐX[ÐW\Ð]ó_Ødgð	hûðhús|   Á( R. Å?C+S- É*S,Ê#S- Ê%S- Ê43S- Ë'ASÌ;A"S- ÎS- Î,D S- Ò.SÒ9SÓSÓS- ÓS*	Ó$	S- Ó-,UÔUÔ-UÕUc                óÔ   €  ^ RI Hp T! T 3RTR\
        P                  /TB #   \         d:    \        P	                  RT 4       \
        P                  ! \        T 4      3/ TB u # i ; i)u•  ``sqlite3.connect`` that registers the open fd so byte-level probes of a live file are
refused (an ``open()``/``close()`` would cancel every POSIX lock, even a running VACUUM's
EXCLUSIVE).  The ONLY tolerated fallback is the helper being absent (scaffold/embed installs
without hermes_cli); a real connection failure must propagate â€” a silent untracked retry
would disable the guard for that connection.)Úconnect_trackedzihermes_cli.sqlite_safe_read unavailable; opening %s untracked (byte-probe guard inactive in this install)Útracking_pathÚ
connect_fn)Úhermes_cli.sqlite_safe_readrs  r   rÚ   ræ   r[  Úconnectr;   )rs   rt  Úkwargsrs  s   &&, r!   Ú_connect_tracked_dbry  [  sj   € ð4Ý?ñ ˜4Ñc¨}ÐcÌÏÉÐcÐ\bÑcÐcøô ô 4Ü�‰ð CØDHô	Jä�Šœs 4›yÑ3¨FÑ3Ò3ð4ús   ‚# £AA'Á&A'c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r'   rs   r   Úprobe_bytesr*   Úforcer‚   r,   r-   r.   )r/   s   "r!   r0   r0   k  s(   € ÷ ñ ˜$ð ¨Sð ¸ð À/ñ r1   c                óâ   €  V P                  4       '       g   R# T P                  4        ^ RIHpHp V'       g   V! V 4      '       d   R# V! V \        ^V4      VR7      #   \         d     R# i ; i)u�  First ``probe_bytes`` of *path* read WITHOUT opening a SQLite connection, or None when the probe
must not run: special files (a FIFO would block), unreadable paths, or â€” unless ``force`` â€” a path
this process already has a connection to (``close()`` cancels every POSIX lock, even a running
VACUUM's EXCLUSIVE; see #97568).  ``force=True`` only for offline files (quarantined copies, snapshots).N)Úhas_live_connectionÚread_header_bytes_preopen)r+   r|  )Úis_filer=   rv  r~  r  Úmaxrå   )rs   r{  r|  r~  r  s   &&&  r!   Ú_preopen_headerr‚  k  s[   € ð
	Ø�|‰|�~Š~ÙØ�	‰	Œß^ßÑ,¨T×2Ò2ÙÙ(¨´c¸"¸kÓ6JÐRWÔXÐXøÜô Úðús!   ‚A šA ºA Á
A ÁA.Á-A.r{  r|  Fc               ó(   € V ^8„  d   QhRRRRRRRR/# ©r'   rs   r   r{  r*   r|  r‚   r,   r.   )r/   s   "r!   r0   r0   |  s/   € ÷ 	fñ 	f˜Tð 	f°3ð 	fÀTð 	fÐVZñ 	fr1   c               óv  € \         P                  ! \        4      ;_uu_ 4        ^ RIHp V! WVR7      uuRRR4       #   + '       g   i     M; i\        YT4      pTRJ;'       dS    TP                  R4      '       * ;'       d5    \        ;QJ d    R T 4       F  '       d   K   R# 	  R# ! R T 4       4      # )zÉDetect the zeroed state.db signature (0-byte or NUL header).  Prefers
``hermes_cli.backup.is_zeroed_sqlite_file``; this copy keeps SessionDB openable without the CLI
package in constrained embed paths.)Úis_zeroed_sqlite_file)r{  r|  Nó   SQLite format 3c              3  ó*   "  € T F	  q^ 8H  x € K  	  R# 5i©é    Nr.   )Ú.0Úbs   & r!   Ú	<genexpr>Ú%is_zeroed_state_db.<locals>.<genexpr>…  s   é € ÐOeÑ`dÐ[\ÐUVÖPVÓ`dùs   ‚FT)r6   r7   rå   Úhermes_cli.backupr†  r‚  rä   Úall)rs   r{  r|  r†  Úheads   &$$  r!   Úis_zeroed_state_dbr’  |  sŒ   € ô 
×	Ò	œY×	'Õ	'Ý;Ù$ TÈ%ÔP÷ 
(×	'×	'Ò	'úô ˜4¨eÓ4€Dà�tÐ×eÐe D§O¡OÐ4FÓ$GÔ G×eÐeÏCËCÑOeÑ`dÓOeÏCÌCÐeÊCÐeÈCÑOeÑ`dÓOeÓLeÐes	   £>¾A	c               ó(   € V ^8„  d   QhRRRRRRRR/# r„  r.   )r/   s   "r!   r0   r0   ˆ  s0   € ÷ Hñ H¨Dð HÀ#ð HÐTXð HÐeiñ Hr1   c               ó^   € \        WV4      pVRJ;'       d    VP                  R4      '       * # )z¢A pre-existing state.db whose first page is not SQLite: 0-byte, NUL, or clobbered page 0
(#102198).  Zeroed files are the subset :func:`is_zeroed_state_db` names.Nr‡  )r‚  rä   )rs   r{  r|  r‘  s   &$$ r!   Ú!has_invalid_sqlite_header_preopenr•  ˆ  s0   € ô ˜4¨eÓ4€DØ�tÐ×GÐG D§O¡OÐ4FÓ$GÔ GÐGr1   c               ó    € V ^8„  d   QhRRRR/# )r'   rs   r   ÚtimeoutÚfloatr.   )r/   s   "r!   r0   r0   �  s   € ÷ %ñ %¨ð %°uñ %r1   c              #  ót  aa	a
a"  € ^ RI pV P                  V P                  R,           4      pVP                  P	                  RRR7       VP                  R4      o
Rp VP                  4       R8X  d   ^ RIoV
V3R loVV3R	 lpVV3R
 lpM^ RIo	V	V
3R lpV	V
3R lp\        P                  ! 4       V,           pV'       g    V! 4        RpK  Vx €  V'       d   V! 4        S
P                  4        R#   \         d8    \        P                  ! 4       T8¼  d    KN  \        P                  ! R4        K{  i ; i  \        \        3 d     Lji ; i  S
P                  4        i ; i   T'       d   X! 4        M  \        \        3 d     Mi ; iS
P                  4        i   S
P                  4        i ; i; i5i)z8Acquire the cross-process lock for path.quarantine.lock.Nz.quarantine.lockTr?  za+bFÚWindowsc                ól   <€ SP                  ^ 4       SP                  SP                  4       V ^4       R# r‰  )r9   Úlockingr  )rK  rG   Úmsvcrts   &€€r!   Ú_lockÚ,quarantine_cross_process_lock.<locals>._lockš  s$   ø€ Ø—‘˜A”Ø—‘˜vŸ}™}›°°aÖ8r1   c                 ó(   <€ S ! SP                   4      # rÌ   )ÚLK_NBLCK©rž  r�  s   €€r!   r  Ú/quarantine_cross_process_lock.<locals>.<lambda>ž  s   ø€ ¡ f§o¡oÔ 6r1   c                 ó(   <€ S ! SP                   4      # rÌ   )ÚLK_UNLCKr¢  s   €€r!   r  r£  Ÿ  s   ø€ ™e F§O¡OÔ4r1   c                 óz   <€ S P                  SP                  4       S P                  S P                  ,          4      # rÌ   )Úflockr  ÚLOCK_EXÚLOCK_NB©ÚfcntlrG   s   €€r!   r  r£  ¢  s#   ø€  §¡¨F¯M©M«O¸U¿]¹]ÈUÏ]É]Õ=ZÔ [r1   c                 óX   <€ S P                  SP                  4       S P                  4      # rÌ   )r§  r  ÚLOCK_UNrª  s   €€r!   r  r£  £  s   ø€ ˜eŸk™k¨&¯-©-«/¸5¿=¹=ÔIr1   g{®Gáz”?)rã   r  r   rb  rY  r8   Úsystemr�  r«  rT  Ú	monotonicr   Úsleepr   rú   )rs   r—  rã   Ú	lock_pathÚacquiredÚ	_try_lockÚ_unlockÚdeadlinerž  r«  rG   r�  s   &&      @@@@r!   Úquarantine_cross_process_lockr¶  �  sQ  ûé € ó Ø—‘˜tŸy™yÐ+=Õ=Ó>€IØ×Ñ×Ñ 4°$ÐÔ7Ø�^‰^˜EÓ"€FØ€HðØ�?‰?Ó 	Ô)Ûö9õ 7ˆIÝ4‰GãÝ[ˆIÝIˆGÜ—>’>Ó# gÕ-ˆßð"Ù”Ø’ð
 Šð	ßÙ”	ð �L‰LŽNøô ô "Ü—>’>Ó# xÔ/ÚÜ—
’
˜5×!ð"ûô œÐ(ô 	Ùð	ûð �L‰L�Nûð	ßÙ”	ùÜœÐ(ô 	Ùð	úð �L‰L�NøˆF�L‰L�Nÿs¯   †AF8ÁA$E& Ã	C5 ÃE& ÃD: Ã#F8Ã5%D7ÄE& ÄD7Ä3E& Ä6D7Ä7E& Ä:EÅE ÅEÅE ÅE#Å#F8Å&F5Å(E8Å7F Å8FÆ	F ÆFÆF ÆF5Æ F2Æ2F5Æ5F8Úalready_lockedc               ó$   € V ^8„  d   QhRRRRRR/# )r'   rs   r   r·  r‚   r,   zOptional[Path]r.   )r/   s   "r!   r0   r0   ¸  s"   € ÷ . ñ .  dð . ¸tð . ÐP^ñ . r1   c               óò   a € V 3R lpV'       d   V! 4       # \        S 4      ;_uu_ 4       pV'       g"   \        P                  RS 4        RRR4       R# V! 4       uuRRR4       #   + '       g   i     R# ; i)a  Move a non-SQLite state.db (zeroed or clobbered page 0) aside with its -wal/-shm sidecars,
preserving bytes; return the quarantine path.  A cross-process lock stops two concurrent
startups racing: the second re-checks under the lock and finds the file gone (or fresh).c            
     óô  <€ SP                  4       '       g   \        P                  R S4       R# \        S4      '       g   \        P                  RS4       R# \	        S4      '       d   RMRp  \
        P                  ! R4      pSP                   RV  RV R\        P                  ! 4        2pSP                  V R	24      p^ pVP                  4       '       d#   V^,          pSP                  V RV R	24      pK8   SP                  V4       R F‹  p\        \!        S4      T,           4      pTP                  4       '       g   K6  \"        P$                  ! \        4      ;_uu_ 4        TP                  \        \!        T4      T,           4      4       RRR4       K�  	  T#   \         d    Rp EL-i ; i  \         d#   p\        P                  R
ST4        Rp?R# Rp?ii ; i  + '       g   i     Kæ  ; i)z@quarantine_invalid_state_db: %s already moved by another processNzpquarantine_invalid_state_db: %s is no longer invalid (another process quarantined it and a fresh DB was created)ÚzeroedÚnotadbr=  ÚunknownÚ.r>  z.bakz#Failed to quarantine invalid %s: %srf   )rX  rÚ   Úinfor•  r’  rT  rU  rå   r   r<   rW  r  Úrenamer   rí   r   r;   r6   r7   )	ÚkindÚtsrh  r  rj  r    rm   Úsiders   s	           €r!   Ú_do_quarantineÚ3quarantine_invalid_state_db.<locals>._do_quarantine¼  s•  ø€ Ø�{‰{�}Š}Ü�K‰KÐZÐ\`ÔaÙÜ0°×6Ò6Ü�K‰Kð MØNRôTáÜ-¨d×3Ò3‰x¸ˆð	Ü—’˜Ó/ˆBð —)‘)�˜A˜d˜V 1 R D¨¬"¯)ª)«+¨Ð7ˆØ�~‰~   d˜mÓ,ˆØˆØ�k‰k�mŠmØ��FˆAØ—>‘> T F¨!¨A¨3¨dÐ"3Ó4ŠDð	Ø�K‰K˜Ôó 'ˆFÜœ˜D›	 FÕ*Ó+ˆDØ�{‰{�}Œ}Ü×(Ò(¬×1Õ1Ø—K‘K¤¤S¨£Y°Õ%7Ó 8Ô9÷ 2Ñ1ñ 'ð
 ˆøô% ô 	Ø‹Bð	ûô ô 	Ü�L‰LÐ>ÀÀcÔJÝûð	ú÷ 2×1Ð1ús6   Á/F" Ã>F6 Å)+G&Æ"F3Æ2F3Æ6G#ÇGÇG#Ç&G7uM  quarantine lock for %s not acquired within 5s â€” refusing to quarantine without the cross-process lock. The invalid file is left in place. If sessions fail to load, run `hermes sessions recover --source <state.db> --inspect-only`, or restore a snapshot with `/snapshot list` / `/snapshot restore <id>` (terminal `hermes` chat only).N)r¶  rÚ   rí   )rs   r·  rÄ  r²  s   f$  r!   Úquarantine_invalid_state_dbrÆ  ¸  sa   ø€ õ÷> ÙÓÐÜ	& t×	,Ô	,°ßÜ�L‰Lð fð
 ôð ÷ 
-Ñ	,ñ Ó÷ 
-×	,×	,Ó	,ús   ª A%ÁA%Á%A6	c               ó    € V ^8„  d   QhRRRR/# )r'   r(   r   r,   r  r.   )r/   s   "r!   r0   r0   é  s   € ÷ Oñ O Dð O¨^ñ Or1   c           	     ó	  aaa€ ^ RI Hp \        P                  R)4      p\        P
                  ! \        4      ;_uu_ 4        \        \        V 4      R,           4      pVP                  4       '       d   VP                  4       P                  M^ VR&   RRR4        V! \        V 4      \        V 4      RRR7      oR*R T3R llloR*R T3R llloR T3R llp S! R4      TR&   S! R4      TR&   TR,          e&   TR,          e   TR,          TR,          ,          TR&   S! R 4      TR&   S! R!4      pTe   \        T4      MRTR&   S! R"4      TR&   S! R#4      TR	&   \        P
                  ! \        4      ;_uu_ 4        SP!                  R$\"        4      P%                  4        Uu0 uF  qw^ ,          kK  	  pp\"         U	u/ uF  q™Y˜9   bK	  	  up	TR
&   RRR4       T! R4      TR&   \        P
                  ! \        4      ;_uu_ 4        ^ R%IHp
 \+        T
! SP-                  4       4      4      TR&   RRR4       \        P
                  ! \        4      ;_uu_ 4        SP!                  R&4      P/                  4       RJTR&   RRR4       T! R4      ;TR&   pT! R4      ;TR&   pTf   R'MT;'       g    ^ T8  TR&   \        P
                  ! \        4      ;_uu_ 4        SP!                  R(\0        34      P/                  4       pT'       d   \2        P4                  ! T^ ,          4      MRp\7        T\        4      '       d   YÒR&   RRR4       \        P
                  ! \        4      ;_uu_ 4        SP9                  4        RRR4       T#   + '       g   i     ELÿ; i  \         d#   p\        P                  RY4       Tu Rp?# Rp?ii ; iu upi u up	i   + '       g   i     EL; i  + '       g   i     ELÂ; i  + '       g   i     EL‡; i  + '       g   i     L×; i  + '       g   i     T# ; i  \        P
                  ! \        4      ;_uu_ 4        SP9                  4        RRR4       i   + '       g   i     i ; i; i)+u  Best-effort, strictly read-only stats snapshot of a state.db file: ``mode=ro`` with a short
timeout so it can run against a *live* database without taking a write lock.  Every field is
collected independently (a failed pragma/SELECT yields ``None`` for it); never raises.
Deliberately does NOT instantiate :class:`SessionDB` â€” its constructor runs DDL.
``wal_size_bytes`` is 0 when the sidecar is absent; ``fts_storage_version`` None means the
legacy inline layout; ``fts_rebuild_deferral`` is the durable blocked-repair diagnostic.)ry  r.  r2  Úfreelist_countÚlogical_size_bytesÚwal_size_bytesÚjournal_modeÚmessagesÚsessionsÚ
fts_tablesÚfts_storage_versionÚfts_storage_upgrade_neededÚfts_teardown_pendingÚfts_rebuild_pendingÚfts_rebuild_high_waterÚfts_rebuild_progressÚfts_rebuild_deferralrg   NTg       @)rt  Úurir—  z4collect_state_db_stats: cannot open %s read-only: %sc               ó    € V ^8„  d   QhRRRR/# )r'   Úsqlr;   r,   r   r.   )r/   s   "r!   r0   Ú,collect_state_db_stats.<locals>.__annotate__  s   € ÷ ñ �Sð ¨ñ r1   c                óŽ   <€  SP                  W4      P                  4       pV'       d
   V^ ,          # R#   \         d     R# i ; ir‰  )ÚexecuteÚfetchonerå   )rÙ  ÚparamsÚrowÚconns   && €r!   Ú_scalarÚ'collect_state_db_stats.<locals>._scalar  sB   ø€ ð	Ø—,‘,˜sÓ+×4Ñ4Ó6ˆCß �3�q•6Ð* dÐ*øÜô 	Úð	ús   ƒ&5 ª5 ³5 µAÁAc               ó    € V ^8„  d   QhRRRR/# )r'   rÙ  r;   r,   rT   r.   )r/   s   "r!   r0   rÚ    s   € ÷ 9ñ 9�#ð 9 ]ñ 9r1   c                ó6   <€ S! W4      pVe   \        V4      # R # rÌ   )r*   )rÙ  rÞ  Úvaluerá  s   && €r!   Ú_intÚ$collect_state_db_stats.<locals>._int  s!   ø€ Ù˜Ó$ˆØ"Ò.Œs�5‹zÐ8°DÐ8r1   c               ó    € V ^8„  d   QhRRRR/# )r'   rH   r;   r,   rT   r.   )r/   s   "r!   r0   rÚ    s   € ÷ ñ �sð ˜}ñ r1   c                ó>   <€  S! R V 34      #   \          d     R# i ; i)z*SELECT value FROM state_meta WHERE key = ?N)rå   )rH   ræ  s   &€r!   Ú	_meta_intÚ)collect_state_db_stats.<locals>._meta_int  s*   ø€ ð	ÙÐDÀsÀfÓMÐMøÜô 	Úð	ús   ƒ	 �›zPRAGMA page_countzPRAGMA page_sizezPRAGMA freelist_countzPRAGMA journal_modezSELECT COUNT(*) FROM messageszSELECT COUNT(*) FROM sessionszISELECT name FROM sqlite_master WHERE type = 'table' AND name IN (?, ?, ?))Úfts_layout_driftzfSELECT 1 FROM sqlite_master WHERE type = 'table' AND name LIKE 'fts\_v22\_trash\_%' ESCAPE '\' LIMIT 1Fz2SELECT value FROM state_meta WHERE key = ? LIMIT 1)r.  r2  rÉ  rÊ  rË  rÌ  rÍ  rÎ  rÏ  rÐ  rÑ  rÒ  rÓ  rÔ  rÕ  rÖ  )r.   )r   ry  ÚdictÚfromkeysr6   r7   r   r   r;   rX  r=   rR  r   rå   rÚ   ræ   rÜ  Ú_FTS_TABLE_NAMESÚfetchallÚhermes_state_ftsrì  r‚   ÚcursorrÝ  r   ÚjsonÚloadsÚ
isinstancerú   )r(   ry  ÚstatsÚwal_pathr    rê  Újmrß  r   Útrì  Ú
high_waterÚprogressr7  ræ  rá  rà  s   &             @@@r!   Úcollect_state_db_statsrü  é  sÌ  ú€ õ 1Ü ŸM™Mð +Ró S€Eô 
×	Ò	œW×	%Õ	%Üœ˜G› vÕ-Ó.ˆØ=E¿_¹_×=NÒ=N (§-¡-£/×"9Ò"9ÐTUˆÐÑ÷ 
&ðñ #Ô#3°GÓ#<ÌDÐQXËMØ'+°Sô:ˆ÷
ò ÷9ò 9÷ð ð&Ù"Ð#6Ó7ˆˆlÑÙ!Ð"4Ó5ˆˆkÑØ�ÕÒ*¨u°[Õ/AÒ/MØ*/°Õ*=ÀÀkÕ@RÕ*RˆEÐ&Ñ'Ù"&Ð'>Ó"?ˆÐÑÙÐ*Ó+ˆØ+-ª>¤ B¤¸tˆˆnÑÙ Ð!@ÓAˆˆjÑÙ Ð!@ÓAˆˆjÑô × Ò ¤×+Õ+Ø'+§|¡|Ø[Ü ó("ç"*¡(£*ð(-ó .ñ (- ˜—V�Vñ (-ˆEð .õ =MÓ"MÑ<L°q q¡z¢>Ñ<LÑ"MˆE�,Ñ÷	 ,ñ (1Ð1FÓ'GˆÐ#Ñ$Ü× Ò ¤×+Õ+Ý9Ü26Ñ7GÈÏÉËÓ7VÓ2WˆEÐ.Ñ/÷ ,ô × Ò ¤×+Õ+à,0¯L©Lðó-ç#™8›:¨Tð-2ˆEÐ(Ñ)÷ ,ñ
 8AÐAYÓ7ZÐZˆÐ&Ñ'¨*Ù3<Ð=SÓ3TÐTˆÐ$Ñ%¨Ø0:Ò0B¡uÈÏÈÐUVÐZdÑHdˆÐ#Ñ$Ü× Ò ¤×+Õ+Ø—,‘,ÐSÜ 8Ð:ó<ß<D¹H»Jð ç+.”T—Z’Z  A¥Ô'°DˆFÜ˜&¤$×'Ò'Ø06Ð,Ñ-÷ ,ô × Ò ¤×+Õ+Ø�J‰JŒL÷ ,à€L÷C 
&×	%Ð	%ûô ô Ü�‰ÐKÈWÔZØ�ûðüò>.ùò #N÷	 ,×+Ð+ú÷ ,×+Ð+ú÷ ,×+Ð+ú÷ ,×+ú÷ ,Ö+à€Lûô × Ò ¤×+Õ+Ø�J‰JŒL÷ ,×+×+Ð+ýsá   ÁANÂN ÃB%P9 Å>'OÆ%OÆ6
OÇ OÇOÇ5P9 È)O*È1*P9 É%O>Ê 0P9 Ê1+P9 ËA'PÍP9 Í-P%ÎN	ÎO	Î'OÎ>O	ÏO	Ï
OÏO'	Ï!	P9 Ï*O;	Ï5	P9 Ï>P	Ð		P9 ÐP"	ÐP9 Ð%P6	Ð9#R	ÑQ6	Ñ-	R	Ñ6RÒR	c               ó    € V ^8„  d   QhRRRR/# rS   r.   )r/   s   "r!   r0   r0   ;  s   € ÷ ñ ˜dð  }ñ r1   c                ó6  €  \         P                  P                  \        V 4      4      p\        P
                  R8X  dc   \         P                  ! V4      pVP                  VP                  3p\        \        4        UUUUu0 uF  w  rErgWs8X  g   K  VkK  	  upppp4      # \        P
                  P                  R4      '       g   R# \        \        4        UUU	u0 uF  w  rHq˜V8X  g   K  VkK  	  up	pp4      # u uppppi u up	ppi   \         d     R# i ; i)z÷Best-effort count of distinct PIDs holding ``db_path`` open (``/proc/*/fd`` on Linux, libproc
on macOS); ``None`` on any error or other host, never raises.  Uninspectable processes (other
users' without root) are skipped, so this is a lower bound.rá   râ   N)r<   rs   rv   r;   r   rã   r=   r@   rA   r]   rÂ   rä   r–   rå   )
r(   rÁ   rI   r€   r°   rÏ   Ú_pathro   ÚlinkÚ_fd_paths
   &         r!   Úcount_db_holdersr  ;  sÛ   € ðÜ—‘×!Ñ!¤# g£,Ó/ˆÜ�<‰<˜8Ô#ô —’˜“ˆBØŸ	™	 2§9¡9Ð-ˆHÜÔ:QÔ:SÖiÑ:SÑ 6 ¨%ÐW\ÑWhŸ˜Ñ:SÔiÓjÐjÜ�|‰|×&Ñ& w×/Ò/ÙÜÔ3HÔ3JÕ]Ñ3JÑ/˜C xÐV\Én—C�CÑ3JÓ]Ó^Ð^ùõ jùô ^øÜô ÚðúsH   ‚A?D	 ÂC:ÂC:Â	D	 Â!$D	 ÃD	 ÃDÃ+DÃ1D	 Ã:D	 Ä	DÄDc               ó0   € V ^8„  d   QhRRRRRRRRRR	R
R/# )r'   Úppidr*   Úage_secondsr˜  Úmin_age_secondsÚephemeral_backendr‚   Úconnection_statusesz	list[str]r,   r.   )r/   s   "r!   r0   r0   N  s:   € ÷ :ñ :°ð :À%ð :ÐZ_ð :Ø:>ð:ØU^ð:Øcgñ:r1   c                óR   € V R9   ;'       d    W8¬  ;'       d    T;'       d    RV9  # )z9Pure safety predicate for the narrow Desktop holder reap.ÚESTABLISHED)rŠ  é   r.   )r  r  r  r  r  s   $$$$$r!   Ú"_is_inactive_orphan_desktop_holderr  N  s?   € ð �F‰N÷ 9ð 9˜{Ñ=÷ 9ð 9ÐBS÷ 9ð 9ØÐ%8Ñ8ð:r1   c               ó$   € V ^8„  d   QhRRRRRR/# )r'   r(   r   rÑ   rÅ   r,   r$   r.   )r/   s   "r!   r0   r0   U  s(   € ÷ ]ñ ]¨Dð ]Ð;Pð ]ÐU^ñ ]r1   c                ó  a€ \         P                  P                  \         P                  P                  \         P                  ! V 4      4      4      pW"R,           VR,           0o\        \        P                  V3R lV 4       4      4      # )zAReturn unique PIDs proven to hold this DB or one of its sidecars.rg   rh   c              3  ób   <"  € T F$  w  rV^ 8”  g   K  \        V4      S9   g   K   Vx € K&  	  R# 5ir‰  )r
   )r‹  r°   rs   r|   s   &  €r!   r�  Ú1_concrete_state_db_holder_pids.<locals>.<genexpr>Y  s/   øé € ð \Ù$‘	�¨¨a©ŒÔ4IÈ$Ó4OÐSZÑ4Z�Š›Wùs   ƒ/“/¥
/)r<   rs   Únormcasert   ri   r]  rí  rî  )r(   rÑ   Úcanonical_dbr|   s   && @r!   Ú_concrete_state_db_holder_pidsr  U  sk   ø€ ä—7‘7×#Ñ#¤B§G¡G§O¡O´B·I²I¸gÓ4FÓ$GÓH€LØ¨FÕ2°LÀ6Õ4IÐJ€GÜ”—‘ô \Ù$ó\ó \ó ]ð ]r1   )Úmessages_ftsÚmessages_fts_trigramÚmessages_fts_cjki    i  € rÌ   )r—   )[Ú__conditional_annotations__rõ   Ú
__future__r   r6   r‰   r  ró  Úloggingr<   rc  r[  r^   r   rÕ   rT  Úpathlibr   Útypingr   r   r   r   r   r	   Úhermes_state_holdersr
   r   Úhermes_state_commonr   r   rj   Ú	getLoggerrÚ   r"   ÚLockr>   r#   Ú__annotations__r%   rï  rM   rQ   rb   rp   r~   r…   r�   r–   rª   rµ   r¹   r·   r¸   rº   r»   r¼   rš   rØ   r¤   r±   rÂ   rÝ   rè   rî   rS  ra  rZ  r^  r  r3  r   rð   rû   r  r  r#  r(  r8  rq  ry  r‚  r’  r•  Úcontextmanagerr¶  rÆ  rü  r  r  r  )r  s   @r!   Ú<module>r"     sð  øðôõ #ã Û Û Û Û Û 	Û Û Û Û 
Û Û Ý ß =× =ç H÷ð
 
×	Ò	˜>Ó	*€òðF —^’^Ó%Ð Ø57Ð Ð2Ó 7Ø')Ð ˜9Ó )ØOÐ õ"õJ/õ
TõTõõ.BõWò2Bð4 Ð ØÐ ØÐ ØÐ ØÐ ð Ð ØÐ ØÐ Ø€ð #&Ð òõ,ò,õD&õRõ<Að* !0Ð Ø-Ð Ø&'Ð #ð
 +<Ð 'Ø&Ð ØÐ ôY Lô Yõ
õõ4Nõ@]õ
iõ
bõVôrdõ ð"	f¸ð 	fÈE÷ 	fðHÈð HÐ[`÷ Hð ×Ñö%ó ð%ðP. Àe÷ . õbOõdõ&:÷]r1   