
    iD                        U d 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	 ddl
mZ ddlmZmZmZ  ej        e          Zi aeeeeef         f         ed<    ej        d          Z ej        d	          Zd!d
ededz  deeeef         edz  ef         dz  fdZdeeef         dee         ddfdZ 	 	 	 d"deeef         dedz  dededededz  defdZ!deeeeef         f         fdZ"deeeeef         f         fdZ#deeef         fdZ$dede	e         fdZ%	 	 	 d#dedededz  dede	e         f
dZ&	 d!dee         dedz  deeee         ee         f         fd Z'dS )$zShared slash command helpers for skills.

Shared between CLI (cli.py) and gateway (gateway/run.py) so both surfaces
can invoke skills via /skill-name commands.
    N)Path)AnyDictOptional)display_hermes_home)expand_inline_shellload_skills_configsubstitute_template_vars_skill_commandsz
[^a-z0-9-]z-{2,}skill_identifiertask_idreturnc                 h   | pd                                 }|sdS 	 ddlm}m} t	          |                                          }|                                rZ	 t          |                                	                    |                                                    }n'# t          $ r |}Y nw xY w|                    d          }t          j         |||d                    }n# t          $ r Y dS w xY w|                    d          sdS t          |                    d	          p|          }t          |                    d
          pd          }	d}
|                    d          }|rt	          |          }
n-|	r+	 |t	          |	          j        z  }
n# t          $ r d}
Y nw xY w||
|fS )zOLoad a skill by name/path and return (loaded_payload, skill_dir, display_name). Nr   )
SKILLS_DIR
skill_view/F)r   
preprocesssuccessnamepath	skill_dir)striptools.skills_toolr   r   r   
expanduseris_absolutestrresolverelative_to	Exceptionlstripjsonloadsgetparent)r   r   raw_identifierr   r   identifier_path
normalizedloaded_skill
skill_name
skill_pathr   abs_skill_dirs               ;/home/longshao/.hermes/hermes-agent/agent/skill_commands.py_load_skill_payloadr.      s   &,"3355N t<<<<<<<<~..99;;&&(( 	4, !8!8!:!:!F!FzGYGYG[G[!\!\]]

 , , ,+


, (..s33JzJz7uEEE
 
    tt I&& t\%%f--;<<J\%%f--344JI
 !$$[11M ''			 	"T*%5%5%<<II 	 	 	III	 J..sH   =C) AB!  C) !B0-C) /B008C) )
C76C7F F,+F,r)   partsc                    	 ddl m}m}m} t	          |                     d          p|                     d          pd          }|sdS  ||          \  }} ||          }|sdS  ||          }	|	sdS ddt                       dg}
|	                                D ]3\  }}|rt	          |          nd	}|
                    d
| d|            4|
                    d           |	                    |
           dS # t          $ r Y dS w xY w)ae  Resolve and inject skill-declared config values into the message parts.

    If the loaded skill's frontmatter declares ``metadata.hermes.config``
    entries, their current values (from config.yaml or defaults) are appended
    as a ``[Skill config: ...]`` block so the agent knows the configured values
    without needing to read config.yaml itself.
    r   )extract_skill_config_varsparse_frontmatterresolve_skill_config_valuesraw_contentcontentr   Nz[Skill config (from z/config.yaml):z	(not set)z  z = ])agent.skill_utilsr1   r2   r3   r   r$   r   itemsappendextendr    )r)   r/   r1   r2   r3   r4   frontmatter_config_varsresolvedlineskeyvaluedisplay_vals                 r-   _inject_skill_configrC   I   s   	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 ,**=99^\=M=Mi=X=X^\^__ 	F**;77Q//<< 	F..{;; 	FQ,?,A,AQQQR"..** 	5 	5JC(->#e***;KLL3c33k334444SU   s%   AC= 	C= &C= 5BC= =
D
Dr   r   activation_noteuser_instructionruntime_note
session_idc                    ddl m} t          |                     d          pd          }t	                      }|                    dd          rt          |||          }|                    dd          r6t          |                    d	d
          pd
          }	t          |||	          }|d|                                g}
