
    `gj6                       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	m
Z
 ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZ  e       Zd
efdZdeded
efdZdeeef   d
ee   fdZdefdZded
efdZ ej:                  d      Z ej:                  d      Zded
e fdZ!d
e	e   fdZ"dRdededed
e
e   fdZ#dede	e   d
efdZ$	 	 dSded ed!e%de
e   d"e d
dfd#Z&	 	 dTd$e%d%e%d ede
e   d
df
d&Z'	 	 	 	 dUded'ed(e de
e   d)e d*e d+ed
dfd,Z(dVdede
e   d
dfd-Z)dWd$e%d%e%d ed
e*fd.Z+ded
e
e*   fd/Z,	 	 	 dXd0ed1e de
e   d
dfd2Z-dYde
e   de
e   d
dfd3Z.dYde
e   de
e   d
dfd4Z/	 	 dZde
e   de
e   d5e d
dfd6Z0	 	 	 d[dede
e   d)e d*e d
df
d7Z1	 	 	 	 d\ded8e de
e   d)e d*e d
dfd9Z2	 	 d]de
e   d"e d
dfd:Z3dVdede
e   d
dfd;Z4	 	 	 	 d\d<e de
e   d)e d*e d
df
d=Z5	 	 	 d^d>e de
e   d*e d
dfd?Z6	 	 	 	 d\ded8e de
e   d)e d*e d
dfd@Z7d_dAedBede
e   d
dfdCZ8	 	 d`dDedEedBede
e   d
df
dFZ9dDedGedHed
e:fdIZ;dVdJede
e   d
dfdKZ<	 	 dadLed(e de
e   d
dfdMZ=dbdNZ>dVdOede
e   d
dfdPZ?ded
dfdQZ@y)cuW  
Skills Hub CLI — Unified interface for the Hermes Skills Hub.

Powers both:
  - `hermes skills <subcommand>` (CLI argparse entry point)
  - `/skills <subcommand>` (slash command in the interactive chat)

All logic lives in shared do_* functions. The CLI entry point and slash command
handler are thin wrappers that parse args and delegate.
    N)Path)AnyDictListOptional)Console)Panel)Table)display_hermes_homeis_excluded_skill_pathreturnc                     | j                   dk(  r$t        | dd      xs i j                  d      }|r|S | j                   S )a  Human-facing source label for a result row.

    GitHub-tap skills are stored under source="github"; surface their per-tap
    provider label (NVIDIA / OpenAI / ...) when present so the table reflects
    the real origin instead of the generic "github".
    githubextraNprovider)sourcegetattrget)rr   s     H/root/.hermes/venv/lib/python3.12/site-packages/hermes_cli/skills_hub.py_display_sourcer      s?     	xx8Aw-388DO88O    nameconsolec           	      B   ddl m} |xs t        }|j                  d|  d        || |dd      }|D cg c]0  }|j                  j                         | j                         k(  s/|2 }}t        |      dk(  r1|j                  d	|d   j                   d
       |d   j                  S t        |      dkD  r|j                  d|  d       t               }|j                  dd       |j                  dd       |j                  dddd       |D ]m  }ddddj                  |j                  d      }	|j                  dk(  rdn|j                  }
|j                  |j                  d|	 d|
 d
|j                         o |j                  |       |j                  d       y|r[|j                  d|  d        |d!d" D ]-  }|j                  d#|j                   d$|j                          / |j                          y|j                  d%|  d&       yc c}w )'a,  
    Resolve a short skill name (e.g. 'pptx') to a full identifier by searching
    all sources. If exactly one match is found, returns its identifier. If multiple
    matches exist, shows them and asks the user to use the full identifier.
    Returns empty string if nothing found or ambiguous.
    r   )unified_searchz[dim]Resolving 'z'...[/]all   source_filterlimit   z[dim]Resolved to: [/]z 
[yellow]Multiple skills named 'z' found:[/]SourcedimstyleTrust
Identifier	bold cyanfoldFr(   overflowno_wrapbright_cyangreenyellowbuiltintrusted	communityofficial[]z<[bold]Use the full identifier to install a specific one.[/]
 z[yellow]No exact match for 'z '. Did you mean one of these?[/]N   z  [cyan]u   [/] — z$[bold red]Error:[/] No skill named 'z' found in any source.
)tools.skills_hubr   _consoleprintr   lowerlen
identifierr
   
