Ë
    ãß²jçº  ã                   ó"  — U d Z ddlZddlZddlZddlmZmZ ddl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mZ ddlZddlmZmZ ddlmZmZ ddlmZ dd	lmZmZm Z!m"Z" dd
l#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+m,Z,m-Z-m.Z/ ddl0m1Z1m2Z2m3Z3m4Z4m5Z5 ddl6m7Z7m8Z8m9Z9  ejt                  e;«      Z<de=fd„Z>dedee?   fd„Z@ e«       ZAeAdz  ZBeBZCdefd„ZDde?defd„ZEde?fd„ZFd„ ZGdZHdZIdZJdZK e	j˜                  d«      ZMh d£ZN e	j˜                  d«      ZOdZPde?fd„ZQd e?d!e?d"e?dee?   fd#„ZRde?dee?   fd$„ZSd%ee?   dee?   fd&„ZTd'd(œd)e?d*e=dee?   fd+„ZUd£d)e?d!e?dee?   fd,„ZVd)e?de?fd-„ZWd¤de?d%e?defd.„ZXd/efd0„ZYde?deee?ef      fd1„ZZde?deee?ef      fd2„Z[d¥de?d3e?de?fd4„Z\d5e?dee?   fd6„Z]ded5e?fd7„Z^d¥d8d9œde?d:e?d;e?d<e=fd=„Z_de?ded>ed:e?d!e?d)e?deee?ef      fd?„Z`d@ee?ef   de?dedee?ef   fdA„Zad@ee?ef   d)e?dee?ef   fdB„Zbd¤d@ee?ef   dCedDee?   ddfdE„ZcdFe?dGeddHe?de?fdI„Zed¤de?d)e?d%e?dee?ef   fdJ„Zfde?d)e?dee?ef   fdK„Zg	 	 d¦de?dLe?dMe?d5e?dNe=dee?ef   fdO„Zhd¤de?dPee?   dee?ef   fdQ„ZidRedSeddfdT„Zjde?d5e?dUe?dee?ef   fdV„Zkde?d5e?dee?ef   fdW„Zl ejÚ                  dXd'¬Y«      ZndZeod[<   d\„ Zpd]„ Zqd^Zrd_ee?ef   de?fd`„Zsd_ee?ef   de?fda„Zti Zuee?ejì                  f   eodb<    ejî                  «       ZxdcZydde?ddfde„Zzdf„ Z{dg„ dh„ e{di„ dj„ dk„ dlœZ|	 	 d§dm„Z}	 	 	 	 d¨d:e?de?d)e?d%e?d5e?dUe?dLe?dMe?dNe=dPe?dne?doe?de?fdp„Z~dqe?de?fdr„Zde€fds„Z�dtduiZ‚dudvdwœZƒdudxdwœZ„dudydwœZ…d:e?dze€d{e†de€fd|„Z‡d} ed~«      dd€d�d‚dƒ e‡d„dud…dwœdud†dwœd‡œdˆ«       e‡d‰eƒe„dŠd‹dwœdudŒdwœd�œdŽ«       e‡d‰d)dud�dwœidˆ«       e‡d�e…dud‘dwœd’œd’«       e‡d“d5dud”dwœid•«       e‡d–dPdud—dwœid˜«      gid™œid€gdšœd›œZˆddœl‰mŠZŠm‹Z‹  eŠ�j                  d}deˆd�dž„ e�¬Ÿ«       d d¡iZ�d¢„ ZŽy)©u‘  Skill Manager Tool â€” agent-managed skill creation & editing.

Skills are the agent's procedural memory (narrow "how to do X"; MEMORY.md/USER.md are
broad, declarative). New skills land in ~/.hermes/skills/ (or ``skills.create_dir``);
existing skills (bundled, hub, user) are modified in place. Layout:
``<skills>/[category/]<skill>/SKILL.md`` + optional ``references/ templates/ scripts/ assets/``.
é    N)Ú	ExitStackÚsuppress)ÚPath)ÚAnyÚDictÚListÚOptionalÚTuple)Úget_hermes_homeÚdisplay_hermes_home)Úatomic_write_textÚis_truthy_value)Úcfg_get)Úextract_skill_descriptionÚ)is_skill_description_truncated_for_promptÚparse_frontmatterÚSKILL_PROMPT_DESC_LIMIT)Ú_background_review_preflightÚ*_background_review_read_before_write_guardÚ_background_review_write_guardÚ_containing_skills_rootÚ#_curator_consolidation_delete_guardÚ_maybe_auto_propose_org_editÚ_org_mirror_write_guardÚ_pinned_guardÚ_validate_delete_targetÚ_is_background_reviewÚ_refusal)Ú_PATCH_EITHER_ORÚ_PATCH_NEEDS_NEW_STRINGÚ_PATCH_NEEDS_OLD_STRINGÚ_op_shape_errorÚ_skill_manage_batch)Ú
scan_skillÚshould_allow_installÚformat_scan_reportÚreturnc                  óh   — 	 ddl m}  t        t         | «       dd«      d¬«      S # t        $ r Y yw xY w)u]   skills.guard_agent_created (default False): opt-in â€” terminal() runs the same code ungated.r   ©Úload_configÚskillsÚguard_agent_createdF©Údefault)Úhermes_cli.configr*   r   r   Ú	Exceptionr)   s    ú=/home/ubuntu/.hermes/hermes-agent/tools/skill_manager_tool.pyÚ_guard_agent_created_enabledr2   *   s6   € ðÝ1Üœw¡{£}°hÐ@UÓVÐ`eÔfÐføÜò Ùðús   ‚"% ¥	1°1Ú	skill_dirc                 ó  — t        «       sy	 t        | d¬«      }t        |«      \  }}|€t        j	                  d|«       |durd|› dt        |«      › �S 	 y# t        $ r#}t        j	                  d| |d¬	«       Y d}~yd}~ww xY w)
z¤Post-write scan (opt-in); error string if blocked, else None. An "ask" verdict
    (dangerous findings) is surfaced as an error so the agent can retry without them.Nzagent-created)Úsourcez4Agent-created skill blocked (dangerous findings): %sTz"Security scan blocked this skill (z):
zSecurity scan failed for %s: %s©Úexc_info)r2   r$   r%   ÚloggerÚwarningr&   r0   )r3   ÚresultÚallowedÚreasonÚes        r1   Ú_security_scan_skillr>   3   sŸ   € ô (Ô)ØðWÜ˜I¨oÔ>ˆÜ.¨vÓ6‰ˆ�Øˆ?Ü�N‰NÐQÐSYÔZØ˜$ÑØ7¸°x¸tÔDVÐW]ÓD^ÐC_Ð`Ð`ð ð øô ò WÜ�‰Ð8¸)ÀQÐQUˆ×VÐVØûðWús   �AA Á	BÁ A>Á>Br+   c                  óP   — t        t        «      } | t        k7  r| S t        «       dz  S )a‡  Active profile's skills dir at call time (multi-profile runtimes rebind per session).
    An explicitly patched module-level ``SKILLS_DIR`` (tests) wins over the live HERMES_HOME.

    Long-lived multi-profile runtimes (Dashboard/TUI/Desktop backend, cron, kanban workers) import this
    module once under the launch HERMES_HOME and later bind a different profile per session (#40677).
    r+   )r   Ú
SKILLS_DIRÚ_SKILLS_DIR_AT_IMPORTr   )Ú
configureds    r1   Ú_skills_dirrC   J   s*   € ô ”jÓ!€JØ#Ô'<Ò<ˆ:Ð^Ä/ÓBSÐV^ÑB^Ð^ó    Únamec                 ó´   — t        j                  t        | «      j                  j	                  dd«      «      j                  «       }t        «       dz  |› d�z  S )ai  Per-skill lock file under ``<skills>/.locks/`` (same idiom as the usage ledger's
    ``.usage.json.lock``), never inside the skill dir so delete/recreate cannot unlink it under a
    waiting writer. Keyed by a digest of the basename so ``foo`` and ``category/foo`` share one
    lock and no name can hit a filesystem limit (callers validate the basename first).úutf-8Úsurrogatepassz.locksz.lock)ÚhashlibÚsha256r   rE   ÚencodeÚ	hexdigestrC   )rE   Údigests     r1   Ú_skill_lock_pathrN   U   sI   € ô
 �^‰^œD ›JŸO™O×2Ñ2°7¸OÓLÓM×WÑWÓY€FÜ‹=˜8Ñ#¨¨°Ð&6Ñ6Ð6rD   c                 ó0   — ddl m}  |t        | «      «      S )zRExclusive lock held across one skill's whole read-modify-write; thread-re-entrant.r   ©Úskill_file_lock)Útools.skill_usagerQ   rN   )rE   rQ   s     r1   Ú_skill_mutation_lockrS   ^   s   € å1ÙÔ+¨DÓ1Ó2Ð2rD   c                 ó¬   — ddl m} t        «       }t        | D �ch c]  }t	        |«      ’Œ c}«      D ]  }|j                   ||«      «       Œ |S c c}w )z`Every lock of an atomic batch, acquired in one stable path order (deadlock-free across batches).r   rP   )rR   rQ   r   ÚsortedrN   Úenter_context)ÚnamesrQ   ÚstackÚnÚ	lock_paths        r1   Ú_skill_mutation_locksr[   d   sO   € å1Ü‹K€EÜ¸%Ö@°QÔ-¨aÕ0Ò@ÓAò 8ˆ	Ø×Ñ™O¨IÓ6Õ7ð8à€Lùò As   šAé@   i   i † i   z^[a-z0-9][a-z0-9._-]*$>   ÚassetsÚscriptsÚ	templatesÚ
