§
    øžyj>É  ã                  óB  — U d Z ddl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
 ddlmZ ddlmZmZmZmZmZmZ ddlmZ dd	lmZmZ  ej        e¦  «        ZdZ	 ddlZn# e$ r dZ	 ddlZn# e$ r Y nw xY wY nw xY wd
ZdZ dZ!ee e!hZ"dhZ#de$d<   dud„Z%dvd„Z&dvd„Z'ed„ ¦   «         Z(dvd„Z)dwd„Z*dxd„Z+dyd"„Z,dzd$„Z-d{d%„Z.d{d&„Z/d|d'„Z0dvd(„Z1d{d)„Z2d}d,„Z3d~d-„Z4d~d.„Z5dd0„Z6dd1„Z7d€d4„Z8dud5„Z9dud6„Z:dud7„Z;d�d8„Z<d‚dƒd;„Z=d„d<„Z>dud=„Z?dd>„Z@d…d@„ZAd†dB„ZBd‡dC„ZCdˆdE„ZDd‰dG„ZEdŠdH„ZFd~dI„ZGdJdKœd‹dM„ZHdŒdN„ZI	 d‚d�dP„ZJdddddddQœdŽdZ„ZKd~d[„ZLddd\œd�d]„ZMd^ddd_œd�d`„ZNddd\œd‘db„ZOd~dc„ZPd~dd„ZQd’df„ZRd“dh„ZSd”dj„ZTdudk„ZUd~dl„ZVd†dm„ZWd†dn„ZXd•do„ZYd•dp„ZZd…dq„Z[d…dr„Z\d�ds„Z]d…dt„Z^dS )–a¼  Skill usage telemetry + provenance tracking for the Curator feature.

Tracks per-skill usage metadata in a sidecar JSON file (~/.hermes/skills/.usage.json)
keyed by skill name. Counters are bumped by the existing skill tools (skill_view,
skill_manage); the curator orchestrator reads the derived activity timestamp to
decide lifecycle transitions.

Design notes:
  - Sidecar, not frontmatter. Keeps operational telemetry out of user-authored
    SKILL.md content and avoids conflict pressure for bundled/hub skills.
  - Atomic writes via tempfile + os.replace (same pattern as .bundled_manifest).
  - All counter bumps are best-effort: failures log at DEBUG and return silently.
    A broken sidecar never breaks the underlying tool call.
  - Provenance filter: curator-managed skills are explicitly marked when
    created through skill_manage. Bundled / hub-installed skills stay
    off-limits, and manually authored skills are not inferred from location.

Lifecycle states:
    active    -> default
    stale     -> unused > stale_after_days (config)
    archived  -> unused > archive_after_days (config); moved to .archive/
    pinned    -> opt-out from auto transitions (boolean flag, orthogonal to state)
é    )ÚannotationsN)Úcontextmanager)ÚdatetimeÚtimezone)ÚPath)ÚAnyÚDictÚListÚOptionalÚSetÚTuple©Úget_hermes_home)Úis_excluded_skill_pathÚis_external_skill_pathÚactiveÚstaleÚarchivedÚplanúSet[str]ÚPROTECTED_BUILTIN_SKILLSÚ
skill_nameÚstrÚreturnÚboolc                ó   — | t           v S )a:  Whether *skill_name* is a load-bearing built-in the curator never touches.

    Protected built-ins are exempt from archival and consolidation on every
    path: the automatic state-transition walk, the LLM consolidation pass (they
    are dropped from the candidate list), and direct ``archive_skill`` calls.
    )r   ©r   s    ú7/home/ragecks/.hermes/hermes-agent/tools/skill_usage.pyÚis_protected_builtinr   G   s   € ð Õ1Ð1Ð1ó    r   c                 ó$   — t          ¦   «         dz  S )NÚskillsr   © r    r   Ú_skills_dirr$   Q   s   € ÝÑÔ˜xÑ'Ð'r    c                 ó$   — t          ¦   «         dz  S )Nz.usage.json©r$   r#   r    r   Ú_usage_filer'   U   s   € Ý‰=Œ=˜=Ñ(Ð(r    c               #  óX  K  — t          ¦   «                              d¦  «        } | j                             dd¬¦  «         t          €t
          €dV — dS t
          rH|                      ¦   «         r|                      ¦   «         j        dk    r|  	                    dd¬¦  «         t          | t
          rd	nd
d¬¦  «        }	 t          r t	          j        |t          j        ¦  «         nG|                     d¦  «         t          j        |                     ¦   «         t
          j        d¦  «         dV — t          r8	 t	          j        |t          j        ¦  «         n~# t$          t&          f$ r Y nkw xY wt
          r`	 |                     d¦  «         t          j        |                     ¦   «         t
          j        d¦  «         n# t$          t&          f$ r Y nw xY w|                     ¦   «          dS # t          r8	 t	          j        |t          j        ¦  «         n~# t$          t&          f$ r Y nkw xY wt
          r`	 |                     d¦  «         t          j        |                     ¦   «         t
          j        d¦  «         n# t$          t&          f$ r Y nw xY w|                     ¦   «          w xY w)z@Serialize .usage.json read-modify-write cycles across processes.z
.json.lockT©ÚparentsÚexist_okNr   Ú úutf-8©Úencodingzr+za+é   )r'   Úwith_suffixÚparentÚmkdirÚfcntlÚmsvcrtÚexistsÚstatÚst_sizeÚ
write_textÚopenÚflockÚLOCK_EXÚseekÚlockingÚfilenoÚLK_LOCKÚLOCK_UNÚOSErrorÚIOErrorÚLK_UNLCKÚclose)Ú	lock_pathÚfds     r   Ú_usage_file_lockrH   Y   s�  è è € õ ‘”×)Ò)¨,Ñ7Ô7€IØÔ×Ò 4°$ÐÑ7Ô7Ð7å€}�˜ØˆˆˆØˆåð 4�y×'Ò'Ñ)Ô)ð 4¨Y¯^ª^Ñ-=Ô-=Ô-EÈÒ-JÐ-JØ×Ò˜S¨7ÐÑ3Ô3Ð3å	ˆi¥Ð1˜˜¨T¸GÐ	DÑ	DÔ	D€BðÝð 	;ÝŒK˜�EœMÑ*Ô*Ð*Ð*à�GŠG�A‰JŒJˆJÝŒN˜2Ÿ9š9™;œ;­¬¸Ñ:Ô:Ð:Øˆˆˆåð 
	ðÝ”˜B¥¤Ñ.Ô.Ð.Ð.øÝ�WÐ%ð ð ð Ø�ðøøøåð 	ðØ—’˜‘
”
�
Ý”˜rŸyšy™{œ{­F¬O¸QÑ?Ô?Ð?Ð?øÝ�WÐ%ð ð ð Ø�ðøøøà
�Š‰
Œ
ˆ
ˆ
ˆ
øõ ð 
	ðÝ”˜B¥¤Ñ.Ô.Ð.Ð.øÝ�WÐ%ð ð ð Ø�ðøøøåð 	ðØ—’˜‘
”
�
Ý”˜rŸyšy™{œ{­F¬O¸QÑ?Ô?Ð?Ð?øÝ�WÐ%ð ð ð Ø�ðøøøà
�Š‰
Œ
ˆ
ˆ
øøøs{   Â?A2G- Ä9E ÅE-Å,E-Å8AG  Ç GÇGÇ-J)Ç6HÈJ)ÈH*È'J)È)H*È*
J)È5AI=É<J)É=JÊJ)ÊJÊJ)c                 ó$   — t          ¦   «         dz  S )Nz.archiver&   r#   r    r   Ú_archive_dirrJ   }   s   € Ý‰=Œ=˜:Ñ%Ð%r    c                 ób   — t          j        t          j        ¦  «                             ¦   «         S ©N)r   Únowr   ÚutcÚ	isoformatr#   r    r   Ú_now_isorP   �   s    € ÝŒ<�œÑ%Ô%×/Ò/Ñ1Ô1Ð1r    Úvaluer   úOptional[datetime]c                óÒ   — | sdS 	 t          j        t          | ¦  «        ¦  «        }n# t          t          f$ r Y dS w xY w|j        € |                     t          j        ¬¦  «        }|S )z<Parse an ISO timestamp defensively for activity comparisons.N)Útzinfo)	r   Úfromisoformatr   Ú	TypeErrorÚ
ValueErrorrT   Úreplacer   rN   )rQ   Úparseds     r   Ú_parse_iso_timestamprZ   …   su   € àð ØˆtðÝÔ'­¨E©
¬
Ñ3Ô3ˆˆøÝ•zÐ"ð ð ð Øˆtˆtðøøøà„}ÐØ—’¥x¤|�Ñ4Ô4ˆØ€Ms   †!( ¨=¼=ÚrecordúDict[str, Any]úOptional[str]c                ó˜   — d}d}dD ]B}|                       |¦  «        }t          |¦  «        }|€Œ)|�||k    r|}t          |¦  «        }ŒC|S )a(  Return the newest actual activity timestamp for a usage record.

    "Activity" means a skill was used, viewed, or patched. Creation time is
    intentionally excluded so callers can still distinguish never-active skills;
    lifecycle code can fall back to ``created_at`` as its own anchor.
    N)Úlast_used_atÚlast_viewed_atÚlast_patched_at)ÚgetrZ   r   )r[   Ú	latest_dtÚ
latest_rawÚkeyÚrawÚdts         r   Úlatest_activity_atrh   ’   sf   € ð %)€IØ $€JØDð "ð "ˆØ�jŠj˜‰oŒoˆÝ! #Ñ&Ô&ˆØˆ:ØØÐ  Y¢ ØˆIÝ˜S™œˆJøØÐr    Úintc                ó’   — d}dD ]A}	 |t          |                      |¦  «        pd¦  «        z  }Œ+# t          t          f$ r Y Œ>w xY w|S )zFReturn the total observed activity count across use/view/patch events.r   )Ú	use_countÚ
view_countÚpatch_count)ri   rb   rV   rW   )r[   Útotalre   s      r   Úactivity_countro   ¦   sh   € à€EØ9ð ð ˆð	Ø•S˜Ÿš C™œÐ-¨AÑ.Ô.Ñ.ˆEˆEøÝ�:Ð&ð 	ð 	ð 	ØˆHð	øøøà€Ls   ˆ'0°AÁAc                 óþ  — t          ¦   «         dz  } |                      ¦   «         st          ¦   «         S t          ¦   «         }	 |                      d¬¦  «                             ¦   «         D ]^}|                     ¦   «         }|sŒ|                     dd¦  «        d                              ¦   «         }|r|                     |¦  «         Œ_n2# t          $ r%}t           
                    d|¦  «         Y d}~nd}~ww xY w|S )	zÔReturn the set of skill names that were seeded from the bundled repo.

    Reads ~/.hermes/skills/.bundled_manifest (format: "name:hash" per line).
    Returns empty set if the file is missing or unreadable.
    z.bundled_manifestr-   r.   ú:r0   r   z#Failed to read bundled manifest: %sN)r$   r6   ÚsetÚ	read_textÚ
