§
    ÛŽ’jç†  ã                   ó&  — d Z ddlZddlZddlZddlZddlZddlZddlmZm	Z	m
Z
 ddlZddl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 ddlmZ ddlmZmZmZ  G d„ de
¦  «        Z G d„ de
¦  «        Z de!de!fd„Z" G d„ de¦  «        Z#dS )zThe local workspace class.é    N)ÚAsyncIteratorÚLiteralÚ	TypedDicté   )ÚDEFAULT_WORKSPACE_INSTRUCTIONSé   )Úlogger)Ú_generate_idÚ_normalize_local_path)Ú	MCPClient)ÚSkill)ÚToolBase)ÚLocalBackend)ÚDEFAULT_MAX_EXTRACTED_BYTESÚ_EXTRACT_ARCHIVE_SHIMÚWorkspaceBasec                   ó*   — e Zd ZU dZeed<   	 eed<   dS )Ú_SkillEntryz)A single entry in the .skills index file.ÚhashÚ
skill_nameN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚstrÚ__annotations__© ó    úSC:\Projects\DSCons\.venv\Lib\site-packages\agentscope\workspace\_local_workspace.pyr   r      s-   € € € € € € Ø3Ð3à
€I€I�IØ7Ø€O€O�OØMÐMr   r   c                   ó:   — e Zd ZU dZeed<   	 eeef         ed<   dS )Ú_SkillsFilez:Schema of the .skills index file stored inside skills_dir.Úskills_dir_mtimeÚskillsN)	r   r   r   r   Úfloatr   Údictr   r   r   r   r   r!   r!   %   s=   € € € € € € ØDÐDàÐÐÑØEØ��kÐ!Ô"Ð"Ð"Ñ"ØNÐNr   r!   ÚnameÚreturnc                 ó.   — t          j        dd| ¦  «        S )a¥  Sanitize a skill name into a safe directory name.

    Allowed characters: ASCII letters, digits, CJK unified ideographs,
    hyphens, and underscores. Everything else is replaced with ``_``.

    Args:
        name (`str`):
            The raw skill name from SKILL.md frontmatter.

    Returns:
        `str`:
            A sanitized string safe to use as a directory name on Windows,
            macOS, and Linux.
    u   [^\wä¸€-é¿¿-]Ú_)ÚreÚsub©r&   s    r   Ú_sanitize_dir_namer-   .   s   € õ Œ6Ð" C¨Ñ.Ô.Ð.r   c                   óä  ‡ — e Zd ZdZdddedœdededz  dee         dz  dee         dz  ded	dfˆ fd
„Zd	ee	         fd„Z
d*d„Zd	efd„Zded	efd„Zdeded	dfd„Zded	eeeef         dz  fd„Zded	eeeef         dz  fd„Zd*d„Zd*d„Zd	ee         fd„Zdededed	efd„Zdeded	edz  fd„Zded	dfd„Zd ed	dfd!„Zded	dfd"„Zefd#ee         d$e d%         d&ed'e!d	df
d(„Z"d ed	dfd)„Z#ˆ xZ$S )+ÚLocalWorkspaceuM  Local-directory workspace.

    Layout::

        {workdir}/
        â”œâ”€â”€ .mcp          # persisted MCP client configs (JSON array)
        â”œâ”€â”€ data/         # offloaded multimodal files
        â”œâ”€â”€ skills/       # skill subdirectories
        â””â”€â”€ sessions/     # per-session context and tool-result files
    N)Úworkspace_idÚdefault_mcpsÚskill_pathsÚinstructionsÚworkdirr0   r1   r2   r3   r'   c                ó¼  •— t          ¦   «                              |¬¦  «         t          j                             |¦  «        | _        |                     d| j        ¬¦  «        | _        t          |pg ¦  «        | _	        d„ |pg D ¦   «         | _
        t          ¦   «         | _        g | _        t          j        ¦   «         | _        t          j        ¦   «         | _        dS )a  Construct a :class:`LocalWorkspace`.

        Args:
            workdir (`str`):
                Filesystem path to the workspace root. Created on
                demand. Always resolved to an absolute path.
            workspace_id (`str | None`, optional):
                Existing workspace identifier to adopt. ``None``
                generates a fresh UUID.
            default_mcps (`list[MCPClient] | None`, optional):
                MCP clients seeded into a brand-new workspace.
                Ignored on subsequent restarts that already have a
                persisted ``<workdir>/.mcp`` file.
            skill_paths (`list[str] | None`, optional):
                Local skill directories seeded into
                ``<workdir>/skills`` on first :meth:`initialize`.
            instructions (`str`, defaults to             `_DEFAULT_WORKSPACE_INSTRUCTIONS`):
                System-prompt fragment template returned by
                :meth:`get_instructions`. Supports the ``{workdir}``
                placeholder.
        )r0   Úlocal)Úbackendr4   c                 ó,   — g | ]}t          |¦  «        ‘ŒS r   )r   )Ú.0Úpaths     r   ú
<listcomp>z+LocalWorkspace.__init__.<locals>.<listcomp>v   s.   € ð '
ð '
ð '
Ø,0Õ! $Ñ'Ô'ð'
ð '
ð '
r   N)ÚsuperÚ__init__Úosr:   Úabspathr4   Úformatr3   Úlistr1   r2   r   Ú_backendÚ_mcpsÚasyncioÚLockÚ_skill_lockÚ	_mcp_lock)Úselfr4   r0   r1   r2   r3   Ú	__class__s         €r   r=   zLocalWorkspace.__init__L   sÌ   ø€ õ> 	‰Œ×Ò lÐÑ3Ô3Ð3õ ”w—’ wÑ/Ô/ˆŒØ(×/Ò/ØØ”Lð 0ñ 
ô 
ˆÔõ .2°,Ð2DÀ"Ñ-EÔ-EˆÔð'
ð '
Ø4?Ð4EÀ2ð'
ñ '
ô '
ˆÔõ
 %™œˆŒØ&(ˆŒ
å"œ<™>œ>ˆÔÝ œ™œˆŒˆˆr   c              ƒ   óR  K  — ddl m}m}m}m}m}m}m} |                      ¦   «         }d|i}	| j	        �
| j	        |	d<   t          j        dk    r || j        |¬¦  «        }
n || j        |¬¦  «        }
|
 ||¬¦  «         |d	i |	¤Ž ||¬¦  «         ||¬¦  «         ||¬¦  «        gS )