referencesz
\n---\s*\nz?Use lowercase letters, numbers, hyphens, dots, and underscores.c                  óV   — 	 ddl m}   | «       S # t        $ r t        «       › d�cY S w xY w)zNSkill-creation dir for schema/instruction text; follows ``skills.create_dir``.r   ©Údisplay_skill_create_dirz/skills/)Úagent.skill_utilsrc   r0   r   rb   s    r1   Ú_display_create_dirre   w   s3   € ð2Ý>Ù'Ó)Ð)øÜò 2Ü%Ó'Ð(¨Ð1Ò1ð2ús   ‚ �(§(ÚvalueÚlabelÚinvalidc                 óp   — t        | «      t        kD  r|› dt        › d�S t        j                  | «      rd S |S )Nz	 exceeds ú characters.)ÚlenÚMAX_NAME_LENGTHÚVALID_NAME_REÚmatch)rf   rg   rh   s      r1   Ú_check_identifierro   ‚   s:   € Ü
ˆ5ƒz”OÒ#Ø�˜	¤/Ð!2°,Ð?Ð?Ü ×&Ñ& uÔ-ˆ4Ð:°7Ð:rD   c           	      ó8   — | syt        | dd| › dt        › d�«      S )NzSkill name is required.z
Skill namezInvalid skill name 'ú'. z# Must start with a letter or digit.)ro   Ú
_NAME_RULE©rE   s    r1   Ú_validate_namert   ˆ   s/   € ÙØ(ÜØˆlÐ2°4°&¸¼J¸<ÐGjÐkómð mrD   Úcategoryc                 óÒ   — | � t        | t        «      r| j                  «       sy t        | t        «      sy| j                  «       } d| › dt        › d�}d| v sd| v r|S t	        | d|«      S )NzCategory must be a string.zInvalid category 'rq   z, Categories must be a single directory name.ú/ú\ÚCategory)Ú
isinstanceÚstrÚstriprr   ro   )ru   rh   s     r1   Ú_validate_categoryr}   �   sq   € ØÐœJ x´Ô5¸h¿n¹nÔ>NØÜ�h¤Ô$Ø+Ø�~‰~Ó€HØ# H :¨S´°ð ==ð =€Gà
ˆh�˜$ (Ñ*ØˆÜ˜X z°7Ó;Ð;rD   F©Ú	new_skillÚcontentr   c                óä  — | j                  «       sy| j                  d«      } | j                  d«      syt        j	                  | dd «      }|sy	 t        j                  | d|j                  «       dz    «      }t        |t        «      sy	d
D ]  }||vsŒd|› d�c S  t        |d   «      }t        |«      t        kD  r
dt        › d�S |r]t        |j                  «       j                  d«      «      t        kD  r.dt        |j                  «       «      › dt        › dt        dz
  › d�S | |j                  «       dz   d j                  «       syy# t
        j                  $ r}d|› �cY d}~S d}~ww xY w)a
  Validate frontmatter (name + description) and a non-empty body. ``new_skill`` (create
    only) also enforces SKILL_PROMPT_DESC_LIMIT so new skills never lose routing signal to
    index truncation; edit/patch skip it so existing over-limit skills stay maintainable.zContent cannot be empty.u   ï»¿z---zPSKILL.md must start with YAML frontmatter (---). See existing skills for format.é   NzISKILL.md frontmatter is not closed. Ensure you have a closing '---' line.zYAML frontmatter parse error: z6Frontmatter must be a YAML mapping (key: value pairs).)rE   ÚdescriptionzFrontmatter must include 'z' field.rƒ   zDescription exceeds rj   z'"zDescription is u#    chars â€” new skills must fit the z-char system-prompt budget (one sentence, trigger first, ends with a period). The skill index truncates longer descriptions to zO chars + '...', destroying the routing signal. Move detail into the skill body.zRSKILL.md must have content after the frontmatter (instructions, procedures, etc.).)r|   ÚlstripÚ
startswithÚ_FRONTMATTER_END_REÚsearchÚyamlÚ	safe_loadÚstartÚ	YAMLErrorrz   Údictr{   rk   ÚMAX_DESCRIPTION_LENGTHr   Úend)r€   r   Ú	end_matchÚparsedr=   ÚfieldÚdescs          r1   Ú_validate_frontmatterr“   œ   s~  € ð �=‰=Œ?Ø)Ø�n‰n˜XÓ&€GØ×Ñ˜eÔ$ØaÜ#×*Ñ*¨7°1°2¨;Ó7€IÙØZð4Ü—‘ ¨¨)¯/©/Ó*;¸aÑ*?Ð @ÓAˆô �fœdÔ#ØGØ(ò @ˆØ˜ÒØ/°¨w°hÐ?Ò?ð@ô ˆv�mÑ$Ó%€DÜ
ˆ4ƒyÔ)Ò)Ø%Ô&<Ð%=¸\ÐJÐJÙ”S˜Ÿ™›×+Ñ+¨EÓ2Ó3Ô6MÒMàœc $§*¡*£,Ó/Ð0Ð0SÜ&Ð'ð (Uä&¨Ñ*Ð+ð ,/ð0ð	1ð �9—=‘=“? QÑ&Ð'Ð(×.Ñ.Ô0ØcØøô' �>‰>ò 4Ø/°¨sÐ3Õ3ûð4ús   Á)E ÅE/Å E*Å$E/Å*E/c                 ó\   — t        | «      t        kD  r|› dt        | «      d›dt        d›d�S y )Nz content is ú,z characters (limit: za). Consider splitting into a smaller SKILL.md with supporting files in references/ or templates/.)rk   ÚMAX_SKILL_CONTENT_CHARS)r€   rg   s     r1   Ú_validate_content_sizer—   À   sB   € Ü
ˆ7ƒ|Ô-Ò-àˆg�\¤# g£,¨qÐ!1Ð1EÔF]Ð^_ÐE`ð að ð	ð rD   c           	      ó  — t        t        «      5  t        j                  | dd «      }|rNt	        t        j                  | d|j                  «       dz    «      j                  dd«      «      dd cddd«       S 	 ddd«       y# 1 sw Y   yxY w)zBFirst 120 chars of the frontmatter description; '' on any failure.r‚   Nrƒ   Ú éx   )	r   r0   r†   r‡   r{   rˆ   r‰   rŠ   Úget)r€   Úfm_ends     r1   Ú_description_previewr�   É   s‰   € ä	”)Ó	ñ cÜ$×+Ñ+¨G°A°B¨KÓ8ˆÙÜ”t—~‘~ g¨a°·±³ÀÑ0BÐ&CÓD×HÑHÈÐXZÓ[Ó\Ð]aÐ^aÐb÷cñ cà÷cð ÷	cð ús   �ABÂBc                 óž   — t        «       }	 ddlm}  |«       xs |}||xs dz  | z  S # t        $ r t        j                  dd¬«       Y Œ.w xY w)zFNew-skill dir; honors ``skills.create_dir`` (e.g. a shared fleet dir).r   )Úget_skill_create_dirzskills.create_dir lookup failedTr6   r™   )rC   rd   rŸ   r0   r8   Údebug)rE   ru   ÚbaserŸ   s       r1   Ú_resolve_skill_dirr¢   Ò   sY   € ä‹=€DðGÝ:Ù#Ó%Ò-¨ˆð �8’>˜rÑ" TÑ)Ð)øô ò GÜ�‰Ð6ÀˆÖFðGús   Œ) © AÁAÚrootc              #   ór   K  — ddl m} | j                  d«      D ]  } ||«      rŒ|j                  –— Œ y ­w)Nr   )Úis_excluded_skill_pathúSKILL.md)rd   r¥   ÚrglobÚparent)r£   r¥   Úskill_mds      r1   Ú_iter_skill_dirsrª   Ý   s3   è ø€ Ý8Ø—J‘J˜zÓ*ò "ˆÙ% hÕ/Ø—/‘/Ó!ñ"ùs   ‚#7¦7c                 óÜ  — ddl m} d}d| v sd| v r	 t        «       j                  «       } |«       D ]‰  }|j                  «       sŒt        |«      D ]h  }|j                  | k(  rd	|ic c S |€Œ|j                  «       }|j                  |«      sŒ?|j                  |«      j                  «       | k(  sŒbd	|ic c S  Œ‹ y# t        $ r$ t
        j                  dd¬«       t        «       }Y ŒÀw xY w)
