+
    Ki(*                        R t ^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIHt ^ RI	H
t
HtHt ]P                  ! ]4      t]! 4       t]R,          t]R,          tR R ltR	 R
 ltR R ltR R ltR R ltR R ltR(R R llt]R8X  d   ]! R4       ]! RR7      t]! ]R,          4       R2]! ]R,          4       R2]R,           R2.t]R,          '       d"   ]P=                  ]! ]R,          4       R 24       ]R!,          '       d"   ]P=                  ]! ]R!,          4       R"24       ]! R#R$P?                  ]4       R%]R&,           R'24       R# R# ))u  
Skills Sync -- Manifest-based seeding and updating of bundled skills.

Copies bundled skills from the repo's skills/ directory into ~/.hermes/skills/
and uses a manifest to track which skills have been synced and their origin hash.

Manifest format (v2): each line is "skill_name:origin_hash" where origin_hash
is the MD5 of the bundled skill at the time it was last synced to the user dir.
Old v1 manifests (plain names without hashes) are auto-migrated.

Update logic:
  - NEW skills (not in manifest): copied to user dir, origin hash recorded.
  - EXISTING skills (in manifest, present in user dir):
      * If user copy matches origin hash: user hasn't modified it → safe to
        update from bundled if bundled changed. New origin hash recorded.
      * If user copy differs from origin hash: user customized it → SKIP.
  - DELETED by user (in manifest, absent from user dir): respected, not re-added.
  - REMOVED from bundled (in manifest, gone from repo): cleaned from manifest.

The manifest lives at ~/.hermes/skills/.bundled_manifest.
NPath)get_hermes_home)DictListTupleskillsz.bundled_manifestc                $    V ^8  d   QhR\         /#    returnr   )formats   "./home/ubuntu/hermes-agent/tools/skills_sync.py__annotate__r   (   s     	3 	3$ 	3    c                     \         P                  ! R4      p V '       d   \        V 4      # \        \        4      P                  P                  R,          # )zLocate the bundled skills/ directory.