add_columnr   trust_levelr   add_row)r   sourcesr   r   cresultsr   exacttabletrust_styletrust_labels              r   _resolve_short_namerL   1   s    08AGGtfG,-T7%rJG  B1166<<>TZZ\#AQBEB
5zQ	$U1X%8%8$9=>Qx"""
5zA~	3D6EF/. 	[6SXY 	VA&3V^_ccdedqdqsxyK()J(>*AMMKMM!((a}Ak]#$FU	V 	
	OP 	.tf4TUV! 	?AGGhqvvhhq||n=>	?		GG24&8PQR? Cs   0H'Hr   c                    g }| s|S | j                  d      r|j                  d| d           | j                  d      r|j                  d| d           | j                  d      r|j                  d| d           | j                  d      r|j                  d| d           | j                  d	      r|j                  d
| d	           | j                  d      |j                  d| d           | j                  d      r|j                  d| d           | j                  d      }t        |t              rE|rCdj	                  d t        |j                               D              }|j                  d|        |S )Nrepo_urlz[bold]Repo:[/] 
detail_urlz[bold]Detail Page:[/] 	index_urlz[bold]Index:[/] endpointz[bold]Endpoint:[/] install_commandz[bold]Install Command:[/] installsz[bold]Installs:[/] weekly_installsz[bold]Weekly Installs:[/] security_audits, c              3   0   K   | ]  \  }}| d |   yw)=N ).0r   statuss      r   	<genexpr>z/_format_extra_metadata_lines.<locals>.<genexpr>x   s     \<4tfAfX.\s   z[bold]Security:[/] )r   append
isinstancedictjoinsorteditems)r   linessecurityordereds       r   _format_extra_metadata_linesrf   b   ss   EyyuZ'8&9:;yy-eL.A-BCDyy'k(:';<=yy*5+<*=>?yy"#1%8I2J1KLMyy(*5+<*=>?yy"#1%8I2J1KLMyy*+H(D!h))\6(..JZC[\\*7)45Lr   rA   c                    d}d}d}|D ]F  }|	 |j                  |       }|r|}	 |j                  |       }|s0|}|	 |j                  |       } n |||fS # t        $ r d}Y @w xY w# t        $ r d}Y ?w xY w# t        $ r d}Y 7w xY w)z6Resolve metadata and bundle for a specific identifier.N)inspect	Exceptionfetch)rA   rE   metabundlematched_sourcesrcs         r   _resolve_source_meta_and_bundlero   ~   s    DFN <{{:.%(N	YYz*F  N| ;;z2D '* ''    	F	 !  D s3   AA(A9A%$A%(A65A69BBinstall_pathc                 T    t        |       }t        |j                        }|dk(  rdS |S )N.r:   )r   strparent)rp   pathrt   s      r   "_derive_category_from_install_pathrv      s+    DF32*F*r   z^[a-z][a-z0-9_-]*$z^[a-z][a-z0-9_/-]*$c                     t        | t              sy| j                         j                         }|r|dv ryt	        t
        j                  |            S )zAAccept identifier-shaped names, reject empty / sentinel-y values.F>   unnamed-skillindexskillreadme)r^   rs   stripr?   bool_VALID_NAME_REmatch)r   	candidates     r   _is_valid_installed_skill_namer      sG    dC 

""$I	%RR$$Y/00r   c                     ddl m}  g }	 | j                         D ]  }|j                         r|j                  j                  d      r/|dz  j                         rC	 t        d |j                  d      D              r|j                  |j                          	 t        t        |            S # t        $ r Y w xY w# t        t        f$ r g cY S w xY w)a!  Return sorted subdirectory names under ``~/.hermes/skills/`` that look
    like category buckets (contain at least one ``SKILL.md`` somewhere below).

    Used to suggest reusable categories when interactively installing from a
    URL. Hidden dirs (``.hub``, ``.trash``) are skipped.
    r   
SKILLS_DIRrr   SKILL.mdc              3   4   K   | ]  }t        |         y wNr   )rZ   ps     r   r\   z'_existing_categories.<locals>.<genexpr>   s        /q11s   )r<   r   iterdiris_dirr   
startswithexistsanyrglobr]   OSErrorFileNotFoundErrorra   set)r   outentrys      r   _existing_categoriesr      s     ,C'') 	E<<>UZZ%:%:3%? 
"**, "[[4  JJuzz*	& #c(	  w' 	s6   AC  <B1C  1	B=:C  <B==C   CCrF   urldefaultc                 :   | j                          | j                  d| d       |rd| dnd}| j                  d| d       	 t        d      j                         }|s|r|}t        |      s| j                  d
|d       y	|S # t        t        f$ r Y y	w xY w)zBPrompt interactively for a skill name. Returns None on cancel/EOF.z[yellow]The SKILL.md at zx doesn't declare a `name:` in its frontmatter,[/]
[yellow]and the URL path doesn't produce a valid identifier either.[/]z [r9   r:   z[bold]Enter a skill namezT:[/] [dim](lowercase letters, digits, hyphens, underscores; starts with a letter)[/]zName: Nz[bold red]Invalid name:[/] z. Aborting install.
)r>   inputr|   EOFErrorKeyboardInterruptr   )rF   r   r   default_hintanswers        r   _prompt_for_skill_namer      s    GGIGG
"3% (  	!
 '.Ry?2LGG
"<. 1Z 	[x&&( g)&1	-fZ7LMNM '( s   B BBexistingc                 r   | j                          |r6| j                  d       | j                  ddj                  |       d       n| j                  d       	 t        d      j                         }|syt        j                  |      s| j                  d|d	       y|S # t        t
        f$ r Y yw xY w)
zIPrompt interactively for a category. Empty/None input means flat install.zk[bold]Pick a category[/] [dim](reuse an existing bucket, type a new one, or press Enter to install flat)[/]z[dim]Existing: rV   r$   u`   [bold]Category[/] [dim](optional — press Enter to install flat at ~/.hermes/skills/<name>/)[/]z
Category: r:   z[dim]Invalid category u    — installing flat.[/])r>   r`   r   r|   r   r   _VALID_CATEGORY_REr   )rF   r   r   s      r   _prompt_for_categoryr      s    GGI	a	
 	
/$))H"5!6c:;	n	
|$**, ##F+	(
2JKLM '( s   B$ $B65B6queryr   r"   as_jsonc                 |   ddl m}m}m} |xs t        } |       }	 ||	      }
|rt || |
||      }|D cg c]<  }|j
                  |j                  |j                  |j                  |j                  d> }}t        t        j                  |d             y|j                  d|         |j                  d	      5   || |
||      }ddd       s|j                  d
       yt        dt        |       d      }|j!                  dd       |j!                  dd       |j!                  dd       |j!                  dd       |j!                  dddd       |D ]  }ddddj#                  |j                  d      }|j                  dk(  rdn|j                  }|j%                  |j
                  |j                  dd t        |j                        dkD  rd nd!z   t'        |      d"| d#| d$|j                          |j                  |       |j                  d%       yc c}w # 1 sw Y   gxY w)&a  Search registries and display results as a Rich table.

    When ``as_json=True`` writes a JSON array of result records to stdout
    (one object per skill: ``name``, ``identifier``, ``source``,
    ``trust_level``, ``description``) and skips the table render. This is
    the scripting / copy-paste handle: the full identifier is always
    intact, even for browse-sh slugs that the table would otherwise wrap.
    r   )
GitHubAuthcreate_source_routerr   r    )r   rA   r   rC   description   )indentNz
[bold]Searching for:[/] z[bold]Searching registries...z-[dim]No skills found matching your query.[/]
u   Skills Hub — z
 result(s)titleNamer+   r'   Description<   	max_widthr%   r&   r)   r*   r,   Fr-   r0   r1   r2   r3   r7   ...r:   r8   r9   r$   z[dim]Use: hermes skills inspect <identifier> to preview, hermes skills install <identifier> to install (--json for scripting)[/]
)r<   r   r   r   r=   r   rA   r   rC   r   r>   jsondumpsr[   r
   r@   rB   r   rD   r   )r   r   r"   r   r   r   r   r   rF   authrE   rG   r   payloadrI   rJ   rK   s                    r   	do_searchr     s8    RQ8A<D"4(G !vUS 	
  ll(( }} }}	
 	
 	djj+,GG(01	
1	2 T vUST 	@A/#g,zBCE	V;/	]b1	XU+	WE*
 
\O 	
"/GRZ[__`a`m`motu$%HH
$:jFFMM#23q}}+=+B%KA}Ak]#.LL	
	
 GGENGG * +Y	
T Ts   AH,?H11H;page	page_sizec                 	  &'( ddl m}m}m} t	        dt        |d            }|xs t        } |       } ||      }	dddd&dd	d	d
d	ddddd	}
|j                  d      5 (g 'dt        dt        ddf'(fd} ||	d|
|d|      \  }}}ddd       s|j                  d       yddl m}m} |j                         j                         |v r! |||      }|s|j                  d| d       yi }|D ]h  }&j                  |j                   d      }|j"                  |vs-|&j                  ||j"                     j                   d      kD  sZ|||j"                  <   j t%        |j'                               }|j)                  &fd       t+        |      }t	        d||z   dz
  |z        }t	        dt        | |            } | dz
  |z  }t        ||z   |      }||| }t-        d |D              }|dk7  rd| nd}| d }r|d!t+        |       d"z  }|j                  d#| d$| d%|  d&| d'	       |dkD  r| dk(  r|j                  d(| d)       |j                          t/        d*d+,      }|j1                  d-d.d/d01       |j1                  d2d3d45       |j1                  d6d78       |j1                  d9d.d:;       |j1                  d<d=>       |j1                  d?d.d@dAB       t3        ||dz   C      D ]  \  }}dDdEdFdj                  |j                   d.      }|j4                  dGk(  rdHn|j                   } |j6                  dd7 }!t+        |j6                        d7kD  r|!dIz  }!|j9                  t        |      |j:                  |!t=        |      dJ| dK|  dL|j"                          |j                  |       g }"| dkD  r|"j?                  dM| dz
   dN       | |k  r|"j?                  dM| dz    dO       |"r#|j                  dPdQjA                  |"              |dk(  rVrTtC        |jE                               D #$cg c]  \  }#}$|# dR|$  }%}#}$|j                  dSd!jA                  |%       dL       |r$|j                  dTd!jA                  |       dU       |j                  dV       y# 1 sw Y   (xY wc c}$}#w )WzBrowse all available skills across registries, paginated.

    Official skills are always shown first, regardless of source filter.
    r   r   r   parallel_search_sourcesr#   d      r   r3   i@B    2     	zhermes-indexr7   z	skills-shz
well-knownr   clawhubzclaude-marketplacelobehubz	browse-shz([bold]Fetching skills from registries...sidcountr   Nc                 |    j                  |  d| d       j                  ddj                         d       y )Nz ()z8[bold]Fetching skills from registries...[/]  [dim]done: rV   r$   )r]   updater`   )r   r   _doner[   s     r   _on_source_donez"do_browse.<locals>._on_source_doney  sC    LLC55'+,MM"ii./s4r   r:      )r   per_source_limitsr!   overall_timeouton_source_donez+[dim]No skills found in the Skills Hub.[/]
)_PROVIDER_FILTER_VALUES_filter_results_by_providerz#[dim]No skills found for provider 'z'.[/]
c                     j                  | j                  d       | j                  dk7  | j                  j	                         fS Nr   r7   r   rC   r   r   r?   r   _TRUST_RANKs    r   <lambda>zdo_browse.<locals>.<lambda>  s8    		**	J	  r   keyc              3   @   K   | ]  }|j                   d k(  sd  yw)r7   r#   Nr   )rZ   r   s     r   r\   zdo_browse.<locals>.<genexpr>  s     Fqqxx:/EFs   r   u   — u   — all sourcesz skills loadedrV   z source(s) still loadingu   
[bold]Skills Hub — Browse z[/]  [dim](z, page /z)[/]u   [bright_cyan]★ z1 official optional skill(s) from Nous Research[/]Tbold)show_headerheader_style#r&      right)r(   widthjustifyr   r+      )r(   r   r   ,   r   r%      )r(   r   r)   
   )r   r*   r,   Fr-   )startr0   r1   r2   r7   u   ★ officialr   r8   r9   r$   z[cyan]--page u   [/] ← prevu   [/] → nextz  z | : z  [dim]Sources: u$     [yellow]⚡ Slow sources skipped: u$    — run again for cached results[/]z[dim]Tip: 'hermes skills inspect <identifier>' to preview, 'hermes skills install <identifier>' to install, 'hermes skills search <query>' to search deeper[/]
)#r<   r   r   r   maxminr=   r[   rs   intr>   r   r   r|   r?   r   rC   rA   listvaluessortr@   sumr
   rB   	enumerater   r   rD   r   r   r]   r`   ra   rb   ))r   r   r   r   r   r   r   rF   r   rE   _PER_SOURCE_LIMITr   all_resultssource_counts	timed_outr   r   seenr   rankdedupedtotaltotal_pagesr   end
page_itemsofficial_countsource_labelloaded_labelrI   irJ   rK   desc	nav_partsr   ctpartsr   r   r[   s)                                         @@@r   	do_browser  K  s;    
 As9c*+I8A<D"4(G  AA>K  c#SS	 
<	= 
 	 	S 	T 	 1H/ *1
-]I!
2 	>?
 V||~!881+vFGG9&IJ
 D #q}}a0<<t#tkood1<<>P>\>\^_.`'`!"D# 4;;=!G LL L  LEa%)+a/I=>Kq#dK()DAX"E
ei
'Cs#J FGFFN '-oT&?;LLWN+L"S^,,DEEGG,\N ;#nGD6;-tE Fdai	#N#33defGGI d8E	SQ@	V;"=	]b1	XU"5	WB' 
\O*EAI6 
1"/G$,..1c!--.G 	()J(>nAMM}}Sb!q}}"EMDFFFA}Ak]#.LL	

$ GGEN Iax=
,?@k=
,?@	"UZZ	*+,- =/5m6I6I6K/LMGCC52$MM	"499U#3"4C89	6tyy7K6L M6 7 	8 GG C DC
 
t Ns    *R0 R=0R:categoryforceskip_confirminvalidate_cachename_overridec                    ddl m}m}m}	m}
m}m} ddlm}m	}m
} |xs t        } |	         |       } ||      }d| vrt        | ||      } | sy|j                  d|         t        | |      \  }}}|sLt        d |D              }|j                  d|  d	       |r|j                  d
       y|j                          yt!        |di       xs i }|j"                  dk(  r|j$                  r|j'                  d      r|r&t)        |      r|j+                         |_        d|d<   n|r|j                  d|d       y|r1|j'                  d      xs | }|j                  d| d| d| d       y|j'                  d      xs | }t-        ||      }|s|j                  d       y||_        d|d<   |"|j$                  |_        |j$                  |_        |j"                  dk(  r|s|st1        |t3                     }|j"                  dk(  r?|s=|j4                  j7                  d      }t9        |      dk\  rdj;                  |dd       } |       }|j=                  |j$                        }|r8|j                  d|j$                   d|d           |s|j                  d       yt?        t!        |di       xs i       }|jA                  t!        |di       xs i        	  |
|      }|j                  d$|jK                  |jL                  jL                  jL                         d%       |j                  d&       |j"                  dk(  rd}!n t!        |d'd(      xs t!        |d'd(      xs | }!dd)l m'}"m(}#  |||! |#|      |"d*z  +      \  }$}%|j                   ||$             |%d,   rd,nd-}&|j                  d.|& d/|%d0    d1|%d2    d%       d3j;                  |%d4         xs d5}'|j                  d6|%d7    d8|%d9    d:|' d%        ||$|;      \  }(})|(s}|j                  d<|)        tS        jT                  |d=>       dd!l m"}   | d"|j$                  |j"                  |jF                  |$jV                  t9        |$jX                         d?       y|r9t[        |      }*|*r,|j                  t]        d j;                  |*      d@dAB             |s|s|j                          |j"                  dk(  r@|j                  t]        dCt_                dD|r|dz   nd( |j$                   dEdFdGB             n?|j                  t]        dHt_                dD|r|dz   nd( |j$                   dEdIdJB             |j                  dK|j$                   dL       	 ta        dM      j+                         jc                         }+|+dOvr)|j                  d       tS        jT                  |d=>       y	  |||j$                  |||$      },ddPl m4}- |j                  dQ|,jK                  |-              |j                  dRd3j;                  |jj                  jm                                dS       	 ddTl7m8}.m9}/m:}0 	  |/|j$                        }1|1 |0|1      }3|3>|j                  dV|j$                   dW|1jv                   dX       |j                  dY       n=|j                  dV|j$                   dW|1jv                   dZ       |j                  d[       |r	 dd\l=m>}4  |4d=]       y|j                  d^       |j                  d_       y# tB        $ rY}|j                  d| d        dd!l m"}   | d"|j$                  |j"                  |jF                  d#tI        |             Y d}~yd}~ww xY w# td        tf        f$ r dN}+Y w xY w# tB        $ rp}|j                  d| d        tS        jT                  |d=>       dd!l m"}   | d"|j$                  |j"                  |jF                  d#tI        |             Y d}~yd}~ww xY w# |.$ r"}2|j                  dU|2 d        d}1Y d}2~2d}2~2ww xY w# tx        $ r Y ew xY w# tx        $ r Y yw xY w)`a  Fetch, quarantine, scan, confirm, and install a skill.

    ``name_override`` lets non-interactive callers (slash commands, gateway,
    scripts) supply a skill name when the upstream SKILL.md lacks a valid
    ``name:`` frontmatter field. On interactive TTY surfaces, a missing name
    triggers a prompt instead; ``skip_confirm=True`` means "non-interactive"
    (so pair it with ``name_override`` when installing from a URL that has
    no frontmatter).
    r   )r   r   ensure_hub_dirsquarantine_bundleinstall_from_quarantineHubLockFile)scan_skill_cachedshould_allow_installformat_scan_reportr   Nz
[bold]Fetching:[/] c              3   j   K   | ]+  }t        |d d      xs t        t        |dd      d d       - yw)is_rate_limitedFr   N)r   )rZ   rn   s     r   r\   zdo_install.<locals>.<genexpr>  sF      
  C*E2 OwsHd35FNO
s   13z%[bold red]Error:[/] Could not fetch 'z' from any source.z[yellow]Hint:[/] GitHub API rate limit exhausted (unauthenticated: 60 requests/hour).
Set [bold]GITHUB_TOKEN[/] in your .env or install the [bold]gh[/] CLI and run [bold]gh auth login[/] to raise the limit to 5,000/hr.
metadatar   awaiting_nameFz[bold red]Invalid --name:[/] z`. Must be a lowercase identifier (letters, digits, hyphens, underscores; starts with a letter).
z&[bold red]Cannot install from URL:[/] z
[yellow]The SKILL.md has no `name:` in its frontmatter, and the URL path doesn't produce a valid identifier.[/]

Retry with an explicit name:
  [bold]/skills install z5 --name <your-name>[/]
  [bold]hermes skills install zm --name <your-name>[/]

[dim]Or ask the SKILL.md's author to add a `name:` field to its YAML frontmatter.[/]
z [dim]Installation cancelled.[/]
r7   r   r#   z[yellow]Warning:[/] 'z' is already installed at rp   zUse --force to reinstall.
r   z#[bold red]Installation blocked:[/] 
)append_audit_logBLOCKEDinvalid_pathz[dim]Quarantined to r$   z![bold]Running security scan...[/]rA   r:   )HUB_DIRsource_url_for_bundlez
scan-cache)r   
source_url	cache_dirfreshcachedz[dim]Scan provenance: z
; scanner scanner_versionz; hash bundle_hashrV   rulesnonez[dim]Source: r  z
; scanned 
scanned_atz	; rules: r  z$
[bold red]Installation blocked:[/] T)ignore_errors	_findingszUpstream Metadatablue)r   border_stylez[bold bright_cyan]This is an official optional skill maintained by Nous Research.[/]

It ships with hermes-agent but is not activated by default.
Installing will copy it to your skills directory where the agent can use it.

Files will be at: [cyan]z/skills/z/[/]zOfficial Skillr0   a  [bold yellow]You are installing a third-party skill at your own risk.[/]

External skills can contain instructions that influence agent behavior,
shell commands, and scripts. Even after automated scanning, you should
review the installed files before use.

Files will be at: [cyan]
Disclaimerr2   z[bold]Install ''?[/]Confirm [y/N]: n>   yyesr   z[bold green]Installed:[/] z[dim]Files: [/]
)BlueprintErrorblueprint_spec_for_installedregister_blueprint_suggestionz0[yellow]Blueprint block present but invalid:[/] z[bold cyan]Blueprint:[/] 'z#' is an automation (schedule [bold]z[/]).uc   [dim]Added to your suggestions — run[/] [bold]/suggestions[/] [dim]to schedule or dismiss it.[/]
u   [/]), but it wasn't added to your suggestions (already offered/dismissed, or the pending list is full — run [bold]/suggestions[/] to review).zh[dim]You can still schedule it any time by asking the agent or via[/] [bold]hermes cron add[/][dim].[/]
 clear_skills_system_prompt_cacheclear_snapshotz5[dim]Skill will be available in your next session.[/]zl[dim]Use /reset to start a new session now, or --now to activate immediately (invalidates prompt cache).[/]
)?r<   r   r   r  r  r  r  tools.skills_guardr  r  r  r=   rL   r>   ro   r   r   r   r   r   r   r|   r   ru   r   r   rA   splitr@   r`   get_installedr_   r   
ValueErrorr  rC   rs   relative_tort   r  r  shutilrmtreeverdictfindingsrf   r	   r   r   r?   r   r   r   fileskeystools.blueprintsr3  r4  r5  scheduleri   agent.prompt_builderr7  )5rA   r  r  r   r  r	  r
  r   r   r  r  r  r  r  r  r  rF   r   rE   rk   rl   _matched_sourcerate_limitedbundle_metar   chosenid_partslockr   extra_metadataq_pathexcr  scan_sourcer  r  resultscan_provenance	freshnessr$  allowedreasonmetadata_linesr   install_dirr   r3  r4  r5  spec_rec_err
registeredr7  s5                                                        r   
do_installr\    s     _^8A <D"4(G *(Wa@
GG#J<01$CJPW$X!D&/ 
 
 

 	
7
|CUVWGG4 	 GGI &*b17RK}}v{{kooo6V;MJ'--/FK+0K(GG//@ A8 8
  //%(6JCGG8 >+ ,/% 0114 6--	  //%(6JC+As3F;< FK+0K( DIDI
 }}h|'+?+AB
 }}
"8$$**3/x=Axx2/H =D!!&++.H	'}4NxXfOgNhijGG12'$4:;N'&*b9?R@"6* GG"6#5#5fmm6J6J6Q6Q#R"SSVWX GG/0}}
"  FL"- t\2. 	
 @/(0L(	FO GGv&'*73IGG
 :,-
.gom6T5UUX	Z IIog./96EGG
56j<(
)5'	> +6?OGV	7x@AfD15FKK++V^^01;	= 	5nEGGE$))N3;N]cde 		==J&GGE+ ,?+@*A\d(UX.jlImntnynymzz~@ '*  GGE+ ,?+@*A\d(UX.jlImntnynymzz~	@
 #%  	
/&++e45	,-335;;=F %GG78MM&5-ffkk8VU[\ ,GG()@)@)L(MNOGGl499V\\%6%6%89:%@A"pp	/<D 6t<J%0 >''+}}oU< ; 0 >''+}}o 6MM D 	M,DA 	
GH	  	Ao  	5cU"=>5FKK++^SX	G` +, 	F	  	5cU"=>fD15FKK++^SX	G*  	GGFxjPRSTD	8    		s   "\? '^$ )^< %
a" 0`8 Ba" a2 ?	^!A^^!$^98^9<	`5A&`00`58a=aa" aa" "	a/.a/2	a>=a>c                 t   ddl m}m} |xs t        } |       } ||      }d| vrt	        | ||      } | syt        | |      \  }}}	|s|j                  d|  d       y|j                          ddd	d
j                  |j                  d      }
|j                  dk(  rdn|j                  }d|j                   d|j                   d|j                   d|
 d| dd|j                   g}|j                  r-|j                  ddj                  |j                                |j!                  t#        |j$                               |j                  t'        dj                  |      d|j                                |rd|j(                  v r|j(                  d   }t+        |t,              r|j/                  dd      }|j1                  d      }dj                  |dd       }t3        |      dkD  r|dt3        |      dz
   dz  }|j                  t'        |d d!"             |j                          y)#z6Preview a skill's SKILL.md content without installing.r   r   r   r   Nz$[bold red]Error:[/] Could not find 'z' in any source.
r0   r1   r2   r3   r&   r7   z[bold]Name:[/] z[bold]Description:[/] z[bold]Source:[/] z[bold]Trust:[/] [r9   r$   z[bold]Identifier:[/] z[bold]Tags:[/] rV   r  zSkill: r   r   utf-8replaceerrorsr   

... ( more lines)zSKILL.md Previewz%hermes skills install <id> to install)r   subtitle)r<   r   r   r=   rL   ro   r>   r   rC   r   r   r   rA   tagsr]   r`   extendrf   r   r	   rC  r^   bytesdecoder;  r@   )rA   r   r   r   rF   r   rE   rk   rl   rH  rJ   rK   
info_linescontentrc   previews                   r   
do_inspectrm    s   A8A<D"4(G
*(Wa@
$CJPW$X!D&/	6zlBTUVGGI+hW[[\`\l\lnstK $z 9*t?O?OK $))%
 !1!1 23
DKK=)
K=+c:
01J yyODIIdii,@+ABC24::>?GGE$))J'/DEF*,,,z*gu%nnWYn?Gd#))E#2J'u:?3u:?"3<@@G	g%7BijkGGIr   c           
      8   ddl m}m}m} t	        dt        |d            }dddddddd	dd
d
d
dd	} |       } ||      } ||d||d      \  }	}
}|	sg ddddS i }|	D ]h  }j                  |j                  d      }|j                  |vs-|j                  ||j                     j                  d      kD  sZ|||j                  <   j t        |j                               }|j                  fd       t        |      }t	        d||z   dz
  |z        }t	        dt        | |            } | dz
  |z  }||t        ||z   |       }|D cg c]<  }|j                  |j                  |j                  |j                  |j                  d> c}| ||dS c c}w )zPaginated hub browse for programmatic callers (e.g. TUI gateway).

    Returns ``{"items": [...], "page": int, "total_pages": int, "total": int}``.
    r   r   r#   r   r   r   r3   i     r   r   r   r:   r   )r   r   r!   r   )rb   r   r   r   c                     j                  | j                  d       | j                  dk7  | j                  j	                         fS r   r   r   s    r   r   zbrowse_skills.<locals>.<lambda>g  s:    !B BAHHPZDZ\]\b\b\h\h\jk r   r   )r   r   r   trustrA   )r<   r   r   r   r   r   r   rC   rA   r   r   r   r@   r   r   r   )r   r   r   r   r   r   r   r   rE   r   _counts
_timed_outr   r   r   r   r   r   r   r   r   s                       @r   browse_skillsrt  E  s   
  As9c*+IAA>K *.3S')SR/1bsT <D"4(G (?r->b($K* Qq1EED #q}}a0<<t#tkood1<<>P>\>\^_.`'`!"D# 4;;=!GLLkLlLEa%)+a/I=>Kq#dK()DAX"EUY%6!>?J R\]LM 66!--188]]!,,H ]" ]s   AFc                 h   ddl m}m}  G d d      } |       } |       } ||      }| }d|vrt        |||      }|syt	        ||      \  }}	}
|sy|j
                  |j                  |j                  |j                  |j                  rt        |j                        ng d}|	rd|	j                  v r|	j                  d   }t        |t              r|j                  d	d
      }|j                  d      }dj!                  |dd       }t#        |      dkD  r|dt#        |      dz
   dz  }||d<   |S )z=Skill metadata (+ SKILL.md preview) for programmatic callers.r   r^  c                       e Zd Zd Zy)inspect_skill.<locals>._Qc                      y r   rY   )selfaks      r   r>   zinspect_skill.<locals>._Q.print{  s    r   N)__name__
__module____qualname__r>   rY   r   r   _Qrw  z  s    	r   r  r   N)r   r   r   rA   rf  r   r_  r`  ra  r  r   rc  rd  skill_md_preview)r<   r   r   rL   ro   r   r   r   rA   rf  r   rC  r^   rh  ri  r;  r`   r@   )rA   r   r   r  rF   r   rE   identrk   rl   _r   rk  rc   rl  s                  r   inspect_skillr  v  s-   A  	A<D"4(GE
%#E7A65eWEOD&!		''++oo#'99TYY"C *,,,z*gu%nnWYn?Gd#))E#2J'u:?3u:?"3<@@G")Jr   r!   enabled_onlyc                 h   ddl m}m} ddlm} ddlm} ddlm} |xs t        } |         |       }	|	j                         D 
ci c]  }
|
d   |

 }}
t         |             } |d      } |       }d	}|r|d
z  }t        |      }|j                  dd       |j                  dd       |j                  dd       |j                  dd       |j                  dd       d}d}d}d}d}t        |d       D ]  }|d   }|j                  dd      }|j                  |      }|r'd}|j                  dd      }|j                  dd      }n||v rd}d}d}nd}d}d}| dk7  r| |k7  rp||v}|r|sy|dk(  r|dz  }n|dk(  r|dz  }n|dz  }|r|dz  }d }n|dz  }d!}d"d#d$dd%j                  |d      }|d&k(  rd&n|} |j!                  |||d'| d(|  d)|        |j#                  |       d*| d+| d,| d-}!|r
|!d.| d/z  }!n|!d.| d0| d1z  }!|!d2z  }!|j#                  |!       y3c c}
w )4u  List installed skills, distinguishing hub, builtin, and local skills.

    Args:
        source_filter: ``all`` | ``hub`` | ``builtin`` | ``local``.
        enabled_only: If True, hide disabled skills from the output.

    Enabled/disabled state is resolved against the currently active profile's
    config — ``hermes -p <profile> skills list`` reads that profile's
    ``skills.disabled`` list because ``-p`` swaps ``HERMES_HOME`` at process
    start.  No explicit profile flag needed here.
    r   )r  r  )_read_manifest)_find_all_skills)get_disabled_skill_namesr   T)skip_disabledzInstalled Skillsz (enabled only)r   r   r+   r'   Categoryr&   r%   r)   Statusc                 6    | j                  d      xs d| d   fS )Nr  r:   r   r   )ss    r   r   zdo_list.<locals>.<lambda>  s    1553D3JAfI2V r   r   r  r:   hubr   rC   r6   r4   localr   r#   z[bold green]enabled[/]z[dim red]disabled[/]r0   r1   r2   )r4   r5   r6   r  r7   r8   r9   r$   [dim]z hub-installed, z
 builtin, z localu    — z enabled shownz
 enabled, z	 disabledr2  N)r<   r  r  tools.skills_syncr  tools.skills_toolr  agent.skill_utilsr  r=   list_installedr   r
   rB   ra   r   rD   r>   )"r!   r  r   r  r  r  r  r  rF   rM  ehub_installedbuiltin_names
all_skillsdisabled_namesr   rI   	hub_countbuiltin_countlocal_countenabled_countdisabled_countrz   r   r  	hub_entrysource_typesource_displayrq  
is_enabledstatus_cellrJ   rK   summarys"                                     r   do_listr    s    >02:8A=D+/+>+>+@AaQvY\AMA()M "5J-/NE""E	V;/	Zu-	XU+	WE*	XU+IMKMN
(VW )gV}99Z,!%%d+	K&]]8U;NMM-=E]"#K&NE!K$NEE!m{&B/

%NII%QM1KQM2KaN0K"/GRZejkoopuw|}$2j$@jedHn+a}TW6XZefS)gV GGENi[ 0z+V\]GU=/88U=/N3C9MMwGGGGU Bs   H/c           	         ddl m} |xs t        } ||       }|s|j                  d       yt	        d      }|j                  dd	
       |j                  dd
       |j                  dd
       |D ]E  }|j                  |j                  dd      |j                  dd      |j                  dd             G |j                  |       t        d |D              }|j                  d| dt        |       d       y)z0Check hub-installed skills for upstream updates.r   )check_for_skill_updatesr   z*[dim]No hub-installed skills to check.[/]
NzSkill Updatesr   r   r+   r'   r%   r&   r  r   r:   r   r[   c              3   J   K   | ]  }|j                  d       dk(  sd  yw)r[   update_availabler#   Nr  )rZ   r   s     r   r\   zdo_check.<locals>.<genexpr>  s!     [U81DHZ1Zq[s   ##r  z update(s) available across z checked skill(s)[/]
)
r<   r  r=   r>   r
   rB   rD   r   r   r@   )r   r   r  rF   rG   rI   r   update_counts           r   do_checkr    s    88A%40G	=>(E	V;/	XU+	XU+ _eii+UYYx-DeiiPXZ\F]^_ GGEN[g[[LGGeL>!=c'l^Kabcr   c                    ddl m}m} |xs t        } |       } ||       D cg c]  }|j	                  d      dk(  s| }}|s|j                  d       y|D ]^  }|j                  |d         }|rt        |j	                  d	d
            nd
}	|j                  d|d           t        |d   |	d|       ` |j                  dt        |       d       yc c}w )z2Update hub-installed skills with upstream changes.r   )r  r  r  r[   r  z[dim]No updates available.[/]
Nr   rp   r:   z[bold]Updating:[/] rA   Tr  r  r   z[bold green]Updated z skill(s).[/]
)
r<   r  r  r=   r   r>   r<  rv   r\  r@   )
r   r   r  r  rF   rM  r   updates	installedr  s
             r   	do_updater    s    E8A=D"9t"Dr		RZH[_qHqurGr	12 R&&uV}5	\e5immNTV6WXkm	%eFm_565&qQ	R GG"3w<.@A ss
   CCdeepc           	         ddl m}m} ddlm}m} |xs t        } |       }|j                         }	|	s|j                  d       y|	}
| r0|	D cg c]  }|d   | k(  s| }
}|
s|j                  d|  d       y|j                  d	t        |
       d
       |rddl
m}m} |
D ]  }||d   z  }|j                         s|j                  d|d    d|d           9 |||j                  d|d               }|j                   ||             |r"|j                    |      |d                |j                           yc c}w )u   Re-run security scan on installed hub skills.

    When ``deep=True``, also runs an opt-in AST-level diagnostic on Python
    files (review aid only — not a security gate; skills_guard.py verdicts
    are unchanged).
    r   )r  r   
scan_skillr  z*[dim]No hub-installed skills to audit.[/]
Nr   z[bold red]Error:[/] 'z ' is not a hub-installed skill.
z
[bold]Auditing z skill(s)...[/]
)ast_scan_pathformat_ast_reportrp   z[yellow]Warning:[/] u    — path missing: rA   r   r   )
skill_name)r<   r  r   r:  r  r  r=   r  r>   r@   tools.skills_ast_auditr  r  r   r   )r   r   r  r  r   r  r  rF   rM  r  targetsr  r  r  r   
skill_pathrR  s                    r   do_auditr  *  sO    9A8A=D##%I	=>G'=1V9+<1==GG+D61RSTGGG~->?@K %"77
  "GG*5=/9LUSaMbLcdeJuyyuX/WX	"6*+GG%mJ&?ERXMZ[		 >s   EEc                    ddl m} |xs t        }|sS|j                  d|  d       	 t	        d      j                         j                         }|dvr|j                  d       y	 ||       \  }}|rK|j                  d
| d       |r	 ddl	m
}	  |	d       y	|j                  d       |j                  d       y	|j                  d| d       y	# t        t        f$ r d}Y w xY w# t        $ r Y y	w xY w)z/Remove a hub-installed skill with confirmation.r   )uninstall_skillz
[bold]Uninstall 'r-  r.  r/  >   r0  r1  [dim]Cancelled.[/]
N[bold green]r2  r6  Tr8  5[dim]Change will take effect in your next session.[/]i[dim]Use /reset to start a new session now, or --now to apply immediately (invalidates prompt cache).[/]
[bold red]Error:[/] r  )r<   r  r=   r>   r   r|   r?   r   r   rG  r7  ri   )
r   r   r  r	  r  rF   r   successmsgr7  s
             r   do_uninstallr  X  s    18A 	%dV512	,-335;;=F %GG*+"4(LGS	,se5)*Q0E GGKLGG  A  B	&se2./' +, 	F	  s#   'C C+ C('C(+	C76C7restorec                 V   ddl m} |xs t        }|sf|rd|j                  d|  d       |j                  d       	 t	        d      j                         j                         }|dvr|j                  d	       y
 || |      }|d   s|j                  d|d    d       y
|j                  d|d    d       |j                  d      xs i }	|	j                  d      r'|j                  ddj                  |	d          d       |	j                  d      r'|j                  ddj                  |	d          d       |j                          |r	 ddlm}
  |
d       y
|j                  d       |j                  d       y
# t        t        f$ r d}Y 5w xY w# t        $ r Y y
w xY w)zNReset a bundled skill's manifest tracking (+ optionally restore from bundled).r   )reset_bundled_skillz
[bold]Restore 'z' from bundled source?[/]zK[dim]This will DELETE your current copy and re-copy the bundled version.[/]r.  r/  >   r0  r1  r  Nr  okr  messager  r  r$   syncedcopiedz[dim]Copied: rV   updatedz[dim]Updated: r6  Tr8  r  r  )r  r  r=   r>   r   r|   r?   r   r   r   r`   rG  r7  ri   )r   r  r   r  r	  r  rF   r   rR  r  r7  s              r   do_resetr  {  s   
 68AG	#D6)BCD	]^	,-335;;=F %GG*+ w7F$<	&vi'8&9<=GGl6),-S12ZZ!'RFzz(	-		&*: ;<C@Azz)	.6)+<!= >cBCGGI	M,DA 	
GH	|}9 +, 	F	0  		s#   'F F FF	F('F(c           	         ddl m} | xs t        } |       }|r7ddl}|j	                   |j
                  |D cg c]  }|d   	 c}             y|s|j	                  d       y|j	                  dt        |       d       |D ]  }|j	                  d|d            |j	                          |j	                  d	       |j	                  d
       |j	                  d       yc c}w )zFList bundled skills the user has edited (which `hermes update` keeps).r   )!list_user_modified_bundled_skillsNr   uH   [dim]No user-modified bundled skills — everything tracks upstream.[/]

[bold]zK user-modified bundled skill(s)[/] [dim](kept as-is by `hermes update`):[/]z  [yellow]~[/] z0[dim]See changes:   hermes skills diff <name>[/]zY[dim]Resume updates: hermes skills reset <name>          (keep your copy, re-baseline)[/]z>[dim]Revert to stock: hermes skills reset <name> --restore[/]
)r  r  r=   r   r>   r   r@   )r   r   r  rF   modifiedr   mr   s           r   do_list_modifiedr    s     D8A02H	


x8!AfI89:	[\GGhs8}o &7 7 8 3	/%-123GGIGG>?GGghGGMN 9s   C%c                 ~   ddl m} |xs t        } ||       }|d   s|j                  d|d    d       y|d   s|j                  d	|d    d
       y|j                  d|d    d
       |d   D ]#  }|d   }|dk(  r|d   j	                         D ]  }|j                  d      r'|j                  d      s|j                  d	| d       ;|j                  d      r'|j                  d      s|j                  d| d       s|j                  d      r|j                  d| d       |j                  |d        |dk(  r|j                  d|d           |dk(  r|j                  d|d           |j                  d|d    d       & |j                          |j                  d |  d!       y)"zKShow how the user's copy of a bundled skill differs from the stock version.r   )diff_bundled_skillr  r  r  r  Nr  z[green]r2  r  diffsr[   diff+z+++r$   ----z[red]z@@z[cyan]F)	highlightaddedz[green]+ only in your copy:[/] ru   removedz[red]- only in stock:[/] z
[yellow]~ z:[/] binary file differsz&[dim]Revert with: hermes skills reset z --restore[/]
)r  r  r=   r>   
splitlinesr   )r   r   r  rF   rR  r   r[   lines           r   do_diffr    s   48A%F$<	&vi'8&9<=*	'&+,E23GGhvi()/0 JxZf002 3??3'0FGGgdV3/0__S)$//%2HGGeD6-.__T*GGfTF#./GGDEG23 wGG5eFm_EFy GG/f?@GGjv/GHI%J& GGIGG4TF/JKr   removec                    ddl m}m} |xs t        } |d      }|d   s|j	                  d|d    d       y|j	                  d	|d    d
       |j	                  d|d    d
       | s|j	                  d       y |d      }|d   }	|d   }
|	s|j	                  d       y|j	                  dt        |	       d       |j	                  ddj                  |	       d
       |
r|j	                  dt        |
       d       |sO|j	                  d       	 t        d      j                         j                         }|dvr|j	                  d       y |d      }|j	                  d	|d    d
       |d   r'|j	                  ddj                  |d          d
       |j	                          |r	 ddlm}  |d        yy# t        t        f$ r d}Y w xY w# t        $ r Y yw xY w)!a5  Opt the active profile out of bundled-skill seeding.

    Always writes the .no-bundled-skills marker (stop future seeding). With
    ``remove``, also deletes already-present bundled skills that are pristine
    (manifest-tracked AND unmodified); user-edited and non-bundled skills are
    never touched.
    r   )set_bundled_skills_opt_outremove_pristine_bundled_skillsTr  r  r  r  Nr  r$   z[dim]Marker: markerzs[dim]Existing skills on disk were left in place. Re-run with --remove to also delete unmodified bundled skills.[/]
)dry_runr  skippedz`[dim]No pristine bundled skills to remove (nothing tracked, or all are user-modified/local).[/]
z
[bold]Will remove z  unmodified bundled skill(s):[/]r  rV   z[dim]Keeping z# (user-modified or non-bundled).[/]zZ[dim]This deletes the on-disk copies. User-edited and hub/local skills are NOT touched.[/]r.  r/  >   r0  r1  z([dim]Marker kept; no skills deleted.[/]
Fz[dim]Removed: r6  r8  )r  r  r  r=   r>   r@   r`   r   r|   r?   r   r   rG  r7  ri   )r  r   r  r	  r  r  rF   resrl  
candidateskeptr   rR  r7  s                 r   
do_opt_outr    s   
 	8A %T
*Ct9	&s9~&6b9:GGl3y>*#./GGmCM?#./	 V 	W -T:G#J9D	 J 	KGG"3z?"33STUGGeDIIj)*#./	-D	{*MNO	 7 	8	,-335;;=F %GG?@+E:FGGl6),-S12i	.6)+<!= >cBCGGI	M,DA  +, 	F	   		s$   'G 7G GG	G+*G+syncc                 |   ddl m}m} |xs t        } |d      }|d   s|j	                  d|d    d       y|j	                  d	|d    d
       | rK |d      }t        |j                  dg             }|j	                  d| d       |r	 ddlm}	  |	d       |j	                          y# t        $ r Y w xY w)zRemove the opt-out marker so bundled-skill seeding resumes.

    With ``sync``, immediately re-seed bundled skills instead of waiting for
    the next ``hermes update``.
    r   )r  sync_skillsFr  r  r  r  Nr  r$   T)quietr  z[dim]Re-seeded z bundled skill(s).[/]r6  r8  )
r  r  r  r=   r>   r@   r   rG  r7  ri   )
r  r   r	  r  r  rF   r  r  r  r7  s
             r   	do_opt_inr  1  s     J8A
$U
+Ct9	&s9~&6b9:GGl3y>*#./4(VZZ"-.	/&)>?@Q0E GGI  s   B/ /	B;:B;c                    ddl m} |xs t        }|rf|sd|j                  d|  d       |j                  d       	 t	        d      j                         j                         }|dvr|j                  d	       y
 || |      }|j                  d      s&|j                  d|j                  dd       d       y
|j                  d|d    d       |j                  d      r'|j                  ddj                  |d          d       |j                  d      r'|j                  ddj                  |d          d       |j                  d      rK|j                  ddj                  |d          d       |j                  d|j                  d       d       |j                          |r	 ddlm}	  |	d       y
y
# t        t        f$ r d}Y sw xY w# t        $ r Y y
w xY w)z>Backfill or restore official optional skills from repo source.r   )restore_official_optional_skillz(
[bold]Restore official optional skill 'z' from repo source?[/]zm[dim]Existing matching active copies will be moved to a restore backup before copying the official source.[/]r.  r/  >   r0  r1  r  Nr  r  r  r  zRepair failedr  r  r$   restoredz[dim]Restored: rV   
backfilledz[dim]Backfilled provenance: 	backed_upz[dim]Backed up: z[dim]Backup dir: 
backup_dirr6  Tr8  )r  r  r=   r>   r   r|   r?   r   r   r   r`   rG  r7  ri   )
r   r  r   r  r	  r  rF   r   rR  r7  s
             r   do_repair_officialr  P  s   
 B8A|	;D6AWXY	  	A	,-335;;=F %GG*+,T7CF::d	&vzz)_'M&NbQRGGl6),-S12zz*	/$))F:,>"?!@DEzz,	.tyy9M/N.OsSTzz+	"499VK-@#A"B#FG	#FJJ|$<#=SABGGI	M,DA + +, 	F	2  		s#   'G 1G GG	G&%G&actionrepoc                 p   ddl m} |xs t        } |       }| dk(  r|j                         }|s|j	                  d       yt        d      }|j                  dd	
       |j                  dd
       |D ]\  }|j                  d      xs% |j                  d      xs |j                  dd      }	|j                  |	|j                  dd             ^ |j	                  |       |j	                          y| dk(  rQ|s|j	                  d       y|j                  |      r|j	                  d| d       y|j	                  d| d       y| dk(  rQ|s|j	                  d       y|j                  |      r|j	                  d| d       y|j	                  d| d       y|j	                  d|  d       y)z)Manage taps (custom GitHub repo sources).r   TapsManagerr   z?[dim]No custom taps configured. Using default sources only.[/]
NzConfigured Tapsr   Repor+   r'   r   r&   r  r   ru   unknownskills/addzK[bold red]Error:[/] Repo required. Usage: hermes skills tap add owner/repo
z[bold green]Added tap:[/] r  z[yellow]Tap already exists:[/] r  zN[bold red]Error:[/] Repo required. Usage: hermes skills tap remove owner/repo
z[bold green]Removed tap:[/] z#[bold red]Error:[/] Tap not found: z![bold red]Unknown tap action:[/] z. Use: list, add, remove
)r<   r   r=   	list_tapsr>   r
   rB   r   rD   r  r  )
r  r  r   r   rF   mgrtapsrI   tlabels
             r   do_tapr
  z  s   ,8A
-C}}GGVW-.{3u- 	;AEE&MNQUU6]NaeeFI6NEMM%vy!9:	; 	
			5GGbc774=GG0b9:GG5dV2>?	8	GGef::dGG24&;<GG9$rBC 	
3F8;UVWr   r  targetc                    ddl m}m} ddlm}m} |xs t        }t        |       }	|	j                         s||	z  }	|	j                         r|	dz  j                         s|j                  d|	 d       yddl}
|	dz  j                  d	      }|j                  d
      }i }|j                  d      rFddl} |j                   d|dd       }|r*	 |
j#                  |d|j%                         dz          xs i }|j)                  d|	j*                        }|j)                  dd      }|s|j                  d       y|j                  d| d        ||	d      }|j                   ||             |j,                  dk(  r|j                  d       y|dk(  r|s|j                  d       y |       }|j/                         s|j                  dt1                d       y|j                  d| d| d       t3        |	|||      \  }}|r|j                  d| d        y|j                  d!| d       y|d"k(  r|j                  d#       y|j                  d$| d%       y# |
j&                  $ r Y }w xY w)&zFPublish a local skill to a registry (GitHub PR or ClawHub submission).r   )r   r   r  r   z)[bold red]Error:[/] No SKILL.md found at r  Nr_  encodingu   ﻿r  z
\n---\s*\nr   r   r   r:   zG[bold red]Error:[/] SKILL.md must have a 'description' in frontmatter.
z[bold]Scanning 'z' before publish...[/]ry  r   	dangerousz<[bold red]Cannot publish a skill with DANGEROUS verdict.[/]
r   zz[bold red]Error:[/] --repo required for GitHub publish.
Usage: hermes skills publish <path> --to github --repo owner/repo
zH[bold red]Error:[/] GitHub authentication required.
Set GITHUB_TOKEN in z/.env or run 'gh auth login'.
z[bold]Publishing 'z' to z...[/]r  r2  r  r   za[yellow]ClawHub publishing is not yet supported. Submit manually at https://clawhub.ai/submit[/]
z[bold red]Unknown target:[/] z. Use 'github' or 'clawhub'.
)r<   r   r   r:  r  r  r=   r   is_absoluter   r>   yaml	read_textlstripr   research	safe_loadr   	YAMLErrorr   r   rA  is_authenticatedr   _github_publish)r  r  r  r   r   r   r  r  rF   ru   r  skill_mdfmr  r   r   r   rR  r   r  r  s                        r   
do_publishr    s    8A8A
D D ;;=
!2 : : <	;D6DE z!,,g,>Hx(H	B5!		-!"6^^HQu{{}q/@$ABHb 66&$))$D&&+K	Z[ GGtf$:;<V,FGGv&'~~$	OPGG Z [|$$&GG ++>+@*AA`b c	$TF%vV<=&tT4>GGl3%u-.GG*3%r23	9		 D 	E 	
/x7UVWQ >> s   )I" "I54I5r  target_repoc           
         ddl }|j                         }	 |j                  d| d|d      }|j                  dv r|j	                         }|d   }n$|j                  d	k(  ry
dd| d|j                   fS 	 	 |j                  d| |d      }|j	                         j                  dd      }
	 |j                  d| d|
 |d      }|j	                         d   d   }d| }	 |j                  d| d|dd| |d       | j                  d      D ]  }|j                         st        |j                  |             }d| d| }	 ddl}|j                  |j                               j                         }|j!                  d| d| |dd | d!| ||d"        	 |j                  d| d$|dd%| d&| d'|j#                  d      d    d(| |
d)      }|j                  d*k(  r'|j	                         j                  d+d,      }d-d.| fS dd/|j                   d0|j$                  dd1  fS # |j
                  $ r}	dd|	 fcY d}	~	S d}	~	ww xY w# t        $ r d}
Y w xY w# t        $ r}	dd|	 fcY d}	~	S d}	~	ww xY w# t        $ r}	dd|	 fcY d}	~	S d}	~	ww xY w# t        $ r}	dd#| d|	 fcY d}	~	c S d}	~	ww xY w# |j
                  $ r}	dd2|	 fcY d}	~	S d}	~	ww xY w)3zHCreate a PR to a GitHub repo with the skill. Returns (success, message).r   Nzhttps://api.github.com/repos/z/forksr   )headerstimeout>   r      	full_namei  )Fz+GitHub token lacks permission to fork reposFzFailed to fork r   zNetwork error forking repo:    default_branchmainz/git/refs/heads/objectshazFailed to get base branch: z
add-skill-z	/git/refszrefs/heads/)refr'  )r  r   r   zFailed to create branch: *r  r   z
/contents/zAdd z skill: )r  rk  branchzFailed to upload z/pullszAdd skill: zSubmitting the `zd` skill via Hermes Skills Hub.

This skill was scanned by the Hermes Skills Guard before submission.:)r   bodyheadbase   html_urlr:   TzPR created: zFailed to create PR:  r   zNetwork error creating PR: )httpxget_headerspoststatus_coder   	HTTPErrorr   ri   r   is_filers   r>  base64	b64encode
read_bytesri  putr;  text)r  r  r  r   r2  r  respfork	fork_repor  r$  base_shabranch_namefrelupload_pathr8  content_b64pr_urls                      r   r  r    s     G9zz+K=?R  
 z)99;D[)I$GOK=4;K;K:LMMM	  yy+K=9R  
 )96B
8yy+I;6F~FVWR  
 99;x(/
 zl+K6

+I;i@R&{m4XF 	 	
 c" 9yy{!--
+,
|1SE2	9 **1<<>:AACKII/	{*[MR!%j\#?*)  9*8zz+K=?R&zl3*:, 7_ `$??3/231[MB&  

 s"YY[__Z4F<x0001$2B2B1C1TYYtPS_DUVVVQ ?? 94QC8889      83A37778  61!5556*  	9-cU"QC888	9* ?? 83A37778s   AH9 "H9 87I 00I. &J AJ(&A1K
  K
 9IIIII+*I+.	J7J=JJ	J%J J% J%(	K1	K:KK
K*K%K*%K*output_pathc                 ^   ddl m}m} |xs t        } |       } |       }|j	                         }|j                         }dt        d      j                  j                  t        d      j                  j                        j                         |D 	cg c]n  }	|	d   |	j                  dd      |	j                  dd      d	|	j                  d
d      v r.t        t        |	j                  d
d            j                        nddp c}	|d}
t!        j"                  |
dd      dz   }| dk(  r ddl}|j&                  j)                  |       yt        |       }|j+                  |d       |j-                  d|        |j-                  dt/        |       dt/        |       d       yc c}	w )z?Export current hub skill configuration to a portable JSON file.r   )r  r   z0.1.0datetimer   r   r:   rA   r   rp   )r   r   rA   r  )hermes_versionexported_atskillsr  r   F)r   ensure_asciir  r  Nr_  r  z"[bold green]Snapshot exported:[/] r  z skill(s), z tap(s)[/]
)r<   r  r   r=   r  r  
__import__rI  nowtimezoneutc	isoformatr   rs   r   rt   r   r   sysstdoutwrite
write_textr>   r@   )rG  r   r  r   rF   rM  r  r  tap_listr   snapshotr   rS  r   s                 r   do_snapshot_exportrY  L  s~   98A=D=D##%I~~H "!*-66::z"++//

)+ #	
  f))Hb1#iib9"eii&CC  UYY~r%B C J JKIK	
 H$ jj!%@4GGc

!;w1	4SE:;	%I'{3x=/NO+	
s   A3F*
input_pathc                    ddl m} |xs t        }t        |       }|j	                         s|j                  d| d       y	 t        j                  |j                  d            }|j                  d	g       }|rc |       }|D ]9  }	|	j                  d
d      }
|
s|j                  |
|	j                  dd             ; |j                  dt        |       d       |j                  dg       }|s|j                  d       y|j                  dt        |       d       |D ]  }|j                  dd      }|j                  dd      }|s&|j                  d|j                  dd       d       O|j                  d|j                  d|       d       t        ||||        |j                  d       y# t        j                  $ r |j                  d| d       Y yw xY w)z'Re-install skills from a snapshot file.r   r  z$[bold red]Error:[/] File not found: r  Nr_  r  z$[bold red]Error:[/] Invalid JSON in r  r  r:   ru   r  z[dim]Restored z
 tap(s)[/]rL  z*[dim]No skills in snapshot to install.[/]
z[bold]Importing z skill(s) from snapshot...[/]
rA   r  z+[yellow]Skipping entry with no identifier: r   ?r$   z
[bold]--- z ---[/]r  z)[bold green]Snapshot import complete.[/]
)r<   r   r=   r   r   r>   r   loadsr  JSONDecodeErrorr   r  r@   r\  )rZ  r  r   r   rF   inprX  r  r  tapr  rL  r   rA   r  s                  r   do_snapshot_importra  t  s    -8A
z
C::<	6se2>?::cmmWm=> <<#Dm 	:C7762&Dcggfi89	: 	
.T:67 \\(B'F	=>GGs6{m+JKL JYY|R0
99Z,GGA%))FTWBXAYY\]^	*UYYvz:;7CD:qIJ GG89?  	6se2>?s   %F< <(G'&G'c                 "   t        | dd      }|dk(  r-t        | j                  | j                  | j                         y|dk(  r9t        | j                  | j                  | j                  t        | dd             y|d	k(  rIt        | j                  | j                  | j                  t        | d
d      t        | dd      xs d       y|dk(  rt        | j                         y|dk(  r#t        | j                  t        | dd             y|dk(  rt        t        | dd             y|dk(  rt        t        | dd             y|dk(  r$t!        t        | dd      t        | dd             y|dk(  rt#        | j$                         y|dk(  r/t'        | j$                  t        | dd      t        | d
d             y|dk(  rt)        t        | dd             y|dk(  rt+        | j$                         y|dk(  r$t-        t        | d d      t        | d
d      !       y|d"k(  rt/        t        | d#d      $       y|d%k(  r/t1        | j$                  t        | dd      t        | d
d             y|d&k(  r/t3        | j4                  t        | d'd(      t        | d)d      *       y|d+k(  rft        | d,d      }|d-k(  rt7        | j8                         y|d.k(  r#t;        | j<                  t        | d/d      0       yt>        jA                  d1       y|d2k(  rOt        | d3d      }t        | d)d      xs t        | dd      }|st>        jA                  d4       ytC        ||5       yt>        jA                  d6       t>        jA                  d7       y)8uK   Router for `hermes skills <subcommand>` — called from hermes_cli/main.py.skills_actionNbrowse)r   r   r   r  r   F)r   r"   r   installr1  r   r:   )r  r  r  r
  rh   r   r  )r!   r  checkr  r   auditr  )r   r  	uninstallresetr  )r  r  list-modified)r   r  zopt-outr  )r  r  zopt-inr  )r  zrepair-officialpublishtor   r  )r  r  rX  snapshot_actionexportimportr  r'  z.Usage: hermes skills snapshot [export|import]
r`  
tap_actionz+Usage: hermes skills tap [list|add|remove]
)r  zUsage: hermes skills [browse|search|install|inspect|list|list-modified|diff|check|update|audit|uninstall|reset|opt-out|opt-in|publish|snapshot|tap]
z2Run 'hermes skills <command> --help' for details.
)"r   r  r   sizer   r   r   r"   r\  rA   r  r  rm  r  r  r  r  r  r   r  r  r  r  r  r  r  r  rY  outputra  r   r=   r>   r
  )argsr  snap_actionrp  r  s        r   skills_commandru    s   T?D1FtyyDIIdkkJ	8	$**T[[

!$6	8	9	4??T]]$** 'eU ;!(vr!:!@b	B 
9	4??#	6	++ ~u=	
 
7	gdFD12	8	wtVT23	7	gdFD1dFE2	4	;	TYY	7	GD)U$C%dE59	;	?	"vu!=>	6				9	'$%8 'eU ;	=	8	wtVU34	$	$499gdIu.M(/eU(C	E	9	OO4x0vr*	

 
:	d$5t<("t{{+H$tzzw1NONNLM	5T<6
tVR(EGD&",ENNIJz%  o  	pLMr   cmdc           	         |xs t         }| j                         j                         }|r|d   j                         dk(  r|dd }|st	        |       y|d   j                         }|dd }|dk(  rd}d}d}d}	|	t        |      k  r||	   dk(  r)|	dz   t        |      k  r	 t        ||	dz            }|	d	z  }	n]||	   d
k(  r)|	dz   t        |      k  r	 t        ||	dz            }|	d	z  }	n,||	   dk(  r|	dz   t        |      k  r||	dz      }|	d	z  }	n|	dz  }	|	t        |      k  rt        ||||       y|dk(  r|s|j                  d       yd}d}
d}g }d}	|	t        |      k  r||	   dk(  r|	dz   t        |      k  r||	dz      }|	d	z  }	nZ||	   dk(  r)|	dz   t        |      k  r	 t        ||	dz            }
|	d	z  }	n)||	   dk(  rd}|	dz  }	n|j                  ||	          |	dz  }	|	t        |      k  rt        dj                  |      ||
||       y|dk(  r|s|j                  d       y|d   }d}d}d}d|v }d|v }t        |      D ]D  \  }	}|dk(  r|	dz   t        |      k  r	||	dz      }%|dk(  s+|	dz   t        |      k  s=||	dz      }F t        |||||||       y|dk(  r%|s|j                  d       yt        |d   |        y|d!k(  rId}d"|v xs d#|v }d|v r*|j!                  d      }|dz   t        |      k  r||dz      }t#        |||$       y|d%k(  r|r|d   nd}t%        ||&       y|d'k(  r|r|d   nd}t'        ||&       y|d(k(  r0|r|d   j)                  d)      s|d   nd}d*|v }t+        |||+       y|d,k(  r-|s|j                  d-       yd}d|v }t-        |d   |||.       y|d/k(  rT|s4|j                  d0       |j                  d1       |j                  d2       y|d   }d3|v }d|v }t/        |||d|4       y|d5v rt1        |d|v 6       y|d7k(  r%|s|j                  d8       yt3        |d   |        y|d9k(  r~|s|j                  d:       y|d   }d;}d}t        |      D ]C  \  }	}|d<k(  r|	dz   t        |      k  r||	dz      }|d=k(  s*|	dz   t        |      k  s<||	dz      }E t5        ||||>       y|d?k(  rx|s|j                  d@       y|d   }|dAk(  rt        |      dkD  rt7        |d   |        y|dBk(  r$t        |      dkD  rd|v }t9        |d   ||C       y|j                  d@       y|dDk(  r9|st;        d!|        y|d   }t        |      dkD  r|d   nd}t;        |||E       y|dFv rt	        |       y|j                  dG|        t	        |       y# t        $ r Y w xY w# t        $ r Y w xY w# t        $ r Y 7w xY w)Ha  
    Parse and dispatch `/skills <subcommand> [args]` from the chat interface.

    Examples:
        /skills search kubernetes
        /skills install openai/skills/skill-creator
        /skills install openai/skills/skill-creator --force
        /skills install https://example.com/path/SKILL.md
        /skills inspect openai/skills/skill-creator
        /skills list
        /skills list --source hub
        /skills check
        /skills update
        /skills audit
        /skills audit my-skill
        /skills audit --deep
        /skills audit my-skill --deep
        /skills uninstall my-skill
        /skills tap list
        /skills tap add owner/repo
        /skills tap remove owner/repo
    r   /skillsr#   Nrd  r   r   z--pager   z--sizez--source)r   r   r   r   r  z[bold red]Usage:[/] /skills search <query> [--source skills-sh|github|official|nvidia|openai|anthropic|huggingface] [--limit N] [--json]
ro  Fz--limitz--jsonTr1  )r   r"   r   r   re  zm[bold red]Usage:[/] /skills install <identifier-or-url> [--name <name>] [--category <cat>] [--force] [--now]
r:   z--forcez--nowz
--categoryz--name)r  r  r  r	  r
  r   rh   z1[bold red]Usage:[/] /skills inspect <identifier>
r   r   z--enabled-onlyz	--enabled)r!   r  r   rf  )r   r   r   rg  z--z--deep)r   r   r  rh  z5[bold red]Usage:[/] /skills uninstall <name> [--now]
)r   r  r	  ri  z=[bold red]Usage:[/] /skills reset <name> [--restore] [--now]
zd[dim]Clears the bundled-skills manifest entry so future updates stop marking it as user-modified.[/]zR[dim]Pass --restore to also replace the current copy with the bundled version.[/]
z	--restore)r  r   r  r	  >   r  rj  )r   r   r  z([bold red]Usage:[/] /skills diff <name>
rk  zS[bold red]Usage:[/] /skills publish <skill-path> [--to github] [--repo owner/repo]
r   z--toz--repo)r  r  r   rX  zT[bold red]Usage:[/] /skills snapshot export <file> | /skills snapshot import <file>
rn  ro  )r  r   r`  )r  r   >   -h--helphelpz[bold red]Unknown action:[/] )r=   r|   r;  r?   _print_skills_helpr@   r   r=  r  r>   r]   r   r`   r   r\  rm  ry   r  r  r  r   r  r  r  r  r  r  rY  ra  r
  )rv  r   rF   r  r  rs  r   r   r   r   r"   r   query_partsrA   r  r
  r  r  r	  rz  r!   r  idxr   r  r  r  r  r  rt  rp  s                                  r   handle_skills_slashr    s   . 	8AIIKE q!Y.ab	11X^^F9D	#d)mAw("q1us4y'8tAE{+D QaH$QT): #DQK 0I QaJ&1q53t9+<a!eQQ# #d)m$ 	tyK	8	GG  a  b#d)mAw*$QT):a!eQaI%!a%#d)*;QU,E QaH$Q""47+Q #d)m  	#((;'eW	. 
9	GG  E  F!W
 T! #d?dO 	,DAqL QUSY%6A;h1q53t9#4 $QU		,
 	: ,?O!.	; 
9	GGHI47A&	6	'4/F;$3F**Z(CQwT" $S1Wm,PQR	7	tAwDdA&	8	tAwDtQ'	7	tAw'9'9$'?tAwT4dAD1	;	GGLM"d?T!Wal&6	8 
7	GGTUGGz{GGijAw%"d?w"2	4 
0	0H,<=	6	GG?@Q#	9	GGjk!W
dO 	#DAqF{q1us4y0a!eH}QT!2AE{		#
 	:f4C	:	GGkl1g("s4y1}tAw2H$TQ%EtAweQ?GGkl	561%!W
d)a-tAwRza0	+	+1 	
/x891O "  " 4 " s6   !W W &W" 	WW	WW"	W/.W/c                 <    | j                  t        dd             y)z)Print help for the /skills slash command.a  [bold]Skills Hub Commands:[/]

  [cyan]browse[/] [--source official]   Browse all available skills (paginated)
  [cyan]search[/] <query>              Search registries for skills
  [cyan]install[/] <identifier>        Install a skill (with security scan)
  [cyan]inspect[/] <identifier>        Preview a skill without installing
  [cyan]list[/] [--source hub|builtin|local] [--enabled-only]
       List installed skills; --enabled-only filters to the active profile's live set
  [cyan]check[/] [name]                Check hub skills for upstream updates
  [cyan]update[/] [name]               Update hub skills with upstream changes
  [cyan]audit[/] [name]                Re-scan hub skills for security
  [cyan]uninstall[/] <name>            Remove a hub-installed skill
  [cyan]list-modified[/]               List bundled skills you've edited (kept by update)
  [cyan]diff[/] <name>                 Diff your copy of a bundled skill vs the stock version
  [cyan]reset[/] <name> [--restore]    Reset bundled-skill tracking (fix 'user-modified' flag)
  [cyan]publish[/] <path> --repo <r>   Publish a skill to GitHub via PR
  [cyan]snapshot[/] export|import      Export/import skill configurations
  [cyan]tap[/] list|add|remove         Manage skill sources
rx  r   N)r>   r	   ry  s    r   r}  r}    s     MM%	H" % r   )r:   )r   r   NF)r#   r   r   N)r:   FNFTr:   r   )r#   r   r   )r   FN)NN)NNF)NFT)FNFT)NF)FNT)r:   N)r   r:   N)FN)r   N)A__doc__r   r  r?  pathlibr   typingr   r   r   r   rich.consoler   
rich.panelr	   
rich.tabler
   hermes_constantsr   r  r   r=   rs   r   rL   r   rf   ro   rv   compiler~   r   r}   r   r   r   r   r   r   r  r\  rm  r_   rt  r  r  r  r  r  r  r  r  r  r  r  r  r
  r  tupler  rY  ra  ru  r  r}  rY   r   r   <module>r     s  	  	   , ,     1 49# $.c .W . .bS#X 49 8( (<+S +S + 12RZZ 67 1 1 1d3i @g C # xPS} 2G tCy S 2 =?AFB+S B+# B+c B+(B+:>B+KOB+J AF+/hDC hD hD# hD(hD48hDV CHGL(,$&ZA3 ZA# ZA4 ZA )ZA@DZA!%ZA "ZA ,0ZAz/3 /'): /d /d. .C .c .d .b#c #htn #L "'!&)-`3 ``g&`26`Fd8C= d(72C dt d.BHSM B8G3D BPT B( GK+8C= +(72C ++$(+\ :>&+*. 0s  0Xg%6  0# 0#' 037 0F ).*."'&**~3 *~ *~w'*~*~  $*~ 04*~Z 37%*Ohw/ O"O/3O8$L# $L 1 $LT $LN $,0$)(,Ct C )C!C "&C 26CL !+/'+D ( $04> 3848,104'S '4 ' ( 1'%)' *.' :>'T(X3 (Xc (X'1B (Xd (XV EG,0CX3 CX CXc CX )CX59CXL^8 ^8# ^8C ^8"^8B%PC %P(72C %Pt %PP 7<48,:3 ,:t ,: ( 1,:=A,:fCNTUS U8G+< U Up D r   