us  Find a skill (local skills dir, then skills.external_dirs) -> ``{"path": Path}`` | None.

    Accepts the bare dir name (``axolotl``; matches category-nested skills too) and the
    categorized relative path (``mlops/axolotl``) â€” the two forms skill_view resolves. The
    categorized form matches RELATIVE to the local root only (relative_to raises for external dirs).r   )Úget_all_skills_dirsNrw   rx   zOskills dir resolve failed; categorized lookups fall back to the unresolved pathTr6   Úpath)rd   r¬   rC   ÚresolveÚOSErrorr8   r    Úexistsrª   rE   Úis_relative_toÚrelative_toÚas_posix)rE   r¬   Ú
local_rootÚ
skills_dirr3   Úresolveds         r1   Ú_find_skillr·   ä   sû   € õ 6Ø€JØ
ˆd�{�d˜d‘lð	'Ü$›×.Ñ.Ó0ˆJñ *Ó+ò 
/ˆ
Ø× Ñ Ô"ØÜ)¨*Ó5ò 	/ˆIØ�~‰~ Ò%Ø 	Ð*Ô*ØÑ%Ø$×,Ñ,Ó.�Ø×+Ñ+¨JÕ7Ø$×0Ñ0°Ó<×EÑEÓGÈ4ÓOØ" IÐ.Ô.ñ	/ð
/ð øô! ò 	'Ü�L‰LØaØð ô ô %›ŠJð		'ús   ’B> Â>*C+Ã*C+c                 ó”  ‡ — g }	 ddl m}  |«       }t        «       }|j	                  «       r|j                  «       n|}g }t        t        t        «      5  |dz  j                  «       |k7  r|j                  d|dz  f«       ddd«       |dz  j                  «       r{t        t        «      5  |dz  j                  «       D ]L  }|j                  «       sŒ	 |dz  j                  «       |k(  rŒ,	 |j                  |j                  |dz  f«       ŒN 	 ddd«       |D ]a  \  }}	|	j                  «       sŒt        t        «      5  t        ˆ fd„t        |	«      D «       d«      }
|
�|j                  ||
f«       ddd«       Œc |S # t        $ r |cY S w xY w# 1 sw Y   �ŒxY w# t        t        f$ r Y Œïw xY w# 1 sw Y   Œ¤xY w# 1 sw Y   Œ®xY w)z�``(profile, skill_dir)`` pairs for OTHER profiles holding ``name`` (so the not-found
    error can explain a wrong-profile mistake). Fail-quiet.r   )Úget_default_hermes_rootr+   r.   NÚprofilesc              3   óB   •K  — | ]  }|j                   ‰k(  sŒ|–— Œ y ­w©Nrs   )Ú.0ÚdrE   s     €r1   ú	<genexpr>z0_find_skill_in_other_profiles.<locals>.<genexpr>"  s   øè ø€ ÒR˜aÀ1Ç6Á6ÈTÃ>œÑRùs   ƒ˜)Úhermes_constantsr¹   r0   rC   r°   r®   r   r¯   ÚRuntimeErrorÚappendÚis_dirÚiterdirrE   Únextrª   )rE   Úmatchesr¹   r£   Ú_activeÚ
active_dirÚ
candidatesÚentryÚprofile_namerµ   Úhits   `          r1   Ú_find_skill_in_other_profilesrÍ     sØ  ø€ ð ')€GðÝ<Ù&Ó(ˆô ‹m€GØ&-§n¡nÔ&6�—‘Ô"¸G€Jð *,€JÜ	”'œ<Ó	(ñ <Ø�8‰O×$Ñ$Ó&¨*Ò4Ø×Ñ˜y¨$°©/Ð:Ô;÷<ð 	ˆzÑ×!Ñ!Ô#Ü”gÓñ 		BØ Ñ+×4Ñ4Ó6ò B�Ø—|‘|”~ØðØ Ñ(×1Ñ1Ó3°zÒAØ ð Bð ×!Ñ! 5§:¡:¨u°xÑ/?Ð"@ÕAñB÷		Bð %/ò 4Ñ ˆ�jØ× Ñ Ô"ØÜ”gÓñ 	4ÜÓRÔ#3°JÓ#?ÔRÐTXÓYˆCØˆØ—‘ ¨cÐ2Ô3÷	4ð 	4ð4ð €Nøô9 ò ØŠðú÷<ñ <ûô  ¤Ð.ò Ùðú÷		Bð 		Bú÷	4ð 	4úsY   …E? Á-FÂ+(F2ÃFÃ*$F2Ä?4F>Å?FÆFÆFÆF/Æ,F2Æ.F/Æ/F2Æ2F;Æ>G	Úsuffixc                 óø   — ddl m} d| › d |«       › d�}t        | «      }t        |«      dk(  r|d   \  }}|d|› d|› d	|› d
�z  }||z   S |r&dj	                  d„ |D «       «      }|d|› d�z  }||z   S |dz  }||z   S )zKNot-found error naming other profiles that hold the skill, plus ``suffix``.r   )Ú_resolve_active_profile_nameúSkill 'z' not found in active profile 'ú'.é   z) A skill by that name exists in profile 'ú' (z+). To edit it, switch profiles (`hermes -p z5`) or edit the file directly (file tools / terminal).ú, c              3   ó.   K  — | ]  \  }}d |› d �–— Œ y­w)ú'N© )r½   ÚpÚ_s      r1   r¿   z)_skill_not_found_error.<locals>.<genexpr>4  s   è ø€ Ò6¡t q¨!˜A˜a˜S œ(Ñ6ùs   ‚z. Skills by that name exist in other profiles: zi. Switch profiles (`hermes -p <name>`) to edit there, or edit the files directly (file tools / terminal).z+ Use skills_list() to see available skills.)Úagent.file_safetyrÐ   rÍ   rk   Újoin)rE   rÎ   rÐ   r¡   ÚothersÚother_profileÚ
other_pathrW   s           r1   Ú_skill_not_found_errorrà   (  s×   € å>Ø�T�FÐ9Ñ:VÓ:XÐ9YÐY[Ð\€DÜ*¨4Ó0€FÜ
ˆ6ƒ{�aÒØ$*¨1¡IÑ!ˆ�zØØ7¸°ÀcÈ*Èð V/Ø/<¨oð >'ð(ñ	)ˆð �&‰=Ðñ 
Ø—	‘	Ñ6¨vÔ6Ó6ˆØØ<¸U¸Gð DZð [ñ	\ˆð
 �&‰=Ðð 	Ð=Ñ=ˆØ�&‰=ÐrD   Ú	file_pathc                 ó  — ddl m} | syt        | «      j                  } || «      ry|r|d   dk(  rt	        |«      dv ry|r|d   t
        vr'd	j                  t        t
        «      «      }d
|› d| › d�S t	        |«      dk  r	d|d   › d�S y)zKValidate a write_file/remove_file path: under an allowed subdir, no escape.r   )Úhas_traversal_componentzfile_path is required.z%Path traversal ('..') is not allowed.éÿÿÿÿr¦   )rÓ   é   NrÕ   zFile must be under one of: z. Got: 'r×   rå   z5Provide a file path, not just a directory. Example: 'z/myfile.md')Útools.path_securityrã   r   Úpartsrk   ÚALLOWED_SUBDIRSrÜ   rU   )rá   rã   rç   r;   s       r1   Ú_validate_file_pathré   =  s™   € å;ÙØ'Ü�‹O×!Ñ!€Eá˜yÔ)Ø6á��r‘˜jÒ(¬S°«Z¸6Ñ-AØÙ�E˜!‘H¤OÑ3Ø—)‘)œF¤?Ó3Ó4ˆØ,¨W¨I°X¸i¸[ÈÐJÐJÜ
ˆ5ƒz�A‚~ØFÀuÈQÁxÀjÐP[Ð\Ð\ØrD   c                 ór   — ddl m} | |xs dz  }t        |«      xs	  ||| «      }|rdt        |«      fS |dfS )znValidate ``file_path`` and resolve it inside ``skill_dir``
    -> ``(target, None)`` | ``(None, error_dict)``.r   )Úvalidate_within_dirr™   N)ræ   rë   ré   Ú_err)r3   rá   rë   ÚtargetÚerrs        r1   Ú_resolve_supporting_filerï   Q  sF   € õ 8Ø˜)š/ rÑ*€FÜ
˜iÓ
(Ò
RÑ,?ÀÈ	Ó,R€CÙ #ˆD”$�s“)ÐÐ7¨&°$¨Ð7rD   T©Ú	org_guardÚactionÚnot_found_suffixrñ   c                ó¨   — t        | «      }|sdt        t        | |«      «      fS |d   }|xr t        | ||«      xs t	        | ||«      }|rd|fS |dfS )z™Find the skill; run the org-mirror (unless ``org_guard=False``) and background-review
    write guards -> ``(skill_dir, None)`` | ``(None, error_dict)``.Nr­   )r·   rì   rà   r   r   )rE   rò   ró   rñ   Úexistingr3   Úguards          r1   Ú_locate_for_writer÷   Z  ss   € ô ˜4Ó €HÙØ”TÔ0°Ð7GÓHÓIÐIÐIØ˜Ñ €IØÒLÔ3°D¸)ÀVÓLò HÜ.¨t°YÀÓGð 
á!ˆD�%ˆ=Ð8¨	°4Ð'8Ð8rD   rí   c                 óH  — d}|j                  «       r$t        | |||«      x}r|S |j                  d¬«      }ddlm}  ||j
                  «       t        ||dd¬«       t        |«      }	|	sy|�t        ||d¬	«       t        |	«      S |j                  d¬
«       t        |	«      S )z¬Read-before-write guard (existing targets only), atomic write, then the security scan;
    a blocked scan restores the original (or unlinks a new file). Error dict or None.NrG   ©Úencodingr   ©Úmkdir_under_hermes_homeTé¤  ©Úpreserve_modeÚcreate_mode)rÿ   )Ú
missing_ok)
r°   r   Ú	read_textrÀ   rü   r¨   r   r>   Úunlinkrì   )
rE   r3   rí   rò   rg   r€   ÚoriginalÚ
read_guardrü   Ú
scan_errors
             r1   Ú_guarded_writer  g  sª   € ð €HØ‡}�}„ÜCÀDÈ&ÐRXÐZ_Ó`Ð`ˆ:Ð`ØÐØ×#Ñ#¨WÐ#Ó5ˆÝ8Ù˜FŸM™MÔ*Ü�f˜g°TÀuÕMÜ% iÓ0€JÙØØÐÜ˜& (¸$Õ?ô �
ÓÐð 	�‰ ˆÔ&Ü�
ÓÐrD   r:   c                 óF   — t        ||«      x}r|| d<   | d   › d|› �| d<   | S )NÚorg_sharingÚmessageÚ )r   )r:   rE   r3   Úorg_notes       r1   Ú_attach_org_noter  }  s>   € Ü/°°iÓ@Ð@€xÐ@Ø (ˆˆ}ÑØ% iÑ0Ð1°°8°*Ð=ˆˆyÑØ€MrD   c                 óp   — t        |«      \  }}t        |«      rdt        |«      › dt        dz
  › d�| d<   | S )NzSystem prompt will show: "u3   " â€” keep the trigger self-contained in the first r‚   z chars.Úsystem_prompt_preview)Ú_parse_frontmatterr   r   r   )r:   r€   ÚfmrÚ   s       r1   Ú_add_description_prompt_previewr  „  sQ   € Ü˜wÓ'�E€BˆÜ0°Ô4à)Ô*CÀBÓ*GÐ)Hð I+Ü+BÀQÑ+FÐ*GÀwðPð 	Ð&Ñ'ð €MrD   r©   Úbeforec                 óv  — 	 ddl m}m}  ||«      }|�I |||j                  ¬«      D �ch c]  }|j                  ’Œ }}|D �cg c]  }|j                  |vsŒ|‘Œ }}|sy|D �cg c]&  }|j                  |j                  |j                  dœ‘Œ( c}| d<   d| d<   yc c}w c c}w # t
        $ r d}Y ŒUw xY wc c}w )	a  Attach ADVISORY authoring findings (hard rejects already ran in _validate_frontmatter).
    With ``before`` (the pre-write content) only rules the write INTRODUCED are attached, so a
    patch reports the line it crossed rather than re-listing the skill's standing findings.r   )Úlint_contentÚ
lint_skillN)r3   )ÚseverityÚruler
  Úlint_warningsu¤   The write succeeded. These are advisory authoring-convention findings (not blockers) â€” fix them with skill_manage(action='patch') to match Hermes skill standards.Ú	lint_hint)Útools.skill_linterr  r  r¨   r  r0   r  r
  )r:   r©   r  r  r  ÚfindingsÚfÚstandings           r1   Ú_attach_lint_findingsr  �  sÃ   € ðß?Ù˜hÓ'ˆØÐÙ(4°VÀxÇÁÔ(WÖX 1˜Ÿ›ÐXˆHÐXØ#+ÖF˜a¨q¯v©v¸XÒ/EšÐFˆHÐFñ ØàPXöZØKL�Q—Z‘Z¨¯©¸A¿I¹IÓFòZ€Fˆ?Ñð	Zð ˆ;Òùò YùÚFøÜò ØŠðüòZs9   ‚(B% ªB½B% ÁB ÁB ÁB% Á$+B6Â
B% Â%B3Â2B3ÚtextrY   Úellipsisc                 ó6   — | d | t        | «      |kD  r|z   S dz   S )Nr™   )rk   )r   rY   r!  s      r1   Ú_clipr#  ¢  s%   € Ø��ˆ8¤3 t£9¨q¢=�xÑ9Ð9°bÑ9Ð9rD   c                 ó€  — t        | «      xs' t        |«      xs t        |d¬«      xs t        |«      x}rt	        |«      S t        | «      x}rt	        d| › d|d   › d�«      S t        | |«      }ddlm}  ||«       |d	z  }t        ||dd
¬«       t        |«      x}r"t        j                  |d¬«       t	        |«      S t        «       }	|j                  |	«      r|j                  |	«      n|}
dd| › d�t!        |
«      t!        |«      dt#        |«      idœ|rd|ini ¥dd| › d�i¥}t%        t'        ||«      |«       |S )NTr~   zA skill named 'z' already exists at r­   ú.r   rû   r¦   rý   rþ   )Úignore_errorsrÑ   z
' created.rƒ   )Úsuccessr
  r­   r©   Ú_changeru   Úhintz[To add reference files, templates, or scripts, use skill_manage(action='write_file', name='z9', file_path='references/example.md', file_content='...'))rt   r}   r“   r—   rì   r·   r¢   rÀ   rü   r   r>   ÚshutilÚrmtreerC   r±   r²   r{   r�   r  r  )rE   r€   ru   rî   rõ   r3   rü   r©   r  r£   Údisplayr:   s               r1   Ú_create_skillr-  ¨  s{  € Ü˜dÓ#ò dÔ'9¸(Ó'Cò dÜ'¨¸4Ô@òdÜDZÐ[bÓDcðe€sð eä�C‹yÐÜ˜tÓ$Ð$€xÐ$Ü�o d VÐ+?ÀÈÑ@PÐ?QÐQRÐSÓTÐTÜ" 4¨Ó2€IÝ8Ù˜IÔ&Ø˜:Ñ%€HÜ�h °tÈÕOÜ)¨)Ó4Ð4€zÐ4Ü�‰�i¨tÕ4Ü�JÓÐÜ‹=€DØ-6×-EÑ-EÀdÔ-Kˆi×#Ñ# DÔ)ÐQZ€Gà g¨d¨V°:Ð$>ÌÈGËÜ˜“M¨}Ô>RÐSZÓ>[Ð.\ñ'ñ &.ˆJ˜Ñ!°2ð'ð 	ð ;Ø;?¸&ð A&ð&ñ	'€Fô Ô9¸&À'ÓJÈHÔUØ€MrD   c                 ó  — t        |«      xs t        |«      x}rt        |«      S t        | d«      \  }}|xs t	        | ||dz  dd|«      x}r|S dd| › d�t        |«      dt        |«      idœ}t        t        || |«      |«      S )z:Replace the SKILL.md of any existing skill (full rewrite).Úeditr¦   TrÑ   z' updated (full rewrite).rƒ   )r'  r
  r­   r(  )	r“   r—   rì   r÷   r  r{   r�   r  r  )rE   r€   rî   r3   rö   r:   s         r1   Ú_edit_skillr0  Ã  sª   € ä# GÓ,ÒOÔ0FÀwÓ0OÐO€sÐOÜ�C‹yÐÜ(¨¨vÓ6Ñ€IˆuàÒmœ¨¨i¸ÀZÑ9OÐQWÐYcÐelÓmÐm€uÐmØˆà g¨d¨VÐ3LÐ$MÜ�I“¨MÔ;OÐPWÓ;XÐ+Yñ[€Fô +Ô+;¸FÀDÈ)Ó+TÐV]Ó^Ð^rD   Ú
old_stringÚ
new_stringÚreplace_allc           
      ó^  — |st        t        «      S |€t        t        «      S t        | d«      \  }}|r|S |xs d}|rt	        ||«      \  }}	|	r|	S |dz  }|j                  «       st        d|j                  |«      › �«      S t        | |d|«      x}