z?Return builtin tools, using PowerShell as the shell on Windows.r   )ÚBashÚEditÚGlobÚGrepÚ
PowerShellÚReadÚWriter7   NÚglob_helper_pathÚnt)Úcwdr7   )r7   r   )ÚtoolrK   rL   rM   rN   rO   rP   rQ   Úget_backendÚ_glob_helper_pathr>   r&   r4   )rH   rK   rL   rM   rN   rO   rP   rQ   r7   Úglob_kwargsÚshells              r   Ú
list_toolszLocalWorkspace.list_tools�   s	  è è € àJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJÐJà×"Ò"Ñ$Ô$ˆØ&¨Ð0ˆØÔ!Ð-Ø.2Ô.DˆKÐ*Ñ+åŒ7�dŠ?ˆ?Ø(˜j¨T¬\À7ÐKÑKÔKˆEˆEà�D˜Tœ\°7Ð;Ñ;Ô;ˆEð ØˆD˜Ð!Ñ!Ô!ØˆDÐÐ�;ÐÐØˆD˜Ð!Ñ!Ô!ØˆD˜Ð!Ñ!Ô!ØˆE˜'Ð"Ñ"Ô"ð
ð 	
r   c           
   ƒ   óî	  K  — | j         rdS t          j        | j        d¬¦  «         t          j                             | j        d¦  «        }| j                             |¦  «        ƒ d{V —†r»| j                             |¦  «        ƒ d{V —†}t          j
        |                     d¦  «        ¦  «        }|D ]p}	 | j                             t          j        |¦  «        ¦  «         Œ0# t           $ r4}t#          j        d|                     dd¦  «        |¦  «         Y d}~Œid}~ww xY wn3t)          | j        ¦  «        | _        |                      ¦   «         ƒ d{V —† g }| j        D ]s}|j        rj|j        sc	 |                     ¦   «         ƒ d{V —† Œ,# t           $ r:}t#          j        d	|j        |¦  «         |                     |¦  «         Y d}~Œkd}~ww xY wŒt|D ]}| j                             |¦  «         Œt          j                             | j        d
¦  «        }t          j        |d¬¦  «         |                      |¦  «        ƒ d{V —†}	|	d
         }
d„ |
                     ¦   «         D ¦   «         }d„ |
                     ¦   «         D ¦   «         }t=          |
                     ¦   «         ¦  «        }d}| j         D �]æ}|  !                    |¦  «        ƒ d{V —†}|€Œ!|\  }}}||v rt#          j"        d||dd…         ¦  «         ŒJ|}d}||v r|› d|› d�}|dz  }||v °tG          |¦  «        }|}d}||v r|› d|› �}|dz  }||v °t          j                             ||¦  «        }t          j         $                    |¦  «         %                    t          j         $                    |¦  «        t          j&        z   ¦  «        st#          j        d|¦  «         �Œ	 tO          j(        tR          j*        ||d¬¦  «        ƒ d{V —† n<# t           $ r/}t#          j        d||tW          |¦  «        ¦  «         Y d}~�Œ{d}~ww xY wt#          j"        d||||¦  «         ||dœ}||
