
    `gjI                    R	   U d Z ddlZddlZddlZddlmZmZ ddlZddlZddl	m
Z
 ddlmZmZmZ ddlmZmZmZmZmZmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZm Z!  ejD                  e#      Z$i Z%e&e'd<   dZ(dZ)dZ*de+fdZ, e       Z-e-dz  Z.e.Z/defdZ0dZ1dZ2ddddZ3 ejh                  d      Z5 e6h d      Z7da8de9dee9   fdZ:dee9e9f   fdZ; G d de9e
      Z<g d Z=e>e'd!<   dd"Z?d#ee9ef   de@fd$ZAd#ee9ef   de@fd%ZBd&edee9   fd'ZCd#ee9ef   deee9   ee9   f   fd(ZDd#ee9ef   dee9ef   fd)ZE	 dd#ee9ef   d*ee9   dz  deee9ef      fd+ZFd,e9d-eee9ef      dee9ef   fd.ZGde@fd/ZHde9fd0ZI	 dd1e9d2ee9e9f   dz  de@fd3ZJdd4d5eee9ef      d6ee9ef   d2ee9e9f   dz  dee9   fd7ZKde9fd8ZL	 dd9e<d:ee9   d;e9dz  de9dz  fd<ZMde@fd=ZNd>e9deee9ef   e9f   fd?ZOd@edee9   fdAZPdee9   fdBZQdee9   fdCZRde9fdDZSdde9dEe9de@fdFZTdGdHdIe@deee9ef      fdJZUdeee9ef      deee9ef      fdKZVddLe9dMe9de9fdNZWdOddPdQedRe9dSe9dTe@dUe9dz  de9fdVZX	 	 	 dde9dWe9dMe9dTe@de9f
dXZYe#dYk(  r	  eZdZ        eZd[        eZd\        ej                   eW             Z\e\d]   r eZd^e\d_    d` e]e\j                  dag              db        eZdce\j                  dag                eZdd       e\d   dde D ]8  Z_e_j                  dL      r	dfe_dL    dgndhZ` eZdie` e_d    dje_dk   ddl  dm       : n eZdne\do            eZdp        ej                   eYdq            Z\e\d]   rb eZdre\d            eZdse\j                  dkdt      ddu  dm        eZdv e]e\d>          dw       e\j                  dx      r eZdye\dx           n eZdne\do            eZdz        ej                   eYdqd{            Z\e\d]   r6 eZd|e\d}            eZdv e]e\d>          dw        eZd~e\d>   dd  dm       n eZdne\do           ddddLdddig ddZadddddddddddgddZb ej                  ddead eNd       d Zd ej                  ddebedeNd       y)u  
Skills Tool Module

This module provides tools for listing and viewing skill documents.
Skills are organized as directories containing a SKILL.md file (the main instructions)
and optional supporting files like references, templates, and examples.

Inspired by Anthropic's Claude Skills system with progressive disclosure architecture:
- Metadata (name ≤64 chars, description ≤1024 chars) - shown in skills_list
- Full Instructions - loaded via skill_view when needed
- Linked Files (references, templates) - loaded on demand

Directory Structure:
    skills/
    ├── my-skill/
    │   ├── SKILL.md           # Main instructions (required)
    │   ├── references/        # Supporting documentation
    │   │   ├── api.md
    │   │   └── examples.md
    │   ├── templates/         # Templates for output
    │   │   └── template.md
    │   └── assets/            # Supplementary files (agentskills.io standard)
    └── category/              # Category folder for organization
        └── another-skill/
            └── SKILL.md

SKILL.md Format (YAML Frontmatter, agentskills.io compatible):
    ---
    name: skill-name              # Required, max 64 chars
    description: Brief description # Required, max 1024 chars
    version: 1.0.0                # Optional
    license: MIT                  # Optional (agentskills.io)
    platforms: [macos]            # Optional — restrict to specific OS platforms
                                  #   Valid: macos, linux, windows
                                  #   Omit to load on all platforms (default)
    prerequisites:                # Optional — legacy runtime requirements
      env_vars: [API_KEY]         #   Legacy env var names are normalized into
                                  #   required_environment_variables on load.
      commands: [curl, jq]        #   Command checks remain advisory only.
    compatibility: Requires X     # Optional (agentskills.io)
    metadata:                     # Optional, arbitrary key-value (agentskills.io)
      hermes:
        tags: [fine-tuning, llm]
        related_skills: [peft, lora]
    ---

    # Skill Title

    Full instructions and content here...

Available tools:
- skills_list: List skills with metadata (progressive disclosure tier 1)
- skill_view: Load full skill content (progressive disclosure tier 2-3)

Usage:
    from tools.skills_tool import skills_list, skill_view, check_skills_requirements

    # List all skills (returns metadata only - token efficient)
    result = skills_list()

    # View a skill's main content (loads full instructions)
    content = skill_view("axolotl")

    # View a reference file within a skill (loads linked file)
    content = skill_view("axolotl", "references/dataset-formats.md")
    N)get_hermes_homedisplay_hermes_home)Enum)PathPurePosixPathPureWindowsPath)DictAnyListOptionalSetTuple)registry
tool_error)cfg_get)env_var_enabled)EXCLUDED_SKILL_DIRSis_skill_support_path_SKILLS_CACHEg      >@with_disabledfilteredreturnc                    ddl m} t        t        |dd      dd      }g }| D ]  }	 |j                         j                  }	 t        j                  |      5 }|D ]8  }	 |j                  d      r#|j                  d      j                  }	|	|kD  r|	}: 	 ddd       |j                  t        |      |f        t        |      t        |      |fS # t
        $ r Y w xY w# t
        $ r Y w xY w# 1 sw Y   \xY w# t
        $ r Y jw xY w)	uN  Cheap change-signature for the skill scan inputs.

    O(#dirs + #categories) stat calls, not a recursive walk. Includes the
    platform the scan's ``skill_matches_platform`` filter will use (read
    from ``agent.skill_utils``'s ``sys`` so test patches of that module
    are honored) — the scan result is platform-dependent.
    r   )skill_utilssysNplatform F)follow_symlinks)agentr   getattrstatst_mtimeOSErrorosscandiris_dirappendstrtuple	frozenset)
