Ë
    âß²j©  ã                   óŽ  — U d Z ddlZddlZddlZddlZddlmZ ddlmZm	Z	 	 ddl
Z
dZde	e   fd„ZdZdefd	„Z eh d
£«      Zdae	e   ed<   dedefd„Zdefd„Zdefd„Zdededefd„Z ej2                  «       Zded<   deddfd„Zdae	e   ed<    ej<                  «       Zde	e   ddfd„Z de	e   fd„Z!y# e$ r dZ
Y Œœw xY w)a   Live-DB test-isolation guard and the per-process "last init error" record.
Every SessionDB construction resolves its path through _ensure_test_isolation
so a pytest-context process (env OR ancestry) can never open a production
state.db; env-based so subprocess children are protected too.é    N)ÚPath)ÚAnyÚOptionalÚHERMES_STATE_DB_GUARD_BYPASSÚreturnc                  óV  — 	 t        t        j                  j                  d«      «      } t        j
                  dk(  rJt        j                  j                  dd«      j                  «       }|rt        |«      dz  n
| dz  dz  dz  }n| dz  }|j                  «       S # t        $ r Y y	w xY w)
zÍThe REAL platform-default Hermes root. Avoids ``Path.home()`` /
    ``hermes_constants`` (tests monkeypatch Path.home to a tempdir); ``expanduser``
    reads HOME/passwd, which the conftest never rewrites.Ú~Úwin32ÚLOCALAPPDATAÚ ÚhermesÚAppDataÚLocalz.hermesN)r   ÚosÚpathÚ
expanduserÚsysÚplatformÚenvironÚgetÚstripÚresolveÚ	Exception)ÚhomeÚbaseÚroots      ú7/home/ubuntu/.hermes/hermes-agent/hermes_state_guard.pyÚ_real_platform_state_rootr      s“   € ð	Ü”B—G‘G×&Ñ& sÓ+Ó,ˆÜ�<‰<˜7Ò"Ü—:‘:—>‘> .°"Ó5×;Ñ;Ó=ˆDÙ,0”4˜“: Ò(°d¸YÑ6FÈÑ6PÐS[Ñ6[‰Dà˜)Ñ#ˆDØ�|‰|‹~ÐøÜò Ùðús   ‚BB Â	B(Â'B(ÚHERMES_TEST_ISOLATIONc                  óÞ   — t        t        j                  j                  d«      xsD t        j                  j                  d«      xs# t        j                  j                  t        «      «      S )zBTrue when this process (or a parent test process) is a pytest run.ÚPYTEST_CURRENT_TESTÚPYTEST_VERSION)Úboolr   r   r   Ú_TEST_ISOLATION_MARKER_ENV© ó    r   Ú_running_under_pytestr'   6   sL   € äÜ
�
‰
�‰Ð,Ó-ò 	6Ü�:‰:�>‰>Ð*Ó+ò	6ä�:‰:�>‰>Ô4Ó5óð r&   >   úpy.testú
pytest.exeúpy.test.exeÚpytestÚ_PYTEST_ANCESTORÚprocc                 óB  — 	 | j                  «       xs g }|D ]g  }	 t        |«      j                  d«      j                  d«      j	                  dd«      j                  dd«      d   j                  «       }|t        v sŒg y y# t        $ r Y yw xY w# t        $ r Y Œ…w xY w)	z“True when *proc*'s command line is a pytest invocation. Unreadable cmdline
    => not pytest: guessing the other way would refuse production opens.Fú"ú'ú\ú/é   éÿÿÿÿT)Úcmdliner   Ústrr   ÚreplaceÚrsplitÚlowerÚ_PYTEST_LAUNCHER_NAMES)r-   r5   ÚargÚnames       r   Ú_process_looks_like_pytestr=   G   s®   € ðØ—,‘,“.Ò& Bˆð ò ˆð	ä�s“8—>‘> #Ó&×,Ñ,¨SÓ1×9Ñ9¸$ÀÓD×KÑKÈCÐQRÓSÐTVÑW×]Ñ]Ó_ˆDð Ô)Ò)Ùðð øô ò Ùðûô ò 	Ùð	ús#   ‚B œABÂ	BÂBÂ	BÂBc                  óÈ   — t         �t         S d} t        �7	 t        d„ t        j                  «       j	                  «       D «       «      } | a | S | a | S # t
        $ r d} Y | a | S w xY w)aH  True when an ancestor process is a pytest run: a child spawned with a
    rebuilt env loses PYTEST_* and the HERMES_HOME redirect together, ancestry
    survives that. Fails open without psutil / on walk errors.

    ``_running_under_pytest`` reads ``PYTEST_*`` env vars, which a child spawned with a rebuilt environment
    loses at the same moment it loses the ``HERMES_HOME`` redirect: that child aims at the production DB
    *and* disarms the guard in one step (#82770). Ancestry is the one test-context signal that survives an
    env rebuild, so it backs the env check up.
    Fc              3   ó2   K  — | ]  }t        |«      –— Œ y ­w)N)r=   )Ú.0Úps     r   ú	<genexpr>z'_has_pytest_ancestor.<locals>.<genexpr>i   s   è ø€ ÒZ¸!Ô2°1×5ÑZùs   ‚)r,   ÚpsutilÚanyÚProcessÚparentsr   )Úfounds    r   Ú_has_pytest_ancestorrH   Y   s{   € ô Ð#ÜÐØ€EÜÐð	ÜÑZ¼v¿~¹~Ó?O×?WÑ?WÓ?YÔZÓZˆEð ÐØ€Lð ÐØ€Løô ò 	Ø‰EØÐØ€Lð	ús   –2A ÁA!Á A!c                  ó.   — t        «       xs
 t        «       S )zBTest run by environment or ancestry (memoised; env checked first).)r'   rH   r%   r&   r   Ú_in_test_contextrJ   p   s   € ä Ó"Ò<Ô&:Ó&<Ð<r&   Úresolvedr   c                 ó¨   — | j                   |k(  ry	 | j                  |«      j                  }t	        |«      dk(  xr |d   dk(  S # t        $ r Y yw xY w)z‘*resolved* is ``<root>/state.db`` or ``<root>/profiles/<name>/state.db``;
    deeper scratch paths (repo worktrees) are deliberately NOT matched.TFé   r   Úprofiles)ÚparentÚrelative_toÚpartsÚ