splitlinesÚstripÚsplitÚaddrB   ÚloggerÚdebug)ÚmanifestÚnamesÚlineÚnameÚes        r   Ú_read_bundled_manifest_namesr   µ   s  € õ ‰}Œ}Ð2Ñ2€HØ�?Š?ÑÔð Ý‰uŒuˆÝ‘e”e€Eð	?Ø×&Ò&°Ð&Ñ8Ô8×CÒCÑEÔEð 	 ð 	 ˆDØ—:’:‘<”<ˆDØð ØØ—:’:˜c 1Ñ%Ô% aÔ(×.Ò.Ñ0Ô0ˆDØð  Ø—	’	˜$‘”�øð	 øõ ð ?ð ?ð ?Ý�ŠÐ:¸AÑ>Ô>Ð>Ð>Ð>Ð>Ð>Ð>øøøøð?øøøà€Ls   ÁBC Ã
C:ÃC5Ã5C:c                 ó–  — t          ¦   «         dz  dz  } |                      ¦   «         st          ¦   «         S 	 t          j        |                      dd¬¦  «        ¦  «        }t          |t          ¦  «        �r‡|                     d¦  «        pi }t          |t          ¦  «        �rZd„ | 	                    ¦   «         D ¦   «         }t          ¦   «         }| 
                    ¦   «         D �]}t          |t          ¦  «        sŒ|                     d¦  «        }t          |t          ¦  «        r|                     ¦   «         sŒXt          |¦  «        }|                     ¦   «         s||z  }	 |                     ¦   «         }|                     |                     ¦   «         ¦  «         n# t"          t$          f$ r Y ŒÐw xY w|d	z  }	|	                     ¦   «         r)|                     t)          |	|j        ¬
¦  «        ¦  «         �Œ|S n># t"          t          j        f$ r%}
t.                               d|
¦  «         Y d}
~
nd}
~
ww xY wt          ¦   «         S )z•Return the set of skill names installed via the Skills Hub.

    Reads ~/.hermes/skills/.hub/lock.json (see tools/skills_hub.py :: HubLockFile).
    z.hubz	lock.jsonr-   rX   ©r/   ÚerrorsÚ	installedc                ó,   — h | ]}t          |¦  «        ’ŒS r#   )r   )Ú.0Úks     r   ú	<setcomp>z,_read_hub_installed_names.<locals>.<setcomp>á   s   € Ð:Ð:Ð: A�˜Q™œÐ:Ð:Ð:r    Úinstall_pathúSKILL.md©Úfallbackz Failed to read hub lock file: %sN)r$   r6   rr   ÚjsonÚloadsrs   Ú
isinstanceÚdictrb   ÚkeysÚvaluesr   ru   r   Úis_absoluteÚresolveÚrelative_torB   rW   rw   Ú_read_skill_namer}   ÚJSONDecodeErrorrx   ry   )rF   Údatarƒ   r{   Ú
skills_dirÚentryrˆ   Ú	skill_dirÚresolvedÚskill_mdr~   s              r   Ú_read_hub_installed_namesr�   Ì   sK  € õ
 ‘” Ñ&¨Ñ4€IØ×ÒÑÔð Ý‰uŒuˆð"<õ Œz˜)×-Ò-°wÀyÐ-ÑQÔQÑRÔRˆÝ�d�DÑ!Ô!ñ 	ØŸš Ñ-Ô-Ð3°ˆIÝ˜)¥TÑ*Ô*ñ Ø:Ð:¨¯ªÑ)9Ô)9Ð:Ñ:Ô:�Ý(™]œ]�
Ø&×-Ò-Ñ/Ô/ð Vñ V�EÝ% e­TÑ2Ô2ð !Ø Ø#(§9¢9¨^Ñ#<Ô#<�LÝ% lµCÑ8Ô8ð !À×@RÒ@RÑ@TÔ@Tð !Ø Ý $ \Ñ 2Ô 2�IØ$×0Ò0Ñ2Ô2ð ;Ø$.°Ñ$:˜	ð!Ø#,×#4Ò#4Ñ#6Ô#6˜Ø ×,Ò,¨Z×-?Ò-?Ñ-AÔ-AÑBÔBÐBÐBøÝ#¥ZÐ0ð !ð !ð !Ø ˜ð!øøøà'¨*Ñ4�HØ—’Ñ(Ô(ð VØŸ	š	Õ"2°8ÀhÄmÐ"TÑ"TÔ"TÑUÔUÐUùØ�øøÝ•TÔ)Ð*ð <ð <ð <Ý�ŠÐ7¸Ñ;Ô;Ð;Ð;Ð;Ð;Ð;Ð;øøøøð<øøøå‰5Œ5€Ls=   ¸D,G? Å%;F!Æ G? Æ!F5Æ2G? Æ4F5Æ5AG? Ç?H:ÈH5È5H:c                 óV  — 	 ddl m}   | ¦   «         }t          |t          ¦  «        r|                     d¦  «        nd}t          |t          ¦  «        r#t          |                     dd¦  «        ¦  «        S n2# t          $ r%}t                               d|¦  «         Y d}~nd}~ww xY wdS )uÂ  Whether bundled built-in skills are eligible for curator pruning.

    Reads ``curator.prune_builtins`` from config (default True). Lazy import
    keeps this module importable without the CLI config layer (e.g. in the
    update/sync context); on any failure we fall back to the default. The real
    safety against a mass-prune is the curator's seed-on-first-sight, not this
    flag â€” built-ins only archive after a fresh inactivity window.
    r   )Úload_configÚcuratorNÚprune_builtinsTz)Failed to read curator.prune_builtins: %s)	Úhermes_cli.configrŸ   rŽ   r�   rb   r   Ú	Exceptionrx   ry   )rŸ   ÚcfgÚcurr~   s       r   Ú_prune_builtins_enabledr¦   ú   sÊ   € ðEØ1Ð1Ð1Ð1Ð1Ð1àˆk‰mŒmˆÝ$.¨sµDÑ$9Ô$9ÐCˆc�gŠg�iÑ Ô Ð ¸tˆÝ�c�4Ñ Ô ð 	9Ý˜ŸšÐ 0°$Ñ7Ô7Ñ8Ô8Ð8ð	9øåð Eð Eð EÝ�ŠÐ@À!ÑDÔDÐDÐDÐDÐDÐDÐDøøøøðEøøøàˆ4s   ‚A3A7 Á7
B&ÂB!Â!B&c                 ó$   — t          ¦   «         dz  S )Nz.curator_suppressedr&   r#   r    r   Ú_suppressed_filer¨     s   € Ý‰=Œ=Ð0Ñ0Ð0r    c                 óÀ  — t          ¦   «         } |                      ¦   «         st          ¦   «         S t          ¦   «         }	 |                      d¬¦  «                             ¦   «         D ]B}|                     ¦   «         }|r*|                     d¦  «        s|                     |¦  «         ŒCn2# t          $ r%}t           
                    d|¦  «         Y d}~nd}~ww xY w|S )u  Built-in skills the curator pruned â€” the re-seeder must leave archived.

    One skill name per line in ``~/.hermes/skills/.curator_suppressed``. This is
    what makes pruning a built-in durable: without it, ``hermes update`` would
    re-copy the bundled skill on the next sync.
    r-   r.   ú#z+Failed to read curator suppression list: %sN)r¨   r6   rr   rs   rt   ru   Ú
startswithrw   rB   rx   ry   )Úpathr{   r|   r~   s       r   Úread_suppressed_namesr­     së   € õ ÑÔ€DØ�;Š;‰=Œ=ð Ý‰uŒuˆÝ‘e”e€EðGØ—N’N¨G�NÑ4Ô4×?Ò?ÑAÔAð 	 ð 	 ˆDØ—:’:‘<”<ˆDØð  ˜DŸOšO¨CÑ0Ô0ð  Ø—	’	˜$‘”�øð	 øõ ð Gð Gð GÝ�ŠÐBÀAÑFÔFÐFÐFÐFÐFÐFÐFøøøøðGøøøà€Ls   Á A+B, Â,
CÂ6CÃCr{   ÚNonec                ó  — t          ¦   «         }	 |j                             dd¬¦  «         d                     t	          | ¦  «        ¦  «        | rdndz   }t          j        t          |j        ¦  «        dd¬¦  «        \  }}	 t          j	        |dd	¬
¦  «        5 }| 
                    |¦  «         |                     ¦   «          t          j        |                     ¦   «         ¦  «         d d d ¦  «         n# 1 swxY w Y   t          j        ||¦  «         d S # t          $ r( 	 t          j        |¦  «         n# t"          $ r Y nw xY w‚ w xY w# t$          $ r(}t&                               d|d¬¦  «         Y d }~d S d }~ww xY w)NTr)   Ú