|<   | ,                    |¦  «         | ,                    |¦  «         | ,                    |¦  «         d}�Œè|rJ|
|	d
<   | j         -                    |¦  «        ƒ d{V —†}|�|nd|	d<   |  .                    ||	¦  «        ƒ d{V —† d| _         dS )a5  Initialise the workspace.

        MCP state is restored from ``.mcp`` if it exists; otherwise
        ``default_mcps`` are used and persisted so the next start picks
        them up from disk. ``skill_paths`` are seeded on first use.

        Idempotent: a no-op when the workspace is already alive.
        NT©Úexist_okú.mcpúutf-8z#Skipping invalid MCP entry '%s': %sr&   Ú?z2Failed to connect stateful MCP '%s': %s, removing.r#   c                 ó   — h | ]
}|d          ’ŒS ©r   r   ©r9   Úes     r   ú	<setcomp>z,LocalWorkspace.initialize.<locals>.<setcomp>Ï   ó   € Ð$JÐ$JÐ$J°1 Q v¤YÐ$JÐ$JÐ$Jr   c                 ó   — h | ]
}|d          ’ŒS ©r   r   rc   s     r   re   z,LocalWorkspace.initialize.<locals>.<setcomp>Ð   ó)   € ð *
ð *
ð *
Ø !ˆAˆlŒOð*
ð *
ð *
r   Fú1Skill '%s' (hash: %s...) already exists, skippingé   r   ú (ú)r)   z0Skill '%s' resolves outside skills_dir, skipping©Údirs_exist_okz%Failed to copy skill '%s' from %s: %sú2Copied skill '%s' (agent name: '%s') from %s to %s©r   r   ç        r"   )/Úis_aliver>   Úmakedirsr4   r:   ÚjoinrB   Úfile_existsÚ	read_fileÚjsonÚloadsÚdecoderC   Úappendr   Úmodel_validateÚ	Exceptionr	   ÚwarningÚgetrA   r1   Ú_save_mcp_fileÚis_statefulÚis_connectedÚconnectr&   ÚremoveÚ_load_skills_fileÚvaluesÚsetÚkeysr2   Ú_validate_and_hash_skillÚinfor-   ÚrealpathÚ
startswithÚseprD   Ú	to_threadÚshutilÚcopytreer   ÚaddÚ
stat_mtimeÚ_save_skills_file)rH   Úmcp_fileÚrawÚraw_listÚmrd   ÚfailedÚmcpÚ
skills_dirÚskills_fileÚexistingÚexisting_hashesÚexisting_agent_namesÚexisting_dir_namesÚupdatedÚ
skill_pathÚresultr)   Úraw_nameÚ
skill_hashÚ
agent_nameÚcounterÚbase_dirÚdir_nameÚ	dest_pathÚentryÚmtimes                              r   Ú
initializezLocalWorkspace.initialize˜   sk  è è € ð Œ=ð 	ØˆFå
Œ�D”L¨4Ð0Ñ0Ô0Ð0õ ”7—<’< ¤¨fÑ5Ô5ˆØ”×*Ò*¨8Ñ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4ð 	(Øœ×/Ò/°Ñ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9ˆCÝ”z #§*¢*¨WÑ"5Ô"5Ñ6Ô6ˆHØð ð �ðØ”J×%Ò%¥iÔ&>¸qÑ&AÔ&AÑBÔBÐBÐBøÝ ð ð ð Ý”NØ=ØŸš˜f cÑ*Ô*Øñô ð ð ð ð ð ð øøøøðøøøðõ ˜dÔ/Ñ0Ô0ˆDŒJØ×%Ò%Ñ'Ô'Ð'Ð'Ð'Ð'Ð'Ð'Ð'à"$ˆØ”:ð 
	'ð 
	'ˆCØŒð 	' sÔ'7ð 	'ð'ØŸ+š+™-œ-Ð'Ð'Ð'Ð'Ð'Ð'Ð'Ð'øÝ ð 'ð 'ð 'Ý”NØLØœØñô ð ð
 —M’M #Ñ&Ô&Ð&Ð&Ð&Ð&Ð&Ð&øøøøð'øøøøð ð 	#ð 	#ˆCØŒJ×Ò˜cÑ"Ô"Ð"Ð"õ ”W—\’\ $¤,°Ñ9Ô9ˆ
Ý
Œ�J¨Ð.Ñ.Ô.Ð.à ×2Ò2°:Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>ˆØ+6°xÔ+@ˆð %KÐ$J¸¿ºÑ8IÔ8IÐ$JÑ$JÔ$Jˆð*
ð *
Ø%-§_¢_Ñ%6Ô%6ð*
ñ *
ô *
Ðõ (+¨8¯=ª=©?¬?Ñ';Ô';ÐàˆØÔ*ð H	ñ H	ˆJØ×8Ò8¸ÑDÔDÐDÐDÐDÐDÐDÐDˆFØˆ~Øà&,Ñ#ˆAˆx˜ð ˜_Ð,Ð,Ý”ØGØØ˜r ˜r”Nñô ð ð
 ð "ˆJØˆGØÐ 4Ð4Ð4Ø (Ð6Ð6¨GÐ6Ð6Ð6�
Ø˜1‘�ð Ð 4Ð4Ð4õ
 *¨(Ñ3Ô3ˆHØˆHØˆGØÐ0Ð0Ð0Ø&Ð2Ð2¨Ð2Ð2�Ø˜1‘�ð Ð0Ð0Ð0õ œŸš Z°Ñ:Ô:ˆIõ ”7×#Ò# IÑ.Ô.×9Ò9Ý”× Ò  Ñ,Ô,­r¬vÑ5ñô ð õ ”ØFØñô ð ñ ðÝÔ'Ý”OØØØ"'ð	ñ ô ð ð ð ð ð ð ð ð øõ ð ð ð Ý”Ø;ØØÝ˜‘F”Fñ	ô ð ð ���‘øøøøðøøøõ ŒKØDØØØØñô ð ð +5ÀJÐ!OÐ!OˆEØ!&ˆH�XÑØ×Ò 
Ñ+Ô+Ð+Ø ×$Ò$ ZÑ0Ô0Ð0Ø×"Ò" 8Ñ,Ô,Ð,ØˆG‰Gàð 	BØ$,ˆK˜Ñ!Øœ-×2Ò2°:Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>ˆEàÐ*��°ð Ð*Ñ+ð ×(Ò(¨°[ÑAÔAÐAÐAÐAÐAÐAÐAÐAàˆŒˆˆsH   Â8,C%Ã%
D#Ã/*DÄD#Å4FÆ
GÆ0GÇGÏ(PÐ
P:Ð$P5Ð5P:c              ƒ   ó   K  — | j         S )zGet the workspace instructions.)r3   )rH   s    r   Úget_instructionszLocalWorkspace.get_instructions*  s   è è € àÔ Ð r   rš   c              ƒ   ó*  K  — t           j                             |d¦  «        }| j                             |¦  «        ƒ d{V —†sdi dœS 	 | j                             |¦  «        ƒ d{V —†}t          j        |                     d¦  «        ¦  «        }t          t          |                     dd¦  «        ¦  «        |                     di ¦  «        ¬¦  «        S # t          $ r2}t          j        d|t          |¦  «        ¦  «         di dœcY d}~S d}~ww xY w)	zòLoad the .skills index file, returning an empty structure if absent.

        Args:
            skills_dir (`str`): The skills directory path.

        Returns:
            `_SkillsFile`: The parsed index, or a fresh empty structure.
        ú.skillsNrr   )r"   r#   r_   r"   r#   z"Failed to load .skills from %s: %s)r>   r:   ru   rB   rv   rw   rx   ry   rz   r!   r$   r   r}   r	   r~   r   )rH   rš   r:   r•   Údatard   s         r   r…   z LocalWorkspace._load_skills_file.  s7  è è € õ Œw�|Š|˜J¨	Ñ2Ô2ˆØ”]×.Ò.¨tÑ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4ð 	;Ø(+°rÐ:Ð:Ð:ð		;Øœ×/Ò/°Ñ5Ô5Ð5Ð5Ð5Ð5Ð5Ð5ˆCÝ”:˜cŸjšj¨Ñ1Ô1Ñ2Ô2ˆDÝÝ!& t§x¢xÐ0BÀCÑ'HÔ'HÑ!IÔ!IØ—x’x ¨"Ñ-Ô-ðñ ô ð øõ ð 	;ð 	;ð 	;ÝŒNÐ?ÀÅsÈ1ÁvÄvÑNÔNÐNØ(+°rÐ:Ð:Ð:Ð:Ð:Ð:Ð:Ð:øøøøð	;øøøs   Á	BC Ã
DÃ 'DÄDÄDr±   c              ƒ   óT  K  — t           j                             |d¦  «        }	 | j                             |t          j        |dd¬¦  «                             d¦  «        ¦  «        ƒ d{V —† dS # t          $ r.}t          j
        d|t          |¦  «        ¦  «         Y d}~dS d}~ww xY w)z¨Persist the .skills index file.

        Args:
            skills_dir (`str`): The skills directory path.
            data (`_SkillsFile`): The index to write.
        r°   r   F)ÚindentÚensure_asciir_   Nz Failed to save .skills to %s: %s)r>   r:   ru   rB   Ú
write_filerx   ÚdumpsÚencoder}   r	   r~   r   )rH   rš   r±   r:   rd   s        r   r“   z LocalWorkspace._save_skills_fileF  sÜ   è è € õ Œw�|Š|˜J¨	Ñ2Ô2ˆð	MØ”-×*Ò*ØÝ”
˜4¨¸Ð>Ñ>Ô>×EÒEÀgÑNÔNñô ð ð ð ð ð ð ð ð ð øõ ð 	Mð 	Mð 	MÝŒNÐ=¸tÅSÈÁVÄVÑLÔLÐLÐLÐLÐLÐLÐLÐLøøøøð	Møøøs   ¤A	A/ Á/
B'Á9#B"Â"B'r¡   c              ƒ   ó†  K  — t           j                             |d¦  «        }	 | j                             |¦  «        ƒ d{V —†st          j        d|¦  «         dS | j                             |¦  «        ƒ d{V —†}|                     d¦  «        }t          j
        |¦  «        }|                     d¦  «        }|                     d¦  «        }|r|st          j        d|¦  «         dS t          |¦  «        t          |¦  «        |fS # t          $ r.}t          j        d|t          |¦  «        ¦  «         Y d}~dS d}~ww xY w)	aI  Validate if a skill path contains a valid SKILL.md file.

        Args:
            skill_path (`str`):
                The path to the skill directory.

        Returns:
            `tuple[str, str, str] | None`:
                A tuple of (name, description, skill_md_content) if valid,
                None otherwise.
        úSKILL.mdNz'Invalid skill at %s: SKILL.md not foundr_   r&   ÚdescriptionzKInvalid skill at %s: SKILL.md missing required fields (name or description)z"Failed to validate skill at %s: %s)r>   r:   ru   rB   rv   r	   r~   rw   rz   Úfrontmatterry   r   r   r}   )	rH   r¡   Úskill_md_pathr•   Úcontent_strÚcontentr&   rº   rd   s	            r   Ú_validate_skillzLocalWorkspace._validate_skillZ  sy  è è € õ œŸš Z°Ñ<Ô<ˆð"	àœ×2Ò2°=ÑAÔAÐAÐAÐAÐAÐAÐAð Ý”Ø=Øñô ð ð �tð œ×/Ò/°Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>ˆCØŸ*š* WÑ-Ô-ˆKõ "Ô'¨Ñ4Ô4ˆGØ—;’;˜vÑ&Ô&ˆDØ!Ÿ+š+ mÑ4Ô4ˆKàð ˜{ð Ý”ð3àñô ð ð
 �tå�t‘9”9�c +Ñ.Ô.°Ð;Ð;øåð 	ð 	ð 	ÝŒNØ4ØÝ�A‘”ñô ð ð
 �4�4�4�4�4øøøøð	øøøs$   ¤5D ÁBD Ã)D Ä