r|
S |j                  d¬«      }ddl	m
}  |||||«      \  }}}}|rGt        t        «      5  dd	l	m} | |||||«      z  }ddd«       t        |«      d
t        |dd«      iz  S t        ||¬«      x}	rt        |	«      S |st!        |«      x}	rt        d|	› �«      S t#        | ||d||«      x}r|S dd|› d| › d|› d|dkD  rdnd› d�	t        |dd«      t        |dd«      dœdœ}t%        || |«      }|st'        |||¬«       |S # 1 sw Y   ŒÁxY w)zfTargeted find-and-replace in SKILL.md (default) or a supporting file; unique match unless replace_all.NÚpatchr¦   zFile not found: rG   rù   r   )Úfuzzy_find_and_replace)Úformat_no_match_hintÚfile_previewiô  z...©rg   z&Patch would break SKILL.md structure: TzPatched z in skill 'rÔ   z replacementrÓ   Úsr™   ú).éÈ   u   â€¦)ÚoldÚnew)r'  r
  r(  )r  )rì   r!   r    r÷   rï   r°   r²   r   r  Útools.fuzzy_matchr6  r   r0   r7  r#  r—   r“   r  r  r  )rE   r1  r2  rá   r3  r3   rö   Útarget_labelrí   rî   r  r€   r6  Únew_contentÚmatch_countÚ	_strategyÚmatch_errorr7  r:   s                      r1   Ú_patch_skillrE  Ñ  s!  € ñ ÜÔ+Ó,Ð,ØÐÜÔ+Ó,Ð,ô )¨¨wÓ7Ñ€IˆuÙØˆØÒ* 
€LÙÜ.¨y¸)ÓD‰ˆ�ÙØˆJà˜ZÑ'ˆØ�=‰=Œ?ÜÐ& v×'9Ñ'9¸)Ó'DÐ&EÐFÓGÐGÜ?ÀÀfÈgÐWcÓdÐd€zÐdØÐØ×Ñ¨ÐÓ0€Gõ 9Ù7MØ�˜Z¨ó86Ñ4€K�˜i¨áÜ”iÓ ñ 	_Ý>ØÑ/°¸[È*ÐV]Ó^Ñ^ˆK÷	_ô �KÓ  N´E¸'À3ÈÓ4NÐ#OÑOÐOÜ$ [¸ÔEÐE€sÐEÜ�C‹yÐÙÔ!6°{Ó!CÐC˜#ÐCÜÐ<¸S¸EÐBÓCÐCÜ˜t Y°¸ÀÈ{Ó[Ð[€uÐ[ØˆàØ˜l˜^¨;°t°f¸CÀ¸}ÈLÐ`kÐnoÒ`oÑY\ÐuwÐXxÐxzÐ{Ü  ¨S°%Ó8ÄÀzÐSVÐX]ÓA^Ñ_ña€Fô ˜f d¨IÓ6€Fñ Ü˜f f°WÕ=Ø€M÷'	_ð 	_ús   ÃF#Æ#F,Úabsorbed_intoc                 ó   — t        | d«      \  }}|xs t        | |«      x}r|S t        | «      x}rt        |«      S t	        |t
        «      r|j                  «       nd}|r.|| k(  rt        d|› d�«      S t        |«      st        d|› d�«      S t        |«      }t        |«      x}rt        |«      S |rd|› d�nd}t        «       r.	 dd	lm}	  |	| «      \  }
}|
st        |«      S dd| › d|› d|› �ddœS t        j                  |«       t!        |j"                  |«       dd| › d|› �dœS # t        $ r}t        d
| › d|› �«      cY d}~S d}~ww xY w)z»Delete a skill. ``absorbed_into``: None = undeclared (legacy, accepted); "" = explicit prune;
    "<skill>" = absorbed into that umbrella, which must exist (so the model can't claim one).Údeleter™   zabsorbed_into='z'' cannot equal the skill being deleted.zR' does not exist. Create or patch the umbrella skill first, then retry the delete.z Content absorbed into 'rÒ   r   )Úarchive_skillzfailed to archive 'z': NTrÑ   z' archived (r;  )r'  r
  Ú	_archivedz
' deleted.©r'  r
  )r÷   r   r   rì   rz   r{   r|   r·   r   r   r   rR   rI  r0   r*  r+  Ú_rmdir_if_emptyr¨   )rE   rF  r3   rö   Ú
pinned_errÚabsorbed_targetÚskills_rootÚunsafeÚabsorbed_noterI  ÚokÚarchive_msgr=   s                r1   Ú_delete_skillrT    s¢  € ô )¨¨xÓ8Ñ€IˆuØÒQÔ<¸TÀ=ÓQÐQ€uÐQØˆÜ" 4Ó(Ð(€zÐ(Ü�JÓÐÜ/9¸-ÌÔ/M�m×)Ñ)Ô+ÐSU€OÙØ˜dÒ"Ü˜/¨/Ð):Ð:aÐbÓcÐcÜ˜?Ô+Ü˜/¨/Ð):ð ;[ð \ó ]ð ]ä)¨)Ó4€KÜ(¨Ó3Ð3€vÐ3Ü�F‹|Ðñ GVÐ.¨Ð.?¸rÑBÐ[]€MÜÔð	<Ý7Ù+¨DÓ1‰OˆB�ñ Ü˜Ó$Ð$ØØ$ T F¨,°{°mÀ2ÀmÀ_ÐUØ!ñ#ð 	#ô ‡M�M�)ÔÜ�I×$Ñ$ kÔ2Ø¨'°$°°zÀ-ÀÐ(QÑRÐRøô ò 	<ÜÐ-¨d¨V°3°q°cÐ:Ó;Õ;ûð	<ús   ÃD) Ä)	EÄ2EÅEÅEr¨   Ústopc                 ó†   — | |k7  r<| j                  «       r+t        | j                  «       «      s| j                  «        y y y y r¼   )r°   ÚanyrÄ   Úrmdir)r¨   rU  s     r1   rL  rL  *  s2   € Ø�‚~˜&Ÿ-™-œ/´#°f·n±nÓ6FÔ2GØ�‰�ð 3H˜/€~rD   Úfile_contentc                 ó"  — t        |«      x}rt        |«      S |s|dk7  rt        d«      S t        |j                  d«      «      x}t        kD  rt        d|d›dt        d›d�«      S t        ||¬«      x}rt        |«      S t        | d	d
«      \  }}|r|S t        ||«      \  }}|xs t        | ||d	||«      x}r|S t        dd|› d| › d�t        |«      dœ| |«      }|j                  d«      r"|dz  j                  «       rt        ||dz  «       |S )z>Add or overwrite a supporting file within any skill directory.r™   zfile_content is required.rG   zFile content is r•   z bytes (limit: z7 bytes / 1 MiB). Consider splitting into smaller files.r9  Ú
write_filez& Create it first with action='create'.TúFile 'z' written to skill 'rÒ   )r'  r
  r­   zreferences/r¦   )ré   rì   rk   rK   ÚMAX_SKILL_FILE_BYTESr—   r÷   rï   r  r  r{   r…   r°   r  )	rE   rá   rY  rî   Úcontent_bytesr3   rö   rí   r:   s	            r1   Ú_write_filer_  /  sU  € ä! )Ó,Ð,€sÐ,Ü�C‹yÐÙ˜L¨BÒ.ÜÐ/Ó0Ð0Ü˜\×0Ñ0°Ó9Ó:Ð:ˆÔ>RÒRÜÐ& }°QÐ&7°ÔG[Ð\]ÐF^ð _Mð Nó Oð 	Oä$ \¸ÔCÐC€sÐCÜ�C‹yÐÜ(¨¨|Ð=eÓfÑ€IˆuÙØˆÜ*¨9°iÓ@�K€FˆCØÒe”~ d¨I°v¸|ÈYÐXdÓeÐe€uÐeØˆÜ¨$¸VÀIÀ;ÐNbÐcgÐbhÐhjÐ;kÜ'*¨6£{ñ4Ø59¸9óF€Fð ×Ñ˜MÔ*°	¸JÑ0F×/NÑ/NÔ/PÜ˜f i°*Ñ&<Ô=Ø€MrD   c           
      ó8  — t        |«      x}rt        |«      S t        | dd¬«      \  }}|r|S t        ||«      \  }}|r|S |j	                  «       s�t
        D ��cg c]X  }||z  j	                  «       rC||z  j                  d«      D ],  }|j                  «       rt        |j                  |«      «      ‘Œ. ŒZ }}}t        d|› d| › d�|xs d¬	«      S t        | |d|«      x}	r|	S |j                  «        t        |j                  |«       d