|rC|
	                    d           |
	                    d| d           |
	                    d           t          | |
           |                     d          r|
                    ddg           n|                     d          r"|
                    dd| d          dg           nK|                     d          r6|                     d          r!|
                    dd| d          dg           g }|                     d          pi }|                                D ],}t          |t                    r|                    |           -|s|rdD ]}||z  }|                                rt!          |                    d                    D ]a}|                                rK|                                s7t          |                    |                    }|	                    |           b|r|r	 t          |                    |                    }n# t*          $ r
 |j        }Y nw xY w|
	                    d           |
	                    d           |D ] }|
	                    d| d||z              !|
	                    d| d| d           |r-|
	                    d           |
	                    d|            |r.|
	                    d           |
	                    d| d           d                    |
          S ) z9Format a loaded skill into a user/system message payload.r   )r   r5   r   template_varsTinline_shellFinline_shell_timeout
   z[Skill directory: r6   zResolve any relative paths in this skill (e.g. `scripts/foo.js`, `templates/config.yaml`) against that directory, then run them with the terminal tool using the absolute path.setup_skippedz[Skill setup note: Required environment setup was skipped. Continue loading the skill and explain any reduced functionality if it matters.]gateway_setup_hintz[Skill setup note: setup_needed
setup_notelinked_files)
references	templatesscriptsassets*z"[This skill has supporting files:]z- z  ->  z)
Load any of these with skill_view(name="zM", file_path="<path>"), or run scripts directly by absolute path (e.g. `node z/scripts/foo.js`).zPThe user has provided the following instruction alongside the skill invocation: z[Runtime note: 
)r   r   r   r$   _load_skills_config_substitute_template_varsint_expand_inline_shellr   r9   rC   r:   values
isinstancelistexistssortedrglobis_file
is_symlinkr   
ValueErrorr   join)r)   r   rD   rE   rF   rG   r   r5   
skills_cfgtimeoutr/   
supportingrQ   entriessubdirsubdir_pathfrelskill_view_targetsfs                       r-   _build_skill_messagerp   p   s    -,,,,,,""9--344G
 %&&J~~ot,, L+GY
KK~~ne,, Djnn%;R@@FBGG&w	7CCb'--//2E  
R6)666777>	
 	
 	
 u---(( 
 ^	
 	
 	
 	
 
		.	/	/ 
Kl3G&HKKK	
 	
 	
 	
 
		.	)	) 
l.>.>|.L.L 
Cl<&@CCC	
 	
 	
 J##N339rL&&(( ' 'gt$$ 	'g&&& /) /F 	/ 	/F#f,K!!## / 1 1# 6 677 / /Ayy{{ /1<<>> /!!--	":":;;"))#... 
i 
	/ #I$9$9*$E$E F F 	/ 	/ 	/ )	/ 	R9::: 	: 	:BLL8b88	B88999999J 9 9$9 9 9	
 	
 	
  |Rzhxzz{{{ 8R6|66677799Us   "K/ /LLc                     i a 	 ddlm} m}m}m} ddlm}m}  |            }t                      }g }| 
                                r|                    |            |                     |                       |D ]}	 ||	d          D ]}
t          d |
j        D                       r"	 |
                    d          } ||          \  }} ||          sS|                    d|
j        j                  }||v rx||v r}|                    d	d
          }|sa|                                                    d          D ]9}|                                }|r!|                    d          s|dd         } n:|                    |           |                                                    dd                              dd          }t2                              d
|          }t6                              d|                              d          }|s||pd| dt9          |
          t9          |
j                  dt           d| <   # t:          $ r Y w xY wn# t:          $ r Y nw xY wt           S )zScan ~/.hermes/skills/ and return a mapping of /command -> skill info.

    Returns:
        Dict mapping "/skill-name" to {name, description, skill_md_path, skill_dir}.
    r   )r   _parse_frontmatterskill_matches_platform_get_disabled_skill_names)get_external_skills_dirsiter_skill_index_fileszSKILL.mdc              3      K   | ]}|d v V  	dS ))z.gitz.githubz.hubz.archiveN ).0parts     r-   	<genexpr>z&scan_skill_commands.<locals>.<genexpr>   s(      bb4tFFbbbbbb    zutf-8)encodingr   descriptionr   rW   #NP    -r<   zInvoke the z skill)r   r~   skill_md_pathr   r   )r   r   r   rr   rs   rt   r7   ru   rv   setr_   r9   r:   anyr/   	read_textr$   r%   r   r   split