E Ä#D;Ä;E c              ƒ   óÌ   K  — |                       |¦  «        ƒ d{V —†}|€dS |\  }}}t          j        |                     d¦  «        ¦  «                             ¦   «         }|||fS )a6  Validate a skill and compute its hash.

        Args:
            skill_path (`str`):
                The path to the skill directory.

        Returns:
            `tuple[str, str, str] | None`:
                A tuple of (skill_path, skill_name, skill_hash) if valid,
                None otherwise.
        Nr_   )r¿   ÚhashlibÚsha256r·   Ú	hexdigest)rH   r¡   Úvalidation_resultr   r)   Úskill_md_contentr¤   s          r   r‰   z'LocalWorkspace._validate_and_hash_skill�  s…   è è € ð #'×"6Ò"6°zÑ"BÔ"BÐBÐBÐBÐBÐBÐBÐØÐ$Ø�4à*;Ñ'ˆ
�AÐ'õ ”^Ø×#Ò# GÑ,Ô,ñ
ô 
ç
Š)‰+Œ+ð 	ð ˜: zÐ1Ð1r   c              ƒ   óH  K  — | j         4 ƒd{V —† | j        D ]^}|j        rU|j        rN	 |                     ¦   «         ƒ d{V —† Œ,# t
          $ r%}t          j        d|j        |¦  «         Y d}~ŒVd}~ww xY wŒ_	 ddd¦  «        ƒd{V —† n# 1 ƒd{V —†swxY w Y   d| _	        dS )u’  Close every stateful MCP attached to this workspace.

        ``LocalWorkspace`` itself owns no resources (the workdir is
        the persistence layer and is left untouched), but stdio /
        stateful HTTP MCPs hold long-lived sessions that have to be
        closed explicitly. Stateless HTTP MCPs are skipped â€” they
        spin up an ad-hoc session per call and have nothing to close.
        Nz7Failed to close MCP %r when closing local workspace: %sF)
rG   rC   r�   r‚   Úcloser}   r	   r~   r&   rs   )rH   r™   rd   s      r   rÇ   zLocalWorkspace.close«  s{  è è € ð ”>ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	Ø”zð ð �Ø”?ð  sÔ'7ð ð
Ø!Ÿiši™kœkÐ)Ð)Ð)Ð)Ð)Ð)Ð)Ð)øÝ$ð ð ð Ýœð!Cð  œHØñô ð ð ð ð ð ð øøøøðøøøøð	ð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð ˆŒˆˆs:   �B
©AÁB
Á
A3ÁA.Á)B
Á.A3Á3B
Â

BÂBc              ƒ   óP  K  — | j         4 ƒd{V —† | j        D ]^}|j        rU|j        rN	 |                     ¦   «         ƒ d{V —† Œ,# t
          $ r%}t          j        d|j        |¦  «         Y d}~ŒVd}~ww xY wŒ_g | _        t          j
                             | j        d¦  «        }| j                             |¦  «        ƒ d{V —† ddd¦  «        ƒd{V —† n# 1 ƒd{V —†swxY w Y   | j        4 ƒd{V —† t          j
                             | j        d¦  «        }| j                             |¦  «        ƒ d{V —† ddd¦  «        ƒd{V —† n# 1 ƒd{V —†swxY w Y   dD ]G}t          j
                             | j        |¦  «        }| j                             |¦  «        ƒ d{V —† ŒHdS )zõReturn the workspace to an empty state.

        Closes and drops all MCPs (including the persisted ``.mcp``)
        and deletes ``skills/``, ``sessions/``, and ``data/``.
        ``default_mcps`` and ``skill_paths`` are not re-seeded.
        Nz$MCP %r close failed during reset: %sr^   r#   )Úsessionsr±   )rG   rC   r�   r‚   rÇ   r}   r	   r~   r&   r>   r:   ru   r4   rB   Údelete_pathrF   )rH   r™   rd   r”   Úskills_pathr+   r:   s          r   ÚresetzLocalWorkspace.resetÄ  s  è è € ð ”>ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6Ø”zð 	ð 	�Ø”?ð  sÔ'7ð ðØ!Ÿiši™kœkÐ)Ð)Ð)Ð)Ð)Ð)Ð)Ð)øÝ$ð ð ð ÝœØBØœHØñô ð ð ð ð ð ð øøøøðøøøøð ˆDŒJå”w—|’| D¤L°&Ñ9Ô9ˆHØ”-×+Ò+¨HÑ5Ô5Ð5Ð5Ð5Ð5Ð5Ð5Ð5ð	6ð 	6ð 	6ñ 	6ô 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6ð 	6øøøð 	6ð 	6ð 	6ð 	6ð  Ô#ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9Ýœ'Ÿ,š, t¤|°XÑ>Ô>ˆKØ”-×+Ò+¨KÑ8Ô8Ð8Ð8Ð8Ð8Ð8Ð8Ð8ð	9ð 	9ð 	9ñ 	9ô 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9ð 	9øøøð 	9ð 	9ð 	9ð 	9ð (ð 	2ð 	2ˆCÝ”7—<’< ¤¨cÑ2Ô2ˆDØ”-×+Ò+¨DÑ1Ô1Ð1Ð1Ð1Ð1Ð1Ð1Ð1Ð1ð	2ð 	2sN   �C©AÁCÁ
A3ÁA.Á)CÁ.A3Á3ACÃ
CÃ"CÃ3AEÅ
EÅEc           	   ƒ   óN  ‡ ‡K  — t           j                             ‰ j        d¦  «        Š‰ j        4 ƒd{V —† ‰ j                             ‰¦  «        ƒ d{V —†sg cddd¦  «        ƒd{V —† S ‰                      ‰¦  «        ƒ d{V —†}‰ j                             ‰¦  «        ƒ d{V —†}|€d}||d         k    r‰  	                    ‰||¦  «        ƒ d{V —†}ˆ ˆfd„|d          
                    ¦   «         D ¦   «         }t          j        |ddiŽƒ d{V —†}g }t          |d         |¦  «        D ]U\  }}t          |t          ¦  «        r$t!          j        d|t%          |¦  «        ¦  «         Œ>|�|                     |¦  «         ŒV|cddd¦  «        ƒd{V —† S # 1 ƒd{V —†swxY w Y   dS )	aƒ  List all skills available in the workspace.

        The method uses the .skills index for agent-facing names, compares the
        skills directory mtime to detect manual additions/removals since the
        last write, and reconciles the index when a change is found.

        Returns:
            `list[Skill]`:
                A list of Skill objects found in the workspace.
        r#   Nrr   r"   c                 óŠ   •— g | ]?\  }}‰                      t          j                             ‰|¦  «        |d          ¦  «        ‘Œ@S rh   )Ú_load_single_skillr>   r:   ru   )r9   r¨   rª   rH   rš   s      €€r   r;   z.LocalWorkspace.list_skills.<locals>.<listcomp>  sZ   ø€ ð ð ð ñ
 $�H˜eð	 ×'Ò'Ý”G—L’L ¨XÑ6Ô6Ø˜,Ô'ñô ðð ð r   Úreturn_exceptionsTú Failed to load skill from %s: %s)r>   r:   ru   r4   rF   rB   Úis_dirr…   r’   Ú_reconcile_skills_dirÚitemsrD   ÚgatherÚzipÚ
isinstancer}   r	   r~   r   r{   )	rH   r›   Úcurrent_mtimeÚtasksÚresultsr#   r¨   r¢   rš   s	   `       @r   Úlist_skillszLocalWorkspace.list_skillsã  sì  øøè è € õ ”W—\’\ $¤,°Ñ9Ô9ˆ
ØÔ#ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	Øœ×-Ò-¨jÑ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9ð Øð&	ð &	ð &	ð &	ñ &	ô &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð !%× 6Ò 6°zÑ BÔ BÐBÐBÐBÐBÐBÐBˆKØ"&¤-×":Ò":¸:Ñ"FÔ"FÐFÐFÐFÐFÐFÐFˆMØÐ$Ø #�ð  Ð,>Ô ?Ò?Ð?Ø$(×$>Ò$>ØØØ!ñ%ô %ð ð ð ð ð ð �ðð ð ð ð ð
 (3°8Ô'<×'BÒ'BÑ'DÔ'Dðñ ô ˆEõ $œN¨EÐJÀTÐJÐJÐJÐJÐJÐJÐJÐJˆGàˆFÝ$'¨°HÔ(=¸wÑ$GÔ$Gð *ð *Ñ �˜&Ý˜f¥iÑ0Ô0ð *Ý”NØ:Ø Ý˜F™œñô ð ð ð
 Ð'Ø—M’M &Ñ)Ô)Ð)øàðM&	ð &	ð &	ð &	ñ &	ô &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	ð &	øøøð &	ð &	ð &	ð &	ð &	ð &	s   ·"FÁ,DFÆ
FÆ!Fr›   rØ   c              ƒ   ó.  K  — |d         }|d         }| j                              |¦  «        ƒ d{V —†}t          ¦   «         }|D ]W}t          j                             ||¦  «        }	| j                              |	¦  «        ƒ d{V —†r|                     |¦  «         ŒXt          |                     ¦   «         ¦  «        }
d}|
|z
  D ]}t          j
        d|¦  «         ||= d}Œd„ |                     ¦   «         D ¦   «         }d„ |                     ¦   «         D ¦   «         }||
