+
    i;                     Z   R 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 ]P                   ! ]4      tRRRRRR	/t]! R'4      tRsR
 R ltR R ltR R ltR(R R l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t!R R  lt"R! R" lt#R# R$ lt$R% R& lt%R# ))a  Lightweight skill metadata utilities shared by prompt_builder and skills_tool.

This module intentionally avoids importing the tool registry, CLI config, or any
heavy dependency chain.  It is safe to import at module level without triggering
tool registration or provider resolution.
N)Path)AnyDictListOptionalSetTuple)get_hermes_homemacosdarwinlinuxwindowswin32c                $    V ^8  d   QhR\         /# )   contentstr)formats   "./home/ubuntu/hermes-agent/agent/skill_utils.py__annotate__r   "   s     " "s "    c                   aa \         f2   ^ RIo\        SRR4      ;'       g    SP                  oR VV3R llpVs \        V 4      # )z7Parse YAML with lazy import and CSafeLoader preference.NCSafeLoaderc                $    V ^8  d   QhR\         /# )r   valuer   )r   s   "r   r   yaml_load.<locals>.__annotate__*   s     	3 	3 	3r   c                 *   < SP                  V SR 7      # ))Loader)load)r   loaderyamls   &r   _loadyaml_load.<locals>._load*   s    99U6922r   )_yaml_load_fnr!   getattr
SafeLoader)r   r"   r    r!   s   & @@r   	yaml_loadr'   "   sD     }d3FFt	3 	3 !!r   c                t    V ^8  d   QhR\         R\        \        \         \        3,          \         3,          /# )r   r   return)r   r   r   r   )r   s   "r   r   r   4   s,     " "s "uT#s(^S-@'A "r   c                0   / pT pV P                  R4      '       g   W3# \        P                  ! RV R,          4      pV'       g   W3# V ^VP                  4       ^,            pWP	                  4       ^,           R p \        V4      p\        V\        4      '       d   TpW3#   \         di    TP                  4       P                  R4       F@  pRT9  d   K  TP                  R^4      w  rxTP                  4       YP                  4       &   KB  	   Y3# i ; i)zParse YAML frontmatter from a markdown string.

Uses yaml with CSafeLoader for full YAML support (nested metadata, lists)
with a fallback to simple key:value splitting for robustness.

Returns:
    (frontmatter_dict, remaining_body)
z---z
\n---\s*\n:   NNN
:)
startswithresearchstartendr'   
isinstancedict	Exceptionstripsplit)	r   frontmatterbody	end_matchyaml_contentparsedlinekeyr   s	   &        r   parse_frontmatterr?   4   s    #%KDe$$  		-5I  1y0145L==?Q&()D
5<(fd## K   5 &&(..t4D$C+JC',{{}K		$	 5 5s   <#B" "A.DDc                R    V ^8  d   QhR\         \        \        3,          R\        /# r   r8   r)   )r   r   r   bool)r   s   "r   r   r   \   s"      S#X 4 r   c                L   V P                  R4      pV'       g   R# \        V\        4      '       g   V.p\        P                  pV FY  p\        V4      P                  4       P                  4       p\        P                  WD4      pVP                  V4      '       g   KX   R# 	  R# )ar  Return True when the skill is compatible with the current OS.

Skills declare platform requirements via a top-level ``platforms`` list
in their YAML frontmatter::

    platforms: [macos]          # macOS only
    platforms: [macos, linux]   # macOS and Linux

If the field is absent or empty the skill is compatible with **all**
platforms (backward-compatible default).
	platformsTF)