startswithaddlowerreplace_SKILL_INVALID_CHARSsub_SKILL_MULTI_HYPHENr   r    )r   rr   rs   rt   ru   rv   disabled
seen_namesdirs_to_scanscan_dirskill_mdr5   r;   bodyr   r~   linecmd_names                     r-   scan_skill_commandsr      s    O5wwwwwwwwwwwwVVVVVVVV,,..%%
  	,
+++4466777$ '	 '	H228ZHH & &bbS[Sabbbbb #&00'0BBG(:(:7(C(C%K11+>> ! &??68?3GHHDz)) x'' "-//-"D"DK& &$(JJLL$6$6t$<$< & &D#'::<<D# &DOOC,@,@ &.23B3i %NN4(((  $zz||33C==EEc3OOH377HEEH266sHEEKKCPPH# !  $'2'P6PD6P6P6P),X%(%9%9	7 7ONNN33 !   HK&'	P    sg   B'I* ,/II* $I I* II* DII* 7II* 
I$ I* #I$$I* *
I76I7c                  :    t           st                       t           S )z@Return the current skill commands mapping (scan first if empty).)r   r   rx   r|   r-   get_skill_commandsr     s     r|   c                  l   dt           t          t           t          t          f         f         dt           t          t          f         fd}  | t                    t	                      } | |          t          t                    t                    z
            }t          t                    t                    z
            }t          t                    t                    z            }fd|D             }fd|D             }|||t                    t          |          dS )u  Re-scan the skills directory and return a diff of what changed.

    Rescans ``~/.hermes/skills/`` and any ``skills.external_dirs`` so the
    slash-command map (``agent.skill_commands._skill_commands``) reflects
    skills added or removed on disk.

    This does NOT invalidate the skills system-prompt cache. Skills are
    called by name via ``/skill-name``, ``skills_list``, or ``skill_view``
    — they don't need to be in the system prompt for the model to use them.
    Keeping the prompt cache intact preserves prefix caching across the
    reload, so a user invoking ``/reload-skills`` pays no cache-reset cost.

    Returns:
        Dict with keys::

            {
              "added":      [{"name": str, "description": str}, ...],
              "removed":    [{"name": str, "description": str}, ...],
              "unchanged":  [skill names present before and after],
              "total":      total skill count after rescan,
              "commands":   total /slash-skill count after rescan,
            }

        ``description`` is the skill's full SKILL.md frontmatter
        ``description:`` field — the same string the system prompt renders
        as ``    - name: description`` for pre-existing skills.
    cmdsr   c                     i }|                                  D ]6\  }}|                    d          }|pi                     d          pd||<   7|S )Nr   r~   r   )r8   r!   r$   )r   out	slash_keyinfobares        r-   	_snapshotz reload_skills.<locals>._snapshot?  s\     #zz|| 	> 	>OIt##C((D((77=2CII