z
  D ]Å}t          j                             ||¦  «        }|                      |¦  «        ƒ d{V —†}|€Œ@|\  }}}||v rt          j
        d	|¦  «         Œ`|}d
}||v r|› d|› d�}|d
z  }||v °||dœ}|||<   |                     |¦  «         |                     |¦  «         d}t          j
        d||¦  «         ŒÆ||d<   ||d<   |s||k    r|                      ||¦  «        ƒ d{V —† |S )ak  Reconcile the .skills index after the skills directory has changed.

        Handles:
        - Manually deleted subdirectories: removed from the index.
        - Manually added subdirectories: validated and added with conflict
          resolution for both directory name and agent-facing skill name.

        Args:
            skills_dir (`str`): Path to the skills directory.
            skills_file (`_SkillsFile`): The current (stale) index.
            current_mtime (`float`): The freshly-read mtime of skills_dir.

        Returns:
            `_SkillsFile`: The updated index (also persisted to disk).
        r#   r"   NFz,Skill directory '%s' removed, updating indexTc                 ó   — h | ]
}|d          ’ŒS rh   r   rc   s     r   re   z7LocalWorkspace._reconcile_skills_dir.<locals>.<setcomp>E  ri   r   c                 ó   — h | ]
}|d          ’ŒS rb   r   rc   s     r   re   z7LocalWorkspace._reconcile_skills_dir.<locals>.<setcomp>H  rf   r   z;Manually added skill '%s' already tracked by hash, skippingr   rl   rm   rq   z4Manually added skill '%s' indexed as agent name '%s')rB   Úlist_dirr‡   r>   r:   ru   rÒ   r‘   rˆ   r	   rŠ   r†   r‰   r“   )rH   rš   r›   rØ   rœ   Úoriginal_mtimeÚentriesÚactual_dirsÚdÚdir_pathÚindexed_dirsr    Úremovedrž   r�   Únew_dirr¡   r¢   r)   r£   r¤   r¥   r¦   rª   s                           r   rÓ   z$LocalWorkspace._reconcile_skills_dir  sç  è è € ð* ,7°xÔ+@ˆØ$Ð%7Ô8ˆð œ×.Ò.¨zÑ:Ô:Ð:Ð:Ð:Ð:Ð:Ð:ˆÝ #¡¤ˆØð 	#ð 	#ˆAÝ”w—|’| J°Ñ2Ô2ˆHØ”]×)Ò)¨(Ñ3Ô3Ð3Ð3Ð3Ð3Ð3Ð3ð #Ø—’ Ñ"Ô"Ð"øå˜8Ÿ=š=™?œ?Ñ+Ô+ˆàˆð $ kÑ1ð 	ð 	ˆGÝŒKØ>Øñô ð ð ˜Ð!ØˆGˆGð*
ð *
Ø%-§_¢_Ñ%6Ô%6ð*
ñ *
ô *
Ðð %KÐ$J¸¿ºÑ8IÔ8IÐ$JÑ$JÔ$Jˆà" \Ñ1ð 	ð 	ˆGÝœŸš j°'Ñ:Ô:ˆJØ×8Ò8¸ÑDÔDÐDÐDÐDÐDÐDÐDˆFØˆ~Øà&,Ñ#ˆAˆx˜à˜_Ð,Ð,Ý”ðàñô ð ð
 à!ˆJØˆGØÐ 4Ð4Ð4Ø (Ð6Ð6¨GÐ6Ð6Ð6�
Ø˜1‘�ð Ð 4Ð4Ð4ð +5ÀJÐ!OÐ!OˆEØ %ˆH�WÑØ ×$Ò$ ZÑ0Ô0Ð0Ø×Ò 
Ñ+Ô+Ð+ØˆGÝŒKØFØØñô ð ð ð !)ˆ�HÑØ*7ˆÐ&Ñ'ð ð 	B�m ~Ò5Ð5Ø×(Ò(¨°[ÑAÔAÐAÐAÐAÐAÐAÐAÐAàÐr   Ú	skill_dirr   c              ƒ   ó„  K  — t           j                             |d¦  «        }	 | j                             |¦  «        ƒ d{V —†sdS | j                             |¦  «        ƒ d{V —†}|€d}| j                             |¦  «        ƒ d{V —†}|                     d¦  «        }t          j	        |¦  «        }| 
                    d¦  «        }|st          j        d|¦  «         dS t          |t          |¦  «        ||j        |¬¦  «        S # t           $ r.}	t          j        d|t          |	¦  «        ¦  «         Y d}	~	dS d}	~	ww xY w)	a¢  Load a single skill from disk using the agent-facing name from
        the index.

        Args:
            skill_dir (`str`):
                The skill directory path containing SKILL.md.
            skill_name (`str`):
                The agent-facing name stored in the .skills index.

        Returns:
            `Skill | None`:
                A Skill object or None if the SKILL.md is missing/invalid.
        r¹   Nrr   r_   rº   z2SKILL.md in %s is missing 'description'. Skipping.)r&   rº   ÚdirÚmarkdownÚ
updated_atrÑ   )r>   r:   ru   rB   rv   r’   rw   rz   r»   ry   r   r	   r~   r   r   r¾   r}   )
rH   rè   r   r¼   rì   r•   r½   r¾   rº   rd   s
             r   rÏ   z!LocalWorkspace._load_single_skillw  sˆ  è è € õ$ œŸš Y°
Ñ;Ô;ˆð"	Øœ×2Ò2°=ÑAÔAÐAÐAÐAÐAÐAÐAð Ø�tà#œ}×7Ò7¸ÑFÔFÐFÐFÐFÐFÐFÐFˆJØÐ!Ø �
àœ×/Ò/°Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>ˆCØŸ*š* WÑ-Ô-ˆKÝ!Ô'¨Ñ4Ô4ˆGà!Ÿ+š+ mÑ4Ô4ˆKØð Ý”ØHØñô ð ð �tåØÝ Ñ,Ô,ØØ œØ%ðñ ô ð øõ ð 	ð 	ð 	ÝŒNØ2ØÝ�A‘”ñô ð ð
 �4�4�4�4�4øøøøð	øøøs$   ¤ D ÁBD Ã!%D Ä
D?Ä#D:Ä:D?Ú
mcp_clientc              ƒ   ó˜  ‡K  — | j         4 ƒd{V —† t          ˆfd„| j        D ¦   «         ¦  «        rt          d‰j        ›d�¦  «        ‚‰j        r!‰j        s‰                     ¦   «         ƒ d{V —† | j                             ‰¦  «         |  	                    ¦   «         ƒ d{V —† ddd¦  «        ƒd{V —† dS # 1 ƒd{V —†swxY w Y   dS )a|  Add an MCP client, connect it if stateful, and persist.

        Args:
            mcp_client (`MCPClient`):
                The MCP client to add.

        Raises:
            ValueError:
                If an MCP with the same name already exists. Names are
                unique because they compose the model-facing tool name
                ``mcp__{name}__{tool}``.
        Nc              3   ó8   •K  — | ]}|j         ‰j         k    V — Œd S )Nr,   )r9   r—   rí   s     €r   ú	<genexpr>z)LocalWorkspace.add_mcp.<locals>.<genexpr>½  s,   øè è € ÐAÐA°�1”6˜Zœ_Ò,ÐAÐAÐAÐAÐAÐAr   zMCP z already exists in workspace.)
rG   ÚanyrC   Ú
ValueErrorr&   r�   r‚   rƒ   r{   r€   )rH   rí   s    `r   Úadd_mcpzLocalWorkspace.add_mcp¯  s�  øè è € ð ”>ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ÝÐAÐAÐAÐA°d´jÐAÑAÔAÑAÔAð Ý ØK˜:œ?ÐKÐKÐKñô ð ð Ô%ð +¨jÔ.Eð +Ø ×(Ò(Ñ*Ô*Ð*Ð*Ð*Ð*Ð*Ð*Ð*ØŒJ×Ò˜jÑ)Ô)Ð)Ø×%Ò%Ñ'Ô'Ð'Ð'Ð'Ð'Ð'Ð'Ð'ð	(ð 	(ð 	(ñ 	(ô 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(ð 	(øøøð 	(ð 	(ð 	(ð 	(ð 	(ð 	(s   ‘BB9Â9
CÃCr&   c              ƒ   óÂ  K  — | j         4 ƒd{V —† t          | j        ¦  «        D ]€\  }}|j        |k    rp|j        r!|j        r|                     ¦   «         ƒ d{V —† | j                             |¦  «         |                      ¦   «         ƒ d{V —†  ddd¦  «        ƒd{V —† dS Œ�	 ddd¦  «        ƒd{V —† n# 1 ƒd{V —†swxY w Y   t          j
        d|¦  «         dS )z©Remove an MCP client by name, disconnecting it if stateful.

        Args:
            name (`str`):
                The ``name`` field of the client to remove.
        Nz$MCP client %r not found in workspace)rG   Ú	enumeraterC   r&   r�   r‚   rÇ   Úpopr€   r	   r~   )rH   r&   Úir™   s       r   Ú
remove_mcpzLocalWorkspace.remove_mcpÆ  sÁ  è è € ð ”>ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	Ý# D¤JÑ/Ô/ð ð ‘��3Ø”8˜tÒ#Ð#Ø”ð *¨3Ô+;ð *Ø!Ÿiši™kœkÐ)Ð)Ð)Ð)Ð)Ð)Ð)Ø”J—N’N 1Ñ%Ô%Ð%Ø×-Ò-Ñ/Ô/Ð/Ð/Ð/Ð/Ð/Ð/Ð/Øð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	à#ðð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	õ 	ŒÐ=¸tÑDÔDÐDÐDÐDs   �BB9Â%B9Â9
CÃCc              ƒ   óœ  K  — t          |¦  «        }t          j                             | j        d¦  «        }| j        4 ƒd{V —† t          j        |d¬¦  «         |                      |¦  «        ƒ d{V —†}|€t          d|›d�¦  «        ‚|\  }}}|  	                    |¦  «        ƒ d{V —†}|d         }d„ | 
                    ¦   «         D ¦   «         }	||	v r2t          j        d||dd	…         ¦  «         	 ddd¦  «        ƒd{V —† dS d
„ | 
                    ¦   «         D ¦   «         }