ValueErrorÚlen)rK   r   rQ   s      r   Ú_is_production_state_dbrT   u   s`   € ð ‡�˜$ÒØðØ×$Ñ$ TÓ*×0Ñ0ˆô ˆu‹:˜‰?Ò5˜u Q™x¨:Ñ5Ð5øô ò Ùðús   ’A Á	AÁAzweakref.WeakSet[Any]Ú_test_instance_registryÚdbc                 ó–   — t         j                  j                  t        «      r	 t        j                  | «       yy# t        $ r Y yw xY w)zGTrack *db* for suite-level teardown closing (test-isolation runs only).N)r   r   r   r$   rU   Úaddr   )rV   s    r   Ú_register_test_instancerY   �   s?   € ä	‡z�z‡~�~Ô0Ô1ð	Ü#×'Ñ'¨Õ+ð 2øô ò 	Ùð	ús   ¥< ¼	AÁAÚ_last_init_errorÚmsgc                 ó>   — t         5  | addd«       y# 1 sw Y   yxY w)z¸Record (or clear with None) the most recent init failure. __init__ never
    clears on success: a concurrent open would erase the cause another thread's
    /resume is about to format.N)Ú_last_init_error_lockrZ   )r[   s    r   Ú_set_last_init_errorr^   Ÿ   s"   € ô
 
ñ ØÐ÷÷ ñ ús   ‡“c                  ó   — t         S )zAMost recent state.db init failure (None if none/never attempted).)rZ   r%   r&   r   Úget_last_init_errorr`   ¨   s   € äÐr&   )"Ú__doc__r   r   Ú	threadingÚweakrefÚpathlibr   Útypingr   r   rC   ÚImportErrorÚ_STATE_DB_GUARD_BYPASS_ENVr   r$   r#   r'   Ú	frozensetr:   r,   Ú__annotations__r=   rH   rJ   rT   ÚWeakSetrU   rY   rZ   r6   ÚLockr]   r^   r`   r%   r&   r   ú<module>rl      s@  ðòAó
 
Û 
Û Û Ý ß  ðÛð <Ð ð 8¨D¡>ó ð2 5Ð ð˜tó ñ #Ò#UÓVÐ ð $(Ð �(˜4‘.Ó 'ð Sð ¨Tó ð$˜dó ð.=˜$ó =ð
	6 dð 	6°$ð 	6¸4ó 	6ð0 3B°'·/±/Ó2CÐ Ð/Ó Cð ð ¨ó ð #'Ð �(˜3‘-Ó &Ø&˜	Ÿ™Ó(Ð ð˜h s™mð °ó ð˜X c™]ô øðs ò Ø‚Fðús   £B: Â:CÃC