r|   c                 &    g | ]}||         d S )r   r~   rx   )ry   nafters     r-   
<listcomp>z!reload_skills.<locals>.<listcomp>R  s%    GGGaaa11GGGr|   c                 &    g | ]}||         d S r   rx   )ry   r   befores     r-   r   z!reload_skills.<locals>.<listcomp>U  s%    LLL&)44LLLr|   )addedremoved	unchangedtotalcommands)r   r   r   r   r   r`   r   len)	r   new_commandsadded_namesremoved_namesr   r   r   r   r   s	          @@r-   reload_skillsr     s+   @S$sCx.01 d38n     Y''F '((LIl##EUc&kk122K3v;;U344Ms5zzCKK/00IGGGG;GGGE MLLLmLLLG U%%  r|   commandc                 d    | sdS d|                      dd           }|t                      v r|ndS )uV  Resolve a user-typed /command to its canonical skill_cmds key.

    Skills are always stored with hyphens — ``scan_skill_commands`` normalizes
    spaces and underscores to hyphens when building the key. Hyphens and
    underscores are treated interchangeably in user input: this matches
    ``_check_unavailable_skill`` and accommodates Telegram bot-command names
    (which disallow hyphens, so ``/claude-code`` is registered as
    ``/claude_code`` and comes back in the underscored form).

    Returns the matching ``/slug`` key from ``get_skill_commands()`` or
    ``None`` if no match.
    Nr   r<   r   )r   r   )r   cmd_keys     r-   resolve_skill_command_keyr   `  sG      t-'//#s++--G!3!5!555774?r|   r   c                 "   t                      }|                    |           }|sdS t          |d         |          }|sd|d          dS |\  }}}		 ddlm}
  |
|	           n# t
          $ r Y nw xY wd	|	 d
}t          ||||||          S )aE  Build the user message content for a skill slash command invocation.

    Args:
        cmd_key: The command key including leading slash (e.g., "/gif-search").
        user_instruction: Optional text the user typed after the command.

    Returns:
        The formatted message string, or None if the skill wasn't found.
    Nr   r   z[Failed to load skill: r   r6   r   bump_usez&[IMPORTANT: The user has invoked the "zf" skill, indicating they want you to follow its instructions. The full skill content is loaded below.])rE   rF   rG   )r   r$   r.   tools.skill_usager   r    rp   )r   rE   r   rF   r   
skill_infoloadedr)   r   r*   r   rD   s               r-   build_skill_invocation_messager   s  s    "##Hg&&J t K!8'JJJF ?>F);>>>>*0'L)Z......   	S 	S 	S 	S   )!   s   A& &
A32A3skill_identifiersc           	         g }g }g }t                      }| D ]}|pd                                }|r||v r|                    |           t          ||          }|s|                    |           ]|\  }	}
}	 ddlm}  ||           n# t          $ r Y nw xY wd| d}|                    t          |	|
||                     |                    |           d	                    |          ||fS )	zLoad one or more skills for session-wide CLI preloading.

    Returns (prompt_text, loaded_skill_names, missing_identifiers).
    r   r   r   r   z9[IMPORTANT: The user launched this CLI session with the "z~" skill preloaded. Treat its instructions as active guidance for the duration of this session unless the user overrides them.])rG   z

)
r   r   r   r.   r9   r   r   r    rp   re   )r   r   prompt_partsloaded_namesmissingseenr&   
identifierr   r)   r   r*   r   rD   s                 r-   build_preloaded_skills_promptr     sr    !L LGUUD+ !( !($*1133
 	Z4//$ZAAA 	NN:&&&.4+i	222222HZ     	 	 	D	7
 7 7 7 	
 	 "	  	
 	
 	
 	J'''';;|$$lG;;s   ;B
BB)N)r   r   N)r   Nr   )(__doc__r"   loggingrepathlibr   typingr   r   r   hermes_constantsr   agent.skill_preprocessingr   r[   r	   rX   r
   rY   	getLogger__name__loggerr   r   __annotations__compiler   r   tupledictr.   r^   rC   rp   r   r   r   r   r   r   rx   r|   r-   <module>r      sv       				       & & & & & & & & & & 0 0 0 0 0 0          
	8	$	$-/c4S>)* / / /!rz-00  bj** +/ +/# +/d
 +/eTXY\^aYaTbdhkodoqtTtNux|N| +/ +/ +/ +/\$tCH~ $d3i $D $ $ $ $V !d dsCx.dd{d d 	d
 d d
d 	d d d dN>T#tCH~"56 > > > >BDd38n!45    >tCH~ > > > >B@s @x} @ @ @ @* 	, ,,, 4Z, 	,
 c], , , ,b 0< 0<Cy0<4Z0< 3S	49$%0< 0< 0< 0< 0< 0<r|   