
    i>                    >   d Z ddlm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 ddlmZm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 ddlmZ  ee      Z ej@                  dd        G d de      Z! G d de      Z" G d de      Z# G d de      Z$y)z8Basic skill provider for handling a single skill folder.    )annotationsN)Sequence)Path)AnyLiteralcast)AnyUrl)ResourceResourceResult)ResourceTemplate)Provider)	SkillInfoparse_frontmatterscan_skill_files)
get_logger)VersionSpectext/markdownz.mdc                  N     e Zd ZU dZded<   dZded<   d
 fdZddZdd	Z xZ	S )SkillResourcez8A resource representing a skill's main file or manifest.r   
skill_infoFboolis_manifestc                    t         |          }t        t        t        t
        f   |d         }| j                  j                  | j                  d|d<   |S )Nfastmcp)namer   skill)	superget_metar   dictstrr   r   r   r   selfmetar   	__class__s      ~/Users/bowang/.openclaw/workspace/ChatDev/.venv/lib/python3.12/site-packages/fastmcp/server/providers/skills/skill_provider.pyr   zSkillResource.get_meta)   sQ    w!tCH~tI7OO((++
     c                   K   | j                   r| j                         S | j                  j                  | j                  j                  z  }|j                         S w)zRead the resource content.)r   _generate_manifestr   path	main_file	read_text)r"   main_file_paths     r%   readzSkillResource.read2   sK     **,,!__11DOO4M4MMN!++--s   AAc                    | j                   j                  | j                   j                  D cg c]&  }|j                  |j                  |j
                  d( c}d}t        j                  |d      S c c}w )z%Generate JSON manifest for the skill.)r)   sizehash)r   files   )indent)r   r   r1   r)   r/   r0   jsondumps)r"   fmanifests      r%   r(   z SkillResource._generate_manifest:   sj     __)) ...A @.
 zz(1--s   +A5returndict[str, Any]r9   str | bytes | ResourceResultr9   r    )
__name__
__module____qualname____doc____annotations__r   r   r-   r(   __classcell__r$   s   @r%   r   r   #   s%    BK.	.r&   r   c                  F    e Zd ZU dZded<   ddZ	 d		 	 	 	 	 	 	 d
dZddZy)SkillFileTemplatez.A template for accessing files within a skill.r   r   c                L  K   |j                  dd      }| j                  j                  |z  }	 |j                         }|j	                  | j                  j                        st        d| d      	 |j                         st        d|       |j                         st        d|       t        j                  t        |            \  }}|r!|j                  d	      r|j                         S |j                         S # t
        $ r}t        d|       |d}~ww xY ww)
z%Read a file from the skill directory.r)    Path  escapes skill directoryzInvalid path: NFile not found: zNot a file: text/)getr   r)   resolveis_relative_to
ValueErrorexistsFileNotFoundErroris_file	mimetypes
guess_typer    
startswithr+   
read_bytes)r"   	arguments	file_path	full_pathe	mime_type_s          r%   r-   zSkillFileTemplate.readK   s    MM&"-	OO((94		:!))+I++DOO,@,@A 53K!LMM B
 !#&6yk$BCC  "|I;788 !++C	N;	1--g6&&((''))  	:~aS129	:s*   ,D$AD 3BD$	D!DD!!D$Nc                d   K   | j                  |       d{   }| j                  |      S 7 w)zServer entry point - read file directly without creating ephemeral resource.

        Note: task_meta is ignored - this template doesn't support background tasks.
        )rX   N)r-   convert_result)r"   uriparams	task_metaresults        r%   _readzSkillFileTemplate._reade   s1      yy6y22""6** 3s   0.0c                  K   |j                  dd      }| j                  j                  |z  j                         }|j	                  | j                  j                        st        d| d      t        j                  t        |            \  }}t        t        |      | j                  j                   d| d| j                  j                   d|xs d| j                  |	      S w)
zCreate a resource for the given URI and parameters.

        Note: This is not typically used since _read() handles file reading directly.
        Provided for compatibility with the ResourceTemplate interface.
        r)   rH   rI   rJ   /
