
    Ji%                        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	m
Z
mZmZmZ ddlmZ  ej        e          Zdddd	Z ed
          ZdadefdZdedee	eef         ef         fdZde	eef         defdZdee         fdZdee         fdZde
e         fdZde
e         fdZde	eef         de	ee
f         fdZ de	eef         defdZ!dedefdZ"dS )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darwinlinuxwin32)macosr   windows)z.gitz.githubz.hubcontentc                     t           ,ddlt          dd          pj        dt          ffd}|a t          |           S )z7Parse YAML with lazy import and CSafeLoader preference.Nr   CSafeLoadervaluec                 2                         |           S )N)Loader)load)r   loaderyamls    ./home/ubuntu/hermes-agent/agent/skill_utils.py_loadzyaml_load.<locals>._load*   s    99U69222    )_yaml_load_fnr   getattr
SafeLoaderstr)r   r   r   r   s     @@r   	yaml_loadr    "   sl     }d33Ft	3 	3 	3 	3 	3 	3 	3 	3 !!!r   returnc                 X   i }| }|                      d          s||fS t          j        d| dd                   }|s||fS | d|                                dz            }| |                                dz   d         }	 t          |          }t          |t                    r|}n# t          $ rt |	                                
                    d          D ]I}d|vr|
                    dd          \  }}|	                                ||	                                <   JY nw xY w||fS )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   N
:   )
startswithresearchstartendr    
isinstancedict	Exceptionstripsplit)	r   frontmatterbody	end_matchyaml_contentparsedlinekeyr   s	            r   parse_frontmatterr8   4   s[    #%KDe$$ !D  	-55I !D  1y001445L9==??Q&(()D
5<((fd## 	! K 5 5 5 &&((..t44 	5 	5D$C++JC',{{}}K		$$		5 	55 s    &B' 'A;D%$D%r1   c                 V   |                      d          }|sdS t          |t                    s|g}t          j        }|D ]h}t          |                                                                          }t                               ||          }|	                    |          r dS idS )a  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)
getr,   listsysplatformr   lowerr/   PLATFORM_MAPr'   )r1   r:   currentr>   
normalizedmappeds         r   skill_matches_platformrD   \   s     ,,I ti&&  K	lG  ]]((**0022
!!*j99f%% 	44	5r   c                     t                      dz  } |                                 st                      S 	 t          |                     d                    }nA# t
          $ r4}t                              d| |           t                      cY d}~S d}~ww xY wt          |t                    st                      S |
                    d          }t          |t                    st                      S t          j        d          }|r;|
                    d          pi 
                    |          }|t          |          S t          |
                    d	                    S )
zRead disabled skill names from config.yaml.

    Resolves platform from ``HERMES_PLATFORM`` env var, falls back to
    the global disabled list.  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platform_disableddisabled)r
   existssetr    	read_textr.   loggerdebugr,   r-   r;   osgetenv_normalize_string_set)config_pathr5   e
skills_cfgresolved_platformrL   s         r   get_disabled_skill_namesrZ   y   s]    "##m3K uu;00'0BBCC   9;JJJuu fd## uuH%%Jj$'' uu	"344 <'^^,?@@FBKK
 
 (():;;; 
!;!;<<<s   #A 
B#)BBBc                 j    | t                      S t          | t                    r| g} d | D             S )Nc                     h | ]D}t          |                                          #t          |                                          ES  )r   r/   ).0vs     r   	<setcomp>z(_normalize_string_set.<locals>.<setcomp>   s9    ===qc!ffllnn=CFFLLNN===r   )rO   r,   r   )valuess    r   rU   rU      s=    ~uu&# ==F====r   c                     t                      dz  } |                                 sg S 	 t          |                     d                    }n# t          $ r g cY S w xY wt          |t                    sg S |                    d          }t          |t                    sg S |                    d          }|sg S t          |t                    r|g}t          |t                    sg S t                      dz  
                                }t                      }g }|D ]}t          |                                          }|s&t          j                            t          j                            |                    }t#          |          
                                }	|	|k    r|	|v r|	                                r+|                    |	           |                    |	           t*                              d|	           |S )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.
    rF   rG   rH   rJ   external_dirsz0External skills dir does not exist, skipping: %s)r
   rN   r    rP   r.   r,   r-   r;   r   r<   resolverO   r/   rS   path
expanduser
expandvarsr   is_diraddappendrQ   rR   )
rV   r5   rX   raw_dirslocal_skillsseenresultentryexpandedps
             r   get_external_skills_dirsrr      s    "##m3K 	;00'0BBCC   			fd## 	H%%Jj$'' 	~~o..H 	(C   :h%% 	#%%099;;LeeDF P PE

  "" 	7%%bg&8&8&?&?@@NN""$$9988:: 	PHHQKKKMM!LLKQOOOOMs   #A AAc                  l    t                      dz  g} |                     t                                 | S )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.
    rJ   )r
   extendrr   )dirss    r   get_all_skills_dirsrv      s5     ()DKK(**+++Kr   c                 d   |                      d          }t          |t                    si }|                     d          pi }t          |t                    si }|                     dg           |                     dg           |                     dg           |                     dg           dS )z>Extract conditional activation fields from parsed frontmatter.metadatahermesfallback_for_toolsetsrequires_toolsetsfallback_for_toolsrequires_tools)rz   r{   r|   r}   )r;   r,   r-   )r1   rx   ry   s      r   extract_skill_conditionsr~      s    z**Hh%% \\(##)rFfd## !',CR!H!H#ZZ(;R@@$jj)=rBB **%5r::	  r   c                     |                      dd          }|sdS t          |                                                              d          }t          |          dk    r|dd         dz   S |S )z8Extract a truncated description from parsed frontmatter.description z'"<   N9   z...)r;   r   r/   len)r1   raw_descdescs      r   extract_skill_descriptionr      sn    }b11H rx==  &&u--D
4yy2~~CRCy5  Kr   
skills_dirfilenamec              #       K   g }t          j                   D ]@\  }}}d |D             |dd<   ||v r%|                    t          |          |z             At	          | fd          D ]}|V  dS )zzWalk skills_dir yielding sorted paths matching *filename*.

    Excludes ``.git``, ``.github``, ``.hub`` directories.
    c                 $    g | ]}|t           v|S r]   )EXCLUDED_SKILL_DIRS)r^   ds     r   
<listcomp>z*iter_skill_index_files.<locals>.<listcomp>  s#    CCCa/B&B&B1&B&B&Br   Nc                 H    t          |                                         S )N)r   relative_to)rq   r   s    r   <lambda>z(iter_skill_index_files.<locals>.<lambda>  s    c!--
2K2K.L.L r   )r7   )rS   walkrj   r   sorted)r   r   matchesrootru   filesre   s   `      r   iter_skill_index_filesr   	  s      
 GWZ00 2 2dECCdCCCQQQuNN4::0111w$L$L$L$LMMM  



 r   )#__doc__loggingrS   r(   r=   pathlibr   typingr   r   r   r   r   r	   hermes_constantsr
   	getLogger__name__rQ   r@   	frozensetr   r   r   r    r8   boolrD   rZ   rU   rr   rv   r~   r   r   r]   r   r   <module>r      sL     				 				 



       8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 , , , , , ,		8	$	$
    i ;<<  "s " " " "$"s "uT#s(^S-@'A " " " "PS#X 4    :=#c( = = = =@>SX > > > >2$t* 2 2 2 2jT$Z    $sCx. T#t)_    (4S> c    t s      r   