d|› d| › d�dœS c c}}w )z2Remove a supporting file from any skill directory.Úremove_fileFrð   Ú*r\  z' not found in skill 'rÒ   N)Úavailable_filesTz' removed from skill 'rK  )ré   rì   r÷   rï   r°   rè   r§   Úis_filer{   r²   r   r  rL  r¨   )
rE   rá   rî   r3   rö   rí   Úsubdirr  Ú	availabler  s
             r1   Ú_remove_filerg  I  sC  € ä! )Ó,Ð,€sÐ,Ü�C‹yÐÜ(¨¨}ÈÔNÑ€IˆuÙØˆÜ*¨9°iÓ@�K€FˆCÙ
Øˆ
Ø�=‰=Œ?ÜAP÷ o°vØ" VÑ+×3Ñ3Ô5À	ÈFÑ@R×?YÑ?YÐZ]Ó?^òoØ:;Ðbc×bkÑbkÔbmô ˜Ÿ™ yÓ1Õ2ð oÐ2ð oˆ	ñ oä�f˜Y˜KÐ'=¸d¸VÀ2ÐFÐXaÒXiÐeiÔjÐjÜ?ÀÀfÈmÐ]fÓgÐg€zÐgØÐØ
‡M�M„OÜ�F—M‘M 9Ô-Ø¨&°°Ð;QÐRVÐQWÐWYÐ(ZÑ[Ð[ùóos   ÁADÚskill_gate_bypassr-   z_ctxvars.ContextVar[bool]Ú_skill_gate_bypassc                 óˆ  — 	 ddl m} |j                  |j                  «      }|j
                  ry|j                  rt        |j                  d¬«      S  | |«      \  }}|j                  |j                  |||j                  «       ¬«      }t        j                  dd|d   ||j                  d	œd¬
«      S # t        $ r Y yw xY w)zÇShared write gate: None to proceed, else a JSON tool result (blocked/staged).
    ``build_staging(wa) -> (payload, gist)`` runs only when staging. Fails open if
    write_approval cannot be imported.r   )Úwrite_approvalNF©r'  )ÚsummaryÚoriginTÚid)r'  ÚstagedÚ
pending_idÚgistr
  ©Úensure_ascii)Útoolsrk  r0   Úevaluate_gateÚSKILLSÚallowÚblockedÚ
tool_errorr
  Ústage_writeÚcurrent_originÚjsonÚdumps)Úbuild_stagingÚwaÚdecisionÚpayloadrr  Úrecords         r1   Ú_run_write_gater„  e  s¼   € ðÝ.ð ×Ñ §	¡	Ó*€HØ‡~‚~ØØ×ÒÜ˜(×*Ñ*°EÔ:Ð:Ù! "Ó%�M€GˆTØ�^‰^˜BŸI™I w¸ÀR×EVÑEVÓEXˆ^ÓY€FÜ�:‰: $°$ÀfÈTÁlØ#°×0@Ñ0@ñBØPUôWð Wøô ò Ùðús   ‚B5 Â5	CÃ Cc                 óf   ‡ ‡‡— ‰ t         vst        j                  «       ryˆ ˆˆfd„}t        |«      S )z[Flat-shape gate: stage the full kwargs so approval can replay them; bypassed during replay.Nc                 óä   •— ‰‰dœ‰j                  «       D ��ci c]  \  }}|€Œ	||“Œ c}}¥}dD �ci c]  }|‰j                  |«      xs d“Œ }}| | j                  ‰‰fi |¤ŽfS c c}}w c c}w )N)rò   rE   )r€   rá   r1  r2  r™   )Úitemsr›   Ú
skill_gist)r€  ÚkÚvr‚  Úgist_kwrò   rE   Úpayload_kwargss        €€€r1   Ú_stagingz)_apply_skill_write_gate.<locals>._staging|  sš   ø€ Ø#¨Tñ QØ'5×';Ñ';Ó'=×O™t˜q !ÀÁ�a˜‘dÓOðQˆð QöRØð �n×(Ñ(¨Ó+Ò1¨rÑ1ð Rˆð Rà˜˜Ÿ™ f¨dÑ>°gÑ>Ð>Ð>ùó PùòRs   ™
A'¤A'²A-)Ú_ACTION_HANDLERSri  r›   r„  )rò   rE   rŒ  r�  s   ``` r1   Ú_apply_skill_write_gater�  x  s-   ú€ àÔ%Ñ%Ô);×)?Ñ)?Ô)AØö?ô ˜8Ó$Ð$rD   )r€   ru   rá   rY  r1  r2  rF  Ú
operationsr‚  c                 óÒ   — t        d| j                  dd«      | j                  dd«      | j                  dd«      dœt        D �ci c]  }|| j                  |«      “Œ c}¤|¤ŽS c c}w )z_Call ``skill_manage`` with the flat-shape fields (and absorbed_into/operations) of ``payload``.rò   r™   rE   r3  F)rò   rE   r3  rØ   )Úskill_manager›   Ú_FLAT_OP_KEYS)r‚  Úextrar‰  s      r1   Ú_skill_manage_fromr•  ‰  sn   € äð ?Ø�{‰{˜8 RÓ(¨w¯{©{¸6À2Ó/FØ—K‘K ¨uÓ5ñ?ô '4Ö
4 ˆ1ˆg�k‰k˜!‹nÑÒ
4ð?ð 9>ñ?ð ?ùò 5s   ÁA$c                 ó¢   — t         j                  d«      }	 t        | «      t         j                  |«       S # t         j                  |«       w xY w)zNReplay a staged skill write, bypassing the gate (the /skills approve handler).T)ri  Úsetr•  Úreset)r‚  Útokens     r1   Úapply_skill_pendingrš  ‘  s=   € ä×"Ñ" 4Ó(€Eð(Ü! 'Ó*ä× Ñ  Õ'øÔ× Ñ  Õ'ús	   —
7 ·AÚ_sync_push_timersg      @Ú
skill_namec                 ó¤  ‡ — 	 ddl m}  |‰ «      sy	 ddlm}  |«       }t        j                  «       }ˆ fd„}t        5  t        j                  |«      }|�|j                  «        t        j                  t        |j                  |f¬«      }d|_        |t        |<   |j!                  «        ddd«       y# t        $ r Y yw xY w# 1 sw Y   yxY w)zºDebounced best-effort sync push after a skill write; never blocks the caller. Skills not
    opted into sync do nothing (no auth/network); ``maybe_push_skills`` enforces the access gate.r   )Úis_sync_enabledN)Úhermes_home_keyc                  ór   •— t        t        «      5  ddlm}   | d‰› �¬«       d d d «       y # 1 sw Y   y xY w)Nr   )Úmaybe_push_skillszsync: )r
  )r   r0   Útools.skills_sync_clientr¡  )r¡  rœ  s    €r1   Ú_firez)_maybe_debounced_sync_push.<locals>._fire¯  s2   ø€ Ü”iÓ ñ 	=ÝBÙ¨¨z¨lÐ&;Õ<÷	=÷ 	=ñ 	=ús   ‘-­6)ÚargsT)rR   rž  r0   rÀ   rŸ  Ú_ctxvarsÚcopy_contextÚ_sync_push_lockr›  r›   ÚcancelÚ	threadingÚTimerÚ_SYNC_PUSH_DEBOUNCE_SÚrunÚdaemonrŠ   )rœ  rž  rŸ  Úhome_keyÚctxr£  ÚpendingÚtimers   `       r1   Ú_maybe_debounced_sync_pushr²  ¡  sÄ   ø€ ðÝ5Ù˜zÔ*Øð +õ 1ÙÓ €Hô ×
Ñ
Ó
!€Cô=ô 
ñ Ü#×'Ñ'¨Ó1ˆØÐØ�N‰NÔÜ—‘Ô 5°s·w±wÀeÀXÔNˆØˆŒØ&+Ô˜(Ñ#Ø�‰Œ÷ð øô ò Ùðú÷ð ús   ƒB7 ¿A/CÂ7	CÃCÃCc                 ó¬   — | d   r| d   s| d   �t        t        d¬«      S | d   rt        | d   | d   «      S t        | d   | d   | d   | d   | d   «      S )	zºTwo shapes: old_string/new_string = targeted replacement (validated in _patch_skill so the
    tool and the helper give the same guidance); content alone = full rewrite (the old 'edit').r€   r1  r2  Frl  rE   rá   r3  )rz  r   r0  rE  ©Úas    r1   Ú