File from  skillapplication/octet-streamr`   r   descriptionr\   r   rY   )rM   r   r)   rN   rO   rP   rT   rU   r    SkillFileResourcer	   r   )r"   r`   ra   rY   rZ   r\   r]   s          r%   create_resourcez!SkillFileTemplate.create_resources   s      JJvr*	__))I5>>@	 ''(<(<=uYK/GHII ++C	N;	1 !sOO(()9+6$T__%9%9$:&A=#=
 	
s   C(C*)rX   r:   r9   r<   N)r`   r    ra   r:   rb   r   r9   r   )r`   r    ra   r:   r9   r
   )r>   r?   r@   rA   rB   r-   rd   rm    r&   r%   rF   rF   F   sE    8*< 	++ + 	+
 
+
r&   rF   c                  B     e Zd ZU dZded<   ded<   d fdZd	dZ xZS )
rl   z7A resource representing a specific file within a skill.r   r   r    rY   c                    t         |          }t        t        t        t
        f   |d         }d| j                  j                  i|d<   |S )Nr   r   r   )r   r   r   r   r    r   r   r   r!   s      r%   r   zSkillFileResource.get_meta   sJ    w!tCH~tI7DOO((
 r&   c                  K   | j                   j                  | j                  z  }|j                         }|j	                  | j                   j                        st        d| j                   d      |j                         st        d| j                         t        j                  t        |            \  }}|r!|j                  d      r|j                         S |j                         S w)zRead the file content.rI   rJ   rK   rL   )r   r)   rY   rN   rO   rP   rQ   rR   rT   rU   r    rV   r+   rW   )r"   rZ   r\   r]   s       r%   r-   zSkillFileResource.read   s     OO((4>>9	 %%'	''(<(<=uT^^$44LMNN!#&6t~~6F$GHH ++C	N;	1--g6&&((''))s   C.C0r8   r;   )r>   r?   r@   rA   rB   r   r-   rC   rD   s   @r%   rl   rl      s    AN*r&   rl   c                       e Zd ZdZ	 	 d
	 	 	 	 	 	 	 d fdZddZedd       ZddZ	 d	 	 	 	 	 ddZ	ddZ
	 d	 	 	 	 	 ddZdd	Z xZS )SkillProvidera  Provider that exposes a single skill folder as MCP resources.

    Each skill folder must contain a main file (default: SKILL.md) and may
    contain additional supporting files.

    Exposes:
    - A Resource for the main file (skill://{name}/SKILL.md)
    - A Resource for the synthetic manifest (skill://{name}/_manifest)
    - Supporting files via ResourceTemplate or Resources (configurable)

    Args:
        skill_path: Path to the skill directory.
        main_file_name: Name of the main skill file. Defaults to "SKILL.md".
        supporting_files: How supporting files (everything except main file and
            manifest) are exposed to clients:
            - "template": Accessed via ResourceTemplate, hidden from list_resources().
              Clients discover files by reading the manifest first.
            - "resources": Each file exposed as individual Resource in list_resources().
              Full enumeration upfront.

    Example:
        ```python
        from pathlib import Path
        from fastmcp import FastMCP
        from fastmcp.server.providers.skills import SkillProvider

        mcp = FastMCP("My Skill")
        mcp.add_provider(SkillProvider(
            Path.home() / ".claude/skills/pdf-processing"
        ))
        ```
    c                    t         |           t        |      j                         | _        || _        || _        d | _        | j                          y rn   )	r   __init__r   rN   _skill_path_main_file_name_supporting_files_skill_info_load_skill)r"   
skill_pathmain_file_namesupporting_filesr$   s       r%   rv   zSkillProvider.__init__   sL     	
+335-!1-1 	r&   c                   | j                   | j                  z  }| j                   j                         st        d| j                          |j                         s(t        d| d| j                   d| j                          |j	                         }t        |      \  }}|j                  dd      }|s|j                         j                  d      D ]a  }|j                         }|r|j                  d      s|d	d
 } n7|j                  d      s?|j                  d      j                         d	d
 } n t        | j                         }t        | j                   j                  |xs d| j                   j                   | j                   | j                  ||      | _        t        j!                  d| j                  j                          y	)z#Load and parse the skill directory.zSkill directory not found: zMain skill file not found: z. Expected z in rk   rH   
#N   zSkill: )r   rk   r)   r*   r1   frontmatterzSkillProvider loaded skill: )rw   rx   rQ   rR   r+   r   rM   stripsplitrV   lstripr   r   r   rz   loggerdebug)r"   r*   contentr   bodyrk   liner1   s           r%   r{   zSkillProvider._load_skill   s   $$t';';;	&&(#&A$BRBRAS$TUU!#-i[ 9 001d6F6F5GI 
 %%'-g6T "oomR8

**40zz| 4"&t*K__S)"&++c"2"8"8":4C"@K 1 !!1!12$!!&&#H1A1A1F1F0G'H!!**#
 	3D4D4D4I4I3JKLr&   c                H    | j                   t        d      | j                   S )zGet the loaded skill info.zSkill not loaded)rz   RuntimeErrorr"   s    r%   r   zSkillProvider.skill_info  s(     #122r&   c                @  K   | j                   }g }|j                  t        t        d|j                   d| j
                         |j                   d| j
                   |j                  d|d             |j                  t        t        d|j                   d      |j                   dd|j                   d|d	             | j                  d