Checks HERMES_BUNDLED_SKILLS env var first (set by Nix wrapper),
then falls back to the relative path from this source file.
HERMES_BUNDLED_SKILLSr   )osgetenvr   __file__parent)env_overrides    r   _get_bundled_dirr   (   s<     9945LL!!>  ''(22r   c                F    V ^8  d   QhR\         \        \        3,          /# r
   r   str)r   s   "r   r   r   4   s      S#X r   c                    \         P                  4       '       g   / #  / p \         P                  RR7      P                  4        F^  pVP	                  4       pV'       g   K  RV9   d7   VP                  R4      w  r#pVP	                  4       WP	                  4       &   KZ  RW&   K`  	  V #   \        \        3 d    / u # i ; i)z
Read the manifest as a dict of {skill_name: origin_hash}.

Handles both v1 (plain names) and v2 (name:hash) formats.
v1 entries get an empty hash string which triggers migration on next sync.
utf-8encoding: )MANIFEST_FILEexists	read_text
splitlinesstrip	partitionOSErrorIOError)resultlinename_hash_vals        r   _read_manifestr/   4   s     !!	!++W+=HHJD::<Dd{$(NN3$7!'/~~'7zz|$  " K W 	s   B	B( (B>=B>c                F    V ^8  d   QhR\         \        \        3,          /# )r   entriesr   )r   s   "r   r   r   O   s     ` `T#s(^ `r   c                0   ^ RI p\        P                  P                  RRR7       RP	                  R \        V P                  4       4       4       4      R,           p VP                  \        \        P                  4      RRR7      w  r4 \        P                  ! VR	R
R7      ;_uu_ 4       pVP                  V4       VP                  4        \        P                  ! VP                  4       4       RRR4       \        P                  ! V\        4       R#   + '       g   i     L-; i  \          d+     \        P"                  ! T4       h   \$         d     h i ; ii ; i  \&         d)   p\(        P+                  R\        TRR7        Rp?R# Rp?ii ; i)zWrite the manifest file atomically in v2 format (name:hash).

Uses a temp file + os.replace() to avoid corruption if the process
crashes or is interrupted mid-write.
NTparentsexist_ok
c              3   4   "   T F  w  rV R V 2x  K  	  R# 5i)r    N ).0r,   r.   s   &  r   	<genexpr>"_write_manifest.<locals>.<genexpr>X   s     X@WndvQxj)@Ws   z.bundled_manifest_z.tmp)dirprefixsuffixwr   r   z&Failed to write skills manifest %s: %s)exc_info)tempfiler"   r   mkdirjoinsorteditemsmkstempr   r   fdopenwriteflushfsyncfilenoreplaceBaseExceptionunlinkr(   	Exceptionloggerdebug)r1   rA   datafdtmp_pathfes   &      r   _write_manifestrW   O   s=    td;99Xw}}@WXX[__D`''M(()' ( 

	2sW55	$ 6 JJx/	 65
  			(#   	  `=}aZ^__`sg   -E" !D* ,AD2#D* D'	"D* *E6EEEEEEE" "F-FFc                h    V ^8  d   QhR\         R\        \        \        \         3,          ,          /# )r   bundled_dirr   )r   r   r   r   )r   s   "r   r   r   p   s(      $ 4c4i8H3I r   c                   . pV P                  4       '       g   V# V P                  R4       FO  p\        V4      pRV9   g   RV9   g   RV9   d   K%  VP                  pVP                  pVP                  WT34       KQ  	  V# )zn
Find all SKILL.md files in the bundled directory.
Returns list of (skill_name, skill_directory_path) tuples.
zSKILL.mdz/.git/z	/.github/z/.hub/)r#   rglobr   r   r,   append)rY   r   skill_mdpath_str	skill_dir
skill_names   &     r   _discover_bundled_skillsra   p   s|    
 F%%j1x=x;(#:h(>ROO	^^
z-. 2 Mr   c                <    V ^8  d   QhR\         R\         R\         /# )r   r_   rY   r   r   )r   s   "r   r   r      s!      d  $ r   c                >    V P                  V4      p\        V,          # )z
Compute the destination path in SKILLS_DIR preserving the category structure.
e.g., bundled/skills/mlops/axolotl -> ~/.hermes/skills/mlops/axolotl
)relative_to
SKILLS_DIR)r_   rY   rels   && r   _compute_relative_destrg      s    
 


,Cr   c                0    V ^8  d   QhR\         R\        /# )r   	directoryr   )r   r   )r   s   "r   r   r      s       # r   c                   \         P                  ! 4       p \        V P                  R4      4       Ft  pVP	                  4       '       g   K  VP                  V 4      pVP                  \        V4      P                  R4      4       VP                  VP                  4       4       Kv  	  VP                  4       #   \        \        3 d     TP                  4       # i ; i)zHCompute a hash of all file contents in a directory for change detection.*r   )hashlibmd5rD   r[   is_filerd   updater   encode
read_bytesr(   r)   	hexdigest)ri   hasherfpathrf   s   &   r   	_dir_hashru      s    [[]FIOOC01E}}''	2c#hoog67e..01	 2  W s   0B9 AB9 9CCFc                0    V ^8  d   QhR\         R\        /# )r   quietr   )booldict)r   s   "r   r   r      s     } }t } }r   c                   \        4       pVP                  4       '       g   R. R. R^ R. R. R^ /# \        P                  RRR7       \	        4       p\        V4      pV UUu0 uF  w  rEVkK	  	  ppp. p. p. p	^ p
V EF  w  r\        W4      p\        V4      pW9  d    VP                  4       '       d   V
^,          p
WV&   KH  VP                  P                  RRR7       \        P                  ! W4       VP                  V4       WV&   V '       g   \        R	V 24       K  K  VP                  4       '       Ed%   VP                  VR4      p\        V4      pV'       g"   VW+&   VV8X  d   V
^,          p
M	V
^,          p
EK  VV8w  d,   V	P                  V4       V '       g   \        RV R24       EK9  VV8w  d    VP!                  R4      p\        P"                  ! \%        V4      \%        V4      4        \        P                  ! W4       WV&   VP                  V4       V '       g   \        RV R24       \        P&                  ! VRR7       EK  V
^,          p
EK  V
^,          p
EK  	  \)        \+        VP-                  4       4      V,
          4      pV F  pW$ K  	  VP/                  R4       Fn  pVP1                  V4      p\        V,          pVP                  4       '       d   K9   VP                  P                  RRR7       \        P2                  ! VV4       Kp  	  \9        V4       RVRVRV