Ú z.curator_suppressed_ú.tmp©ÚdirÚprefixÚsuffixÚwr-   r.   z,Failed to write curator suppression list: %s©Úexc_info)r¨   r2   r3   ÚjoinÚsortedÚtempfileÚmkstempr   ÚosÚfdopenÚwriteÚflushÚfsyncr?   rX   ÚBaseExceptionÚunlinkrB   r£   rx   ry   )r{   r¬   r—   rG   ÚtmpÚfr~   s          r   Ú_write_suppressed_namesrÇ   (  sÙ  € ÝÑÔ€DðWØŒ×Ò $°ÐÑ6Ô6Ð6Ø�yŠy� ™œÑ'Ô'°5Ð+@¨4¨4¸bÑAˆÝÔ"¥s¨4¬;Ñ'7Ô'7Ð@VÐ_eÐfÑfÔf‰ˆˆCð	Ý”˜2˜s¨WÐ5Ñ5Ô5ð %¸Ø—’˜‘”�Ø—’‘	”	�	Ý”˜Ÿš™œÑ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %õ ŒJ�s˜DÑ!Ô!Ð!Ð!Ð!øÝð 	ð 	ð 	ðÝ”	˜#‘”��øÝð ð ð Ø�ðøøøàð	øøøøõ ð Wð Wð WÝ�ŠÐCÀQÐQUˆÑVÔVÐVÐVÐVÐVÐVÐVÐVøøøøðWøøøss   �A1E ÂD ÂAC5Ã)D Ã5C9Ã9D Ã<C9Ã=D Ä
E	Ä"D7Ä6E	Ä7
EÅE	ÅEÅE	Å	E Å
E>ÅE9Å9E>c                ó~   — | sdS t          ¦   «         }| |vr&|                     | ¦  «         t          |¦  «         dS dS )zBRecord that a built-in skill was pruned, so sync won't restore it.N)r­   rw   rÇ   ©r   r{   s     r   Úadd_suppressed_namerÊ   >  sS   € àð ØˆÝ!Ñ#Ô#€EØ˜ÐÐØ�	Š	�*ÑÔÐÝ Ñ&Ô&Ð&Ð&Ð&ð Ðr    c                ó~   — | sdS t          ¦   «         }| |v r&|                     | ¦  «         t          |¦  «         dS dS )z7Clear a built-in's suppression entry (e.g. on restore).N)r­   ÚdiscardrÇ   rÉ   s     r   Úremove_suppressed_namerÍ   H  sS   € àð ØˆÝ!Ñ#Ô#€EØ�UÐÐØ�Š�jÑ!Ô!Ð!Ý Ñ&Ô&Ð&Ð&Ð&ð Ðr    ú	List[str]c                 ó¾  — t          ¦   «         } |                      ¦   «         sg S t          ¦   «         }t          ¦   «         }t	          ¦   «         }t          ¦   «         }g }|                      d¦  «        D ]Î}t          |¦  «        rŒt          |¦  «        rŒ"	 | 	                    | ¦  «         n# t          $ r Y ŒEw xY wt          ||j        j        ¬¦  «        }||v rŒit          |¦  «        rŒy||v r|sŒ€|                     |¦  «         Œ–t!          |                     |¦  «        ¦  «        sŒ¹|                     |¦  «         ŒÏt%          t'          |¦  «        ¦  «        S )u  Enumerate skills the curator may manage.

    Always includes agent-authored skills (those marked in ``.usage.json`` via
    ``skill_manage(action="create")``). When ``curator.prune_builtins`` is
    enabled, bundled built-in skills are ALSO included even though they have no
    agent-created usage record â€” their inactivity clock is anchored on first
    sight (see ``apply_automatic_transitions``). Hub-installed skills are never
    included; manually authored skills are not inferred from filesystem
    location.
    r‰   rŠ   )r$   r6   r�   r   r¦   Ú
load_usageÚrglobr   r   r”   rW   r•   r2   r}   r   ÚappendÚ_is_curator_managed_recordrb   r»   rr   )ÚbaseÚhubÚbundledr¡   Úusager{   rœ   r}   s           r   Úlist_agent_created_skill_namesrØ   R  sy  € õ ‰=Œ=€DØ�;Š;‰=Œ=ð Øˆ	Ý
#Ñ
%Ô
%€CÝ*Ñ,Ô,€GÝ,Ñ.Ô.€NÝ‰LŒL€Eà€Eà—J’J˜zÑ*Ô*ð ð ˆå! (Ñ+Ô+ð 	Øõ " (Ñ+Ô+ð 	Øð	Ø× Ò  Ñ&Ô&Ð&Ð&øÝð 	ð 	ð 	ØˆHð	øøøå °8´?Ô3GÐHÑHÔHˆà�3ˆ;ˆ;Øõ   Ñ%Ô%ð 	ØØ�7ˆ?ˆ?ð "ð ØØ�LŠL˜ÑÔÐØå)¨%¯)ª)°D©/¬/Ñ:Ô:ð 	ØØ�Š�TÑÔÐÐÝ•#�e‘*”*ÑÔÐs   ÂB-Â-
B:Â9B:c                 ó    — t          ¦   «         } |                      ¦   «         sg S t          d„ |                      ¦   «         D ¦   «         ¦  «        S )a  Enumerate skills in ``~/.hermes/skills/.archive/``.

    Archive layout is flat (``.archive/<skill>/``) as set by ``archive_skill``,
    so the directory name is the skill name. Used by ``hermes curator
    list-archived`` to help users pass a name to ``hermes curator restore``.
    c                óD   — h | ]}|                      ¦   «         ¯|j        ’ŒS r#   ©Úis_dirr}   )r…   Úps     r   r‡   z,list_archived_skill_names.<locals>.<setcomp>“  s'   € ÐHÐHÐH˜a¸Q¿XºX¹Z¼ZÐH�1”6ÐHÐHÐHr    )rJ   r6   r»   Úiterdir)Úarchive_roots    r   Úlist_archived_skill_namesrà   ‰  sO   € õ  ‘>”>€LØ×ÒÑ Ô ð Øˆ	ÝÐHÐH <×#7Ò#7Ñ#9Ô#9ÐHÑHÔHÑIÔIÐIr    rœ   r‹   c                óž  — 	 |                       dd¬¦  «        dd…         }n# t          $ r |cY S w xY wd}|                     d¦  «        D ]�}|                     ¦   «         }|dk    r|r nbd	}Œ#|r\|                     d
¦  «        rG|                     dd¦  «        d                              ¦   «                              d¦  «        }|r|c S Œ‚|S )z9Parse the `name:` field from a SKILL.md YAML frontmatter.r-   rX   r�   Ni   Fr°   z---Tzname:rq   r0   z"')rs   rB   rv   ru   r«   )rœ   r‹   ÚtextÚin_frontmatterr|   ÚstrippedrQ   s          r   r•   r•   –  s  € ðØ×!Ò!¨7¸9Ð!ÑEÔEÀeÀtÀeÔLˆˆøÝð ð ð Øˆˆˆðøøøà€NØ—
’
˜4Ñ Ô ð 
ð 
ˆØ—:’:‘<”<ˆØ�uÒÐØð Ø�Ø!ˆNØØð 	˜h×1Ò1°'Ñ:Ô:ð 	Ø—N’N 3¨Ñ*Ô*¨1Ô-×3Ò3Ñ5Ô5×;Ò;¸EÑBÔBˆEØð Ø���øØ€Os   ‚" ¢1°1c                óŽ   — t          ¦   «         t          ¦   «         z  }| |v rdS t          | ¦  «        du ot          | ¦  «        du S )z:Whether *skill_name* is neither bundled nor hub-installed.FN)r   r�   Ú_find_skill_dirÚ_find_external_skill_dir)r   Ú
off_limitss     r   Úis_agent_createdré   «  sX   € å-Ñ/Ô/Õ2KÑ2MÔ2MÑM€JØ�ZÐÐØˆuå˜
Ñ#Ô# tÐ+ð 	=Ý$ ZÑ0Ô0¸Ð<ðð r    c                ó"   — | t          ¦   «         v S )z6Whether *skill_name* was installed via the Skills Hub.)r�   r   s    r   Úis_hub_installedrë   ¶  s   € àÕ2Ñ4Ô4Ð4Ð4r    c                ó"   — | t          ¦   «         v S )z=Whether *skill_name* was seeded from the bundled repo skills.)r   r   s    r   Ú
is_bundledrí   »  s   € àÕ5Ñ7Ô7Ð7Ð7r    c                ó   — d| › d�S )Núskill 'zM' lives in skills.external_dirs; external skills are read-only to the curatorr#   r   s    r   Ú_external_read_only_messagerð   À  s   € ð	7�*ð 	7ð 	7ð 	7ðr    Ú
skill_pathúOptional[Path]c                ó  — |�t          |¦  «        rdS t          | ¦  «        rdS t          | ¦  «        rdS t          | ¦  «        rt	          ¦   «         S t          | ¦  «        }|�t          |¦  «         S t          | ¦  «        �dS dS )uó  Whether the curator may track/archive *skill_name*.

    Agent-created skills are always eligible. Bundled built-ins become eligible
    only when ``curator.prune_builtins`` is enabled. Hub-installed and external
    skill-dir skills are NEVER eligible â€” they have an external upstream owner.
    Org-shared skills ARE eligible for improvement (the curator may patch them
    like any other skill; edits stay local until proposed) but are protected
    from ARCHIVE/DELETE elsewhere â€” removing a shared skill is an org-admin
    action, not a local curation decision.
    Protected built-ins (``PROTECTED_BUILTIN_SKILLS``) are NEVER eligible
    regardless of any flag â€” they back load-bearing UX and must never be
    archived or consolidated.
    NFT)r   r   rë   rí   r¦   ræ   rç   )r   rñ   Ú	local_dirs      r   Úis_curation_eligiblerõ   Ç  sŸ   € ð ÐÕ"8¸Ñ"DÔ"DÐØˆuÝ˜JÑ'Ô'ð ØˆuÝ˜
Ñ#Ô#ð ØˆuÝ�*ÑÔð )Ý&Ñ(Ô(Ð(Ý 
Ñ+Ô+€IØÐÝ)¨)Ñ4Ô4Ð4Ð4Ý 
Ñ+Ô+Ð7ØˆuØˆ4r    c                ó�   — t          | t          ¦  «        sdS |                      d¦  «        dk    p|                      d¦  «        du S )u˜  Return True when a usage record opts a skill into curator management.

    NAMING (issue #67140): the on-disk field is ``created_by``, which reads
    like provenance but is consumed as a **curator-management opt-in policy
    flag**. The two are not the same question:

    * provenance = "who authored this file" â€” historical fact, and for records
      written before the marker existed it is simply unrecoverable.
    * management = "may autonomous curation mutate/archive this" â€” a policy
      decision the user can change at any time via ``hermes curator adopt``.

    ``created_by: "agent"`` therefore means "curator-managed", NOT "proof the
    agent wrote it". The field name is retained because it is already on disk
    in every user's ``.usage.json``; renaming it would strand those records.
    Read it as policy, and prefer ``is_curator_managed()`` at call sites so the
    intent is unambiguous.
    FÚ
created_byÚagentÚagent_createdT)rŽ   r�   rb   ©r[   s    r   rÓ   rÓ   å  sI   € õ$ �f�dÑ#Ô#ð ØˆuØ�:Š:�lÑ#Ô# wÒ.ÐU°&·*²*¸_Ñ2MÔ2MÐQUÐ2UÐUr    c                ó^   — t          t          ¦   «                              | ¦  «        ¦  «        S )a  Whether *skill_name* is opted into curator management.

    Policy-intent alias for the ``created_by``-marker check, so call sites read
    as the question they are actually asking (see ``_is_curator_managed_record``
    for why the stored field name says "created_by").
    )rÓ   rÐ   rb   r   s    r   Úis_curator_managedrü   ü  s$   € õ &¥j¡l¤l×&6Ò&6°zÑ&BÔ&BÑCÔCÐCr    c                 óŽ  — t          ¦   «         } |                      ¦   «         sg S t          ¦   «         }t          ¦   «         }t	          ¦   «         }g }|                      d¦  «        D ]Ä}t          |¦  «        st          |¦  «        rŒ!	 |                     | ¦  «         n# t          $ r Y ŒDw xY wt          ||j        j        ¬¦  «        }||v s||v st          |¦  «        rŒ{t          |                     |¦  «        ¦  «        rŒžt!          ||¦  «        sŒ¯|                     |¦  «         ŒÅt%          t'          |¦  «        ¦  «        S )uû  Enumerate curation-ELIGIBLE skills that carry no provenance marker.

    These are skills the curator *could* manage (they are not hub-installed,
    not external, not protected built-ins) but never will, because nothing
    ever wrote ``created_by: agent`` onto their usage record. Two ways a skill
    lands here:

    * It predates the provenance mechanism entirely â€” records written before
      ``created_by`` existed carry no key at all, so their authorship is
      unknowable from the record alone.
    * It was created by a FOREGROUND ``skill_manage(action="create")`` call,
      which deliberately does not mark provenance (skills a user asks for
      belong to the user).

    Either way the skill is invisible to ``curated_report()`` and therefore to
    every automatic transition. ``hermes curator status`` surfaces this count
    so the blind spot is legible instead of silent, and ``hermes curator
    adopt`` lets the user hand specific skills over explicitly.

    Provenance is a DECLARATION, never an inference: this function only
    reports, and callers must not auto-adopt what it returns. Heavy patch or
    use counts are evidence of maintenance, not of authorship â€” the agent
    edits user-authored skills on the user's behalf routinely.
    r‰   rŠ   )r$   r6   r�   r   rÐ   rÑ   r   r   r”   rW   r•   r2   r}   r   rÓ   rb   rõ   rÒ   r»   rr   )rÔ   rÕ   rÖ   r×   r{   rœ   r}   s          r   Úlist_unmanaged_skill_namesrþ     sU  € õ2 ‰=Œ=€DØ�;Š;‰=Œ=ð Øˆ	Ý