dirs_to_scandisabled_skill_utilsr   sigdmitentryems
             D/root/.hermes/venv/lib/python3.12/site-packages/tools/skills_tool.py_skills_scan_signaturer5   j   s    2w|UD9:rJH
C  	!!A	A !" !E! <<<>!&E!B!K!KB!Av$&!! 	

CFA;# $ #J	(+X66  		 # ! !! !  		s_   CC=C15C"C1C=	CC"	C.	+C1-C.	.C11C:	6C==	D	D	skillsc                  P    t        t              } | t        k7  r| S t               dz  S )aZ  Return the active profile's skills directory at call time.

    Some long-lived runtimes import this module before the active profile has
    set HERMES_HOME. Keep the legacy SKILLS_DIR module attribute for tests and
    external patchers, but when it has not been patched, resolve from the live
    profile-scoped HERMES_HOME on every call.
    r6   )r   
SKILLS_DIR_SKILLS_DIR_AT_IMPORTr   )
configureds    r4   _skills_dirr;      s+     j!J**x''    @   i   darwinlinuxwin32)macosr?   windowsz^[A-Za-z_][A-Za-z0-9_]*$>   sshmodaldockerdaytonasingularitynamec                     ddl m} t        | t              sy| j	                         }t        |      j                         s.t        |      j                         st        |      j                  ry ||      ryy)uD  Return an error if a local skill lookup *name* can escape search roots.

    The skill ``name`` is joined onto each trusted search dir to build the
    on-disk lookup path, so it must stay relative and free of ``..`` segments —
    otherwise ``name="../outside"`` or an absolute path could select a skill
    (and read files) outside the skills directory. Mirrors the ``file_path``
    validation done later via ``tools.path_security``. We also reject Windows
    drive paths (e.g. ``C:\skills``), whose ``:`` would otherwise be misread as
    a plugin namespace separator.
    r   )has_traversal_componentzSkill name must be a string.z?Skill name must be a relative path within the skills directory.z9Skill name cannot contain '..' path traversal components.N)	tools.path_securityrJ   