RV	RVR\;        V4      /# u uppi   \        \        3 d-   pT '       g   \        R
T RT 24        Rp?EK   Rp?EK
  Rp?ii ; i  \        \        3 dX    TP                  4       '       d@   TP                  4       '       g*   \        P"                  ! \%        T4      \%        T4      4       h i ; i  \        \        3 d-   pT '       g   \        RT RT 24        Rp?EK   Rp?EK  Rp?ii ; i  \        \        3 d$   p\4        P7                  RTT4        Rp?EK  Rp?ii ; i)z
Sync bundled skills into ~/.hermes/skills/ using the manifest.

Returns:
    dict with keys: copied (list), updated (list), skipped (int),
                    user_modified (list), cleaned (list), total_bundled (int)
copiedupdatedskippeduser_modifiedcleanedtotal_bundledTr3   z  + z  ! Failed to copy z: Nr!   z  ~ z (user-modified, skipping)z.baku     ↑ z
 (updated))ignore_errorsz  ! Failed to update zDESCRIPTION.mdzCould not copy %s: %s)r   r#   re   rB   r/   ra   rg   ru   r   shutilcopytreer\   printr(   r)   getwith_suffixmover   rmtreerD   setkeysr[   rd   copy2rP   rQ   rW   len)rw   rY   manifestbundled_skillsr,   r-   bundled_namesr{   r|   r~   r}   r`   	skill_srcdestbundled_hashrV   origin_hash	user_hashbackupr   desc_mdrf   	dest_descs   &                      r   sync_skillsr      s    #$Kb)RARB
 	

 TD1H-k:N)78gdTM8FGMG!/
%i= +%C;;==qLG+7Z(KK%%dT%BOOI4MM*-+7Z( ZL12 ! [[]]",,z26K!$I (1$,qLG qLGK'$$Z0D,FGH {*I!--f5FKKD	3v;7	8/;,z2$!F:,j"ABfDAA 1 qLGS "0X S)M9:GN  $$%56!!+.$	!!B  &&td&CWi0 7 H 	&777^, I 92 W% C/
|2aSABB CT $W- !==??4;;=="KKFSY?	
  ) I  5j\A3GHH !I. W% B4gqAABsz    MM3MAM;:O76AN,4P7N	NN	&O43O4	+O44O77P4P//P47Q+Q&&Q+__main__z1Syncing bundled skills into ~/.hermes/skills/ ...)rw   r{   z newr|   z updatedr}   z
 unchangedr~   z user-modified (kept)r   z cleaned from manifestz
Done: z, z. r   z total bundled.)F) __doc__rl   loggingr   r   pathlibr   hermes_constantsr   typingr   r   r   	getLogger__name__rP   HERMES_HOMEre   r"   r   r/   rW   ra   rg   ru   r   r   r*   r   partsr\   rC   r8   r   r   <module>r      sZ  ,   	   , $ $			8	$ 8#
00	36`B(}@ z	
=>u%Fvh 
!&vi !
"(+)
Z(E
 oF?3455JKLiF9-.//EFG	HTYYu%&b)@(A
QR r   