#Ñ
%Ô
%€CÝ*Ñ,Ô,€GÝ‰LŒL€Eà€EØ—J’J˜zÑ*Ô*ð ð ˆÝ! (Ñ+Ô+ð 	Õ/EÀhÑ/OÔ/Oð 	Øð	Ø× Ò  Ñ&Ô&Ð&Ð&øÝð 	ð 	ð 	ØˆHð	øøøå °8´?Ô3GÐHÑHÔHˆð �3ˆ;ˆ;˜$ '˜/˜/Õ-AÀ$Ñ-GÔ-G˜/ØÝ% e§i¢i°¡o¤oÑ6Ô6ð 	ØÝ# D¨(Ñ3Ô3ð 	ØØ�Š�TÑÔÐÐÝ•#�e‘*”*ÑÔÐs   ÂBÂ
B+Â*B+úList[Dict[str, Any]]c                 ó4  — t          ¦   «         } g }t          ¦   «         D ]ø}|                      |¦  «        }t          |t          ¦  «        rt	          |¦  «        nt          ¦   «         }t          ¦   «                              ¦   «         D ]\  }}|                     ||¦  «         Œd|i|¥}t          |t          ¦  «        od|v |d<   t          |t          ¦  «        |d<   t          |¦  «        |d<   t          |¦  «        |d<   | 
                    |¦  «         Œù|S )a¬  Rows for every skill :func:`list_unmanaged_skill_names` returns.

    Each row carries the usual activity fields plus ``has_provenance_key``:
    False when the record has no ``created_by`` key at all (pre-dates the
    mechanism), True when the key is present but unset (a foreground create
    under the current policy). The distinction matters for explaining WHY a
    skill is unmanaged; it is not a signal to adopt on.
    r}   r÷   Úhas_provenance_keyÚ
has_recordÚlast_activity_atro   )rÐ   rþ   rb   rŽ   r�   Ú_empty_recordÚitemsÚ
setdefaultrh   ro   rÒ   )r×   Úrowsr}   rf   Úrecr†   ÚvÚrows           r   Úunmanaged_reportr  ;  s  € õ ‰LŒL€EØ!#€DÝ*Ñ,Ô,ð 
ð 
ˆØ�iŠi˜‰oŒoˆÝ+5°c½4Ñ+@Ô+@ÐU�d 3™iœi˜iÅmÁoÄoˆÝ!‘O”O×)Ò)Ñ+Ô+ð 	!ð 	!‰DˆAˆqØ�NŠN˜1˜aÑ Ô Ð Ð Ø�tÐ#˜sÐ#ˆÝ$.¨sµDÑ$9Ô$9Ð$Q¸lÈcÐ>QˆÐ Ñ!Ý& s­DÑ1Ô1ˆˆLÑÝ"4°SÑ"9Ô"9ˆÐÑÝ .¨sÑ 3Ô 3ˆÐÑØ�Š�CÑÔÐÐØ€Kr    úTuple[bool, str]c                ó>  — | sdS t          | ¦  «        rdd| › d�fS t          | ¦  «        rdd| › d�fS t          | ¦  «        rdd| › d�fS t          | ¦  «        }|€t	          | ¦  «        �dd| › d�fS dd	| › d
�fS t          |¦  «        rdt          | ¦  «        fS t          ¦   «         }t          | 	                    | ¦  «        ¦  «        rdd| › d�fS t          | ¦  «         t          t          ¦   «          	                    | ¦  «        ¦  «        sdd| › d�fS dd| › d�fS )uw  Hand *skill_name* to the curator by user declaration.

    Writes the same ``created_by: agent`` marker the background review fork
    writes, so the skill joins ``curated_report()`` and the automatic
    transition walk. The inactivity clock is NOT reset: the skill's existing
    ``last_activity_at`` still governs staleness, so adopting something idle
    for months does not buy it a fresh window (nor does it archive it on the
    spot â€” the state machine decides on the next pass).

    Returns (ok, message). Refuses hub-installed, external, and protected
    built-in skills, which have an owner other than the user.
    )Fzno skill name givenFú'z7' is a protected built-in; the curator never manages itz(' is hub-installed; its upstream owns ituU   ' is a bundled built-in â€” it is governed by curator.prune_builtins, not by adoptionNz?' lives in skills.external_dirs and is read-only to the curatorrï   ú' not foundTz' is already curator-managedzcould not mark 'z' as curator-managedz	adopted 'z' into curator management)r   rë   rí   ræ   rç   r   rð   rÐ   rÓ   rb   Úmark_agent_created)r   rš   r×   s      r   Úadopt_skillr  T  s¨  € ð ð ,Ø+Ð+Ý˜JÑ'Ô'ð ^ØÐ]˜*Ð]Ð]Ð]Ð]Ð]Ý˜
Ñ#Ô#ð OØÐN˜*ÐNÐNÐNÐNÐNÝ�*ÑÔð 
ð
 ð6�
ð 6ð 6ð 6ð
ð 	
õ   
Ñ+Ô+€IØÐÝ# JÑ/Ô/Ð;ØÐi˜jÐiÐiÐiÐiÐiØÐ7 
Ð7Ð7Ð7Ð7Ð7Ý˜iÑ(Ô(ð >ØÕ1°*Ñ=Ô=Ð=Ð=Ý‰LŒL€EÝ! %§)¢)¨JÑ"7Ô"7Ñ8Ô8ð BØÐA˜ÐAÐAÐAÐAÐAÝ�zÑ"Ô"Ð"Ý%¥j¡l¤l×&6Ò&6°zÑ&BÔ&BÑCÔCð JØÐI¨ÐIÐIÐIÐIÐIØÐB˜ZÐBÐBÐBÐBÐBr    c                 óD   — d ddd d dddd t          ¦   «         t          dd dœS )Nr   F)r÷   rk   rl   r_   r`   rm   Úpatch_generationÚlast_reused_patch_generationra   Ú
created_atÚstateÚpinnedÚarchived_at)rP   ÚSTATE_ACTIVEr#   r    r   r  r  „  s<   € àØØØØØØØ()ØÝ‘j”jÝØØðð ð r    úDict[str, Dict[str, Any]]c                 óØ  — t          ¦   «         } |                      ¦   «         si S 	 t          j        |                      d¬¦  «        ¦  «        }nA# t
          t          j        f$ r(}t                               d| |¦  «         i cY d}~S d}~ww xY wt          |t          ¦  «        si S i }|                     ¦   «         D ],\  }}t          |t          ¦  «        r||t          |¦  «        <   Œ-|S )zGRead the entire .usage.json map. Returns empty dict on missing/corrupt.r-   r.   zFailed to read %s: %sN)r'   r6   rŒ   r�   rs   rB   r–   rx   ry   rŽ   r�   r  r   )r¬   r—   r~   Úcleanr†   r	  s         r   rÐ   rÐ   –  sñ   € å‰=Œ=€DØ�;Š;‰=Œ=ð Øˆ	ðÝŒz˜$Ÿ.š.°'˜.Ñ:Ô:Ñ;Ô;ˆˆøÝ•TÔ)Ð*ð ð ð Ý�ŠÐ,¨d°AÑ6Ô6Ð6Øˆ	ˆ	ˆ	ˆ	ˆ	ˆ	øøøøðøøøõ �d�DÑ!Ô!ð Øˆ	à')€EØ—
’
‘”ð ð ‰ˆˆ1Ý�a�ÑÔð 	ØˆE•#�a‘&”&‰MøØ€Ls   ¦(A ÁBÁ%BÂBÂBr—   c                óº  — t          ¦   «         }	 |j                             dd¬¦  «         t          j        t          |j        ¦  «        dd¬¦  «        \  }}	 t          j        |dd¬¦  «        5 }t          j	        | |d	dd
¬¦  «         | 
                    ¦   «          t          j        |                     ¦   «         ¦  «         ddd¦  «         n# 1 swxY w Y   t          j        ||¦  «         dS # t          $ r( 	 t          j        |¦  «         n# t           $ r Y nw xY w‚ w xY w# t"          $ r)}t$                               d||d¬¦  «         Y d}~d