isinstancer(   stripr   is_absoluter   drive)rH   rJ   	candidates      r4   _skill_lookup_path_errorrQ      s`     <dC -

Ii ,,.9%1139%++Py)Jr<   c                     t               dz  } i }| j                         s|S | j                  d      5 }|D ]  }|j                         }|s|j	                  d      r(d|v s-|j	                  d      r|dd }|j                  d      \  }}}|j                         j                  d	      ||j                         <    	 ddd       |S # 1 sw Y   |S xY w)
z@Load profile-scoped environment variables from HERMES_HOME/.env.z.envutf-8encoding#=zexport    N"')r   existsopenrM   
startswith	partition)env_pathenv_varsflinekey_values          r4   load_envre      s     6)H!H??		( CA 	CD::<DDOOC0SD[??9-8D $s 3Q(-(;(;E(B%	CC OC Os   CCC$ACCc                       e Zd ZdZdZdZy)SkillReadinessStatus	availablesetup_neededunsupportedN)__name__
__module____qualname__	AVAILABLESETUP_NEEDEDUNSUPPORTED r<   r4   rg   rg      s    I!LKr<   rg   )	zignore previous instructionszignore all previouszyou are nowzdisregard yourzforget your instructionsznew instructions:zsystem prompt:z<system>z]]>_INJECTION_PATTERNSc                     | a y N)_secret_capture_callback)callbacks    r4   set_secret_capture_callbackrw      s    'r<   frontmatterc                     ddl m}  ||       S )u   Check if a skill is compatible with the current OS platform.

    Delegates to ``agent.skill_utils.skill_matches_platform`` — kept here
    as a public re-export so existing callers don't need updating.
    r   )skill_matches_platform)agent.skill_utilsrz   rx   _impls     r4   rz   rz      s     Br<   c                     ddl m}  ||       S )uX  Check if a skill is relevant to the current runtime environment.

    Delegates to ``agent.skill_utils.skill_matches_environment`` — kept here
    as a public re-export so existing callers don't need updating. This is an
    offer-time relevance gate (kanban/docker/s6), NOT a hard-compatibility gate;
    explicit skill loads bypass it.
    r   )skill_matches_environment)r{   r   r|   s     r4   r   r     s     Er<   rd   c                     | sg S t        | t              r| g} | D cg c]'  }t        |      j                         st        |      ) c}S c c}w rt   )rL   r(   rM   )rd   items     r4   _normalize_prerequisite_valuesr     s@    	%"'=$3t9??+<CI===s
   AAc                     | j                  d      }|rt        |t              sg g fS t        |j                  d            t        |j                  d            fS )Nprerequisitesr_   commands)getrL   dictr   )rx   prereqss     r4   _collect_prerequisite_valuesr     sS     ooo.G*Wd32v&w{{:'>?&w{{:'>? r<   c           	      8   | j                  d      }t        |t              sd g dS |j                  d      }t        |t              r)|j	                         rt        |      j	                         nd }|j                  d      }t        |t              r|g}t        |t
              sg }g }|D ]  }t        |t              st        |j                  d      xs d      j	                         }|sCt        |j                  d      xs d|       j	                         }t        |j                  d	      xs |j                  d
      xs d      j	                         }	||t        |j                  dd            d}
|	r|	|
d	<   |j                  |
        ||dS )Nsetup)helpcollect_secretsr   r   env_varr   promptEnter value for provider_urlurlsecretT)r   r   r   )r   rL   r   r(   rM   listboolr'   )rx   r   	help_textnormalized_helpcollect_secrets_rawr   r   r   r   r   r2   s              r4   _normalize_setup_metadatar   #  s   OOG$EeT"44		&!I i%)//*; 	I   ))$56%t,23)40 ,.O# &$%dhhy)/R0668TXXh'G-=gY+GHNNP488N3LtxxL"MSSU 488Hd34!

 $0E.!u%%&*  * r<   legacy_env_varsc                 D  	 t        |       	| j                  d      }t        |t              r|g}t        |t              sg }g t               dt        t        t        f   dd f	fd}|D ]6  }t        |t              r |d|i       t        |t              s/ ||       8 	d   D ]N  } ||j                  d      |j                  d      |j                  d	      xs 	j                  d
      d       P |t        |       \  }}|D ]  } |d|i        S )Nrequired_environment_variablesr2   r   c                    t        | j                  d      xs | j                  d      xs d      j                         }|r|v ry t        j	                  |      sy |t        | j                  d      xs d|       j                         d}| j                  d      xs7 | j                  d      xs$ | j                  d	      xs j                  d      }t        |t               r#|j                         r|j                         |d<   | j                  d
      }t        |t               r#|j                         r|j                         |d
<   | j                  d      rd|d<   j                  |       j                  |       y )NrH   r   r   r   r   )rH   r   r   r   r   required_foroptionalT)r(   r   rM   _ENV_VAR_NAME_REmatchrL   addr'   )r2   env_name
normalizedr   r   requiredseenr   s        r4   _append_requiredz=_get_required_environment_variables.<locals>._append_required^  sU   uyy(FEIIi,@FBGMMO8t+%%h/ %))H-N3CH:1NOUUW&

 IIf !yy(!yy! yy 	 	 i%)//*;!*!2Jvyy0lC(\-?-?-A)5););)=J~&99Z %)Jz"
#r<   rH   r   r   r   r   r   )rH   r   r   )
r   r   rL   r   r   setr	   r(   r
   r   )
rx   r   required_rawr   r   rc   r   r   r   r   s
          @@@r4   #_get_required_environment_variablesr   P  s1    &k2E??#CDL,%$~lD)%'HUD$S#X $4 $>  #dC fd^,dD!T"# '( 
+((8,0EEIIf4E	

 9+F" ,&'*+, Or<   
skill_namemissing_entriesc                    |sg dd dS |D cg c]  }|d   	 }}t               rt        d      s|dt               dS t        |dd dS d}g }|D ]  }d| i}|j	                  d      r|d   |d<   |j	                  d      r|d   |d<   	 t        |d   |d   |      }t        |t              xr t        |j	                  d            }t        |t              xr t        |j	                  d            }	|r|	sd
}|j                  |d           ||d dS c c}w # t
        $ r* t        j                  d	|d    d
       d|d   dd
d}Y w xY w)NF)missing_namessetup_skippedgateway_setup_hintrH   HERMES_INTERACTIVEr   r   r   r   z#Secret capture callback failed for Texc_info)success	stored_as	validatedskippedr   r   )_is_gateway_surfacer   _gateway_setup_hintru   r   	ExceptionloggerwarningrL   r   r   r'   )
r   r   r2   r   r   remaining_namesmetadatacallback_resultr   r   s
             r4   '_capture_required_environment_variablesr     s    ""&
 	
 1@@uU6]@M@ _5I%J*""5"7
 	
  '*""&
 	
 M!#O  ". *-99V$V}HV99^$',^'<H^$	6fhO  _d3 
	*9
 _d3 
	*9
 7uV}-E".J )&" y AJ  		NN5eFm_EPT   !"6]"	O			s   D
D0EEc                  H    t        d      ryddlm}  t         | d            S )NHERMES_GATEWAY_SESSIONTr   get_session_envHERMES_SESSION_PLATFORM)r   gateway.session_contextr   r   r   s    r4   r   r     s"    /07 9:;;r<   c                      t        t        j                  dd            j                         j	                         xs dS )NTERMINAL_ENVlocal)r(   r$   getenvrM   lowerrq   r<   r4   _get_terminal_backend_namer     s/    ryy1288:@@BMgMr<   var_nameenv_snapshotc                     |
t               }| |v rt        |j                  |             S t        t        j                  |             S rt   )re   r   r   r$   r   )r   r   s     r4   _is_env_var_persistedr     sC     z<L$$X.//		(#$$r<   r   required_env_varscapture_resultc                    t        |d         }|
t               }g }| D ];  }|d   }|j                  d      r||v st        ||      r+|j	                  |       = |S )Nr   rH   r   )r   re   r   r   r'   )r   r   r   r   	remainingr2   rH   s          r4   %_remaining_required_environment_namesr     st     78MzI" #V}99Z = (=dL(QT"# r<   c                  N    	 ddl m}  | S # t        $ r dt                dcY S w xY w)Nr   *GATEWAY_SECRET_CAPTURE_UNSUPPORTED_MESSAGEziSecure secret entry is not available. Load this skill in the local CLI to be prompted, or add the key to z/.env manually.)gateway.platforms.baser   r   r   r   s    r4   r   r     sM    bU99 bz  |O  |Q  {R  Ra  b  	bbs   
 $$readiness_statusmissing
setup_helpc                 v    | t         j                  k(  r&|rdj                  |      nd}d| d}|r| d| S |S y )N, zrequired prerequisitesz.Setup needed before using this skill: missing . )rg   ro   join)r   r   r   missing_strnotes        r4   _build_setup_noter     sP    
 /<<<,3dii(9Q?}ANV1ZL))r<   c                       y)zOSkills are always available -- the directory is created on first use if needed.Trq   rq   r<   r4   check_skills_requirementsr   #  s    r<   contentc                     ddl m}  ||       S )u   Parse YAML frontmatter from markdown content.

    Delegates to ``agent.skill_utils.parse_frontmatter`` — kept here
    as a public re-export so existing callers don't need updating.
    r   )parse_frontmatter)r{   r   )r   r   s     r4   _parse_frontmatterr   (  s     4W%%r<   
skill_pathc                    t               g}	 ddlm} |j                   |              |D ]5  }	 | j                  |      }|j                  }t        |      dk\  r|d   c S 7 y# t        $ r Y Fw xY w# t        $ r Y Sw xY w)z
    Extract category from skill path based on directory structure.

    For paths like: ~/.hermes/skills/mlops/axolotl/SKILL.md -> "mlops"
    Also works for external skill dirs configured via skills.external_dirs.
    r   get_external_skills_dirs   N)	r;   r{   r   extendr   relative_topartslen
ValueError)r   dirs_to_checkr   
skills_dirrel_pathr   s         r4   _get_category_from_pathr   2  s     !]OM>578 $ 
	!--j9HNNE5zQQx 	     		s"   A$ /A3$	A0/A03	A?>A?c                    | sg S t        | t              r*| D cg c]  }|st        |      j                           c}S t        |       j                         } | j	                  d      r| j                  d      r| dd } | j                  d      D cg c]2  }|j                         s|j                         j                  d      4 c}S c c}w c c}w )uB  
    Parse tags from frontmatter value.

    Handles:
    - Already-parsed list (from yaml.safe_load): [tag1, tag2]
    - String with brackets: "[tag1, tag2]"
    - Comma-separated string: "tag1, tag2"

    Args:
        tags_value: Raw tags value — may be a list or string

    Returns:
        List of tag strings
    []   ,rY   )rL   r   r(   rM   r\   endswithsplit)
tags_valuets     r4   _parse_tagsr  L  s     	 *d#(281aA88 Z&&(JS!j&9&9#&>"%
,6,<,<S,AOqQWWYAGGIOOE"OO 9 Ps   CCC(!Cc                      ddl m}   |        S )u   Load disabled skill names from config.

    Delegates to ``agent.skill_utils.get_disabled_skill_names`` — kept here
    as a public re-export so existing callers don't need updating.
    r   get_disabled_skill_names)r{   r  r  s    r4   _get_disabled_skill_namesr  k  s     ;#%%r<   c                  F    	 ddl m}   | d      xs dS # t        $ r Y yw xY w)zResolve the current platform from gateway session context.

    Mirrors the platform-resolution logic in
    ``agent.skill_utils.get_disabled_skill_names`` so that
    ``_is_skill_disabled`` respects ``HERMES_SESSION_PLATFORM``.
    r   r   r   r   )r   r   r   r   s    r4   _get_session_platformr
  u  s-    ;89?R? s    	  r   c                    	 ddl m}  |       }|j                  di       }|xs! t        j                  d      xs
 t               }|j                  dg       }|rt        |d|      }|
| |v xs | |v S | |v S # t        $ r Y yw xY w)a  Check if a skill is disabled in config.

    Resolves the active platform from (in order of precedence):
    1. Explicit ``platform`` argument
    2. ``HERMES_PLATFORM`` environment variable
    3. ``HERMES_SESSION_PLATFORM`` from gateway session context
    r   )load_configr6   HERMES_PLATFORMr,   platform_disabledF)hermes_cli.configr  r   r$   r   r
  r   r   )rH   r   r  config
skills_cfgresolved_platformglobal_disabledr  s           r4   _is_skill_disabledr    s    1ZZ"-
$_		2C(D_H]H_$..R8 '
4GIZ [ , 00KDO4KK&& s   A0A7 3A7 7	BBF)skip_disabledr  c           	         ddl m}m} | rt        nt        }| r
t               n	t               }g }t               }|j                         r|j                  |       |j                   |              t        ||      }t        j                         }t        j                  |      }	|	3|	d   |k(  r+||	d   z
  t         k  r|	d   D 
cg c]  }
t#        |
       c}
S g }t               }|D ]W  } ||d      D ]G  }t%        d |j&                  D              r!|j(                  }	 |j+                  d	      dd
 }t-        |      \  }}t/        |      s]t1        |      si|j                  d|j2                        dt4         }||v r||v r|j                  dd      }|sL|j7                         j9                  d      D ]*  }|j7                         }|s|j;                  d      r(|} n t=        |      t>        kD  r|dt>        dz
   dz   }tA        |      }|jC                  |       |j                  |||d       J Z |||ft        |<   |D 
cg c]  }
t#        |
       c}
S c c}
w # tD        tF        f$ r"}tH        jK                  d||       Y d}~d}~wtL        $ r$}tH        jK                  d||d       Y d}~d}~ww xY wc c}
w )a=  Recursively find all skills in ~/.hermes/skills/ and external dirs.

    Args:
        skip_disabled: If True, return ALL skills regardless of disabled
            state (used by ``hermes skills`` config UI). Default False
            filters out disabled skills.

    Returns:
        List of skill metadata dicts (name, description, category).

    Results are cached per-session; the cache is invalidated when the scan
    signature changes (dir/category mtimes or the disabled-set) and expires
    after a short TTL to bound staleness from in-place SKILL.md edits.
    r   )r   iter_skill_index_filesNr      SKILL.mdc              3   ,   K   | ]  }|t         v   y wrt   )_EXCLUDED_SKILL_DIRS).0parts     r4   	<genexpr>z#_find_all_skills.<locals>.<genexpr>  s     KD4//Ks   rS   rT   i  rH   descriptionr   
rV   r   ...)rH   r  categoryz Failed to read skill file %s: %sz)Skipping skill at %s: failed to parse: %sTr   )'r{   r   r  _SKILLS_CACHE_KEY_DISABLED_SKILLS_CACHE_KEY_FILTEREDr   r  r;   rZ   r'   r   r5   time	monotonicr   r   _SKILLS_CACHE_TTL_SECONDSr   anyr   parent	read_textr   rz   r   rH   MAX_NAME_LENGTHrM   r  r\   r   MAX_DESCRIPTION_LENGTHr   r   UnicodeDecodeErrorPermissionErrorr   debugr   )r  r   r  	cache_keyr,   r+   active_skills_dir	signaturenowcachedsr6   
seen_namesscan_dirskill_md	skill_dirr   rx   bodyrH   r  ra   r"  es                           r4   _find_all_skillsr<    s    S.;*A[I &su+D+FH
 L#!-.023&|X>I
..
Cy)F1I"6!9_ 99
 "(+AQ++FeJ ! 2.xD 1	HKHNNKK I+",,g,>uE$6w$?!T-k:0="vy~~>?OP:%8#)oomR@" $

 2 24 8 "#zz|(<*.K!	" {#&<<"-.I/E/I"JU"RK28<t$ #. ( I1	2p !*37M)#$DG$$A ,d '8 ?1M ?1W[   	 %sV   I(#.I-I-'I-I-AI-I-&AI-K-K	<JK	%KK	c                     t        | d       S )z3Keep every skill listing path ordered the same way.c                 6    | j                  d      xs d| d   fS )Nr"  r   rH   r   )r5  s    r4   <lambda>z_sort_skills.<locals>.<lambda>  s    z):)@b!F)(L r<   )rb   )sorted)r6   s    r4   _sort_skillsrB    s    &LMMr<   r"  task_idc                    	 t               }|j                         s;|j                  dd       t        j                  dg g dt                ddd      S t               }|st        j                  dg g ddd      S | r$|D cg c]  }|j                  d	      | k(  s| }}t        |      }t        |D ch c]%  }|j                  d	      s|j                  d	      ' c}      }t        j                  d||t        |      d
dd      S c c}w c c}w # t        $ r }t        t        |      d      cY d}~S d}~ww xY w)a  
    List all available skills (progressive disclosure tier 1 - minimal metadata).

    Returns only name + description to minimize token usage. Use skill_view() to
    load full content, tags, related files, etc.

    Args:
        category: Optional category filter (e.g., "mlops")
        task_id: Optional task identifier used to probe the active backend

    Returns:
        JSON string with minimal skill info: name, description, category
    T)parentsexist_okz-No skills found. Skills directory created at z/skills/)r   r6   
categoriesmessageFensure_asciiz%No skills found in skills/ directory.r"  z@Use skill_view(name) to see full content, tags, and linked files)r   r6   rG  counthintr   N)r;   rZ   mkdirjsondumpsr   r<  r   rB  rA  r   r   r   r(   )r"  rC  r1  
all_skillsr5  rG  r;  s          r4   skills_listrR    sY   41'M '')##D4#@::# "$!NObOdNeemn	 #  &'
::# "$F	 #  %/Q1553D3P!QJQ "*-
 (2H1aeeJ6GQUU:H

 zz$(ZZ 	
 		
 R I  1#a&%001sT   AD 'D ?D DD#D 9DD#,D 
D 	E#D>8E>ET
preprocess
session_idr8  	namespacebarerT  rU  c          
         ddl m}m} | |       v r t        j                  dd| d| dd      S 	 | j                  d	      i }	 t              \  }}	t        |      s:t        j                  dd| d| dt        j                  j                  dd      S t        fdt        D              rt        j                  d||       t!        |j#                  dd            }
t%        |
      t&        kD  r|
dt&        dz
   dz   }
	  |       j)                  |      D cg c]	  }||k7  r| }}|r$dj+                  |      }d| d| d| d|d    d	}nd| d}}|r	 ddlm}  || j0                  |      }t        j                  d | d| |r| | n||
dt        j4                  j                  d"d      S # t        $ r-}t        j                  dd
| d| d| dd      cY d}~S d}~ww xY w# t        $ r Y w xY wc c}w # t        $ r d}Y w xY w# t        $ r t        j3                  d||d !       Y w xY w)#z8Read a plugin-provided skill, apply guards, return JSON.r   )_get_disabled_pluginsget_plugin_managerFzPlugin 'z5' is disabled. Re-enable with: hermes plugins enable r   errorrI  rS   rT   Failed to read skill ':': NSkill '$' is not supported on this platform.r   r\  r   c              3   B   K   | ]  }|j                         v   y wrt   )r   )r  pr   s     r4   r  z&_serve_plugin_skill.<locals>.<genexpr>  s     
=A1
=s   zIPlugin skill '%s:%s' contains patterns that may indicate prompt injectionr  r   r   r!  r   z,[Bundle context: This skill is part of the 'z' plugin.
Sibling skills: z..
Use qualified form to invoke siblings (e.g. z).]

z' plugin.]

preprocess_skill_contentrU  z'Could not preprocess plugin skill %s:%sTr   )r   rH   r   r  linked_filesr   )hermes_cli.pluginsrY  rZ  rO  rP  r*  r   r   rz   rg   rp   rd   r(  rr   r   r   r(   r   r   r,  list_plugin_skillsr   agent.skill_preprocessingrf  r)  r/  rn   )r8  rV  rW  rT  rU  rY  rZ  r;  parsed_frontmatterrc   r  r5  siblingssib_listbannerrendered_contentrf  r   s                    @r4   _serve_plugin_skillrq  Y  s    M)++zz yk *==FKI 	
 		

$$g$6 *, 27 ;A ""45zz "9+Qtf4XY$8$D$D$J$J
 
 	
 
=)<
==Wt	

 (,,]B?@K
;00!">$:Q$>?%G)+>>yI
Dy 
 
 yy*H>yk J##+* -??Hk8TU;-W^`  DI;n]F 	J7%  :: k4&)8>&"2!34DT&  4 > > D D	
 
 