_act_patchr¶  ½  sn   € ð 	ˆ‚|˜˜<š¨A¨l©OÐ,GÜÔ*°EÔ:Ð:Øˆ‚|Ü˜1˜V™9 a¨	¡lÓ3Ð3Ü˜˜&™	 1 \¡?°A°l±OÀQÀ{Á^ÐUVÐWdÑUeÓfÐfrD   c                 ó.   — t        | d   | d   | d   «      S )NrE   r€   ru   )r-  r´  s    r1   ú<lambda>r¸  Ê  s   € œ a¨¡i°°9±¸qÀ¹}ÓM€ rD   c                 ó&   — t        | d   | d   «      S )NrE   r€   )r0  r´  s    r1   r¸  r¸  Ë  s   € ”k ! F¡)¨Q¨y©\Ó:€ rD   c                 ó(   — t        | d   | d   ¬«      S )NrE   rF  )rF  )rT  r´  s    r1   r¸  r¸  Í  s   € œ a¨¡i¸qÀÑ?QÔR€ rD   c                 ó.   — t        | d   | d   | d   «      S )NrE   rá   rY  )r_  r´  s    r1   r¸  r¸  Î  s   € œK¨¨&©	°1°[±>À1À^ÑCTÓU€ rD   c                 ó&   — t        | d   | d   «      S )NrE   rá   )rg  r´  s    r1   r¸  r¸  Ï  s   € œ\¨!¨F©)°Q°{±^ÓD€ rD   )Úcreater/  r5  rH  r[  ra  c          	      ó  — t        t        «      5  ddlm} t	        |«      }	| dk(  r|t        |j                  d«      «      dœni }
|
j                  d|fd|ffD ��ci c]  \  }}|sŒ	||“Œ c}}«       |j                  | ||�|ng |	r|	d	   nd|
¬
«       ddd«       t        t        «      5  ddl	m
}  |d¬«       ddd«       t        t        «      5  ddlm}m}m} ddlm} | dk(  r || |«       ||¬«       n/| dv r ||| ||¬«       n| dk(  r|j                  d«      s ||«       ddd«       t        t        «      5  t#        |«       ddd«       yc c}}w # 1 sw Y   ŒÈxY w# 1 sw Y   Œ­xY w# 1 sw Y   ŒKxY w# 1 sw Y   yxY w)z†Best-effort post-mutation side effects (never break the tool): ledger, prompt-cache
    clear, curator telemetry, debounced sync push.r   ©Úskill_ledgerrH  rJ  )rF  ÚarchivedÚ
session_idrá   Nr­   )r  Ú
after_rootÚevidence)Ú clear_skills_system_prompt_cacheT)Úclear_snapshot)Ú
bump_patchÚforgetÚrecord_created)Úis_background_reviewr½  )Úagent_createdÚtask_idrÂ  >   r/  r5  r[  ra  )rò   rÌ  rÂ  )r   r0   ru  rÀ  r·   Úboolr›   ÚupdateÚrecord_mutationÚagent.prompt_builderrÅ  rR   rÇ  rÈ  rÉ  Útools.skill_provenancerÊ  r²  )rò   rE   r:   rá   rF  rÌ  rÂ  Úledger_beforeÚ_ledgerÚ_postÚ	_evidencer‰  rŠ  rÅ  rÇ  rÈ  rÉ  rÊ  s                     r1   Ú_record_successrÖ  Ò  s—  € ô 
”)Ó	ñ 	MÝ1Ü˜DÓ!ˆð  (Ò*ð (5Ä$ÀvÇzÁzÐR]ÓG^ÓB_Ò`Ø02ð 	à×Ñ¨\¸:Ð,FÈÐV_ÐH`Ð+a×g¡4 1 aÒef˜!˜Q™$ÓgÔhØ×ÑØ�D°-Ð2K¡ÐQSÙ(-�u˜V’}°4À)ð 	 ô 	M÷	Mô 
”)Ó	ñ >ÝIÙ(¸Õ=÷>ô 
”)Ó	ñ ßHÑHõ 	@Ø�XÒÙ˜4Ñ/CÓ/EØ#*°zöCàÐEÑEÙ�t F°GÈ
ÖSØ�xÒ¨¯
©
°;Ô(?Ù�4ŒL÷ô  
”)Ó	ñ )Ü" 4Ô(÷)ð )ùó5 h÷	Mð 	Mú÷>ð >ú÷ð ú÷ )ð )úsI   �AEÁ
EÁ'EÁ,)EÂ,E(ÃAE4ÅF ÅEÅE%Å(E1Å4E=Æ F	rÌ  rÂ  c                 óh  ‡ — |�t        ||xs d|
|¬«      S t        ‰ |«      x}�t        j                  |d¬«      S t	        ||||||||	¬«      }t        ‰ |fi |¤Žx}�|S t        ‰ |«      x}�t        |d¬«      S t        ‰ dk(  s|s|nt        |«      j                  «      x}� t        j                  t        |«      d¬«      S t        |«      5  d}t        t        «      5  dd	lm} t#        |«      }|j%                  |r|d
   nd‰ dk(  |¬«      }ddd«       t&        j)                  ‰ ˆ fd„«      } |d|i|¥«      }t+        |t,        «      r|cddd«       S |j)                  d«      rt/        ‰ ||||	|
||¬«       ddd«       t        j                  d¬«      S # 1 sw Y   ŒŒxY w# 1 sw Y   Œ,xY w)zŠDispatch to the action handler -> JSON string. ``operations`` (atomic batch shape,
    see _skill_manage_batch) overrides the flat fields.N)Údefault_namerÌ  rÂ  Frs  )r€   ru   rá   rY  r1  r2  r3  rF  rl  r½  r   r¿  r­   rH  )Úcomplete_packageÚskillc                 ó"   •— t        d‰› d�«      S )NzUnknown action 'z<'. Use: create, edit, patch, delete, write_file, remove_file)rì   )rµ  rò   s    €r1   r¸  zskill_manage.<locals>.<lambda>"  s   ø€ ¼Ø˜v˜hÐ&bÐcó:e€ rD   rE   r'  )rá   rF  rÌ  rÂ  rÒ  )r#   r   r}  r~  rŒ   r�  r"   rz  rt   r   rE   rì   rS   r   r0   ru  rÀ  r·   Úcapture_beforerŽ  r›   rz   r{   rÖ  )rò   rE   r€   ru   rá   rY  r1  r2  r3  rF  rÌ  rÂ  r�  Ú	preflightr¤  Úgate_resultÚ	shape_errÚname_errÚ_ledger_beforerÓ  Ú_preÚhandlerr:   s   `                      r1   r’  r’  ú  sé  ø€ ð ÐÜ"Ø T¢\¨T¸7Èzô[ð 	[ä1°&¸$Ó?Ð?ˆ	ÐLÜ�z‰z˜)°%Ô8Ð8ô ˜¨(¸iÐVbØ%°*È+Ø+ô-€Dô /¨v°tÑD¸tÑDÐDˆÐQØÐÜ$ V¨TÓ2Ð2ˆ	Ð?Ü˜)¨UÔ3Ð3ô #¨6°XÒ+=ÁT¡4ÌtÐTXËzÏÉÓ_Ð_ˆÐlÜ�z‰zœ$˜x›.°uÔ=Ð=ô 
˜dÓ	#ñ Vð ˆÜ”iÓ ñ 	cÝ5Ü˜tÓ$ˆDØ$×3Ñ3Ù $��V’¨$À&ÈHÑBTÐ]að 4ó cˆN÷	cô
 #×&Ñ& vó 0eó fˆá˜& $Ð/¨$Ð/Ó0ˆÜ�fœcÔ"Ø÷!Vñ Vð" �:‰:�iÔ ÜØ˜˜f°	ÈØ¨JÀnõV÷%Vô* �:‰:�f¨5Ô1Ð1÷	cð 	cú÷Vð Vús*   ÃF(Ã!0FÄ>F(Å$F(ÆF%	Æ!F(Æ(F1Ú
create_dirc                 ó   — d| › d�S )Nu  Create, update, or delete skills â€” your procedural memory for recurring task types. The call is an operations array (a single edit is a list of one); it applies atomically â€” any failure rolls every touched skill back. Ops: create (full SKILL.md; lands in uM  ; must precede that skill's other ops), patch (targeted old_string/new_string fix â€” preferred; content alone REPLACES the whole file, read it via skill_view() first), write_file/remove_file (supporting files), delete (sole op only). Existing skills are modified wherever they live. Keep the description's first 57 chars a self-contained trigger: 'Use when <trigger>. <one-line behavior>.' Write lessons, not logs: imperative rule + why, no PR numbers/dates/incident narration, one rule per lesson, references/ named by topic (extend before adding). skill_view() shows format conventions.rØ   )rä  s    r1   Ú_skill_manage_descriptionræ  0  s   € ð	Jð ˆ,ð 	1ð		1ðrD   c                  ó,   — dt        t        «       «      iS )zúRebuild the create-dir hint from the ACTIVE profile at every get_definitions(): the
    multiplexed gateway serves every profile from one process, so a path baked in at import
    would name the launch profile's skills dir for everyone else (#95685).rƒ   )ræ  re   rØ   rD   r1   Ú_skill_manage_schema_overridesrè  C  s   € ð Ô4Ô5HÓ5JÓKÐLÐLrD   ÚtypeÚstringz9Text to find (same matching semantics as the patch tool).)ré  rƒ   z,Replacement; empty string deletes the match.u§   Path RELATIVE to the skill's own directory, e.g. 'references/api.md' â€” no leading slash, never absolute; first segment references/, templates/, scripts/, or assets/.ÚpropsÚrequiredc                 ó2   — ddt         d| gdœdœ|¥ddg|¢dœS )	z¢One self-contained per-action op shape. ``additionalProperties: false`` is what lets a
    grammar-constrained backend refuse another action's text slot outright.ÚobjectFrê  )ré  Úenum)rE   rò   rE   rò   )ré  ÚadditionalPropertiesÚ