S d}~ww xY w)z?Write the usage map atomically and report whether it committed.Tr)   z.usage_r²   r³   r·   r-   r.   é   F)ÚindentÚ	sort_keysÚensure_asciiNzFailed to write %s: %sr¸   )r'   r2   r3   r¼   r½   r   r¾   r¿   rŒ   ÚdumprÁ   rÂ   r?   rX   rÃ   rÄ   rB   r£   rx   ry   )r—   r¬   rG   Útmp_pathrÆ   r~   s         r   Ú
save_usager$  ª  s½  € å‰=Œ=€DðØŒ×Ò $°ÐÑ6Ô6Ð6ÝÔ'Ý�D”KÑ Ô ¨¸6ð
ñ 
ô 
‰ˆˆHð	Ý”˜2˜s¨WÐ5Ñ5Ô5ð %¸Ý”	˜$ ¨!°tÈ%ÐPÑPÔPÐPØ—’‘	”	�	Ý”˜Ÿš™œÑ$Ô$Ð$ð%ð %ð %ñ %ô %ð %ð %ð %ð %ð %ð %øøøð %ð %ð %ð %õ ŒJ�x Ñ&Ô&Ð&Ø�4øÝð 	ð 	ð 	ðÝ”	˜(Ñ#Ô#Ð#Ð#øÝð ð ð Ø�ðøøøàð	øøøøõ ð ð ð Ý�ŠÐ-¨t°QÀˆÑFÔFÐFØˆuˆuˆuˆuˆuøøøøðøøøss   �AD' ÁC2 Á0ACÃC2 ÃCÃC2 ÃCÃC2 Ã2
D$Ã=DÄD$Ä
DÄD$ÄDÄD$Ä$D' Ä'
EÄ1EÅEc                ó  — t          ¦   «         }|                     | ¦  «        }t          |t          ¦  «        st	          ¦   «         S t	          ¦   «         }|                     ¦   «         D ]\  }}|                     ||¦  «         Œ|S )zDReturn the record for *skill_name*, creating a fresh one if missing.)rÐ   rb   rŽ   r�   r  r  r  )r   r—   r  rÔ   r†   r	  s         r   Ú
get_recordr&  Ä  sx   € å‰<Œ<€DØ
�(Š(�:Ñ
Ô
€CÝ�c�4Ñ Ô ð Ý‰ŒÐå‰?Œ?€DØ—
’
‘”ð ð ‰ˆˆ1Ø�Š�q˜!ÑÔÐÐØ€Jr    c                ó°  — | rt          | ¦  «        sdS 	 t          ¦   «         5  t          ¦   «         }t          |                     | ¦  «        t
          ¦  «        r	 ddd¦  «         dS t          ¦   «         || <   t          |¦  «         ddd¦  «         dS # 1 swxY w Y   dS # t          $ r)}t           
                    d| |d¬¦  «         Y d}~dS d}~ww xY w)u¸  Persist a baseline usage record for a curation-eligible skill.

    Built-ins carry no usage record until something touches them, which leaves
    their inactivity clock with no anchor. Seeding a record here fixes
    ``created_at`` to the moment the curator first sees the skill, so the
    archive/stale clock measures non-use FROM THEN â€” not from epoch. No-op when
    a record already exists or the skill isn't curation-eligible.
    Nz1skill_usage.seed_record_if_missing(%s) failed: %sTr¸   )rõ   rH   rÐ   rŽ   rb   r�   r  r$  r£   rx   ry   ©r   r—   r~   s      r   Úseed_record_if_missingr)  Ñ  s[  € ð ð Õ1°*Ñ=Ô=ð ØˆðhÝÑÔð 	ð 	Ý‘<”<ˆDÝ˜$Ÿ(š( :Ñ.Ô.µÑ5Ô5ð Øð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	õ  -™œˆD�ÑÝ�tÑÔÐð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð 	ð 	øõ ð hð hð hÝ�ŠÐHÈ*ÐVWÐbfˆÑgÔgÐgÐgÐgÐgÐgÐgÐgøøøøðhøøøsF   •B" £8BÁB" Á( BÂB" ÂBÂB" ÂBÂB" Â"
CÂ,CÃCF©Úrequire_curation_eligibler+  c               óØ  — | sdS 	 |rt          | ¦  «        sdS t          ¦   «         5  t          ¦   «         }|                     | ¦  «        }t	          |t
          ¦  «        st          ¦   «         } ||¦  «        }||| <   t          |¦  «        s	 ddd¦  «         dS |cddd¦  «         S # 1 swxY w Y   dS # t          $ r)}t           
                    d| |d¬¦  «         Y d}~dS d}~ww xY w)u  Load, apply *mutator(record)* in place, save. Best-effort.

    By default this records telemetry for ANY skill â€” bundled, hub-installed,
    or agent-created â€” because usage tracking is pure observability and is
    orthogonal to whether a skill is ever curated. Lifecycle mutators
    (``set_state``, ``set_pinned``, ``mark_agent_created``) pass
    ``require_curation_eligible=True`` so they never write meaningless state
    onto a skill the curator can't manage (e.g. an ``archived`` flag on a
    hub-installed skill).
    Nz"skill_usage._mutate(%s) failed: %sTr¸   )rõ   rH   rÐ   rb   rŽ   r�   r  r$  r£   rx   ry   )r   Úmutatorr+  r—   r  Úresultr~   s          r   Ú_mutater/  ç  sy  € ð ð ØˆtðØ$ð 	Õ-AÀ*Ñ-MÔ-Mð 	Ø�4ÝÑÔð 		ð 		Ý‘<”<ˆDØ—(’(˜:Ñ&Ô&ˆCÝ˜c¥4Ñ(Ô(ð &Ý#‘o”o�Ø�W˜S‘\”\ˆFØ"ˆD�ÑÝ˜dÑ#Ô#ð Øð		ð 		ð 		ñ 		ô 		ð 		ð 		ð 		ð ð		ð 		ð 		ð 		ñ 		ô 		ð 		ð 		ð 		ð 		ð 		ð 		øøøð 		ð 		ð 		ð 		ð 		ð 		øõ ð ð ð Ý�ŠÐ9¸:ÀqÐSWˆÑXÔXÐXØˆtˆtˆtˆtˆtøøøøðøøøsL   †B6 ™B6 §A'B)ÂB6 ÂB)ÂB6 Â)B-Â-B6 Â0B-Â1B6 Â6
C)Ã C$Ã$C)c                ó    — t          | t          ¦  «        rdS 	 t          dt          | pd¦  «        ¦  «        S # t          t
          f$ r Y dS w xY w)Nr   )rŽ   r   Úmaxri   rV   rW   )rQ   s    r   Ú_non_negative_intr2    s_   € Ý�%�ÑÔð ØˆqðÝ�1•c˜%˜* 1‘o”oÑ&Ô&Ð&øÝ•zÐ"ð ð ð Øˆqˆqðøøøs   ™8 ¸AÁAúOptional[Dict[str, Any]]c                óž  — t          | ¦  «        st          | ¦  «        rdS d| v r7	 ddlm}  |¦   «                              | ¦  «        �dS n# t
          $ r Y nw xY wt          |t          ¦  «        r%|                     d¦  «        }|dk    rdS |dk    rdS t          | ¦  «        �d	S t          | ¦  «        €t          |t          ¦  «        rd
S dS )z;Return the bounded provenance used by shared skill metrics.rƒ   rq   r   )Úget_plugin_managerNr÷   rø   rù   ÚexternalÚlocalÚunknown)rë   rí   Úhermes_cli.pluginsr5  Úfind_plugin_skillr£   rŽ   r�   rb   rç   ræ   )r   r[   r5  r÷   s       r   Útelemetry_provenancer;    s  € õ
 ˜
Ñ#Ô#ð ¥z°*Ñ'=Ô'=ð Øˆ{Ø
ˆjÐÐð	Ø=Ð=Ð=Ð=Ð=Ð=à!Ð!Ñ#Ô#×5Ò5°jÑAÔAÐMØ"�{ð Nøåð 	ð 	ð 	ØˆDð	øøøå�&�$ÑÔð #Ø—Z’Z Ñ-Ô-ˆ
Ø˜Ò$Ð$Ø�;Ø˜Ò Ð Ø"�?Ý 
Ñ+Ô+Ð7ØˆzÝ�zÑ"Ô"Ð.µ*¸VÅTÑ2JÔ2JÐ.ØˆwØˆ9s   ¦#A Á
AÁA©r[   Útask_idÚ
session_idrk   ÚreusedÚreuse_after_patchÚactionr=  r>  rk   úOptional[int]r?  úOptional[bool]r@  c               óÜ   — 	 ddl m}m}	  |d¦  «        sdS  |	d|| t          | |¦  «        |pd|pd|||¬¦	  «	         dS # t          $ r" t
                               d| |d¬	¦  «         Y dS w xY w)
zFEmit one best-effort lifecycle fact after authoritative state changes.r   )Úhas_hookÚinvoke_hookÚon_skill_lifecycleNr±   )rA  r   Ú
provenancer=  r>  rk   r?  r@  z+skill_usage lifecycle hook failed for %s/%sTr¸   )Úhermes_cli.lifecyclerE  rF  r;  r£   rx   ry   )
r   rA  r[   r=  r>  rk   r?  r@  rE  rF  s
             r   Ú_emit_skill_lifecyclerJ  +  sÛ   € ð
Ø>Ð>Ð>Ð>Ð>Ð>Ð>Ð>àˆxÐ,Ñ-Ô-ð 	ØˆFØˆØ ØØ!Ý+¨J¸Ñ?Ô?Ø�M˜rØ!Ð' RØØØ/ð
	
ñ 
	
ô 
	
ð 
	
ð 
	
ð 
	
øõ ð 
ð 
ð 
Ý�ŠØ9ØØØð	 	ñ 	
ô 	
ð 	
ð 	
ð 	
ð 	
ð
øøøs   ‚? —&? ¿(A+Á*A+c                ó.   — dd„}t          | |¦  «         dS )u×   Bump view_count and last_viewed_at. Called from skill_view().

    Tracks every skill regardless of provenance â€” built-ins and hub skills
    included. Usage telemetry is observability, not a curation signal.
    r  r\   r   r®   c                óx   — t          |                      d¦  «        ¦  «        dz   | d<   t          ¦   «         | d<   d S )Nrl   r0   r`   ©r2  rb   rP   ©r  s    r   Ú_applyzbump_view.<locals>._applyZ  s:   € Ý-¨c¯gªg°lÑ.CÔ.CÑDÔDÀqÑHˆˆLÑÝ (¡
¤
ˆÐÑÐÐr    N©r  r\   r   r®   ©r/  ©r   rO  s     r   Ú	bump_viewrS  T  s.   € ð+ð +ð +ð +õ ˆJ˜ÑÔÐÐÐr    )r=  r>  c               ó®   — dd„}t          | |¦  «        }t          |t          ¦  «        r+t          | d||||d         |d         |d         ¬	¦  «         d
S d
S )zÉBump use_count and last_used_at. Called when a skill is actively used
    (e.g. loaded into the prompt path or referenced from an assistant turn).

    Tracks every skill regardless of provenance.
    r  r\   r   c                óš  — t          |                      d¦  «        ¦  «        }t          |                      d¦  «        ¦  «        }t          t          |                      d¦  «        ¦  «        |¦  «        }|dk    }|o||k    }|dz   | d<   t          ¦   «         | d<   || d<   || d<   |r|| d<   |                      d¦  «        | d         ||dœS )	Nrk   r  r  r   r0   r_   r÷   )r÷   rk   r?  r@  )r2  rb   ÚminrP   )r  Úprevious_use_countr  Úlast_reused_generationr?  r@  s         r   rO  zbump_use.<locals>._applyk  só   € Ý.¨s¯wªw°{Ñ/CÔ/CÑDÔDÐÝ,¨S¯WªWÐ5GÑ-HÔ-HÑIÔIÐÝ!$Ý˜cŸgšgÐ&DÑEÔEÑFÔFØñ"
ô "
Ðð $ aÒ'ˆØ"ÐPÐ'7Ð:PÒ'PÐØ-°Ñ1ˆˆKÑÝ&™jœjˆˆNÑØ"2ˆÐÑØ.DˆÐ*Ñ+Øð 	CØ2BˆCÐ.Ñ/àŸ'š' ,Ñ/Ô/Ø˜[Ô)ØØ!2ð	
ð 
ð 	
r    Úloadedrk   r?  r@  r<  N©r  r\   r   r\   ©r/  rŽ   r�   rJ  )r   r=  r>  rO  Úfactss        r   Úbump_user]  `  s‹   € ð
ð 
ð 
ð 
õ, �J Ñ'Ô'€EÝ�%�ÑÔð 