E  
zz*@1TFRUVWUX(YZ
 	

  4
    	LL99dUY  	se   F? 	G8 H  H..H !H ?	G5"G0*G50G58	HHH HH"II	file_pathc                    Z[\ 	 t        |       }|rt        j                  d|ddd      S d}d| v rddlm}m} dd	lm}m}	  ||       \  }
} ||
      s!t        j                  dd
|
 d|  ddd      S  |         |	       }|j                  |       }|R|j                         s2|j                  |        t        j                  dd|  d| ddd      S t        ||
|||      S |j                  |
      }|rFt        j                  dd| d|
 d|D cg c]	  }|
 d|  c}d|
 dt        |       ddd      S |r|
 d| }ddlm} |r(t        |      }|rt        j                  d|ddd      S g }t!               }|j                         r|j#                  |       |j%                   |              |st        j                  dddd      S d}d}ddlm} g [t)               \dt*        t,           dt,        ddf[\fd}|D ]  }|| z  }t/        |      s0|j1                         r |d z  j                         r |||d z         nQ|j3                  d!      j                         r2t/        |j3                  d!            s |d|j3                  d!             |r||z  }t/        |      s0|j1                         r |d z  j                         r |||d z         nQ|j3                  d!      j                         r2t/        |j3                  d!            s |d|j3                  d!              ||d       D ]x  }|j4                  j6                  | k(  r ||j4                  |       0	 |j9                  d"#      }t;        |      \  }}|j?                  d$      | k(  sf ||j4                  |       z |jA                  |  d!      D ]'  }|j6                  d k7  st/        |      r |d|       )  t        [      d%kD  r[D cg c]  \  }}tC        |       } }}tE        jF                  tH              jK                  d&| t        [      d'jM                  |              t        j                  dd(|  d)t        [       d*| d+d,d      S [r[d   \  }}|r|j                         sFtO        tQ                     dd- D cg c]  }|d$   	 }}t        j                  dd|  d.|d/dd      S 	 |j9                  d"#      }!d1}#|jS                         g}$	 |$j%                  d2 |d%d D               |$D ]%  }%	 |jS                         jU                  |%       d}# n |!jY                         Zt[        Zfd3t\        D              }&|#s|&rdg }'|#r|'j#                  d4|        |&r|'j#                  d5       tE        jF                  tH              jK                  d6| d'jM                  |'             i }(	 t;        |!      \  }(}t_        |(      s7t        j                  dd|  d7t`        jb                  jd                  d8d      S |(j?                  d$|j4                  j6                        })tg        |)      rt        j                  dd|) d9dd      S |r|rdd:l4m5}*m6}+  |+|      rt        j                  dd;d<dd      S ||z  }, |*|,|      }-|-rt        j                  d|-d<dd      S |,j                         s]g g g g g d=}.|jA                  d>      D ]  }/|/jo                         s|/j6                  d k7  s$tC        |/jU                  |            }0|0jq                  d?      r|.d@   j#                  |0       d|0jq                  dA      r|.dB   j#                  |0       |0jq                  dC      r|.dD   j#                  |0       |0jq                  dE      r|.dF   j#                  |0       |/jr                  dGv s|.dH   j#                  |0        |.ju                         D 12ci c]  \  }1}2|2s	|1|2 }.}1}2t        j                  ddI| dJ|  d|.dKdLd      S 	 |,j9                  d"#      }!	 ddQl>m?}3  |3|,       t        j                  d1| ||!|,jr                  dTd      S |(}4g }5g }6g }7g }8|rt|d@z  }9|9j                         r6|9j                  dU      D /cg c]  }/tC        |/jU                  |             }5}/|dBz  }:|:j                         rMdVD ]H  };|6j%                  |:jA                  |;      D /cg c]  }/tC        |/jU                  |             c}/       J |dDz  }<|<j                         rP|<jA                  d>      D ]<  }/|/jo                         s|7j#                  tC        |/jU                  |                   > |dFz  }=|=j                         rMdWD ]H  };|8j%                  |=j                  |;      D /cg c]  }/tC        |/jU                  |             c}/       J i }>|4j?                  dX      }?t        |?t              r|?j?                  dYi       xs i }>t        |>j?                  dZ      xs |4j?                  dZd[            }@t        |>j?                  d\      xs |4j?                  d\d[            }Ai }B|5r|5Bd@<   |6r|6BdB<   |7r|7BdD<   |8r|8BdF<   	 tC        |jU                  |            }C|4j?                  d$|s|j                  n|j6                        }Dt        |4      \  }E}t        |4|E      }Ft               }Gt               }H|FD "cg c]$  }"|"j?                  d]      st        |"d$   H      s|"& }I}"t        D|I      }J|Ir
