+
    iHàjŽ"  ã                  ó(  a € 0 t $ R t^ RIH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 ]P                  ! R4      t/ tR]R&   Rt^@tR	 R
 ltR R ltR R ltR R ltR R ltRRRR/R R lltRR/R R lltR R ltR R ltR R lt. R OtR# )!u÷  Workspace and project-root resolution for LSP.

1. **Workspace gate** â€” LSP only runs when the cwd (or the edited file) sits inside a git
   worktree, so gateway users on user-home cwd's never spawn daemons.
2. **Workspace trust** â€” whether a server may load code the project itself ships.
3. **nearest_root** â€” the per-server project-root walk: up from a start path looking for marker
   files (``pyproject.toml``, ``Cargo.toml``, ...), optionally bailing if an exclude marker
   shows up first.
)ÚannotationsN)ÚPath)ÚAbstractSetÚIterableÚIteratorÚOptionalÚSetÚTuplezagent.lsp.workspaceÚdictÚ_workspace_cachei   c               ó    € V ^8„  d   QhRRRR/# )é   ÚpathÚstrÚreturn© )Úformats   "Ú8/home/ubuntu/.hermes/hermes-agent/agent/lsp/workspace.pyÚ__annotate__r      s   € ÷ 5ñ 5˜ð 5 ñ 5ó    c                óz   € \         P                  P                  \         P                  P                  V 4      4      # )uÂ   Expand ``~``, make absolute, collapse ``.``/``..``.  Symlinks are deliberately NOT resolved â€”
some servers (rust-analyzer's Cargo workspace identity) care, and we want the path the user typed.)Úosr   ÚabspathÚ
expanduser)r   s   &r   Únormalize_pathr      s&   € ô �7‰7�?‰?œ2Ÿ7™7×-Ñ-¨dÓ3Ó4Ð4r   c               ó    € V ^8„  d   QhRRRR/# )r   Ústartr   r   zOptional[Path]r   )r   s   "r   r   r   #   s   € ÷ 	ñ 	�cð 	˜nñ 	r   c                ó®   €  \        \        V 4      4      pVP                  4       '       d   VP                  pV#   \        \
        \        3 d     R# i ; i)zPNormalized start directory (a file's parent), or ``None`` on pathological input.N)r   r   Úis_fileÚparentÚOSErrorÚRuntimeErrorÚ
ValueError)r   Ú
start_paths   & r   Ú
_start_dirr$   #   sS   € ðÜœ.¨Ó/Ó0ˆ
Ø×Ñ×ÒØ#×*Ñ*ˆJð Ðøô ”\¤:Ð.ô âðús   ‚6: ºAÁAc               ó    € V ^8„  d   QhRRRR/# )r   r   r   r   zIterator[Path]r   )r   s   "r   r   r   /   s   € ÷ ñ �Dð ˜^ñ r   c              #  ót   "  € T p\        \        4       F  pVx € VP                  pW18X  d    R# TpK   	  R# 5i)zVYield ``start`` and its ancestors up to the filesystem root, bounded by ``_MAX_WALK``.N)ÚrangeÚ	_MAX_WALKr   )r   ÚcurÚ_r   s   &   r   Ú_walk_upr+   /   s4   é € à
€CÜ”9ÖˆØŠ	Ø—‘ˆØŒ=ÚØŠó ùs   ‚68c               ó    € V ^8„  d   QhRRRR/# )r   r   r   r   úOptional[str]r   )r   s   "r   r   r   :   s   € ÷ ñ ˜Sð  ]ñ r   c                ó¤  € \        V 4      pVf   R# \        P                  \        V4      4      pVe
   V^ ,          # Rp\	        V4       F.  p VR,          P                  4       '       d   \        V4      p MK0  	  W3RJ3\        \        V4      &   \        \        4      \        8”  d   \        P                  4        V#   \         d      KR  i ; i)ue   Return the nearest ancestor dir containing ``.git`` (file or dir â€” worktrees count), else ``None``.Nz.git)