ÝØØØØØ!Ø˜KÔ(Ø˜”?Ø#Ð$7Ô8ð		
ñ 		
ô 		
ð 		
ð 		
ð 		
ð

ð 

r    Úpatch)rA  r=  r>  c               ó˜   — |dk    rdnd}d
d„}t          | |¦  «        }t          |t          ¦  «        rt          | ||||¬¦  «         d	S d	S )zƒBump patch_count and last_patched_at. Called from skill_manage (patch/edit).

    Tracks every skill regardless of provenance.
    r^  ÚpatchedÚeditedr  r\   r   c                óò   — t          |                      d¦  «        ¦  «        dz   | d<   t          |                      d¦  «        ¦  «        dz   | d<   t          ¦   «         | d<   d|                      d¦  «        iS )Nrm   r0   r  ra   r÷   rM  rN  s    r   rO  zbump_patch.<locals>._applyœ  sq   € Ý.¨s¯wªw°}Ñ/EÔ/EÑFÔFÈÑJˆˆMÑÝ"3°C·G²GÐ<NÑ4OÔ4OÑ"PÔ"PÐSTÑ"TˆÐÑÝ!)¡¤ˆÐÑØ˜cŸgšg lÑ3Ô3Ð4Ð4r    ©r[   r=  r>  NrZ  r[  )r   rA  r=  r>  Úlifecycle_actionrO  r\  s          r   Ú
bump_patchre  �  s‰   € ð %+¨gÒ$5Ð$5�y�y¸8Ðð5ð 5ð 5ð 5õ �J Ñ'Ô'€EÝ�%�ÑÔð 
ÝØØØØØ!ð	
ñ 	
ô 	
ð 	
ð 	
ð 	
ð
ð 
r    rù   c               óŠ   ‡— dˆfd„}t          | |¦  «        }t          |t          ¦  «        rt          | d|||¬¦  «         dS dS )	zGPersist explicit creation provenance and emit a successful create fact.r  r\   r   c                ó�   •— |                       ¦   «          |                      t          ¦   «         ¦  «         ‰rd| d<   d| d         iS ©Nrø   r÷   )ÚclearÚupdater  )r  rù   s    €r   rO  zrecord_created.<locals>._applyµ  sJ   ø€ ð 	�	Š	‰ŒˆØ�
Š
•=‘?”?Ñ#Ô#Ð#Øð 	(Ø 'ˆC�ÑØ˜c ,Ô/Ð0Ð0r    Úcreatedrc  NrZ  r[  )r   rù   r=  r>  rO  r\  s    `    r   Úrecord_createdrl  ­  s~   ø€ ð1ð 1ð 1ð 1ð 1ð 1õ �J Ñ'Ô'€EÝ�%�ÑÔð 
ÝØØØØØ!ð	
ñ 	
ô 	
ð 	
ð 	
ð 	
ð
ð 
r    c                ó€   — dd„}t          | |¦  «        }t          |t          ¦  «        rt          | d|¬¦  «         dS dS )	zBRecord a successful Skills Hub install without exporting its name.r  r\   r   c                ó>   — d| d<   t           | d<   d | d<   d| d         iS )Nrƒ   r÷   r  r  )r  rN  s    r   rO  z record_installed.<locals>._applyË  s/   € Ø'ˆˆLÑÝ#ˆˆG‰Ø!ˆˆMÑØ˜c ,Ô/Ð0Ð0r    rƒ   rú   NrZ  r[  )r   rO  r\  s      r   Úrecord_installedro  É  sa   € ð1ð 1ð 1ð 1õ �J Ñ'Ô'€EÝ�%�ÑÔð EÝ˜j¨+¸eÐDÑDÔDÐDÐDÐDðEð Er    c                ó2   — d	d„}t          | |d¬¦  «         dS )
zÜOpt a skill created by skill_manage into curator management.

    Viewing or invoking a manually authored skill may still create telemetry,
    but only this explicit marker makes it eligible for automatic curation.
    r  r\   r   r®   c                ó   — d| d<   d S rh  r#   rN  s    r   rO  z"mark_agent_created.<locals>._applyÜ  s   € Ø#ˆˆLÑÐÐr    Tr*  NrP  rQ  rR  s     r   r  r  Ö  s1   € ð$ð $ð $ð $åˆJ˜¸$Ð?Ñ?Ô?Ð?Ð?Ð?r    r  c                ó¦  ‡— ‰t           vrt                               d‰| ¦  «         dS dˆfd„}t          | |d¬¦  «        }t	          |t
          ¦  «        r|                     d	¦  «        sdS t          d
t          di                     ‰¦  «        }‰t          k    r |                     d¦  «        t          k    rd}|�t          | ||¬¦  «         dS dS )zŒSet lifecycle state. No-op if *state* is invalid or the skill isn't
    curator-manageable (hub skills, or built-ins with pruning disabled).z"set_state: invalid state %r for %sNr  r\   r   c                ó   •— |                       d¦  «        }|‰k    rd|                       d¦  «        dœS ‰| d<   ‰t          k    rt          ¦   «         | d<   n‰t          k    rd | d<   d|                       d¦  «        |dœS )Nr  Fr÷   )Úchangedr÷   r  T)rt  r÷   Úprevious_state)rb   ÚSTATE_ARCHIVEDrP   r  )r  ru  r  s     €r   rO  zset_state.<locals>._applyç  s—   ø€ ØŸš Ñ)Ô)ˆØ˜UÒ"Ð"Ø$°C·G²G¸LÑ4IÔ4IÐJÐJÐJØˆˆG‰Ø•NÒ"Ð"Ý!)¡¤ˆC�ÑÐØ•lÒ"Ð"Ø!%ˆC�ÑàØŸ'š' ,Ñ/Ô/Ø,ð
ð 
ð 	
r    Tr*  rt  r   r   ru  Úrestoredrú   rZ  )Ú_VALID_STATESrx   ry   r/  rŽ   r�   rb   rv  ÚSTATE_STALEr  rJ  )r   r  rO  r\  rA  s    `   r   Ú	set_staterz  á  sý   ø€ ð •MÐ!Ð!Ý�ŠÐ9¸5À*ÑMÔMÐMØˆð
ð 
ð 
ð 
ð 
ð 
õ �J À$ÐGÑGÔG€EÝ�e�TÑ"Ô"ð ¨%¯)ª)°IÑ*>Ô*>ð Øˆå˜
Ý�Wð÷ 
‚cˆ%�j„jð ð •ÒÐ §¢Ð+;Ñ!<Ô!<ÅÒ!NÐ!NØˆØÐÝ˜j¨&¸Ð?Ñ?Ô?Ð?Ð?Ð?ð Ðr    r  c                ó8   ‡— dˆfd„}t          | |d¬¦  «         d S )	Nr  r\   r   r®   c                ó,   •— t          ‰¦  «        | d<   d S )Nr  ©r   )r  r  s    €r   rO  zset_pinned.<locals>._apply  s   ø€ Ý˜V™œˆˆH‰ˆˆr    Tr*  rP  rQ  )r   r  rO  s    ` r   Ú
set_pinnedr~    s<   ø€ ð%ð %ð %ð %ð %ð %åˆJ˜¸$Ð?Ñ?Ô?Ð?Ð?Ð?r    Úsyncc                ó8   ‡— d	ˆfd„}t          | |d¬¦  «         dS )
aÎ  Set the sync opt-in flag on a skill's usage record.

    Sync is OPT-IN: nothing propagates to the sync plane unless the user marks
    a skill with ``sync: true`` here. Sits alongside ``pinned``/``created_by``
    on the ``.usage.json`` sidecar and is read by
    ``tools.skills_sync_client.list_synced_skill_names``. Gated on curation
    eligibility so bundled/hub/external skills (which never sync) can't be
    marked. Provisional per the M1-D default.
    r  r\   r   r®   c                ó,   •— t          ‰¦  «        | d<   d S )Nr  r}  )r  r  s    €r   rO  zset_sync.<locals>._apply  s   ø€ Ý˜4‘j”jˆˆF‰ˆˆr    Tr*  NrP  rQ  )r   r  rO  s    ` r   Úset_syncr‚  	  s<   ø€ ð!ð !ð !ð !ð !ð !åˆJ˜¸$Ð?Ñ?Ô?Ð?Ð?Ð?r    c                óJ   — t          | ¦  «                             d¦  «        du S )zBWhether a skill is opted into sync (``sync: true`` in its record).r  T)r&  rb   r   s    r   Úis_sync_enabledr„    s#   € å�jÑ!Ô!×%Ò% fÑ-Ô-°Ð5Ð5r    c                ó  — | sdS 	 t          ¦   «         5  t          ¦   «         }| |v r|| = t          |¦  «         ddd¦  «         dS # 1 swxY w Y   dS # t          $ r)}t                               d| |d¬¦  «         Y d}~dS d}~ww xY w)zFDrop a skill's usage entry entirely. Called when the skill is deleted.Nz!skill_usage.forget(%s) failed: %sTr¸   )rH   rÐ   r$  r£   rx   ry   r(  s      r   Úforgetr†    s  € àð ØˆðXÝÑÔð 	!ð 	!Ý‘<”<ˆDØ˜TÐ!Ð!Ø˜Ð$Ý˜4Ñ Ô Ð ð		!ð 	!ð 	!ñ 	!ô 	!ð 	!ð 	!ð 	!ð 	!ð 	!ð 	!ð 	!øøøð 	!ð 	!ð 	!ð 	!ð 	!ð 	!øõ
 ð Xð Xð XÝ�ŠÐ8¸*ÀaÐRVˆÑWÔWÐWÐWÐWÐWÐWÐWÐWøøøøðXøøøs9   †A ”%A¹A ÁA
Á
A ÁA
ÁA Á
BÁBÂBc                óø  — t          | ¦  «        }|€ t          | ¦  «        �dt          | ¦  «        fS t          | |¦  «        s6t	          | ¦  «        rdd| › d�fS t          | ¦  «        rdd| › d�fS dd| › d�fS |}|€dd| › d�fS t          |¦  «        rdt          | ¦  «        fS t          ¦   «         }	 |                     dd¬	¦  «         n# t          $ r}dd
|› �fcY d}~S d}~ww xY w||j
        z  }|                     ¦   «         r>||j
        › dt          j        t          j        ¦  «                             d¦  «        › �z  }	 |                     |¦  «         nf# t          $ rY ddl}	 |                     t)          |¦  «        t)          |¦  «        ¦  «         n # t*          $ r}dd|› �fcY d}~cY S d}~ww xY wY nw xY wt-          | ¦  «        rt/          | ¦  «         t1          | t2          ¦  «         dd|› �fS )as  Move a curator-eligible skill directory to ~/.hermes/skills/.archive/.

    Returns (ok, message). Never archives hub-installed skills. Bundled
    built-ins are only archivable when ``curator.prune_builtins`` is enabled;
    when one is archived, its name is added to the suppression list so the
    update-time re-seeder leaves it archived instead of restoring it.
    NFrï   zY' is a protected built-in; it backs load-bearing UX and is never archived or consolidatedz!' is hub-installed; never archivezJ' is a bundled built-in; enable curator.prune_builtins to allow pruning itr  Tr)   zfailed to create archive dir: Ú-z%Y%m%d%H%M%Sr   zfailed to archive: zarchived to )ræ   rç   rð   rõ   r   rë   r   rJ   r3   rB   r}   r6   r   rM   r   rN   ÚstrftimeÚrenameÚshutilÚmover   r£   rí   rÊ   rz  rv  )r   Úlocal_skill_dirrš   rß   r~   Údestr‹  Úe2s           r   Úarchive_skillr�  /  sÓ  € õ & jÑ1Ô1€OØÐÕ#;¸JÑ#GÔ#GÐ#SØÕ1°*Ñ=Ô=Ð=Ð=å 
¨OÑ<Ô<ð 
Ý 
Ñ+Ô+ð 	ØðH˜*ð Hð Hð Hðð õ ˜JÑ'Ô'ð 	RØÐQ JÐQÐQÐQÐQÐQØð9�jð 9ð 9ð 9ð
ð 	
ð
  €IØÐØÐ7 
Ð7Ð7Ð7Ð7Ð7Ý˜iÑ(Ô(ð >ØÕ1°*Ñ=Ô=Ð=Ð=å‘>”>€Lð;Ø×Ò 4°$ÐÑ7Ô7Ð7Ð7øÝð ;ð ;ð ;ØÐ:°qÐ:Ð:Ð:Ð:Ð:Ð:Ð:Ð:Ð:øøøøð;øøøð
 ˜)œ.Ñ(€DØ‡{‚{�}„}ð hØ ¤ÐgÐgµ(´,½x¼|Ñ2LÔ2L×2UÒ2UÐVdÑ2eÔ2eÐgÐgÑgˆð5Ø×Ò˜ÑÔÐÐøÝð 5ð 5ð 5àˆˆˆð	5Ø�KŠK�˜I™œ­¨D©	¬	Ñ2Ô2Ð2Ð2øÝð 	5ð 	5ð 	5ØÐ4°Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4Ð4øøøøð	5øøøð 3Ð2ð	5øøøõ �*ÑÔð (Ý˜JÑ'Ô'Ð'åˆj�.Ñ)Ô)Ð)ØÐ& Ð&Ð&Ð&Ð&s`   Â3C Ã
