
    i7                        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 ddlmZm	Z	m
Z
 ddl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 ej        d
          Z	 d#dddededz  def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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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 and built-in prompt-style modes.

Shared between CLI (cli.py) and gateway (gateway/run.py) so both surfaces
can invoke skills via /skill-name commands and prompt-only built-ins like
/plan.
    N)datetime)Path)AnyDictOptional)display_hermes_home_skill_commandsz
[^a-z0-9]+z
[^a-z0-9-]z-{2,} )nowuser_instructionr   returnc                "   | r.| pd                                                                 d         nd}t                              d|                                                               d          }|rUd                    d |                    d          dd         D                       dd                              d          }|pd}|pt          j                    	                    d	          }t          d
          dz  | d| dz  S )a  Return the default workspace-relative markdown path for a /plan invocation.

    Relative paths are intentional: file tools are task/backend-aware and resolve
    them against the active working directory for local, docker, ssh, modal,
    daytona, and similar terminal backends. That keeps the plan with the active
    workspace instead of the Hermes host's global home directory.
    r
   r   -c              3      K   | ]}||V  	d S N .0parts     </home/agentuser/.hermes/hermes-agent/agent/skill_commands.py	<genexpr>z"build_plan_path.<locals>.<genexpr>)   s'      EEEEEEEEE    N   0   zconversation-planz%Y-%m-%d_%H%M%Sz.hermesplansz.md)strip
splitlines_PLAN_SLUG_REsublowerjoinsplitr   r   strftimer   )r   r   slug_sourceslug	timestamps        r   build_plan_pathr'      s    GW^#)r0022==??BB\^KS+"3"3"5"566<<SAAD VxxEEC!)<EEEEEcrcJPPQTUU&&D&001BCCI	??W$)'?'?d'?'?'???r   skill_identifiertask_idc                 f   | 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         |||                    }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).r
   Nr   )
SKILLS_DIR
skill_view/r)   successnamepath	skill_dir)r   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_pathr2   abs_skill_dirs               r   _load_skill_payloadrF   /   s	   &,"3355N t<<<<<<<<~..99;;&&(( 	4, !8!8!:!:!F!FzGYGYG[G[!\!\]]

 , , ,+


, (..s33Jz**Z"I"I"IJJ   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07C( (
C65C6F F+*F+rB   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_utilsrI   rJ   rK   r6   r=   r   itemsappendextendr9   )rB   rG   rI   rJ   rK   rL   frontmatter_config_varsresolvedlineskeyvaluedisplay_vals                 r   _inject_skill_configr[   [   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r2   activation_noteruntime_notec                 (   ddl m} t          |                     d          pd          }|d|                                g}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| d           |r-|                    d           |                    d|            |r.|                    d           |                    d| d	           d                    |          S )z9Format a loaded skill into a user/system message payload.r   )r+   rM   r
   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: rN   setup_needed
setup_notelinked_files)
references	templatesscriptsassets*zH[This skill has supporting files you can load with the skill_view tool:]z- z-
To view any of these, use: skill_view(name="z", file_path="<path>")zPThe user has provided the following instruction alongside the skill invocation: z[Runtime note: 
)r3   r+   r6   r=   r   r[   rR   values
isinstancelistexistssortedrglobis_file
is_symlinkr8   rQ   
ValueErrorr0   r!   )rB   r2   r\   r   r]   r+   rM   rG   
supportingrc   entriessubdirsubdir_pathfrelskill_view_targetsfs                    r   _build_skill_messager{      s    -,,,,,,""9--344Gb'--//2E 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_``` 	$ 	$BLLb####f=Nfff	
 	
 	
  |Rzhxzz{{{ 8R6|66677799Us   "H) )H=<H=c                     i a 	 ddlm} m}m}m} ddl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_dirszSKILL.mdc              3      K   | ]}|d v V  	dS ))z.gitz.githubz.hubNr   r   s     r   r   z&scan_skill_commands.<locals>.<genexpr>   s(      VVtt::VVVVVVr   zutf-8)encodingr0   descriptionr
   ri   #NP    r   rT   zInvoke the z skill)r0   r   skill_md_pathr2   r-   )r	   r3   r+   r}   r~   r   rO   r   setrm   rQ   rR   ro   anyrG   	read_textr=   r>   r0   r   r"   
startswithaddr    replace_SKILL_INVALID_CHARSr   _SKILL_MULTI_HYPHENr6   r9   )r+   r}   r~   r   r   disabled
seen_namesdirs_to_scanscan_dirskill_mdrM   rS   bodyr0   r   linecmd_names                    r   scan_skill_commandsr      s    O5wwwwwwwwwwww>>>>>>,,..%%
  	,
+++4466777$ '	 '	H$NN:66 & &VVx~VVVVV #&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.I1 3/I"I1 #$II1 II1 DI"I1 $7II1 
I+'I1 *I++I1 1
I>=I>c                  :    t           st                       t           S )z@Return the current skill commands mapping (scan first if empty).)r	   r   r   r   r   get_skill_commandsr     s     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-   rT   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}
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.
    Nr2   r.   z[Failed to load skill: r0   rN   z#[SYSTEM: The user has invoked the "zf" skill, indicating they want you to follow its instructions. The full skill content is loaded below.])r   r]   )r   r=   rF   r{   )r   r   r)   r]   commands
skill_infoloadedrB   r2   rC   r\   s              r   build_skill_invocation_messager   ,  s     "##Hg&&J t K!8'JJJF ?>F);>>>>*0'L)Z	Sj 	S 	S 	S   )!   r   skill_identifiersc                    g }g }g }t                      }| D ]}|pd                                }|r||v r|                    |           t          ||          }|s|                    |           ]|\  }	}
}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.   z6[SYSTEM: 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.]z

)r   r   r   rF   rQ   r{   r!   )r   r)   prompt_partsloaded_namesmissingseenr?   
identifierr   rB   r2   rC   r\   s                r   build_preloaded_skills_promptr   R  s     !L LGUUD+ ( ($*1133
 	Z4//$ZAAA 	NN:&&&.4+i7Z 7 7 7 	
 	  	
 	
 	
 	J'''';;|$$lG;;r   )r
   r   )r
   r
   )r
   Nr
   )#__doc__r;   loggingrer   pathlibr   typingr   r   r   hermes_constantsr   	getLogger__name__loggerr	   r6   __annotations__compiler   r   r   r'   tupledictrF   rl   r[   r{   r   r   r   r   r   r   r   r   <module>r      s       				             & & & & & & & & & & 0 0 0 0 0 0		8	$	$-/c4S>)* / / /
=))!rz-00  bj**  @  @ @ @@ 
D@ 
	@ @ @ @*)/ )/# )/d
 )/eTXY\^aYaTbdhkodoqtTtNux|N| )/ )/ )/ )/X$tCH~ $d3i $D $ $ $ $V L LsCx.Ld{L L 	L
 L 	L L L L^>T#tCH~"56 > > > >BDd38n!45    @s @x} @ @ @ @* 	# ### 4Z# 	#
 c]# # # #P '< '<Cy'<4Z'< 3S	49$%'< '< '< '< '< '<r   