t               }Ht        FJH^      }Kt        |K      }L|FD "cg c]  }"|"d$   Kvr|"d$    }M}"|Mr	 dd_lOmP}N  |NM       |4j?                  dag       }Ot        |Ot              sg }Og }POr	 ddblRmS}Q  |QO      }P|Prd1}L|!}R|r	 dddlTmU}S  |S|!||e      }Ri dgd1d$Ddh|4j?                  dhd[      dZ@d\AdiRdjCdk|rtC        |      nddlBrBnddmBrdnnddoFdpg dqKdrPdsg dtLduJdu   dv|Lrt`        j                  jd                  nt`        j                  jd                  i}Tt        dw FD        d      }U|UrUTdx<   Jdy   rJdy   Tdy<   	 ddQl>m?}3  |3|       LriKD Vcg c]  }Vdz|V 	 c}VPD Wcg c]  }Wd{|W 	 c}Wz   }Xt        t`        j                  |XU      }YGt        v rYrY d|Gj                          d}}YYrYTd~<   |4j?                  d      r|4d   Td<   t        |?t              r|?TdX<   t        j                  Td      S c c}w # t<        $ r i }Y 
(w xY wc c}}w c c}w # t<        $ r*}"t        j                  dd0|  d)|" dd      cY d}"~"S d}"~"ww xY w# t<        $ r Y w xY w# tV        $ r Y w xY w# t<        $ r i }(Y 'w xY wc c}2}1w # tv        $ rI t        j                  d1| |dM|,j6                   dN|,jy                         jz                   dOd1dPd      cY S w xY w# t<        $ r t        j                  dR|,d1S       Y -w xY wc c}/w c c}/w c c}/w # tV        $ rT |j4                  j4                  r.tC        |jU                  |j4                  j4                              n|j6                  }CY &w xY wc c}"w c c}"w # t<        $ r t        j                  d`Dd1S       Y vw xY w# t<        $ r t        j                  dcDd1S       Y cw xY w# t<        $ r t        j                  dfDd1S       Y uw xY w# t<        $ r t        j                  dR|d1S       Y w xY wc c}Vw c c}Ww # t<        $ r }"t        tC        |"      d      cY d}"~"S d}"~"ww xY w)a  
    View the content of a skill or a specific file within a skill directory.

    Args:
        name: Name or path of the skill (e.g., "axolotl" or "03-fine-tuning/axolotl").
            Qualified names like "plugin:skill" resolve to plugin-provided skills.
        file_path: Optional path to a specific file within the skill (e.g., "references/api.md")
        task_id: Optional task identifier used to probe the active backend
        preprocess: Apply configured SKILL.md template and inline shell rendering
            to main skill content. Internal slash/preload callers disable this
            because they render the skill message themselves.

    Returns:
        JSON string with skill content or error message
    Fz>Use a skill name or relative path within the skills directory.)r   r\  rL  rI  Nr^  r   )is_valid_namespaceparse_qualified_name)discover_pluginsrZ  zInvalid namespace 'z' in 'z('. Namespaces must match [a-zA-Z0-9_-]+.r[  r`  z' file no longer exists at uT   . The registry entry has been cleaned up — try again after the plugin is reloaded.rS  z' not found in plugin 'z'.zThe 'z' plugin provides z
 skill(s).)r   r\  available_skillsrL  /r   zISkills directory does not exist yet. It will be created on first install.)r  sdsmdr   c                     	 |j                         }|v ry j                  |       j                  | |f       y # t        $ r |}Y 7w xY wrt   )resolver   r   r'   )ry  rz  rb   
candidatesseen_mds      r4   _recordzskill_view.<locals>._recordX  sS    kkm g~KKr3i(  s   = A
Ar  .mdrS   rT   rH   r   u3   Skill name collision for '%s': %d candidates — %sz; zAmbiguous skill name 'r_  u    skills match across your local skills dir and external_dirs. Refusing to guess — load one explicitly by its categorized path.zPass the full relative path instead of the bare name (e.g., 'category/skill-name'), or rename one of the colliding skills so each name is unique.)r   r\  matchesrL     z' not found.z+Use skills_list to see all available skillsr]  Tc              3   <   K   | ]  }|j                           y wrt   )r|  )r  r/   s     r4   r  zskill_view.<locals>.<genexpr>  s      C Cs   c              3   &   K   | ]  }|v  
 y wrt   rq   )r  rd  _content_lowers     r4   r  zskill_view.<locals>.<genexpr>  s     !S!!~"5!Ss   zHskill file is outside the trusted skills directory (~/.hermes/skills/): zBskill content contains patterns that may indicate prompt injectionz#Skill security warning for '%s': %sra  rb  zT' is disabled. Enable it with `hermes skills` or inspect the files directly on disk.)validate_within_dirrJ   z%Path traversal ('..') is not allowed.z.Use a relative path within the skill directory)
references	templatesassetsscriptsother*zreferences/r  z
templates/r  zassets/r  zscripts/r  >   .py.sh.tex.yml.json.yamlr  r  zFile 'z' not found in skill 'z0Use one of the available file paths listed above)r   r\  available_filesrL  z[Binary file: z, size: z bytes])r   rH   filer   	is_binary)!mark_background_review_skill_readz4Could not record background-review skill read for %sr   )r   rH   r  r   	file_type*.md)r  *.pyz*.yamlz*.ymlz*.jsonz*.tex*.sh)r  r  z*.bashz*.jsz*.tsz*.rbr   hermestagsr   related_skillsr   r   )register_env_passthroughz/Could not register env passthrough for skill %srequired_credential_files)register_credential_filesz0Could not register credential files for skill %sre  rg  z)Could not preprocess skill content for %sr   r  r   pathr9  rh  
usage_hintzzTo view linked files, call skill_view(name, file_path) where file_path is e.g. 'references/api.md' or 'assets/config.yaml'r   required_commands&missing_required_environment_variablesmissing_credential_filesmissing_required_commandsri   r   r   c              3   J   K   | ]  }|j                  d       s|d      yw)r   Nr?  )r  r;  s     r4   r  zskill_view.<locals>.<genexpr>5  s     Q155=1V9Qs   #
#r   r   zenv $zfile r   zW-backed skills need these requirements available inside the remote environment as well.
setup_notecompatibilityrM  )]rQ   rO  rP  r{   rt  ru  ri  rv  rZ  find_plugin_skillrZ   remove_plugin_skillrq  rj  r   r   r;   r'   r   r  r   r   r   _is_skill_support_pathr&   with_suffixr)  rH   r*  r   r   r   rglobr(   logging	getLoggerrk   r   r   rB  r<  r|  r   r   r   r(  rr   rz   rg   rp   rd   r  rK   r  rJ   is_filer\   suffixitemsr-  r!   st_sizetools.skill_manager_toolr  r   r/  globrL   r   r  stemr   r   r   re   r   r   r   r   tools.env_passthroughr  r   tools.credential_filesr  rk  rf  ro   rn   nextr   _REMOTE_ENV_BACKENDSupperr   )]rH   rr  rC  rT  lookup_errorlocal_category_namert  ru  rv  rZ  rV  rW  pmplugin_skill_mdrh   r5  r   all_dirsr1  r9  r8  r  r  
search_dirdirect_pathcategorized_pathfound_skill_md
fm_contentfmrc   found_mdrz  pathsr   r;  _outside_skills_dir_trusted_dirs_td_injection_detected	_warningsrl  resolved_namer  rJ   target_filetraversal_errorr  r`   relkvr  rx   reference_filestemplate_filesasset_filesscript_filesreferences_dirtemplates_dirext
assets_dirscripts_dirhermes_metar   r  r  rh  r   r   r   r   backendr   missing_required_env_varsr   remaining_missing_required_envsri   available_env_namesr  required_cred_files_rawmissing_cred_filesr  rp  rf  resultr   r   r  missing_itemsr  r  r}  r~  s]                                                                                             @@@r4   
skill_viewr    sB   *J
1
 05::$)\
 #  +/ $;RO248OIt%i0zz#(1)F4& ID E "'	 	 #%B 2248O*&--/**40::',")$/J#2"3 46!7 &+  +#)&  --i8Izz#(#*4&0G	{RT!UIR,SA	{!A3-?,S"'	{2DS^DTT^ _	 "'  )21TF&;#> 34GHLzz#(!- `
 "'  'M##%OO-.023::$h #  	 	=8:
u	) 	)T 	)d 	) # :	,J %t+K*;7&&( :-557[:%=>((/668AW''.B k55e<=
 ##-0C#C ./?@(//1)J6>>@,.>.KL%11&(#9$007$ D"2">">u"EF #9Z"P 
C!((--5N11>B!/!9!97!9!KJ.z:EB 66&>T)N11>B
C  ',,vS\: ,==J.7M8 D(+	,m:	,x z?Q,67&!SSX7E7h'//Ec*otyy'7 ::$0c#j/9J K] ]  %C # $ ",Q-Ixx0,89I9K,LSb,QRq6RIR::$&tfL9(1I	 # 		(('(:G #*2245	   Chqrl CC ! 	C  "..s3&+#		 !!!S?R!SS"5I"  #kltku!vw"  !efh'//0UW[]a]f]fgp]qr-/	$$6w$?! &&89::$&tf,PQ(<(H(H(N(N
 #  +..vx7K7KLm,::$!- 1` ` #	 	 X 'y1zz#(!H P
 "'  $i/K 2+yIOzz#(!0 P
 "'  %%' #%!# !# #- AAyy{qvv';!!--	":;>>-8+L9@@E ^^L9+K8??D ^^I6+H5<<SA ^^J7+I6==cBXX *  ,G4;;C@)A. 5D4I4I4K"QDAqq1a4"Q"Qzz#(#))4J4&PR!S+: R	 "' %///A	V1+> ::# %&!,!3!3 #	 	 ) &5N$$&;I;N;Nv;V#67Ci01# # &3M##% C #)) &3%8%8%= !  i 89" #X-J  "#))#. JAyy{#**3q}}Y/G+HIJ $i/K!!#M C ''@K@P@PQT@UV1Q]]956V ??:.h%",,x4:K;??62Qkoofb6QR$OO,-VAQSU1V

 )8L&(6L%%0L"&2L#	v8//0ABCH !__HMM	

 :+F?
 -.z '%
55$)!F)\B %
! %
 A%
 %#:L*O%+