C&ÃC!ÃC&Ã!C&ÅE ÅF?Å+0FÆF?Æ
F9Æ&F4Æ,F9Æ-F?Æ4F9Æ9F?Æ>F?c                óB  ‡ ‡— t          ‰ ¦  «        rdd‰ › d�fS t          ‰ ¦  «        rt          ¦   «         sdd‰ › d�fS t          ¦   «         }|                     ¦   «         sdS ˆ fd„|                     d¦  «        D ¦   «         }|s5‰ › d�Št          ˆfd	„|                     d¦  «        D ¦   «         d
¬¦  «        }|sdd‰ › d�fS |d         }t          ¦   «         ‰ z  }|                     ¦   «         rdd|› �fS 	 |                     |¦  «         nf# t          $ rY ddl
}	 |                     t          |¦  «        t          |¦  «        ¦  «         n # t          $ r}dd|› �fcY d}~cY S d}~ww xY wY nw xY wt          ‰ ¦  «         t          ‰ t           ¦  «         d
d|› �fS )u<  Move an archived skill back to ~/.hermes/skills/. Restores to the flat
    top-level layout; original category nesting is NOT reconstructed.

    Refuses to restore under a name that now collides with a hub-installed
    skill â€” that would shadow the upstream version. Also refuses to restore
    over a bundled built-in UNLESS ``curator.prune_builtins`` is enabled (in
    which case built-ins are curator-managed and restoring is the documented
    way to lift a prune). Restoring clears any suppression entry so future
    updates may re-seed the built-in again.
    Frï   zA' is now hub-installed; restore would shadow the upstream versionz;' is now bundled; restore would shadow the upstream version)Fzno archive directoryc                óR   •— g | ]#}|                      ¦   «         ¯|j        ‰k    ¯!|‘Œ$S r#   rÛ   )r…   rÝ   r   s     €r   ú
<listcomp>z!restore_skill.<locals>.<listcomp>‹  s3   ø€ Ð\Ð\Ð\˜¸¿º¹
¼
Ð\ÀqÄvÐQ[ÒG[ÐG[�!ÐG[ÐG[ÐG[r    Ú*rˆ  c                ó  •— g | ]ˆ}|                      ¦   «         rr|j                             ‰¦  «        rXt          |j        ¦  «        t          ‰¦  «        z
  d k    ¯X|j        t          ‰¦  «        d…                              ¦   «         ¯†|‘Œ‰S )é   N)rÜ   r}   r«   ÚlenÚisdigit)r…   rÝ   rµ   s     €r   r“  z!restore_skill.<locals>.<listcomp>–  s”   ø€ ð ð ð ØØ—8’8‘:”:ðð ”F×%Ò% fÑ-Ô-ðõ ˜œ‘K”K¥# f¡+¤+Ñ-°Ò3Ð3Ø”F�3˜v™;œ;˜<˜<Ô(×0Ò0Ñ2Ô2ð 4ð ð 4Ð3Ð3r    T)Úreversez' not found in archiver   zdestination already exists: Nzfailed to restore: zrestored to )rë   rí   r¦   rJ   r6   rÑ   r»   r$   rŠ  rB   r‹  rŒ  r   r£   rÍ   rz  r  )r   rß   Ú