r$   r   Úgetr   r+   Úexistsr    ÚlenÚ_WORKSPACE_CACHE_CAPÚclear)r   r#   ÚcachedÚresolvedr)   s   &    r   Úfind_git_worktreer6   :   sÃ   € ä˜EÓ"€JØÒÙÜ×!Ñ!¤# j£/Ó2€FØÒØ�a�yÐØ€HÜ˜
Ö#ˆð	Ø�f•×$Ñ$×&Ò&Ü˜s›8�Ùñ 'ñ $ð *2À4Ð3GÐ(HÔ”S˜“_Ñ%Ü
ÔÓÔ3Ô3Ü×ÑÔ Ø€Oøô ô 	Ûð	ús   Á(B?Â?CÃCc               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r   Úworkspace_rootr   Úboolr   )r   s   "r   r   r   P   s!   € ÷ ñ ˜cð °3ð ¸4ñ r   c                óª   € \        V 4      p\        V4      pW#8X  d   R#  \        P                  P                  W#.4      V8H  #   \         d     R# i ; i)zÇTrue iff ``path`` is inside (or equal to) ``workspace_root``.  Symlinks are not resolved: a
symlink pointing outside still counts as outside, matching servers that reject didOpen for
unrelated files.TF)r   r   r   Ú
commonpathr"   )r   r8   ÚpÚroots   &&  r   Úis_inside_workspacer>   P   sS   € ô 	�tÓ€AÜ˜.Ó)€DØ„yÙðÜ�w‰w×!Ñ! 1 )Ó,°Ñ4Ð4øÜô Úðús    "A ÁAÁAÚexcludesÚceilingc          
     ó,   € V ^8„  d   QhRRRRRRRRR	R/# )
r   r   r   ÚmarkersúIterable[str]r?   zOptional[Iterable[str]]r@   r-   r   r   )r   s   "r   r   r   _   s:   € ÷ 'ñ 'Øð'àð'ð &ð	'ð
 ð'ð ñ'r   c               ój  € \        V 4      pVf   R# V'       d   \        \        V4      4      MRp\        V4      pV'       d   \        V4      M. pR R lp\	        V4       FN  p	V! W—4      '       d    R# V! V	R.4      '       g   V! W–4      '       d   \        V	4      u # Vf   KE  W•8X  g   KM   R# 	  R# )ub  Walk up from ``start`` for the directory containing the first matched marker.

Returns ``None`` past ``ceiling`` (or the filesystem root), or when an exclude marker is found
first â€” the server is gated off for that file (e.g. typescript skips deno projects when
``deno.json`` precedes ``package.json``).  Marker names are exact filenames â€” no globs.
Nc               ó$   € V ^8„  d   QhRRRRRR/# )r   r)   r   ÚnamesÚlistr   r9   r   )r   s   "r   r   Ú"nearest_root.<locals>.__annotate__s   s!   € ÷ ñ �Tð  $ð ¨4ñ r   c                ó|   € V F#  p W,          P                  4       '       d    R # K%  	  R#   \         d     K7  i ; i)TF)r0   r    )r)   rF   Únames   && r   ÚpresentÚnearest_root.<locals>.presents   sC   € ÛˆDðØ•J×&Ñ&×(Ò(Úñ )ñ ñ øô ô Úðús   ‡,¬;º;z__init__.py)r$   r   r   rG   r+   r   )
r   rB   r?   r@   r#   Úceiling_pathÚmarkers_listÚexcludes_listrK   r)   s
   &&$$      r   Únearest_rootrP   _   s›   € ô ˜EÓ"€JØÒÙß4;”4œ wÓ/Ô0À€LÜ˜“=€Lß&.”D˜”N°B€Mõô ˜