t          |                     ¦   «         ¦  «        }|}d}||
v r|› d|› d�}|dz  }||
v °t          |¦  «        }|}d}||v r|› d|› �}|dz  }||v °t          j                             ||¦  «        }t          j                             |¦  «                             t          j                             |¦  «        t          j        z   ¦  «        st          d|›d�¦  «        ‚t'          j        t*          j        ||d¬¦  «        ƒ d{V —† t          j        d||||¦  «         ||dœ||<   ||d<   | j                             |¦  «        ƒ d{V —†}|�|nd|d<   |                      ||¦  «        ƒ d{V —† ddd¦  «        ƒd{V —† dS # 1 ƒd{V —†swxY w Y   dS )a‚  Add a skill to the workspace by copying from the given path.

        The skill directory must contain a valid ``SKILL.md`` file with
        ``name`` and ``description`` frontmatter fields.  Duplicate skills
        (identified by the SHA-256 hash of ``SKILL.md``) are silently skipped.
        Name and directory conflicts are resolved by appending a numeric
        suffix.

        Args:
            skill_path (`str`):
                Absolute or relative path to the skill directory to copy.

        Raises:
            ValueError: If the skill at ``skill_path`` is invalid (missing or
                malformed ``SKILL.md``).
        r#   NTr\   zInvalid skill at zK: missing or malformed SKILL.md (requires 'name' and 'description' fields).c                 ó   — h | ]
}|d          ’ŒS rb   r   rc   s     r   re   z+LocalWorkspace.add_skill.<locals>.<setcomp>ù  s   € Ð(NÐ(NÐ(N°q¨¨6¬Ð(NÐ(NÐ(Nr   rj   rk   c                 ó   — h | ]
}|d          ’ŒS rh   r   rc   s     r   re   z+LocalWorkspace.add_skill.<locals>.<setcomp>  s)   € ð .ð .ð .Ø$%��,”ð.ð .ð .r   r   rl   rm   r)   zSkill path z resolves outside skills_dir.Frn   rp   rq   rr   r"   )r   r>   r:   ru   r4   rF   rt   r‰   rò   r…   r†   r	   rŠ   r‡   rˆ   r-   r‹   rŒ   r�   rD   rŽ   r�   r�   rB   r’   r“   )rH   r¡   rš   r¢   r)   r£   r¤   r›   rœ   r�   rž   rŸ   r¥   r¦   r§   r¨   r©   r«   s                     r   Ú	add_skillzLocalWorkspace.add_skill×  sß  è è € õ" +¨:Ñ6Ô6ˆ
Ý”W—\’\ $¤,°Ñ9Ô9ˆ
ØÔ#ð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	BÝŒK˜
¨TÐ2Ñ2Ô2Ð2à×8Ò8¸ÑDÔDÐDÐDÐDÐDÐDÐDˆFØˆ~Ý ðK¨
ð Kð Kð Kñô ð ð
 '-Ñ#ˆAˆx˜à $× 6Ò 6°zÑ BÔ BÐBÐBÐBÐBÐBÐBˆKØ/:¸8Ô/DˆHà(NÐ(N¸H¿OºOÑ<MÔ<MÐ(NÑ(NÔ(NˆOØ˜_Ð,Ð,Ý”ØGØØ˜r ˜r”Nñô ð ð
 ð-J	Bð J	Bð J	Bñ J	Bô J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð0.ð .Ø)1¯ªÑ):Ô):ð.ñ .ô .Ð õ ,/¨x¯}ª}©¬Ñ+?Ô+?Ðð "ˆJØˆGØÐ 4Ð4Ð4Ø (Ð6Ð6¨GÐ6Ð6Ð6�
Ø˜1‘�ð Ð 4Ð4Ð4õ
 *¨(Ñ3Ô3ˆHØˆHØˆGØÐ0Ð0Ð0Ø&Ð2Ð2¨Ð2Ð2�Ø˜1‘�ð Ð0Ð0Ð0õ œŸš Z°Ñ:Ô:ˆIå”7×#Ò# IÑ.Ô.×9Ò9Ý”× Ò  Ñ,Ô,­r¬vÑ5ñô ð õ !ØM *ÐMÐMÐMñô ð õ Ô#Ý”ØØØ#ð	ñ ô ð ð ð ð ð ð ð õ ŒKØDØØØØñô ð ð +5ÀJÐ!OÐ!OˆH�XÑØ$,ˆK˜Ñ!Øœ-×2Ò2°:Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>ˆEàÐ*��°ð Ð*Ñ+ð ×(Ò(¨°[ÑAÔAÐAÐAÐAÐAÐAÐAÐAðUJ	Bð J	Bð J	Bñ J	Bô J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bøøøð J	Bð J	Bð J	Bð J	Bð J	Bð J	Bs   ÁB1J;ÄF J;Ê;
KËKÚstreamÚfmt)rÖ   Útarútar.gzr¨   Úmax_extracted_bytesc              ƒ   ó6  K  — t           j                             | j        dt	          ¦   «         › �¦  «        }|› d|dk    rdn|› �}	 | j                             ||¦  «        ƒ d{V —† | j                             ddt          |||t          |¦  «        g¦  «        ƒ d{V —†}| 
                    ¦   «         s+t          d|j                             dd	¦  «        › �¦  «        ‚|                      |                      |¦  «        ƒ d{V —†¦  «        ƒ d{V —† | j                             |¦  «        ƒ d{V —† | j                             |¦  «        ƒ d{V —† dS # | j                             |¦  «        ƒ d{V —† | j                             |¦  «        ƒ d{V —† w xY w)
u¹  Expand a skill archive, then install it as a local directory.

        Unpacks inside the workspace and hands the result to
        :meth:`add_skill`, so hash dedup, name conflict resolution and
        the ``.skills`` index behave exactly as for a path install â€”
        which is also why ``dir_name`` is ignored here: the directory
        name comes from the ``SKILL.md`` front matter.

        Args:
            stream (`AsyncIterator[bytes]`):
                The archive bytes, in order.
            fmt (`Literal["zip", "tar", "tar.gz"]`):
                The archive format.
            dir_name (`str`):
                Unused; kept for interface compatibility.
            max_extracted_bytes (`int`):
                Ceiling on the archive's expanded size.

        Raises:
            ValueError:
                If the archive holds no valid ``SKILL.md``.
            RuntimeError:
                If expanding the archive fails.
        z.skill-staging-ú.r   NÚpython3z-cz Failed to expand skill archive: r_   Úreplace)r>   r:   ru   r4   r
   rB   Úwrite_streamÚ
exec_shellr   r   ÚokÚRuntimeErrorÚstderrrz   rü   Ú_find_skill_rootrÊ   )rH   rý   rþ   r¨   r  ÚstagingÚarchive_pathr¢   s           r   Úadd_skill_archivez LocalWorkspace.add_skill_archive6  s  è è € õ> ”'—,’,ØŒLØ.�l™nœnÐ.Ð.ñ
ô 
ˆð "ÐJÐJ°°x²° H HÀSÐJÐJˆð	:Ø”-×,Ò,¨\¸6ÑBÔBÐBÐBÐBÐBÐBÐBÐBØœ=×3Ò3àØÝ)Ø ØØÝÐ+Ñ,Ô,ðñ
ô 
ð 
ð 
ð 
ð 
ð 
ð 
ˆFð —9’9‘;”;ð Ý"ðBØ”}×+Ò+¨G°YÑ?Ô?ðBð Bñô ð ð —.’. t×'<Ò'<¸WÑ'EÔ'EÐ!EÐ!EÐ!EÐ!EÐ!EÐ!EÑFÔFÐFÐFÐFÐFÐFÐFÐFà”-×+Ò+¨GÑ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ø”-×+Ò+¨LÑ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9Ð9Ð9Ð9øð ”-×+Ò+¨GÑ4Ô4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ø”-×+Ò+¨LÑ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9Ð9Ð9øøøs   ÁCE ÅAFc              ƒ   óð  K  — t           j                             | j        d¦  «        }| j        4 ƒd{V —† | j                             |¦  «        ƒ d{V —†s)t          j        d|¦  «         	 ddd¦  «        ƒd{V —† dS |  	                    |¦  «        ƒ d{V —†}|d         }d}| 
                    ¦   «         D ]\  }}|d         |k    r|} nŒ|€)t          j        d|¦  «         	 ddd¦  «        ƒd{V —† dS t           j                             ||¦  «        }| j                             |¦  «        ƒ d{V —†r7| j                             |¦  «        ƒ d{V —† t          j        d||¦  «         nt          j        d|¦  «         ||= ||d<   | j                             |¦  «        ƒ d{V —†}	|	�|	nd|d	<   |                      ||¦  «        ƒ d{V —† ddd¦  «        ƒd{V —† dS # 1 ƒd{V —†swxY w Y   dS )
a  Remove a skill from the workspace by its agent-facing name.

        The skill directory is deleted from disk and the ``.skills`` index is
        updated.  If no skill with the given name is found, a warning is
        logged and the method returns without error.

        Args:
            name (`str`):
                The agent-facing name of the skill to remove (as stored in the
                ``.skills`` index, i.e. the ``name`` field from ``SKILL.md``
                possibly with a numeric suffix for de-duplication).
        r#   Nz7Skills directory does not exist; cannot remove skill %rr   zSkill %r not found in workspacezRemoved skill '%s' from %sz:Skill directory %r not found on disk; removing index entryrr   r"   )r>   r:   ru   r4   rF   rB   rÒ   r	   r~   r…   rÔ   rÊ   rŠ   r’   r“   )
rH   r&   rš   r›   rœ   Ú
target_dirr¨   rª   Úskill_dir_pathr«   s
             r   Úremove_skillzLocalWorkspace.remove_skillq  sµ  è è € õ ”W—\’\ $¤,°Ñ9Ô9ˆ
ØÔ#ð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	BØœ×-Ò-¨jÑ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9ð Ý”ØMØñô ð ð ð,	Bð ,	Bð ,	Bñ ,	Bô ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð !%× 6Ò 6°zÑ BÔ BÐBÐBÐBÐBÐBÐBˆKØ/:¸8Ô/DˆHà%)ˆJØ#+§>¢>Ñ#3Ô#3ð ð ‘�˜%Ø˜Ô&¨$Ò.Ð.Ø!)�JØ�Eð /ð Ð!Ý”Ð@À$ÑGÔGÐGØð',	Bð ,	Bð ,	Bñ ,	Bô ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bõ*  œWŸ\š\¨*°jÑAÔAˆNØ”]×)Ò)¨.Ñ9Ô9Ð9Ð9Ð9Ð9Ð9Ð9ð Ø”m×/Ò/°Ñ?Ô?Ð?Ð?Ð?Ð?Ð?Ð?Ð?Ý”Ø0ØØ"ñô ð ð õ ”ð/ð #ñô ð ð ˜Ð$Ø$,ˆK˜Ñ!Øœ-×2Ò2°:Ñ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>ˆEàÐ*��°ð Ð*Ñ+ð ×(Ò(¨°[ÑAÔAÐAÐAÐAÐAÐAÐAÐAðY,	Bð ,	Bð ,	Bñ ,	Bô ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bøøøð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bð ,	Bs   µ7G%Á?A'G%Ã9CG%Ç%
G/Ç2G/)r'   N)%r   r   r   r   r   r   rA   r   r=   r   rZ   r¬   r®   r!   r…   r“   Útupler¿   r‰   rÇ   rÌ   r   rÛ   r$   rÓ   rÏ   ró   rø   rü   r   r   Úbytesr   Úintr  r  Ú__classcell__)rI   s   @r   r/   r/   @   sŠ  ø€ € € € € ð	ð 	ð $(Ø/3Ø(,Ø:ð3(ð 3(ð 3(ð ð3(ð ˜D‘jð	3(ð
 ˜9”o¨Ñ,ð3(ð ˜#”Y Ñ%ð3(ð ð3(ð 
ð3(ð 3(ð 3(ð 3(ð 3(ð 3(ðj
 $ x¤.ð 
ð 
ð 
ð 
ð.Pð Pð Pð Pðd!¨ð !ð !ð !ð !ð;°#ð ;¸+ð ;ð ;ð ;ð ;ð0MàðMð ðMð 
ð	Mð Mð Mð Mð(3àð3ð 
ˆs�C˜ˆ}Ô	 Ñ	$ð3ð 3ð 3ð 3ðj2àð2ð 
ˆs�C˜ˆ}Ô	 Ñ	$ð2ð 2ð 2ð 2ð8ð ð ð ð22ð 2ð 2ð 2ð>2 4¨¤;ð 2ð 2ð 2ð 2ðh^àð^ð !ð^ð ð	^ð
 
ð^ð ^ð ^ð ^ð@6àð6ð ð6ð 
�‰ð	6ð 6ð 6ð 6ðp(¨	ð (°dð (ð (ð (ð (ð.E Sð E¨Tð Eð Eð Eð Eð"]B¨#ð ]B°$ð ]Bð ]Bð ]Bð ]BðH $?ð9:ð 9:à˜eÔ$ð9:ð Ð+Ô,ð9:ð ð	9:ð
 !ð9:ð 
ð9:ð 9:ð 9:ð 9:ðv:B sð :B¨tð :Bð :Bð :Bð :Bð :Bð :Bð :Bð :Br   r/   )$r   rD   rÁ   rx   r>   r*   r�   Útypingr   r   r   r»   Ú_utilsr   Ú_loggingr	   Ú_utils._commonr
   r   r™   r   Úskillr   rU   r   Útool._builtin._backendr   Ú_baser   r   r   r   r!   r   r-   r/   r   r   r   ú<module>r     sï  ðà  Ð  à €€€Ø €€€Ø €€€Ø 	€	€	€	Ø 	€	€	€	Ø €€€Ø 4Ð 4Ð 4Ð 4Ð 4Ð 4Ð 4Ð 4Ð 4Ð 4à Ð Ð Ð à 2Ð 2Ð 2Ð 2Ð 2Ð 2Ø Ð Ð Ð Ð Ð Ø @Ð @Ð @Ð @Ð @Ð @Ð @Ð @Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð Ø 1Ð 1Ð 1Ð 1Ð 1Ð 1ðð ð ð ð ð ð ð ð ð ðNð Nð Nð Nð N�)ñ Nô Nð NðOð Oð Oð Oð O�)ñ Oô Oð Oð/˜Sð / Sð /ð /ð /ð /ð$kBð kBð kBð kBð kB�]ñ kBô kBð kBð kBð kBr   