candidatesÚsrcrŽ  r‹  r~   rµ   s   `      @r   Úrestore_skillrœ  l  sw  øø€ õ ˜
Ñ#Ô#ð 
Øð8�jð 8ð 8ð 8ð
ð 	
õ �*ÑÔð 
Õ&=Ñ&?Ô&?ð 
Øð8�jð 8ð 8ð 8ð
ð 	
õ  ‘>”>€LØ×ÒÑ Ô ð -Ø,Ð,ð
 ]Ð\Ð\Ð\˜\×/Ò/°Ñ4Ô4Ð\Ñ\Ô\€JØð 
ð Ð!Ð!Ð!ˆÝðð ð ð Ø'×-Ò-¨cÑ2Ô2ðñ ô ð ð	
ñ 	
ô 	
ˆ
ð ð CØÐB 
ÐBÐBÐBÐBÐBà
�QŒ-€CÝ‰=Œ=˜:Ñ%€DØ‡{‚{�}„}ð <ØÐ;°TÐ;Ð;Ð;Ð;ð4Ø�
Š
�4ÑÔÐÐøÝð 4ð 4ð 4Øˆˆˆð	4Ø�KŠK�˜C™œ¥# d¡)¤)Ñ,Ô,Ð,Ð,øÝð 	4ð 	4ð 	4ØÐ3°Ð3Ð3Ð3Ð3Ð3Ð3Ð3Ð3Ð3Ð3Ð3øøøøð	4øøøð -Ð,ð4øøøõ ˜:Ñ&Ô&Ð&åˆj�,Ñ'Ô'Ð'ØÐ& Ð&Ð&Ð&Ð&sB   Ã:D ÄE3Ä0EÅE3Å
E-ÅE(Å E-Å!E3Å(E-Å-E3Å2E3c                óè   — t          ¦   «         }|                     ¦   «         sdS ddlm}  ||d¦  «        D ]:}t	          |¦  «        rŒt          ||j        j        ¬¦  «        | k    r	|j        c S Œ;dS )aW  Locate the directory for a skill by its frontmatter `name:` field.

    Handles both flat (~/.hermes/skills/<skill>/SKILL.md) and category-nested
    (~/.hermes/skills/<category>/<skill>/SKILL.md) layouts. Uses the gated
    index iterator so M2 org mirrors resolve ONLY for the active org
    (stale ``_org/<other>/`` trees never match).
    Nr   )Úiter_skill_index_filesr‰   rŠ   )r$   r6   Úagent.skill_utilsrž  r   r•   r2   r}   )r   rÔ   rž  rœ   s       r   ræ   ræ   ·  s™   € õ ‰=Œ=€DØ�;Š;‰=Œ=ð ØˆtØ8Ð8Ð8Ð8Ð8Ð8à*Ð*¨4°Ñ<Ô<ð #ð #ˆÝ! (Ñ+Ô+ð 	ØÝ˜H¨x¬Ô/CÐDÑDÔDÈ
ÒRÐRØ”?Ð"Ð"Ð"ð Sàˆ4r    c                ó
  — ddl m}  |¦   «         dd…         D ]i}|                     ¦   «         sŒ|                     d¦  «        D ]<}t	          |¦  «        rŒt          ||j        j        ¬¦  «        | k    r|j        c c S Œ=ŒjdS )zBLocate a skill under configured external dirs by frontmatter name.r   )Úget_all_skills_dirsr0   Nr‰   rŠ   )rŸ  r¡  r6   rÑ   r   r•   r2   r}   )r   r¡  rÔ   rœ   s       r   rç   rç   Ì  s¹   € à5Ð5Ð5Ð5Ð5Ð5à#Ð#Ñ%Ô% a b bÔ)ð 'ð 'ˆØ�{Š{‰}Œ}ð 	ØØŸ
š
 :Ñ.Ô.ð 	'ð 	'ˆHÝ% hÑ/Ô/ð ØÝ °8´?Ô3GÐHÑHÔHÈJÒVÐVØ”Ð&Ð&Ð&Ð&Ð&ð Wð	'ð
 ˆ4r    c                 ó  — t          ¦   «         } g }t          ¦   «         D ]ä}|                      |¦  «        }t          |t          ¦  «        }t          |t          ¦  «        r|nt          ¦   «         }t          ¦   «         }|                     ¦   «         D ]\  }}|                     ||¦  «         Œd|i|¥d|i¥}	t          |	¦  «        |	d<   t          |	¦  «        |	d<   t          |¦  «        |	d<   |                     |	¦  «         Œå|S )aÀ  Return a list of {name, provenance, state, pinned, last_activity_at, ...}
    records for every curator-managed skill. Missing usage records are
    backfilled with defaults so callers can always index fields.

    ``provenance`` is 'agent', 'bundled', or 'hub' (see :func:`provenance`).
    Bundled skills are only included when ``curator.prune_builtins`` is enabled.
    Hub-installed skills are never included.

    Each row carries ``_persisted``: True when a real record exists in
    ``.usage.json``, False when the row is a fresh backfill (e.g. a built-in
    seen for the first time). The curator uses this to seed the inactivity
    clock instead of treating an unrecorded skill as ancient.
    r}   Ú
_persistedr  ro   rH  )rÐ   rØ   rb   rŽ   r�   r  r  r  rh   ro   rH  rÒ   )
r—   r  r}   rf   Ú	persistedr  rÔ   r†   r	  r
  s
             r   Úcurated_reportr¥  ß  s  € õ ‰<Œ<€DØ!#€DÝ.Ñ0Ô0ð ð ˆØ�hŠh�t‰nŒnˆÝ˜s¥DÑ)Ô)ˆ	Ý%/°µTÑ%:Ô%:ÐO˜c˜cÅÁÄˆÝ‰ŒˆØ—J’J‘L”Lð 	!ð 	!‰DˆAˆqØ�NŠN˜1˜aÑ Ô Ð Ð Ø�tÐ<˜sÐ< L°)Ð<Ð<ˆÝ"4°SÑ"9Ô"9ˆÐÑÝ .¨sÑ 3Ô 3ˆÐÑÝ& tÑ,Ô,ˆˆLÑØ�Š�CÑÔÐÐØ€Kr    c                 ó   — t          ¦   «         S )uW  DEPRECATED â€” use :func:`curated_report` instead.

    Used to return everything :func:`curated_report` returns (including bundled
    skills when ``curator.prune_builtins`` is enabled), which made the
    "agent-created" name misleading. Kept as a compatibility alias for
    external callers; new code should call ``curated_report()``.
    )r¥  r#   r    r   Úagent_created_reportr§  þ  s   € õ ÑÔÐr    c                óJ   — t          | ¦  «        rdS t          | ¦  «        rdS dS )uÔ   Classify a skill's origin: 'hub', 'bundled', or 'agent'.

    'agent' covers both agent-authored and local manually-authored skills â€”
    anything not seeded from the bundled repo or installed via the hub.
    rÕ   rÖ   rø   )rë   rí   r   s    r   rH  rH  	  s3   € õ ˜
Ñ#Ô#ð ØˆuÝ�*ÑÔð ØˆyØˆ7r    c                 ó$  — t          ¦   «         } |                      ¦   «         sg S t          ¦   «         }g }t          ¦   «         }|                      d¦  «        D �]&}t          |¦  «        rŒt          ||j        j        ¬¦  «        }||v rŒ3| 	                    |¦  «         | 
                    |¦  «        }t          |t          ¦  «        }t          |t          ¦  «        r|nt          ¦   «         }t          ¦   «         }	|	                     ¦   «         D ]\  }
}|                     |
|¦  «         Œd|i|¥t!          |¦  «        |dœ¥}t#          |¦  «        |d<   t%          |¦  «        |d<   |                     |¦  «         �Œ(t)          |d„ ¬¦  «        S )	uâ  Return usage telemetry for EVERY skill on disk, with provenance.

    Unlike ``curated_report()`` (which is scoped to curator-managed
    candidates), this surfaces all skills â€” bundled built-ins and
    hub-installed included â€” so callers can answer "how often is this skill
    used" independent of whether it's ever curated. Rows carry a
    ``provenance`` field ('agent' | 'bundled' | 'hub') and ``_persisted``
    (whether a real ``.usage.json`` record backs the row).
    r‰   rŠ   r}   )rH  r£  r  ro   c                ó   — | d         S )Nr}   r#   )Úrs    r   ú<lambda>zusage_report.<locals>.<lambda><  s
   €  a¨¤i€ r    )re   )r$   r6   rÐ   rr   rÑ   r   r•   r2   r}   rw   rb   rŽ   r�   r  r  r  rH  rh   ro   rÒ   r»   )rÔ   r—   r  Úseenrœ   r}   rf   r¤  r  Úbase_recr†   r	  r
  s                r   Úusage_reportr¯    s—  € õ ‰=Œ=€DØ�;Š;‰=Œ=ð Øˆ	Ý‰<Œ<€DØ!#€DÝ‘”€DØ—J’J˜zÑ*Ô*ð ñ ˆÝ! (Ñ+Ô+ð 	ØÝ °8´?Ô3GÐHÑHÔHˆØ�4ˆ<ˆ<ØØ�Š�‰ŒˆØ�hŠh�t‰nŒnˆÝ˜s¥DÑ)Ô)ˆ	Ý%/°µTÑ%:Ô%:ÐO˜c˜cÅÁÄˆÝ ‘?”?ˆØ—N’NÑ$Ô$ð 	!ð 	!‰DˆAˆqØ�NŠN˜1˜aÑ Ô Ð Ð à�Dð
àð
õ % TÑ*Ô*Ø#ð	
ð 
ð 
ˆõ #5°SÑ"9Ô"9ˆÐÑÝ .¨sÑ 3Ô 3ˆÐÑØ�Š�CÑÔÐÑÝ�$Ð/Ð/Ð0Ñ0Ô0Ð0r    )r   r   r   r   )r   r   )r   r   )rQ   r   r   rR   )r[   r\   r   r]   )r[   r\   r   ri   )r   r   )r   r   )r{   r   r   r®   )r   r   r   r®   )r   rÎ   )rœ   r   r‹   r   r   r   )r   r   r   r   rL   )r   r   rñ   rò   r   r   )r[   r   r   r   )r   rÿ   )r   r   r   r  )r   r\   )r   r  )r—   r  r   r   )r   r   r   r\   )r   r   r+  r   r   r   )rQ   r   r   ri   )r   r   r[   r3  r   r   )r   r   rA  r   r[   r3  r=  r]   r>  r]   rk   rB  r?  rC  r@  rC  r   r®   )r   r   r=  r]   r>  r]   r   r®   )
r   r   rA  r   r=  r]   r>  r]   r   r®   )
r   r   rù   r   r=  r]   r>  r]   r   r®   )r   r   r  r   r   r®   )r   r   r  r   r   r®   )r   r   r  r   r   r®   )r   r   r   rò   )_Ú__doc__Ú
__future__r   rŒ   Úloggingr¾   r¼   Ú
contextlibr   r   r   Úpathlibr   Útypingr   r	   r
   r   r   r   Úhermes_constantsr   rŸ  r   r   Ú	getLoggerÚ__name__rx   r5   r4   ÚImportErrorr  ry  rv  rx  r   Ú__annotations__r   r$   r'   rH   rJ   rP   rZ   rh   ro   r   r�   r¦   r¨   r­   rÇ   rÊ   rÍ   rØ   rà   r•   ré   rë   rí   rð   rõ   rÓ   rü   rþ   r  r  r  rÐ   r$  r&  r)  r/  r2  r;  rJ  rS  r]  re  rl  ro  r  rz  r~  r‚  r„  r†  r�  rœ  ræ   rç   r¥  r§  rH  r¯  r#   r    r   ú<module>r»     së  ððð ð ð0 #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø €€€Ø %Ð %Ð %Ð %Ð %Ð %Ø 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ø Ð Ð Ð Ð Ð Ø 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8Ð 8à ,Ð ,Ð ,Ð ,Ð ,Ð ,Ø LÐ LÐ LÐ LÐ LÐ LÐ LÐ Là	ˆÔ	˜8Ñ	$Ô	$€ð 
€ðØ€L€L€L€LøØð ð ð Ø€EðØˆˆˆˆøØð ð ð Øˆðøøøøøð	øøøð €Ø€Ø€Ø˜{¨NÐ;€ð ð&Ð ð ð ð ñ ð
2ð 2ð 2ð 2ð(ð (ð (ð (ð)ð )ð )ð )ð ð ð  ñ „ð ðF&ð &ð &ð &ð2ð 2ð 2ð 2ð
ð 
ð 
ð 
ðð ð ð ð(ð ð ð ðð ð ð ð.+ð +ð +ð +ð\ð ð ð ð*1ð 1ð 1ð 1ðð ð ð ð*Wð Wð Wð Wð,'ð 'ð 'ð 'ð'ð 'ð 'ð 'ð4ð 4ð 4ð 4ðn
Jð 
Jð 
Jð 
Jðð ð ð ð*ð ð ð ð5ð 5ð 5ð 5ð
8ð 8ð 8ð 8ð
ð ð ð ðð ð ð ð ð<Vð Vð Vð Vð.Dð Dð Dð Dð2ð 2ð 2ð 2ðjð ð ð ð2)Cð )Cð )Cð )Cð`ð ð ð ð$ð ð ð ð(ð ð ð ð4
ð 
ð 
ð 
ðhð hð hð hð, LQð ð ð ð ð ð ð>ð ð ð ð (,ðð ð ð ð ð@ (,Ø!Ø $Ø#Ø!Ø(,ð"
ð "
ð "
ð "
ð "
ð "
ðR	 ð 	 ð 	 ð 	 ð "Ø $ð	,
ð ,
ð ,
ð ,
ð ,
ð ,
ðd Ø!Ø $ð
ð 
ð 
ð 
ð 
ð 
ðD "Ø $ð
ð 
ð 
ð 
ð 
ð 
ð8
Eð 
Eð 
Eð 
Eð@ð @ð @ð @ð@ð @ð @ð @ðD@ð @ð @ð @ð@ð @ð @ð @ð6ð 6ð 6ð 6ð
Xð Xð Xð Xð$:'ð :'ð :'ð :'ðzH'ð H'ð H'ð H'ðVð ð ð ð*ð ð ð ð&ð ð ð ð>ð ð ð ð
ð 
ð 
ð 
ð&1ð &1ð &1ð &1ð &1ð &1s6   ÁA$ Á$A?Á,A1Á0A?Á1A9Á6A?Á8A9Á9A?Á>A?