propertiesrì  )Ú_NAME)rò   rë  rì  s      r1   Ú
_op_schemaró  W  s6   € ð °eÜ#(¸XÐPVÈxÑ4XÑbÐ\aÐbØ Ð5¨HÐ5ñ7ð 7rD   r’  zthe profile's skills.create_dirrî  r�  Úarrayz�Ordered ops; each names its target skill (lowercase, hyphens/underscores, max 64 chars). Each action is its own shape; another action's text slot is invalid.ÚanyOfr½  z6Full SKILL.md text (YAML frontmatter + markdown body).z)Optional category subdir (e.g. 'devops').)r€   ru   )r€   r5  Úbooleanz(Replace all occurrences (default false).z@Optional supporting file (write_file's shape); default SKILL.md.)r1  r2  r3  rá   )r1  r2  z=Full SKILL.md rewrite (REPLACES the whole file; last resort).r[  z!Full text of the supporting file.)rá   rY  ra  z%Supporting file (write_file's shape).)rá   rH  zOCurator consolidation only: umbrella skill that absorbed this one (must exist).rØ   )ré  rƒ   r‡  )ré  rñ  rì  )rE   rƒ   Ú
parameters)Úregistryrz  u   ðŸ“�c                 óZ   — t        | |j                  d«      |j                  d«      ¬«      S )NrÌ  rÂ  )rÌ  rÂ  )r•  r›   )r¤  Úkws     r1   r¸  r¸     s&   € Ô1Ø�b—f‘f˜YÓ'°B·F±F¸<Ó4Hô J€ rD   )rE   ÚtoolsetÚschemaÚemojirã  Údynamic_schema_overridesÚ!mark_background_review_skill_read)ztools.skill_manager_guardsrÿ  c                 óÌ   — t         j                  | «      }|€t        dt        ›d| ›�«      ‚dd l}ddlm}  |t        | g|¢­Ž  t        |j                  |d   «      |d   «      S )Nzmodule z has no attribute r   )Ú	warn_oncerÓ   )	Ú_PLUGIN_COMPAT_LAZYr›   ÚAttributeErrorÚ__name__Ú	importlibÚhermes_cli.plugin_compatr  ÚgetattrÚimport_module)rE   rí   r  r  s       r1   Ú__getattr__r	  °  se   € Ü ×$Ñ$ TÓ*€FØ€~Ü˜w¤x lÐ2DÀTÀHÐMÓNÐNÛÝ2ÙŒh˜Ð&˜vÓ&Ü�9×*Ñ*¨6°!©9Ó5°v¸a±yÓAÐArD   )r¦   r¼   )r™   )NF)r'   N)NNNNNNFNNNN)�Ú__doc__Úcontextvarsr¥  rI   r}  Ú
contextlibr   r   ÚloggingÚrer*  r©  Úpathlibr   Útypingr   r   r   r	   r
   rˆ   rÀ   r   r   Úutilsr   r   r/   r   rd   r   r   r   r  r   Útools.skill_manager_guardsr   r   r   r   r   r   r   r   r   r   r   rì   Útools.skill_manager_batchr   r    r!   r"   r#   Útools.skills_guardr$   r%   r&   Ú	getLoggerr  r8   rÍ  r2   r{   r>   ÚHERMES_HOMEr@   rA   rC   rN   rS   r[   rl   r�   r–   r]  Úcompilerm   rè   r†   rr   re   ro   rt   r}   r“   r—   r�   r¢   rª   r·   rÍ   rà   ré   rï   r÷   r  r  r  r  Úintr#  r-  r0  rE  rT  rL  r_  rg  Ú
ContextVarri  Ú__annotations__r„  r�  r“  r•  rš  r›  rª  ÚLockr§  r«  r²  r¶  rŽ  rÖ  r’  ræ  rŒ   rè  rò  Ú_OLD_STRINGÚ_NEW_STRINGÚ
_FILE_PATHÚtupleró  ÚSKILL_MANAGE_SCHEMAÚtools.registryrø  rz  Úregisterr  r	  rØ   rD   r1   ú<module>r#     sA  ðòó Û Û ß *Û Û 	Û Û Ý ß 3Õ 3ã ç Aß 4Ý %÷ó ÷
n÷ n÷ nñ n÷nõ nç SÑ Sà	ˆ×	Ñ	˜8Ó	$€ð dó ð Dð ¨X°c©]ó ñ$ Ó€Ø˜8Ñ#€
Ø"Ð ð_�Tó _ð7˜3ð 7 4ó 7ð3˜só 3òð €ØÐ Ø!Ð Ø Ð Ø�—
‘
Ð4Ó5€ÚB€Ø �b—j‘j Ó/Ð ØN€
ð2˜Só 2ð;˜Sð ;¨ð ;°sð ;¸xÈ¹}ó ;ðm˜ð m ¨#¡ó mð
< ¨#¡ð 
<°8¸C±=ó 
<ð >Cò ! 3ð !°dð !ÀxÐPSÁ}ó !ñH Cð °ð ÀXÈcÁ]ó ð #ð ¨#ó ñ*˜Sð *¨Cð *¸4ó *ð"˜4ó "ð�cð ˜h t¨C°¨H¡~Ñ6ó ð<#¨ð #°°U¸3À¸9Ñ5EÑ0Fó #ñL ð ¨cð ¸3ó ð* 3ð ¨8°C©=ó ð(8¨ð 8¸ó 8ð
9Ø(,ò
9˜Cð 
9¨ð 
9Àð 
9Ø!%ó
9ð˜ð ¨ð °tð ÀSð ÐQTð ØðØ$,¨T°#°s°(©^Ñ$<óð,˜T # s (™^ð °3ð À4ð ÈDÐQTÐVYÐQYÉNó ð¨D°°c°©Nð ÀSð ÈTÐRUÐWZÐRZÉ^ó ñ[ $ s¨C x¡.ð [¸Dð [È(ÐSVÉ-ð [Ðcgó [ð*:�ð :˜ð : sð :¨só :ñ˜ð  cð °Sð ÀDÈÈcÈÁNó ð6_�cð _ Cð _¨D°°c°©Nó _ð PTØ%*ñ1�sð 1¨ð 1¸ð 1Èð 1Ø"ð1Ø/3°C¸°H©~ó1ñh"S˜ð "S¨H°S©Mð "SÀTÈ#ÈsÈ(Á^ó "SðJ˜Dð ¨ð °ó ð
�cð  cð ¸ð ÀÀcÈ3ÀhÁó ð4\�sð \ sð \¨t°C¸°H©~ó \ð0 3F°(×2EÑ2EØ ô3(Ð Ð/ó (òWò&
%ð0€ð?  S¨# X¡ð ?¸Có ?ð(  c¨3 h¡ð (°Có (ð 13Ð �4˜˜YŸ_™_Ð,Ñ-Ó 2Ø �)—.‘.Ó"€ØÐ ð¨3ð °4ó ò8gñ NÙ:ØÙRÙUÙDñFÐ ð%)Ø26ó%)ðR Y]ØHLØIMØ'+ñ	12Øð12Øð12Ø%(ð12Ø;>ð12ØRUð12àð12à*-ð12àBEð12ð ð12ð /2ð12ð DGð12ð ð	12ð 14ó	12ðl¨#ð °#ó ð&M¨ó Mð 
�Ð€ØØYñ[€àÐ0^Ñ_€àð	^ñ€
ð7�sð 7 4ð 7°5ð 7¸Tó 7ð ñ -Ð-NÓOààØðjð "Ù˜xØ,4Ø3kñ$mà-5Ø4_ñ%añ*ð
 $ó%ñ ˜wØ&1ÀØ09Ø7añ(cà.6Ø5wñ&yñ	)ð 4ó5ñ ˜wØ!¨HØ3rñ$tð)ð $ó%ñ ˜|Ø%/Ø19ÐJmÑ(nñ.ð 5ó6ñ ˜}Ø#¨hÐGnÑ%oð/à%ó'ñ ˜xØ'°(ð:`ñ*að*ð ó	ð9!$ð !ñ+ð.
ð^ "�Nñc2ñ9Ð ÷z 0à €× Ò Ø	 Ð2EÈVñJà;õ	=ð (Ð)lðÐ ó
BrD   