k(  r|j                  D ]  }|j                  | j
                  k(  rt        j                  |j                        \  }}|j                  t        t        d|j                   d|j                         |j                   d|j                   d|j                   d|xs d||j                                |S w)zList skill resources.skill://rf   r   Fr`   r   rk   r\   r   r   
/_manifestFile listing for application/jsonT	resourcesrg   rh   ri   rj   )r   appendr   r	   r   rx   rk   ry   r1   r)   rT   rU   rl   )r"   r   r   	file_infor\   r]   s         r%   _list_resourceszSkillProvider._list_resources  s    $&	 	Xejj\43G3G2HIJ

|1T%9%9$:;!--) !		
 	Xejj\<=

|:./

|<,  		
 !![0"[[	>>T%9%99(33INNC	1  %"Xejj\9>>:J#KL %

|1Y^^,<=&0F$C"+"I/I#("+..	 )" s   FFc           	     ~  K   | j                   }|j                  d      sy|t        d      d }|j                  dd      }t        |      dk7  ry|\  }}||j                  k7  ry|dk(  r t        t        |      | dd| d	|d
      S || j                  k(  r3t        t        |      | d| j                   |j                  d|d      S | j                  dk(  ra|j                  D ]R  }|j                  |k(  st        j                  |      \  }	}
t        t        |      | d| d| d|	xs d||      c S  yw)zGet a resource by URI.r   Nrf      r2   	_manifestr   r   r   Tr   r   Fr   rg   rh   ri   rj   )r   rV   lenr   r   r   r	   rx   rk   ry   r1   r)   rT   rU   rl   )r"   r`   versionr   	path_partparts
skill_namerY   r   r\   r]   s              r%   _get_resourcezSkillProvider._get_resourceK  sn      ~~j)J)*	Q'u:? %
I## 3K"|:./
|<,    $... 3K"|1T%9%9$:;!--) !  ##{2"[[	>>Y.#,#7#7	#BLIq,"3K *|1YK8&0F$C"+"I/I#("+  ) s   C7D=:AD=c           
        K   | j                   dk7  rg S | j                  }t        d|j                   d|j                   dd|j                   dddd	d
iidgd|      gS w)z=List resource templates for accessing files within the skill.templater   /{path*}_filesAccess files within ri   objectr)   typestringr   
propertiesrequireduri_templater   rk   r\   
parametersr   )ry   r   rF   r   )r"   r   s     r%   _list_resource_templatesz&SkillProvider._list_resource_templates  s      !!Z/I'

|:>

|6*25::,?4$#)FH+=">!'
 !
 	
s   A!A#c           
       K   | j                   dk7  ry| j                  }|j                  d      sy|t        d      d }|j	                  dd      }t        |      dk7  ry|\  }}||j
                  k7  ry|dk(  s|| j                  k(  ryt        d|j
                   d|j
                   d	d
|j
                   dddddiidgd|      S w)z3Get a resource template that matches the given URI.r   Nr   rf   r   r2   r   r   r   r   ri   r   r)   r   r   r   r   )ry   r   rV   r   r   r   rx   rF   )r"   r`   r   r   r   r   r   rY   s           r%   _get_resource_templatez$SkillProvider._get_resource_template  s     
 !!Z/~~j)J)*	Q'u:? %
I# #yD4H4H'H #EJJ<z:JJ<v&.uzzl;0 %'9:#H
 
 	
s   C
Cc                <    d| j                   d| j                  dS )NzSkillProvider(skill_path=z, supporting_files=))rw   ry   r   s    r%   __repr__zSkillProvider.__repr__  s-    '(8(8'; <  $ 6 69<	
r&   )zSKILL.mdr   )r|   z
str | Pathr}   r    r~   z Literal['template', 'resources']r9   None)r9   r   )r9   r   )r9   zSequence[Resource]rn   )r`   r    r   VersionSpec | Noner9   zResource | None)r9   zSequence[ResourceTemplate])r`   r    r   r   r9   zResourceTemplate | Noner=   )r>   r?   r@   rA   rv   r{   propertyr   r   r   r   r   r   rC   rD   s   @r%   rt   rt      s    H )=G	  ;	
 
(MT    0f 7;33!33	3j
. 7;%
%
!3%
	 %
N
r&   rt   )%rA   
__future__r   r4   rT   collections.abcr   pathlibr   typingr   r   r   pydanticr	   fastmcp.resources.resourcer
   r   fastmcp.resources.templater   fastmcp.server.providers.baser   'fastmcp.server.providers.skills._commonr   r   r   fastmcp.utilities.loggingr   fastmcp.utilities.versionsr   r>   r   add_typer   rF   rl   rt   ro   r&   r%   <module>r      s    > "   $  % %  ? 7 2 
 1 2	H	 	  ?E * .H  .FD
( D
N* *LN
H N
r&   