'
 ;< '
y ?? fI
 

 	J()<= #.//2Mr"R148&(##%"L%>?V%W"%#'L #N#;&$ 
t
J
 ;??="=
 D	

 n
 '
 H
 9Y$
 LLd
  W
 -.?
  
 56U
  '(:!
" (#
$ L%
& ^O<'
(  !5 A A G G%//55-
2 Q.?QSWX
#-F< ./+9:N+OF'(		R-h7 3R'/%z" ,>#'%vM
 +$11J
 ..: *|1W]]_,=  >U  V
'1|$ ???+&1/&BF?#h%!)F:zz&u55 -Tb ! B  86 S  	::$5dV3qcB # 	  		  &  	$!#	$r #R & zz#' $ )%3K4D4D3EXkN^N^N`NhNhMiip#q%) "'	 	"  J!  <# " W8  	vLTOOLbLbs8//0F0FGHhphuhuH	v%
,
  E!  *  F!  "  ?VZ  R  	LLF  	*  1#a&%001s  ' A
 8A"  +/ v'( 8 =A F 2 v, '; # /! v>%A1 4 w! :w	   w? ; !x"B 8x A A 0 * 3= 1 C  ) +
x16x1;% "x7 5z & *5 !z4 : :!z9
A A# !z>
"B< { 9A )|#>7 5|( |- ( }  }= ,B< )~% 7 =	 B ' ,v;7 :v;; 		w<w71w<2 7w<< ?	x x 	x x x.* -x..	 7Az	 z		 !z1- 0z11 A|  |   -!} } !}:6 9}:: =!~" !~"" %!
 	

 	A@  ;5A@ ;A@ __main__u   🎯 Skills Tool Testz<============================================================u   
📋 Listing all skills:r   zFound rK  z skills in rG  z categorieszCategories: z
First 10 skills:
   r   z] r   u     • z: r  <   r!  zError: r\  u   
📖 Viewing skill 'axolotl':axolotlzName: zDescription: zN/Ad   zContent length: z charsrh  zLinked files: uE   
📄 Viewing reference file 'axolotl/references/dataset-formats.md':zreferences/dataset-formats.mdzFile: r  z	Preview:    rR  zVList available skills (name + description). Use skill_view(name) to load full content.objectstringz*Optional category filter to narrow results)typer  )r  
propertiesr   )rH   r  
parametersr  ah  Skills allow for loading information about specific tasks and workflows, as well as scripts and templates. Load a skill's full content or access its linked files (references, templates, scripts). First call returns SKILL.md content plus a 'linked_files' dict showing available references/templates/scripts. To access those, call again with file_path parameter.zThe skill name (use skills_list to see available skills). For plugin-provided skills, use the qualified form 'plugin:skill' (e.g. 'superpowers:writing-plans').zOPTIONAL: Path to a linked file within the skill (e.g., 'references/api.md', 'templates/config.yaml', 'scripts/validate.py'). Omit to get the main SKILL.md content.)rH   rr  c                 X    t        | j                  d      |j                  d            S )Nr"  rC  )r"  rC  )rR  r   )argskws     r4   r@  r@    s"    {*%rvvi/@  r<   u   📚)rH   toolsetschemahandlercheck_fnemojic                    | j                  dd      }t        || j                  d      |j                  d            }	 t        j                  |      }t	        |t
              rR|j                  d      rA|j                  d      xs |}|r*ddlm}m}  |t        |              |t        |             |S # t        $ r Y |S w xY w)	ztInvoke skill_view, then bump view_count on success. Best-effort: a
    telemetry failure never breaks the tool call.rH   r   rr  rC  )rr  rC  r   r   )bump_use	bump_view)r   r  rO  loadsrL   r   tools.skill_usager  r  r(   r   )r  r  rH   r  parsedresolvedr  r  s           r4   _skill_view_with_bumpr    s     88FBD-rvvi7HFF#fd#

9(= zz&)1THA#h-( X' M  Ms    A7B9 9	CC)r   Nrt   )NN)NNT)e__doc__rO  r  r%  hermes_constantsr   r   r$   reenumr   pathlibr   r   r   typingr	   r
   r   r   r   r   tools.registryr   r   r  r   utilsr   r{   r   r  r   r  r  rk   r   r   r   __annotations__r'  r#  r$  r)   r5   HERMES_HOMEr8   r9   r;   r+  r,  _PLATFORM_MAPcompiler   r*   r  ru   r(   rQ   re   rg   rr   r   rw   r   rz   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r
  r  r<  rB  rR  rq  r  printr  r  r   r   skillcatSKILLS_LIST_SCHEMASKILL_VIEW_SCHEMAregisterr  rq   r<   r4   <module>r     s  AF    A 	 	  8 8 8 8 / % !
 
		8	$ t   , ' 7e 7H 8#
" (T (  
 
 2::9:  8    3 8C= 6$sCx. $ 3  
 T 
(
S#X 4 	4S> 	d 	># >$s) >	c3h	
49d3i 	*4S> *d38n *^ )-Bc3hB#Y%B 
$sCx.BJKK$sCx.)K 
#s(^K\<T <NC N
 :>%%!%c3h$!6%	% +/	DcN+cN sCx.4'	
 
#Y(bS b "*#Y d
 	4Z	4 
& &d38nc.A(B & # 4PtCy P>&3s8 &s S C 4 4 /4 l%t l%T#s(^8L l%^Nd38n- N$tCH~2F N
B1# B1s B1c B1Z !eee e
 e d
e 	eT 	_
1
_
1_
1 _
1 	_
1
 	_
1H z	
!"	(O 

&'TZZ&FiVG_%[VZZb5Q1R0SS^_	
 	VZZb9:;<"#H%cr* 	QE/4yy/DAeJ'(+"CF3%fb}1Ecr1J0K3OP	Q 	w()* 

+,TZZ
9-.Fivf~&'(fjj>tDESIJ VI%6!7 8?@::n%N6.#9":;<w()* 

RSTZZ
9.MNOFivf~&'( VI%6!7 8?@	&+DS12#67w()* k K
 	    ~ !  A
 !  F	
 H &   	 '
	2   	!&
r<   