getr3   listsysplatformr   lowerr6   PLATFORM_MAPr.   )r8   rD   currentrH   
normalizedmappeds   &     r   skill_matches_platformrN   \   s     ,Ii&&K	llG]((*002
!!*9f%%	 
 r   c                T    V ^8  d   QhR\         R,          R\        \         ,          /# )r   rH   Nr)   )r   r   )r   s   "r   r   r   y   s"     &= &=sTz &=SX &=r   c                   \        4       R,          pVP                  4       '       g   \        4       #  \        VP	                  RR7      4      p\        T\        4      '       g   \        4       # TP                  R4      p\        T\        4      '       g   \        4       # T ;'       g5    \        P                  ! R4      ;'       g    \        P                  ! R4      pT'       d:   TP                  R	4      ;'       g    / P                  T4      pTe   \        T4      # \        TP                  R
4      4      #   \
         d+   p\        P                  RY4       \        4       u Rp?# Rp?ii ; i)au  Read disabled skill names from config.yaml.

Args:
    platform: Explicit platform name (e.g. ``"telegram"``).  When
        *None*, resolves from ``HERMES_PLATFORM`` or
        ``HERMES_SESSION_PLATFORM`` env vars.  Falls back to the
        global disabled list when no platform is determined.

Reads the config file directly (no CLI config imports) to stay
lightweight.
config.yamlutf-8encodingz"Could not read skill config %s: %sNskillsHERMES_PLATFORMHERMES_SESSION_PLATFORMplatform_disableddisabled)r	   existssetr'   	read_textr5   loggerdebugr3   r4   rE   osgetenv_normalize_string_set)rH   config_pathr<   e
skills_cfgresolved_platformrX   s   &      r   get_disabled_skill_namesrf   y   s/    "#m3Ku;00'0BC fd##uH%Jj$''u 	 	0 	099&'	0 	099./ 
 '^^,?@FFBKK
 (():;; 
!;<<+  9;Jus   D8 8E-E("E-(E-c                :    V ^8  d   QhR\         \        ,          /# r   r)   )r   r   )r   s   "r   r   r      s     > >SX >r   c                     V f   \        4       # \        V \        4      '       d   V .p V  Uu0 uF=  p\        V4      P                  4       '       g   K$  \        V4      P                  4       kK?  	  up# u upi N)r[   r3   r   r6   )valuesvs   & r   ra   ra      sR    ~u&#$*=Fqc!fllnNCFLLNF===s   !A2A2c                :    V ^8  d   QhR\         \        ,          /# rh   r   r   )r   s   "r   r   r      s     2 2$t* 2r   c                    \        4       R,          p V P                  4       '       g   . #  \        V P                  RR7      4      p\        T\        4      '       g   . # TP                  R4      p\        T\        4      '       g   . # TP                  R4      pT'       g   . # \        T\        4      '       d   T.p\        T\        4      '       g   . # \        4       R,          P                  4       p\        4       p. pT F  p\        T4      P                  4       pT'       g   K&  \        P                  P                  \        P                  P!                  T4      4      p\#        T4      P                  4       p	Y8X  d   K  Y9   d   K  T	P%                  4       '       d%   TP'                  T	4       TP)                  T	4       K  \*        P-                  RT	4       K  	  T#   \         d    . u # i ; i)a,  Read ``skills.external_dirs`` from config.yaml and return validated paths.

Each entry is expanded (``~`` and ``${VAR}``) and resolved to an absolute
path.  Only directories that actually exist are returned.  Duplicates and
paths that resolve to the local ``~/.hermes/skills/`` are silently skipped.
rQ   rR   rS   rU   external_dirsz0External skills dir does not exist, skipping: %s)r	   rZ   r'   r\   r5   r3   r4   rE   r   rF   resolver[   r6   r_   path
expanduser
expandvarsr   is_diraddappendr]   r^   )
rb   r<   rd   raw_dirslocal_skillsseenresultentryexpandedps
             r   get_external_skills_dirsr      s    "#m3K	;00'0BC fd##	H%Jj$''	~~o.H	(C  :h%%	#%099;LeDFE
  "77%%bgg&8&8&?@N""$988::HHQKMM!LLKQO " MM  	s   G! !G10G1c                :    V ^8  d   QhR\         \        ,          /# rh   rn   )r   s   "r   r   r      s      T$Z r   c                 \    \        4       R,          .p V P                  \        4       4       V # )u   Return all skill directories: local ``~/.hermes/skills/`` first, then external.

The local dir is always first (and always included even if it doesn't exist
yet — callers handle that).  External dirs follow in config order.
rU   )r	   extendr   )dirss    r   get_all_skills_dirsr      s)     ()DKK(*+Kr   c                t    V ^8  d   QhR\         \        \        3,          R\         \        \        3,          /# rA   r   r   r   r   )r   s   "r   r   r      s*      $sCx. T#t)_ r   c                N   V P                  R4      p\        V\        4      '       g   / pVP                  R4      ;'       g    / p\        V\        4      '       g   / pRVP                  R. 4      RVP                  R. 4      RVP                  R. 4      RVP                  R. 4      /# )z>Extract conditional activation fields from parsed frontmatter.metadatahermesfallback_for_toolsetsrequires_toolsetsfallback_for_toolsrequires_tools)rE   r3   r4   )r8   r   r   s   &  r   extract_skill_conditionsr      s    z*Hh%%\\(#))rFfd##,CR!HVZZ(;R@fjj)=rB&**%5r:	 r   c                    V ^8  d   QhR\         \        \        3,          R\        \         \        \        3,          ,          /# rA   r   )r   s   "r   r   r     s/     8 84S> 8d4S>>R 8r   c                   V P                  R4      p\        V\        4      '       g   . # VP                  R4      p\        V\        4      '       g   . # VP                  R4      pV'       g   . # \        V\        4      '       d   V.p\        V\        4      '       g   . # . p\	        4       pV EF  p\        V\        4      '       g   K  \        VP                  RR4      4      P                  4       pV'       d   Wu9   d   KU  \        VP                  RR4      4      P                  4       pV'       g   K  RVRV/p	VP                  R4      p
V
e   WR&   VP                  R4      p\        V\
        4      '       d+   VP                  4       '       d   VP                  4       V	R&   MWR&   VP                  V4       VP                  V	4       EK!  	  V# )	a  Extract config variable declarations from parsed frontmatter.

Skills declare config.yaml settings they need via::

    metadata:
      hermes:
        config:
          - key: wiki.path
            description: Path to the LLM Wiki knowledge base directory
            default: "~/wiki"
            prompt: Wiki directory path

Returns a list of dicts with keys: ``key``, ``description``, ``default``,
``prompt``.  Invalid or incomplete entries are silently skipped.
r   r   configr>    descriptiondefaultprompt)	rE   r3   r4   rF   r[   r   r6   rv   rw   )r8   r   r   rawr{   rz   itemr>   descr|   r   prompt_texts   &           r   extract_skill_config_varsr     s     z*Hh%%	\\(#Ffd##	
**X
C	#tec4  	#%FD$%%$((5"%&,,.ck488M2./55734!
 ((9%&)hhx(k3''K,=,=,?,?)//1E(O"(Oe/ 0 Mr   c                \    V ^8  d   QhR\         \        \        \        3,          ,          /# rh   r   r   r   r   )r   s   "r   r   r   ?  s      $ $T#s(^(< $r   c                 l   . p \        4       p\        4       p\        4        F  pVP                  4       '       g   K  \	        VR4       F  p VP                  RR7      p\        V4      w  rgTP                  R4      ;'       g    TP                  P                  p\        T4      T9   d   Kd  \        T4      '       g   Kw  \        T4      p	T	 FJ  p
T
R,          T9  g   K  \        T4      T
R&   T P                  T
4       TP                  T
R,          4       KL  	  K  	  K  	  V #   \         d     K  i ; i)aE  Scan all enabled skills and collect their config variable declarations.

Walks every skills directory, parses each SKILL.md frontmatter, and returns
a deduplicated list of config var dicts.  Each dict also includes a
``skill`` key with the skill name for attribution.

Disabled and platform-incompatible skills are excluded.
zSKILL.mdrR   rS   namer>   skill)r[   rf   r   ru   iter_skill_index_filesr\   r?   r5   rE   parentr   r   rN   r   rw   rv   )all_vars	seen_keysrY   
skills_dir
skill_filer   r8   _
skill_nameconfig_varsvars              r   discover_all_skill_config_varsr   ?  s    &(HUI')H)+
  ""0ZHJ **G*<!23!7 %0JJJ4E4E4J4JJ:(*)+663K@K"u:Y.#&z?CLOOC(MM#e*-	 # I ,. O!  s   D$$D32D3zskills.configc                R    V ^8  d   QhR\         \        \        3,          R\        /# )r   r   
dotted_keyr   r   r   )r   s   "r   r   r   l  s"     	 	T#s(^ 	 	r   c                    VP                  R4      pT pV F*  p\        V\        4      '       d   WC9   d   W4,          pK)   R# 	  V# )zPWalk a nested dict following a dotted key.  Returns None if any part is missing..N)r7   r3   r4   )r   r   partsrK   parts   &&   r   _resolve_dotpathr   l  sC    S!EGgt$$mG	 
 Nr   c                    V ^8  d   QhR\         \        \        \        3,          ,          R\        \        \        3,          /# )r   r   r)   r   )r   s   "r   r   r   x  s1     # #d38n%#	#s(^#r   c                   \        4       R,          p/ pVP                  4       '       d5    \        VP                  RR7      4      p\	        V\
        4      '       d   Tp/ pV  F  pVR,          p\         RV 2p\        W'4      pVe-   \	        V\        4      '       d)   VP                  4       '       g   VP                  RR4      p\	        V\        4      '       dK   RV9   g   R	V9   d=   \        P                  P                  \        P                  P                  V4      4      pWV&   K  	  V#   \         d     Li ; i)
aB  Resolve current values for skill config vars from config.yaml.

Skill config is stored under ``skills.config.<key>`` in config.yaml.
Returns a dict mapping **logical** keys (as declared by skills) to their
current values (or the declared default if the key isn't set).
Path values are expanded via ``os.path.expanduser``.
rQ   rR   rS   r>   r   r   r   ~z${)r	   rZ   r'   r\   r3   r4   r5   SKILL_CONFIG_PREFIXr   r   r6   rE   r_   rr   rs   rt   )	r   rb   r   r<   resolvedr   logical_keystorage_keyr   s	   &        r   resolve_skill_config_valuesr   x  s    "#m3KF	{44g4FGF&$''  "H%j,-Q{m< 5=Zs33EKKMMGGIr*E eS!!se|tu}GG&&rww'9'9%'@AE %  O%  		s   3D0 0D>=D>c                R    V ^8  d   QhR\         \        \        3,          R\        /# rA   r   )r   s   "r   r   r     s"      4S> c r   c                    V P                  RR4      pV'       g   R# \        V4      P                  4       P                  R4      p\        V4      ^<8  d   VR,          R,           # V# )z8Extract a truncated description from parsed frontmatter.r   r   z'":N9   Nz...)rE   r   r6   len)r8   raw_descr   s   &  r   extract_skill_descriptionr     sT    }b1Hx= &&u-D
4y2~Cy5  Kr   c                0    V ^8  d   QhR\         R\        /# )r   r   filename)r   r   )r   s   "r   r   r     s      t s r   c              #  *  a "   . p\         P                  ! S 4       FP  w  r4pV Uu. uF  qf\        9  g   K  VNK  	  upVR&   W9   g   K/  VP                  \	        V4      V,          4       KR  	  \        VV 3R lR7       F  pVx  K	  	  R# u upi 5i)zrWalk skills_dir yielding sorted paths matching *filename*.

Excludes ``.git``, ``.github``, ``.hub`` directories.
:NNNc                 8   < \        V P                  S4      4      # rj   )r   relative_to)r~   r   s   &r   <lambda>(iter_skill_index_files.<locals>.<lambda>  s    c!--
2K.Lr   )r>   N)r_   walkEXCLUDED_SKILL_DIRSrw   r   sorted)r   r   matchesrootr   filesdrr   s   f&      r   r   r     s     
 GWWZ0E"Cd/B&B11dCQNN4:01 1 w$LM
 N Ds   #BBB	BAB)z.gitz.githubz.hubrj   )&__doc__loggingr_   r/   rG   pathlibr   typingr   r   r   r   r   r   hermes_constantsr	   	getLogger__name__r]   rJ   	frozensetr   r$   r'   r?   rN   rf   ra   r   r   r   r   r   r   r   r   r   r    r   r   <module>r      s     	 	 
  8 8 ,			8	$
 XWw   ;<  "$"P:&=R>2j(8v$T & 	#Rr   