Ö#ˆá�3×&Ò&Úñ �s˜]˜O×,Ò,±¸×1KÒ1KÜ�s“8ŠOØÔ#¨Ö(;Úñ $ñ r   Úcwdc               ó$   € V ^8„  d   QhRRRRRR/# )r   Ú	file_pathr   rQ   r-   r   ztuple[Optional[str], bool]r   )r   s   "r   r   r   ‰   s"   € ÷ ñ ¨#ð °}ð ÐPjñ r   c               óî   €  T;'       g    \         P                  ! 4       pV'       d   \        V4      MRpVe   \	        W4      '       d   VR3# \        V 4      pVe   VR3# R#   \         d    Rp LRi ; i)zøReturn ``(workspace_root, gated_in)`` for a file.  The cwd's worktree wins when the file is
inside it; otherwise the file's own worktree is the fallback anchor (monorepos / unrelated
checkouts).  ``(None, False)`` when neither is in a git worktree.NT)NF)r   Úgetcwdr    r6   r>   )rS   rQ   Ú
cwd_anchorÚcwd_rootÚ	file_roots   &$   r   Úresolve_workspace_for_filerY   ‰   s~   € ðØ×'Ð'œBŸIšI›Kˆ
÷ 1;Ô  Ô,À€HØÒÔ 3°I× HÒ HØ˜ˆ~ÐÜ! )Ó,€IØÒØ˜$ˆÐØÐøô ô ð Š
ð	ús   ‚A$ ‹A$ Á$A4Á3A4c               ó   € V ^8„  d   QhRR/# )r   r   zset[str]r   )r   s   "r   r   r   �   s   € ÷ ñ  (ñ r   c                 óî  € ^ RI Hp  ^ RIHp ^ RIHp ^ RIHp \        P                  P                  R4      '       d   \        4       # \        P                  .pV! V! RR4      4      '       g   VP                  V 4       \        R4      p\        4       pV FG  p \        \!        V! 4       4      4      pTf   K#  \%        YX4      '       d   K6  TP'                  T4       KI  	  V#   \"        T3 d     K]  i ; i)	ap  Git worktrees the operator pointed Hermes at: the launch dir and the surface-set workspace
(``resolve_agent_cwd``: the Desktop/TUI session cwd, ``hermes -w``'s worktree, a gateway's
``terminal.cwd``).  The agent's ``cd`` moves neither (it only moves the terminal's cwd).  A repo at
or above ``$HOME`` never counts: a dotfiles repo would trust every directory below it.)Úresolve_agent_cwd)Úget_session_env)ÚTerminalPolicyUnavailable)Úis_truthy_valueÚHERMES_KANBAN_TASKÚHERMES_CRON_SESSIONÚ Ú~)Úagent.runtime_cwdr\   Úgateway.session_contextr]   Útools.terminal_scoper^   Úutilsr_   r   Úenvironr/   ÚsetrU   Úappendr   r6   r   r    r>   Úadd)	r\   r]   r^   r_   ÚanchorsÚhomeÚrootsÚanchorr=   s	            r   Úoperator_workspace_rootsrp   �   sÇ   € õ
 4Ý7Ý>Ý%ô 
‡z�z‡~�~Ð*×+Ò+Ü‹uˆÜ�y‰yˆk€GÙ™?Ð+@À"ÓE×FÒFØ�‰Ð(Ô)Ü˜#Ó€DÜ“e€EÛˆð	Ü$¤S©«£]Ó3ˆDð ÔÔ$7¸×$CÔ$CØ�I‰I�dŽOñ ð €Løô	 Ð2Ð3ô 	Úð	ús   ÂC#Ã#C4Ã3C4c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   r=   r   Útrusted_rootsrC   Úoperator_rootszAbstractSet[str]r   r9   r   )r   s   "r   r   r   º   s*   € ÷ 5ñ 5˜sð 5°=ð 5ÐRbð 5Ðgkñ 5r   c                ó¤   a € \         ;QJ d    V 3R lV 4       F  '       g   K   RM	  RM! V 3R lV 4       4      '       d   R# \        S 4      V9   # )ar  True iff a language server may load code the project at ``root`` ships (its own interpreter,
TypeScript SDK, config files, build scripts): ``root`` is inside an ``lsp.trusted_workspaces``
entry, or belongs to one of the ``operator_workspace_roots`` worktrees.  A nested clone inside
such a worktree has its own ``.git`` and is not trusted: the agent may have fetched it.c              3  ó<   <"  € T F  p\        SV4      x € K  	  R # 5i)N)r>   )Ú.0Útr=   s   & €r   Ú	<genexpr>Ú'is_trusted_workspace.<locals>.<genexpr>¿   s   øé € Ð
?±¨AÔ˜t Q×'Ð'³ùs   ƒTF)Úanyr6   )r=   rr   rs   s   f&&r   Úis_trusted_workspacer{   º   s9   ø€ ÷
 ƒsÔ
?±Ó
?‡s‡s‚sÔ
?±Ó
?×?Ò?ÙÜ˜TÓ" nÑ4Ð4r   c               ó   € V ^8„  d   QhRR/# )r   r   ÚNoner   )r   s   "r   r   r   Ä   s   € ÷ ñ �Tñ r   c                 ó.   € \         P                  4        R# )zaClear the workspace-resolution cache (on service shutdown, so re-init doesn't see stale results).N)r   r3   r   r   r   Úclear_cacher   Ä   s   € ä×ÑÖr   )r   r6   r>   r{   rP   r   rp   rY   ) Ú__conditional_annotations__Ú__doc__Ú
__future__r   Úloggingr   Úpathlibr   Útypingr   r   r   r   r   r	   Ú	getLoggerÚloggerr   Ú__annotations__r2   r(   r   r$   r+   r6   r>   rP   rY   rp   r{   r   Ú__all__)r€   s   @r   Ú<module>rŠ      sŸ   øðôõ #ã Û 	Ý ß H× Hà	×	Ò	Ð0Ó	1€ð Ð �$Ó ØÐ ð €	õ5õ	õõõ,ð'ð )-ð	'ð
 "÷'ðTÀt÷ õ(õ:5õò
	‚r   