Ë
    âß²j„æ ã                  ó   — 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Zddl	Z	ddl
Z
ddlZddlZddlZddlZddlZddlm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mZm Z m!Z!m"Z"m#Z# dd	l$m%Z%m&Z&m'Z' dd
l(m)Z) ddl*m+Z+ ddl,m-Z- ddl.m/Z/ ddl0m1Z1 ddl2m3Z3m4Z4 ddl5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z> ddl?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZG ddlHmIZImJZJmKZKmLZLmMZMmNZNmOZOmPZP ddlQmRZRmSZSmTZTmUZUmVZVmWZWmXZXmYZYmZZZm[Z[m\Z\m]Z]m^Z^m_Z_m`Z`maZambZbmcZcmdZd ddlemfZfmgZg ddlhmiZimjZjmkZkmlZlmmZmmnZnmoZo d¶d„Zp G d„ deq«      Zr e	jæ                  et«      Zu e+d«      avdawd·d¸d„Zx ex«        h d£Zydezd<   dhZ{dezd <   e+Z| e}«       Z~e G d!„ d"«      «       Z G d#„ d$«      Z€d%d&d'd(d)d*d+d,ifd-d.d/d0d1d2i fd3d4d5d6d7d8i fd9d:d;d<d=d>i fd?d@dAdBdCdDdEdFdGœfdHdIdJdKdLdMddNdOdPœfdQdRdSdTdUdVdWdEifdXdYdZd[d\d]dWdEiffZ�d^ezd_<   d`„ da„ ddbœZ‚dcezdd<   de„ Zƒe�D ]  Z„ e…e€e„d    eƒe„Ž «       Œ [„df„ Z† e‡ eˆe€«      �j                  «       «      D ]5  \  ZŠZ‹ eŒe‹«      sŒeŠ�j                  dg«      seŠdhv sŒ& e…e€eŠ e†e‹«      «       Œ7 [Š[‹d¹di„ZŽ G dj„ dkeIe_ef«      Z�da�dlezdm<   i Z‘dnezdo<    e�j$                  «       Z“d¶dp„Z”dºdq„Z•d»dr„Z–d¼ds„Z—d½dt„Z˜d·d¸du„Z™dašdvezdw<    e�j6                  «       Zœd¼dx„Z�d¾d¿dz„Zžd¶d{„ZŸd¼d|„Z dÀd}„Z¡dÁd~„Z¢dÁd„Z£d»d€„Z¤dÂd�„Z¥dÂd‚„Z¦dÃdƒ„Z§dÄd„„Z¨dÅd…„Z©dÆd†„ZªdÇd‡„Z«dddˆœ	 	 	 	 	 	 	 	 	 	 	 	 	 dÈd‰„Z¬ e�jZ                  «       Z® edŠ¬‹«       G dŒ„ d�«      «       Z¯	 dÉ	 	 	 	 	 dÊdŽ„Z°d¼d�„Z±	 	 	 dË	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dÌd‘„Z²	 	 	 	 	 	 	 	 dÍd’„Z³	 	 	 	 	 	 	 	 dÎd“„Z´	 	 	 	 	 	 	 	 dÎd”„Zµd�d�d�d•œ	 	 	 	 	 	 	 	 	 	 	 dÏd–„Z¶	 	 	 	 	 	 	 	 dÐd—„Z·d�d�d�ddd�dd˜œ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dÑd™„Z¸d�d�dd�d�d�ddddddšœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dÒd›„Z¹d·dÓdœ„Zºd�„ Z»dÔdž„Z¼dyZ½dÕdŸ„Z¾dÖd „Z¿d×d¡„ZÀdØd¢„ZÁdd£lmÂZÂ dd¤lmÃ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§„ZÈ	 dÚ	 	 	 dÛd¨„ZÉd©dªd«d¬d­d®d¯d°d±d²d³d´œZÊdµ„ ZËy)ÜuŠ  Hermes Plugin System â€” discovers, loads, and manages plugins.

Sources, later overriding earlier on key collision: bundled ``<repo>/plugins/<name>/`` (``memory/``
and ``context_engine/`` have their own discovery), user ``~/.hermes/plugins/<name>/``, project
``./.hermes/plugins/<name>/`` (opt-in via ``HERMES_ENABLE_PROJECT_PLUGINS``), and pip packages in
the ``hermes_agent.plugins`` entry-point group. A directory plugin needs a ``plugin.yaml`` manifest
and an ``__init__.py`` exposing ``register(ctx)``. Plugins register callbacks for ``VALID_HOOKS``
(core fires ``invoke_hook(name, **kwargs)``) and tools via ``PluginContext.register_tool()``.
é    )ÚannotationsN)Úsuppress)Ú	dataclassÚfield)Úcached_propertyÚwraps)ÚPath)	ÚAnyÚCallableÚDictÚListÚMappingÚOptionalÚSetÚTupleÚUnion)Úget_hermes_homeÚget_process_hermes_homeÚhermes_home_key)Úreplacement_coordinator)Úenv_var_enabled)Úload_config_readonly)ÚVALID_MIDDLEWARE)Úplugin_capability_granted)ÚRELAY_PLUGINS_CONFIG_ENVÚlegacy_relay_plugin_keys)	Ú_CONFIG_SCHEMA_TYPESÚSUPPORTED_MANIFEST_VERSIONÚPluginManifestÚ_portable_skill_namespaceÚmanifest_keyÚparse_manifest_fileÚresolve_module_originÚresolve_plugin_load_orderÚvalidate_config_schema)ÚENTRY_POINTS_GROUPÚ_get_disabled_pluginsÚ_get_enabled_pluginsÚcollect_directory_manifestsÚdiscover_entrypoint_manifestsÚgate_manifestÚresolve_manifest_winnersÚscan_directory)ÚPluginLoaderMixinÚ_BARE_MODULE_SCOPEÚ_MODULE_NAMESPACE_LOCKÚ
_NS_PARENTÚ_evict_modulesÚ_plugin_home_scopeÚ_serialized_replacementÚin_plugin_load_worker)Ú'DEFAULT_SYSTEM_PROMPT_SECTION_MAX_CHARSÚHERMES_EVENT_NAMESPACEÚMAX_SYSTEM_PROMPT_SECTION_CHARSÚ&MAX_SYSTEM_PROMPT_SECTIONS_TOTAL_CHARSÚPLUGIN_SECTIONS_ENDÚPLUGIN_SECTIONS_STARTÚSYSTEM_PROMPT_SECTION_POSITIONSÚ_EVENT_EMIT_DEPTH_CAPÚ_EVENT_PENDING_CAPÚ_HOOK_CALLBACK_TIMEOUT_SECSÚ!_HOOK_TIMEOUT_SUPPRESSION_SECONDSÚ_MAX_HOOK_CALLBACK_TIMEOUT_SECSÚ$_PRE_TOOL_CALL_TIMEOUT_BLOCK_MESSAGEÚPluginDispatchMixinÚPluginSystemPromptSectionÚ!RenderedPluginSystemPromptSectionÚ_EventSubscriptionÚformat_system_prompt_sectionsÚ!is_valid_system_prompt_section_id)ÚPluginLedgerMixinÚPluginRegistration)ÚPluginStateÚ_locked_plugin_stateÚ_nested_plugin_mappingÚ_nested_plugin_valueÚ_plugin_relative_segmentsÚ_plugin_settings_entryÚsave_plugin_settingc                 ó®   — t        j                  d«      } | rt        | «      S t        t        «      j	                  «       j
                  j
                  dz  S )z�Bundled ``plugins/`` dir: ``HERMES_BUNDLED_PLUGINS`` (Nix wrapper / packaged installs, read-only
    store paths) first, else the in-repo path.ÚHERMES_BUNDLED_PLUGINSÚplugins)ÚosÚgetenvr	   Ú__file__ÚresolveÚparent)Úenv_overrides    ú7/home/ubuntu/.hermes/hermes-agent/hermes_cli/plugins.pyÚget_bundled_plugins_dirr\   D   sE   € ô —9‘9Ð5Ó6€LÙÜ�LÓ!Ð!Ü”‹>×!Ñ!Ó#×*Ñ*×1Ñ1°IÑ=Ð=ó    c                  ó   — e Zd ZdZy)ÚPluginToolOverrideErrorz^Plugin tried to override a built-in tool without ``plugins.entries.<id>.allow_tool_override``.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r]   r[   r_   r_   M   s   „ Úhr]   r_   ÚHERMES_PLUGINS_DEBUGFc                ó¸  — | rt        d«      at        rt        ryt        j                  t
        j                  «      }|j                  t        j                  «       |j                  t        j                  d«      «       t        j                  |«       t        j                  t        j                  «       dt        _        dat        j                  d«       y)zWWhen HERMES_PLUGINS_DEBUG is on, tee plugin logs to stderr at DEBUG (once per process).re   Nz#[plugins] %(levelname)s %(message)sTuC   HERMES_PLUGINS_DEBUG=1 â€” verbose plugin discovery logging enabled)r   Ú_PLUGINS_DEBUGÚ_DEBUG_HANDLER_INSTALLEDÚloggingÚStreamHandlerÚsysÚstderrÚsetLevelÚDEBUGÚsetFormatterÚ	FormatterÚloggerÚ
addHandlerÚ	propagateÚdebug)ÚforceÚhandlers     r[   Ú_install_plugin_debug_handlerrw   Y   s”   € ñ Ü(Ð)?Ó@ˆÝÕ5ØÜ×#Ñ#¤C§J¡JÓ/€GØ×Ñ”W—]‘]Ô#Ø×Ñœ×*Ñ*Ð+PÓQÔRÜ
×Ñ�gÔÜ
‡O�O”G—M‘MÔ"Ø„FÔØ#ÐÜ
‡L�LÐVÕWr]   >)   Ú
pre_verifyÚpre_commandÚpre_llm_callÚon_stream_endÚpost_llm_callÚpre_tool_callÚsubagent_stopÚon_session_endÚpost_tool_callÚsubagent_startÚon_stream_deltaÚon_stream_startÚpre_api_requestÚon_session_resetÚon_session_startÚpost_api_requestÚapi_request_errorÚpre_transcriptionÚagent_loop_stoppedÚon_interim_messageÚon_skill_lifecycleÚpre_auxiliary_callÚkanban_task_blockedÚkanban_task_claimedÚon_session_finalizeÚpost_auxiliary_callÚpre_approval_requestÚpre_gateway_dispatchÚtransform_llm_outputÚkanban_task_completedÚtransform_tool_resultÚgateway_platform_eventÚon_kanban_task_updatedÚpost_approval_responseÚon_kanban_dispatch_tickÚon_kanban_worker_exitedÚon_room_member_activityÚon_kanban_worker_spawnedÚtransform_terminal_outputÚon_kanban_worker_stale_claimÚ"transform_api_error_classificationúSet[str]ÚVALID_HOOKSr    ÚSHELL_UNSUPPORTED_HOOKSc                  óÄ   — e Zd ZU dZded<   dZded<    ee¬«      Zded	<    ee¬«      Z	ded
<    ee¬«      Z
ded<    ee¬«      Zded<   dZded<   dZded<   dZded<   y)ÚLoadedPluginz)Runtime state for a single loaded plugin.r   ÚmanifestNzOptional[types.ModuleType]Úmodule)Údefault_factoryú	List[str]Útools_registeredÚhooks_registeredÚmiddleware_registeredÚcommands_registeredFÚboolÚenabledúOptional[str]ÚerrorÚdeferred)r`   ra   rb   rc   Ú__annotations__r§   r   Úlistrª   r«   r¬   r­   r¯   r±   r²   rd   r]   r[   r¥   r¥   Ö   st   … á3àÓØ)-€FÐ&Ó-Ù"'¸Ô"=Ð�iÓ=Ù"'¸Ô"=Ð�iÓ=Ù',¸TÔ'BÐ˜9ÓBÙ%*¸4Ô%@Ð˜Ó@Ø€GˆTÓØ€Eˆ=Óà€HˆdÔr]   r¥   c                  ó"  — e Zd ZdZdAd„ZdBd„ZedCd„«       ZdDd„ZdEd„Z	dFdGd„Z
dHd	„ZedId
„«       Zed„ «       ZdJdKd„ZdLd„Zddœ	 	 	 	 	 	 	 	 	 dMd„Z	 	 	 	 	 	 	 	 	 	 	 	 	 	 dNd„Zef	 	 	 	 	 	 	 	 	 	 	 dOd„Zedœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dPd„Zdd„ dddœ	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dQd„ZedRd„«       ZedRd„«       ZedCd„«       ZdSd„ZddœdTd„ZdUd„Ze	 	 dV	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dWd „«       ZdXd!„Z	 	 dY	 	 	 	 	 	 	 	 	 dZd"„Z d#Z!e"d[d$„«       Z#e$d\d%„«       Z%d]d&„Z&	 d^dd'œ	 	 	 	 	 	 	 d_d(„Z'd`d)„Z(e	 	 da	 	 	 	 	 	 	 	 	 	 	 dbd*„«       Z)e	 	 dc	 	 	 	 	 	 	 	 	 	 	 ddd+„«       Z*ded,„Z+edfd-„«       Z,dBd.„Z-dBd/„Z.edfd0„«       Z/e	 	 dg	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dhd1„«       Z0	 	 	 	 	 	 did2„Z1djd3„Z2dkd4„Z3edd5œ	 	 	 	 	 	 	 	 	 dld6„«       Z4dmd7„Z5dnd8„Z6dod9„Z7	 	 	 	 	 	 	 	 	 	 	 	 dpd:„Z8d;e9d<œ	 	 	 	 	 	 	 	 	 dqd=„Z:dFdrd>„Z;dsd?„Z<e	 	 dt	 	 	 	 	 	 	 	 	 dud@„«       Z=y)vÚPluginContextz=Facade given to plugins so they can register tools and hooks.c                ó<   — || _         || _        d | _        d| _        y )NF)r¦   Ú_managerÚ_llmÚ_load_abandoned)Úselfr¦   Úmanagers      r[   Ú__init__zPluginContext.__init__é   s!   € Ø ˆŒØˆŒØˆŒ	ð  %ˆÕr]   c                ó   — d| _         y)z_Mark this load as timed out; every later ``register_*``/``subscribe``/``on_unload`` is ignored.TN)rº   ©r»   s    r[   Ú_abandon_loadzPluginContext._abandon_loadñ   s
   € à#ˆÕr]   c                ó,   — t        | j                  «      S )zCReturn the effective registry id used for this plugin's namespaces.)r!   r¦   r¿   s    r[   Ú	plugin_idzPluginContext.plugin_idõ   s   € ô ˜DŸM™MÓ*Ð*r]   c                óp   ‡— t        ˆfd„| j                  j                  j                  «       D «       «      S )z¸Return True when another plugin is loaded and enabled (runtime probe for advisory
        ``requires_plugins``). Matches on registry key or manifest name.

        See #64165.
        c              3  ó€   •K  — | ]5  \  }}|j                   xr  |‰k(  xs |j                  j                  ‰k(  –— Œ7 y ­w©N)r¯   r¦   Úname)Ú.0ÚkeyÚloadedrÂ   s      €r[   ú	<genexpr>z+PluginContext.has_plugin.<locals>.<genexpr>   sB   øè ø€ ò 
á��Vð �N‰NÒV  yÑ 0Ò U°F·O±O×4HÑ4HÈIÑ4UÓVñ
ùs   ƒ;>)Úanyr¸   Ú_pluginsÚitems)r»   rÂ   s    `r[   Ú
has_pluginzPluginContext.has_pluginú   s2   ø€ ô ó 
à#Ÿ}™}×5Ñ5×;Ñ;Ó=ô
ó 
ð 	
r]   c                óx   — 	 t        |«      S # t        $ r# t        j                  d|| j                  «       ‚ w xY w)zGValidated plugin-relative settings path (warn + re-raise on rejection).z&Rejected config path %r from plugin %s)rO   Ú
ValueErrorrq   ÚwarningrÂ   )r»   rÈ   s     r[   Ú	_segmentszPluginContext._segments  s9   € ð	Ü,¨SÓ1Ð1øÜò 	Ü�N‰NÐCÀSÈ$Ï.É.ÔYØð	ús   ‚
 �,9Nc                óü   — | j                  |«      }t        t        «       xs i | j                  «      }|€|S t	        |j                  d«      |t        «      }|t        ur|S t	        |j                  d«      ||«      S )z–Read plugin-relative ``plugins.entries.<plugin_id>.settings.<key>`` (falls back to the
        legacy ``config`` subtree for migration compatibility).ÚsettingsÚconfig)rÒ   rP   r   rÂ   rN   ÚgetÚ_UNSET)r»   rÈ   ÚdefaultÚsegmentsÚentryÚvalues         r[   Ú
get_configzPluginContext.get_config  sq   € ð —>‘> #Ó&ˆÜ&Ô';Ó'=Ò'CÀÀTÇ^Á^ÓTˆØˆ=ØˆNÜ$ U§Y¡Y¨zÓ%:¸HÄfÓMˆØœÑØˆLÜ# E§I¡I¨hÓ$7¸À7ÓKÐKr]   c                óP   — t        | j                  | j                  |«      |«       y)zAAtomically write one value in this plugin's ``settings`` subtree.N)rQ   rÂ   rÒ   )r»   rÈ   rÛ   s      r[   Ú
set_configzPluginContext.set_config  s   € ä˜DŸN™N¨D¯N©N¸3Ó,?ÀÕGr]   c                óV   — t        | j                  | j                  j                  «      S )z7This plugin's profile-scoped durable JSON state facade.)rK   rÂ   r¦   Úskill_namespacer¿   s    r[   ÚstatezPluginContext.state  s   € ô ˜4Ÿ>™>¨4¯=©=×+HÑ+HÓIÐIr]   c                ó2   — ddl m}  || j                  «      S )uT  Capability-gated platform action facade (``add_reaction``, ``set_thread_title``). Every call
        re-checks ``gateway.platform_actions`` (legacy ``plugins.entries.<id>.allow_platform_actions``,
        default OFF) and returns ``{"ok": bool, ...}`` â€” verbs never raise into hook dispatch; no adapter
        handles or raw SDK objects.r   )ÚPlatformActions)Úhermes_cli.platform_actionsrã   rÂ   )r»   rã   s     r[   Úplatform_actionszPluginContext.platform_actions"  s   € õ 	@Ù˜tŸ~™~Ó.Ð.r]   Úac                óŒ   — t        ||«      ryt        j                  d| j                  j                  |||j
                  «       y)zJWarn-and-ignore gate shared by every registrar that requires a base class.FzLPlugin '%s' tried to register %s %s that does not inherit from %s. Ignoring.T)Ú
isinstancerq   rÑ   r¦   rÆ   r`   )r»   ÚobjÚ
base_classÚlabelÚarticles        r[   Ú_wrong_typezPluginContext._wrong_type+  s;   € ä�c˜:Ô&ØÜ�‰ÐeØ—}‘}×)Ñ)¨7°E¸:×;NÑ;Nô	Pàr]   c                óN   — t        d| j                  j                  › d|› d�«      S )zY``ValueError`` for a malformed registration (``what`` completes "tried to register ...").úPlugin 'z' tried to register ú.)rÐ   r¦   rÆ   )r»   Úwhats     r[   Ú_refusezPluginContext._refuse3  s)   € ä˜H T§]¡]×%7Ñ%7Ð$8Ð8LÈTÈFÐRSÐTÓUÐUr]   F©Ú
persistentc               óV   — | j                   j                  | j                  ||||¬«      S )zƒRecord host-owned cleanup for a successful registration (see
        :meth:`PluginManager._track_registration` for ``persistent``).ró   )r¸   Ú_track_registrationr¦   )r»   ÚkindrÈ   Úreleaserô   s        r[   Ú_trackzPluginContext._track7  s)   € ð
 �}‰}×0Ñ0°·±ÀÀcÈ7Ð_iÐ0ÓjÐjr]   c               ón   — t        j                  ||||¬«      }| j                  |||j                  «      S )zFTrack one generation in a replaceable manager-local registration slot.)ÚcurrentÚpreviousÚrestore)r   Úacquirerù   Údispose)r»   r÷   rÈ   Úslotrû   rü   rý   Úleases           r[   Ú_track_replacementz PluginContext._track_replacement>  s3   € ô
 (×/Ñ/°¸gÐPXÐbiÔjˆØ�{‰{˜4  e§m¡mÓ4Ð4r]   c                ó˜   ‡ ‡‡‡— |t         u r‰j                  ‰«      }‰‰‰<   ‰ j                  |‰dt        ‰«      ‰f‰|ˆˆˆˆ fd„¬«      S )zÓStore ``entry`` under ``key`` in a manager-local mapping and lease the slot; unload restores
        ``previous`` (default: the displaced entry, or removes the key) only while ``entry`` is still
        current.Úmanager_mappingc                ó@   •— ‰j                   j                  ‰‰‰| «      S rÅ   )r¸   Ú_restore_mapping)ÚreplacementrÚ   rÈ   Úmappingr»   s    €€€€r[   ú<lambda>z4PluginContext._track_mapping_entry.<locals>.<lambda>Q  s   ø€ ¨¯©×(FÑ(FÀwÐPSÐUZÐ\gÓ(h€ r]   ©r   rû   rü   rý   )r×   rÖ   r  Úid)r»   r÷   rÈ   r  rÚ   rü   s   ` ``` r[   Ú_track_mapping_entryz"PluginContext._track_mapping_entryF  sW   û€ ð ”vÑØ—{‘{ 3Ó'ˆHØˆ�‰Ø×&Ñ&Ø�#Ð.´°7³¸SÐAÈ5Ð[cÞhð 'ó 
ð 	
r]   ©rü   c               ó†   — | j                  |||||«      }t        j                  || j                  j                  g|¢­Ž  |S )z‰Shared tail of the manager-mapping registrars: store + lease the entry, then log
        ``log_fmt % (plugin name, *log_args)`` at debug.)r  rq   rt   r¦   rÆ   )	r»   r÷   rÈ   r  rÚ   Úlog_fmtrü   Úlog_argsÚhandles	            r[   Ú_register_entryzPluginContext._register_entryT  s>   € ð ×*Ñ*¨4°°g¸uÀhÓOˆÜ�‰�W˜dŸm™m×0Ñ0Ð<°8Ó<Øˆr]   c                ó"   — | j                  «       S rÅ   ©Ústrip©Úns    r[   r	  zPluginContext.<lambda>`  s   € ÐRS×RYÑRYÓR[€ r]   )rì   Ú	normalizeÚregisterÚreject_messagec               ó\  — | j                  ||||«      ry|€|j                  n ||j                  «      }
| j                  j                  }|j	                  |
|¬«      }	  |xs |j
                  ||¬«      }|�|r|j	                  |
|¬«      |ury| j                  j                  | j                  ||
|||«      }t        j                  d| j                  j                  ||
«       |S # t        $ r8}|	€‚ t        j                  |	| j                  j                  |«       Y d}~yd}~ww xY w)aQ  Shared body of the ``register_<category>_provider`` methods: type-check (warn + ignore),
        register in the scope-keyed ``registry``, lease the slot so unload restores the displaced entry.
        ``None`` when the registry refused/replaced the provider (``ValueError`` with ``reject_message``
        set, or a falsy ``register``).N©ÚscopezPlugin '%s' registered %s: %s)rí   rÆ   r¸   Ú	scope_keyÚsnapshot_registrationÚregister_providerrÐ   rq   rÑ   r¦   Ú_track_scoped_registrationÚinfo)r»   Úproviderr÷   rê   Úregistryrë   rì   r  r  r  Úregistry_namer  rü   ÚacceptedÚexcr  s                   r[   Ú_register_scoped_providerz'PluginContext._register_scoped_provider^  s(  € ð ×Ñ˜H j°%¸ÔAØØ)2Ð):˜ŸšÁ	È(Ï-É-Ó@XˆØ—‘×'Ñ'ˆØ×1Ñ1°-ÀuÐ1ÓMˆð	Ø>˜Ò> H×$>Ñ$>ÀÐPUÔVˆHð Ð ©°h×6TÑ6TØ ð 7Uó 7
àñ7ð Ø—‘×9Ñ9Ø�M‰M˜4 °¸(ÀHó
ˆô 	�‰Ð3°T·]±]×5GÑ5GÈÐP]Ô^Øˆøô ò 	ØÐ%ØÜ�N‰N˜>¨4¯=©=×+=Ñ+=¸sÔCÜûð		ús   Á C* Ã*	D+Ã3.D&Ä&D+c                ón   — | j                   €ddlm}  || j                  ¬«      | _         | j                   S )zÞHost-owned :class:`agent.plugin_llm.PluginLlm` facade: completions on the user's active
        model/auth. Overrides (model, agent id, auth profile) are fail-closed, gated by
        ``plugins.entries.<plugin_id>.llm.*``.r   )Ú	PluginLlm)rÂ   )r¹   Úagent.plugin_llmr*  rÂ   )r»   r*  s     r[   ÚllmzPluginContext.llm}  s+   € ð
 �9‰9ÐÝ2Ù!¨D¯N©NÔ;ˆDŒIØ�y‰yÐr]   c                ó"   — ddl m}m}  ||«      S )z…Plugin-safe subagent lifecycle service: serializable handles and immutable snapshots,
        never a live agent or private registry.r   )ÚSubagentLifecycleServiceÚget_active_subagent_parent)Úagent.subagent_lifecycler.  r/  )r»   r.  r/  s      r[   Úsubagent_lifecyclez PluginContext.subagent_lifecycle‡  s   € ÷ 	bÙ'Ð(BÓCÐCr]   c                ó<   — 	 ddl m}  |«       S # t        $ r Y yw xY w)uö   Active profile name (``"default"``, the ``~/.hermes/profiles/<name>`` id, or ``"custom"``),
        derived from ``HERMES_HOME`` â€” not ``_cli_ref``, which is None outside the interactive CLI â€”
        so gateway and kanban workers get it too.r   )Úget_active_profile_namerØ   )Úhermes_cli.profilesr3  Ú	Exception)r»   r3  s     r[   Úprofile_namezPluginContext.profile_nameŽ  s%   € ð
	ÝCÙ*Ó,Ð,øÜò 	Ùð	ús   ‚ �	šc                óÂ   — t        |«      st        d«      ‚| j                  dt        |dd«      |«      }t        j                  d| j                  j                  «       |S )z¢Register a cleanup callback for unload: runs in reverse acquisition order interleaved
        with registration teardown; exceptions are logged, never propagated.z#on_unload callback must be callableÚ	on_unloadr`   Úcallbackz'Plugin %s registered on_unload callback)ÚcallableÚ	TypeErrorrù   Úgetattrrq   rt   r¦   rÆ   )r»   r9  r  s      r[   r8  zPluginContext.on_unload™  sR   € ô ˜Ô!ÜÐAÓBÐBØ—‘˜[¬'°(¸JÈ
Ó*SÐU]Ó^ˆÜ�‰Ð>ÀÇÁ×@RÑ@RÔSØˆr]   ©rÆ   c               ój  ‡‡— t        j                  |«      st        d«      ‚t        j                  «       }|xs d| j                  › d�}|j                  ||¬«      Š| j                  d|ˆfd„«      Š‰j                  ˆfd„«       t        j                  d| j                  j                  |«       ‰S )	zVSpawn a supervised asyncio task; unload/force reload cancels it. Needs a running loop.zspawn_task expects a coroutineúplugin:z:taskr=  Úbackground_taskc                 óH   •— ‰ j                  «       xs ‰ j                  «       S rÅ   )ÚdoneÚcancel)Útasks   €r[   r	  z*PluginContext.spawn_task.<locals>.<lambda>©  s   ø€ À4Ç9Á9Ã;ÒC_ÐRV×R]ÑR]ÓR_€ r]   c                ó$   •— ‰j                  «       S rÅ   )rÿ   )Ú_tr  s    €r[   r	  z*PluginContext.spawn_task.<locals>.<lambda>ª  s   ø€ ¨&¯.©.Ó*:€ r]   z%Plugin %s spawned supervised task: %s)ÚasyncioÚiscoroutiner;  Úget_running_looprÂ   Úcreate_taskrù   Úadd_done_callbackrq   rt   r¦   rÆ   )r»   ÚcororÆ   ÚloopÚ	task_namer  rD  s        @@r[   Ú
spawn_taskzPluginContext.spawn_task¢  sœ   ù€ ä×"Ñ" 4Ô(ÜÐ<Ó=Ð=Ü×'Ñ'Ó)ˆØÒ;˜g d§n¡nÐ%5°UÐ;ˆ	Ø×Ñ ¨9ÐÓ5ˆØ—‘Ð.°	Ó;_Ó`ˆØ×ÑÓ:Ô;Ü�‰Ð<¸d¿m¹m×>PÑ>PÐR[Ô\Øˆr]   c           	     ó6  — ddl m} | j                  j                  }t	        |«      j                  «       j                  «       }|dk(  rt        d«      ‚t        j                  d|«      st        d«      ‚t        |«      st        d«      ‚||v r ||   j                  }t        d|›d	|›�«      ‚ |||| j                  t	        t        «       j                  «       «      ¬
«      }t        j!                  d| j                  |«       | j#                  d|||d«       y)a  Register a human approval transport, inactive until ``security.approval.transport:
        <name>`` selects it. It receives a redacted ``ApprovalRequest`` and returns only a
        correlated decision; policy and persistence stay host-owned. ``present_fn`` may be async.r   ©ÚRegisteredApprovalTransportÚbuiltinú-approval transport name 'builtin' is reservedú[a-z0-9][a-z0-9_-]{0,63}ú;approval transport name must match [a-z0-9][a-z0-9_-]{0,63}ú.approval transport present_fn must be callableúapproval transport ú is already registered by ©rÆ   ÚpresentrÂ   Úprofile_homeú+Plugin %s registered approval transport: %sÚapproval_transportN)Úhermes_cli.approval_transportrR  r¸   Ú_approval_transportsÚstrr  ÚlowerrÐ   ÚreÚ	fullmatchr:  r;  rÂ   r   rX   rq   r"  r  )r»   rÆ   Ú
present_fnrR  Ú
transportsÚcleanÚownerrÚ   s           r[   Úregister_approval_transportz)PluginContext.register_approval_transport®  s  € õ 	NØ—]‘]×7Ñ7ˆ
Ü�D“	—‘Ó!×'Ñ'Ó)ˆØ�IÒÜÐLÓMÐMÜ�|‰|Ð7¸Ô?ÜÐZÓ[Ð[Ü˜
Ô#ÜÐLÓMÐMØ�JÑØ˜uÑ%×/Ñ/ˆEÜÐ2°5°)Ð;UÐV[ÐU^Ð_Ó`Ð`Ù+Ø 
°d·n±nÜœ_Ó.×6Ñ6Ó8Ó9ô
ˆô 	�‰ÐAÀ4Ç>Á>ÐSXÔYð 	×!Ñ!Ð"6¸¸zÈ5ÐRVÕWr]   c                ó  ‡ ‡— |
rD‰ j                  ‰«      s3t        d‰ j                  j                  ›d‰›d‰ j                  › d�«      ‚ddlm} ‰ j                  j                  }|j                  ‰|¬«      }|€A|
s?|j                  ‰|¬«      �,t        j                  d	‰ j                  j                  ‰«       y|j                  ‰||||||||	|
|¬
«       |j                  ‰|¬«      }d}|�g||urc|j                  |u rU‰ j                  j                  j!                  ‰«       ‰ j                  j#                  ‰ j                  d‰|||ˆˆ fd„¬«      }t        j%                  d‰ j                  j                  ‰|
rd«       |S d«       |S )uš  Register a tool in the global registry and track it as plugin-provided. ``override=True``
        replaces a same-named built-in (without it a name claimed by another toolset is rejected) and
        needs operator opt-in via ``plugins.entries.<plugin_id>.allow_tool_override: true`` â€” otherwise
        any enabled plugin could silently replace a privileged built-in like ``write_file``.

        ``override=True`` against a built-in tool requires the operator to opt in via
        ``plugins.entries.<plugin_id>.allow_tool_override: true`` in config.yaml â€” mirrors the trust gate
        pattern used for ``ctx.llm`` provider/model overrides (#23194).
        úPlugin z cannot override built-in tool z. Set plugins.entries.zY.allow_tool_override: true in config.yaml to allow this plugin to replace built-in tools.r   ©r$  r  Nz>Plugin %s tried to shadow global tool %s without override=True)rÆ   ÚtoolsetÚschemarv   Úcheck_fnÚrequires_envÚis_asyncÚdescriptionÚemojiÚoverrider  Útoolc                 ó:   •— ‰j                   j                  ‰ «      S rÅ   )r¸   Ú_remove_tool_name_if_unowned©rÆ   r»   s   €€r[   r	  z-PluginContext.register_tool.<locals>.<lambda>î  s   ø€  §¡×!KÑ!KÈDÓ!Q€ r]   ©ÚfinalizezPlugin %s registered tool: %s%sz (override)Ú )Ú_tool_override_allowedr_   r¦   rÆ   rÂ   Útools.registryr$  r¸   r  r  Ú	get_entryrq   rÑ   r  rv   Ú_plugin_tool_namesÚaddr!  rt   )r»   rÆ   rm  rn  rv   ro  rp  rq  rr  rs  rt  r$  r  rü   Ú
registeredr  s   ``              r[   Úregister_toolzPluginContext.register_toolÇ  s¡  ù€ ñ ˜D×7Ñ7¸Ô=Ü)Ø˜$Ÿ-™-×,Ñ,Ð/Ð/NÈtÈhð W#Ø#'§>¡>Ð"2ð 3QðRóð õ
 	,Ø—‘×'Ñ'ˆØ×1Ñ1°$¸eÐ1ÓDˆØÐ¡H°×1CÑ1CÀDÐPUÐ1CÓ1VÐ1bÜ�N‰NÐ[ØŸ=™=×-Ñ-¨tô5àØ×ÑØ˜w¨v¸wÐQYØ%°ÀkÐY^Ø Uð 	ô 	
ð
 ×3Ñ3°DÀÐ3ÓFˆ
ØˆØÐ! j¸Ñ&@ÀZ×EWÑEWÐ[bÑEbØ�M‰M×,Ñ,×0Ñ0°Ô6Ø—]‘]×=Ñ=Ø—‘˜v t¨X°zÀ8ÜQð >ó ˆFô 	�‰Ð6¸¿¹×8JÑ8JÈDÙ&.�]ô	8àˆð 57ô	8àˆr]   c                ól   — | j                   j                  dk(  r|dk(  ryt        | j                  |«      S )a  True when *capability* is live for this plugin (probe, then degrade gracefully). Bundled
        plugins are trusted for ``tools.override``; otherwise granted_capabilities or the legacy
        ``allow_*`` key decides. Unknown ids / unreadable consent -> False (fail closed).Úbundledútools.overrideT)r¦   Úsourcer   rÂ   )r»   Ú
capabilitys     r[   Úhas_capabilityzPluginContext.has_capabilityõ  s2   € ð �=‰=×Ñ 9Ò,°Ð?OÒ1OØÜ(¨¯©¸ÓDÐDr]   c                óò  — || j                  | j                  «      vr3t        d| j                  j                  ›d|›d| j                  › d�«      ‚	 t        |«      }t        dt        |d«      «      }dd	l
m}   ||||«      t        |xs i «      «      }t        j                  d
| j                  j                  |||t        |xs d«      «       | j!                  |«      S # t        t        f$ r d}Y Œ˜w xY w)uo  Call ``tool`` on MCP ``server`` synchronously through :mod:`tools.mcp_tool`'s native client
        (same trust gates, breaker, reconnect â€” never a parallel connection). Servers not in
        ``plugins.entries.<plugin_id>.mcp_allowlist`` raise ``PermissionError`` (default-deny). ``timeout``
        clamps to 1â€“600s; results over ~64KB are truncated with a marker.

        This is a per-server grant, deliberately not ambient authority over every configured server.
        TODO(#64228): swap the per-server allowlist for the declared capability model once it lands
        (per-tool grants, expiry, ro/rw).
        rk  z# is not allowed to call MCP server z. Add it to plugins.entries.zI.mcp_allowlist in config.yaml to grant access (default is no MCP access).ç      >@g      ð?g     À‚@r   )Ú_make_tool_handlerz;Plugin %s called MCP %s/%s (timeout=%ss, %d chars returned)r{  )Ú_mcp_allowlistrÂ   ÚPermissionErrorr¦   rÆ   Úfloatr;  rÐ   ÚmaxÚminÚtools.mcp_tool_handlersr‹  Údictrq   rt   ÚlenÚ_mcp_envelope)r»   Úserverru  Ú	argumentsÚtimeoutr‹  Úraws          r[   Úcall_mcpzPluginContext.call_mcpý  sû   € ð ˜×,Ñ,¨T¯^©^Ó<Ñ<Ü!Ø˜$Ÿ-™-×,Ñ,Ð/ð 0Ø ˜ð $#Ø#'§>¡>Ð"2ð 3>ð?óð ð	Ü˜G“nˆGô �cœ3˜w¨Ó.Ó/ˆÝ>Ø7Ñ  ¨¨wÓ7¼¸Yº_È"Ó8MÓNˆÜ�‰ÐRØ—]‘]×'Ñ'¨°°wÄÀCÂIÈ2Ãô	Pà×!Ñ! #Ó&Ð&øô œ:Ð&ò 	ØŠGð	ús   ÁC" Ã"C6Ã5C6i   c                ó¨  — t        |t        «      s|€dn
t        |«      }t        |«      | j                  kD  }|r|d| j                   dz   }	 t	        j
                  |«      }t        |t        «      rd|v r	d|d   dœ}n2t        |t        «      rd|v rd|d   d	œ}d
|v r|d
   |d
<   n	d|�|n|d	œ}|ri |¥ddi¥S |S # t        t        f$ r d}Y Œnw xY w)z>Normalize an MCP handler result string into a stable envelope.Nr{  u   â€¦ [truncated]r±   F)Úokr±   ÚresultT)r›  rœ  ÚstructuredContentÚ	truncated)	rè   ra  r“  Ú_MCP_RESULT_CHAR_CAPÚjsonÚloadsrÐ   r;  r’  )Úclsr˜  rž  ÚparsedÚenvelopes        r[   r”  zPluginContext._mcp_envelope  s   € ô ˜#œsÔ#Ø˜‘"¬¨S«ˆCÜ˜“H˜s×7Ñ7Ñ7ˆ	ÙØÐ0˜×0Ñ0Ð1Ð4EÑEˆCð	ÜŸ*™* S›/ˆFô �fœdÔ#¨°6Ñ(9Ø.3¸fÀW¹oÑ'N‰HÜ˜¤Ô%¨(°fÑ*<Ø"¨f°XÑ.>Ñ?ˆHØ" fÑ,Ø06Ð7JÑ0K�Ð,Ò-à"¸Ð8J©fÐPSÑTˆHÙ2;Ð.�(Ð.˜K¨Ñ.ÐIÀÐIøô œIÐ&ò 	ØŠFð	ús   ÁB= Â=CÃCc                óæ   — 	 ddl m}  |«       xs i }t        || «      xs i j	                  d«      }t        |t        «      r|D �cg c]  }t        |«      ‘Œ c}S g S # t        $ r g cY S w xY wc c}w )zOOperator-granted MCP server allowlist; missing/unreadable -> [] (default-deny).r   ©Úload_configÚmcp_allowlist)Úhermes_cli.configr§  r5  rP   rÖ   rè   r´   ra  )rÂ   r§  ÚcfgÚ	allowlistÚitems        r[   rŒ  zPluginContext._mcp_allowlist4  sr   € ð	Ý5Ù“-Ò% 2ˆCô ,¨C°Ó;ÒA¸r×FÑFÀÓWˆ	Ü4>¸yÌ$Ô4O iÖ0˜d”�D•	Ò0ÐWÐUWÐWøô ò 	ØŠIð	üò 1s   ‚A ÁA.ÁA+Á*A+c                ó  — | j                   j                  dk(  ry	 ddlm} t	        | j
                  j                  «      5   |«       xs i }ddd«       t        | j                  d¬«      S # 1 sw Y   Œ!xY w# t        $ r Y yw xY w)	uf  Whether this plugin may override built-in tools: bundled plugins are trusted (a maintainer
        choice, not privilege escalation); others need ``tools.override`` via
        :func:`plugin_capability_granted` (granted_capabilities OR legacy ``allow_tool_override: true``).

        Bundled plugins (shipped with Hermes core) are trusted by default â€” an override there is a
        deliberate maintainer choice, not a third-party plugin trying to elevate privilege. For every other
        source, the canonical check is :func:`plugin_capability_granted` with the ``tools.override``
        capability â€” satisfied by EITHER the consent-flow grant
        (``plugins.entries.<plugin_id>.granted_capabilities``) OR the deprecated legacy key
        ``allow_tool_override: true`` (still honored for backward compatibility; #64228 reference
        migration).
        r„  Tr   r¦  NFr…  )rÕ   )
r¦   r†  r©  r§  r3   r¸   Ú	home_pathr5  r   rÂ   )r»   Ú	tool_namer§  rª  s       r[   r|  z$PluginContext._tool_override_allowed?  s|   € ð �=‰=×Ñ 9Ò,Øð	Ý5Ü# D§M¡M×$;Ñ$;Ó<ñ *Ù!“mÒ) r�÷*ô )¨¯©Ð9IÐRUÔVÐV÷*ð *ûäò 	Ùð	ús)   œ%A9 ÁA-ÁA9 Á-A6Á2A9 Á9	BÂB)Úsession_keyc               ó„  — | j                   j                  }|dk(  r|nd|› d|› �}|�7t        |dd«      r|j                  n|j                  }|j                  |«       y|st        j                  d«       y| j                  «       s,t        j                  d| j                  | j                  «       y| j                   j                  st        j                  d	«       y	 t        | j                   j                  ||| j                  ¬
«      «      S # t        $ r% t        j                  d| j                  d¬«       Y yw xY w)aH  Inject a message into a CLI or gateway conversation (new turn if idle, interrupt if running).
        Gateway injection needs an existing ``session_key`` plus
        ``plugins.entries.<plugin_id>.allow_gateway_injection``; ``True`` means the gateway accepted the
        request for async dispatch, not that delivery completed.Úuserú[z] Ú_agent_runningFTz=inject_message: gateway mode requires an existing session_keyzxinject_message: gateway injection denied for plugin %s; set plugins.entries.%s.allow_gateway_injection: true to allow itz,inject_message: no live gateway is available)r°  ÚcontentrÂ   z7inject_message: gateway scheduling failed for plugin %s©Úexc_info)r¸   Ú_cli_refr<  Ú_interrupt_queueÚ_pending_inputÚputrq   rÑ   Ú_gateway_injection_allowedrÂ   Úhas_gateway_message_injectorr®   Úinject_gateway_messager5  )r»   rµ  Úroler°  ÚcliÚmsgÚqueue_s          r[   Úinject_messagezPluginContext.inject_message[  s'  € ð �m‰m×$Ñ$ˆØ š‰g¨q°°°b¸¸	Ð-BˆØˆ?Ü-4°SÐ:JÈEÔ-R�S×)Ò)ÐX[×XjÑXjˆFØ�J‰J�sŒOØÙÜ�N‰NÐZÔ[ØØ×.Ñ.Ô0Ü�N‰Nð ZàŸ>™>¨4¯>©>ô;ð Ø�}‰}×9Ò9Ü�N‰NÐIÔJØð	Ü˜Ÿ™×<Ñ<Ø'°ÀÇÁð =ó ó ð øô ò 	Ü�N‰NÐTÐVZ×VdÑVdØ$(ð ô *áð	ús   Ã 0D Ä+D?Ä>D?c                ó”   — 	 t        «       xs i }t        || j                  «      xs i j	                  d«      du S # t        $ r Y yw xY w)z=Return whether this plugin may trigger gateway session turns.FÚallow_gateway_injectionT)r   r5  rP   rÂ   rÖ   )r»   rª  s     r[   r¼  z(PluginContext._gateway_injection_allowed|  sR   € ð	Ü&Ó(Ò.¨BˆCô ' s¨D¯N©NÓ;ÒA¸r×FÑFÐG`ÓaÐeiÐiÐiøô ò 	Ùð	ús   ‚; »	AÁAc                ó¦   — |||||| j                   j                  | j                  dœ}| j                  d|| j                  j
                  |d|«      S )z—Register a CLI subcommand (``hermes <name> ...``). *setup_fn* receives the argparse
        subparser; *handler_fn* becomes ``set_defaults(func=...)``.)rÆ   Úhelprr  Úsetup_fnÚ
handler_fnÚpluginÚ
plugin_keyÚcli_commandz$Plugin %s registered CLI command: %s)r¦   rÆ   rÂ   r  r¸   Ú_cli_commands)r»   rÆ   rÇ  rÈ  rÉ  rr  rÚ   s          r[   Úregister_cli_commandz"PluginContext.register_cli_command„  s\   € ð  $°{ÐPXØ$°·±×0BÑ0BÐRV×R`ÑR`ñ
ˆð ×#Ñ# M°4¸¿¹×9TÑ9TÐV[Ø$JÈDóRð 	Rr]   c                óŒ  — |j                  «       j                  «       j                  d«      j                  dd«      }|s+t        j                  d| j                  j                  «       yt        t        «      5  ddl
m}  ||«      �5t        j                  d| j                  j                  |«       	 ddd«       y	 ddd«       |xs d	j                  «       }||xs d
| j                  j                  | j                  ||dv r|n|rdnddœ}	| j                  d|| j                  j                  |	d|«      S # 1 sw Y   Œ|xY w)a,  Register an in-session slash command (``/name``); handler ``fn(raw_args: str) -> str | None``
        (sync or async). ``args_hint`` (e.g. ``"<file>"``) lets adapters like Discord surface an argument
        field; without it the command registers parameterless there but still accepts trailing text.ú/ú ú-z;Plugin '%s' tried to register a command with an empty name.Nr   )Úresolve_commandz^Plugin '%s' tried to register command '/%s' which conflicts with a built-in command. Skipping.r{  zPlugin command>   ÚtextÚmixedÚoptionsrÔ  )rv   rr  rÊ  rË  Ú	args_hintÚargument_modeÚcommandz!Plugin %s registered command: /%s)rb  r  ÚlstripÚreplacerq   rÑ   r¦   rÆ   r   r5  Úhermes_cli.commandsrÓ  rÂ   r  r¸   Ú_plugin_commands)
r»   rÆ   rv   rr  r×  rØ  rg  rÓ  ÚhintrÚ   s
             r[   Úregister_commandzPluginContext.register_command’  s-  € ð —
‘
“×"Ñ"Ó$×+Ñ+¨CÓ0×8Ñ8¸¸cÓBˆÙÜ�N‰NÐXÐZ^×ZgÑZg×ZlÑZlÔmØÜ”iÓ ñ 	Ý;Ù˜uÓ%Ð1Ü—‘ð  DØEIÇ]Á]×EWÑEWÐY^ô`à÷	ð 	à1÷	ð ’˜R×&Ñ&Ó(ˆà¨{Ò/NÐ>NØ—m‘m×(Ñ(¸¿¹ÐUYØ.;Ð?[Ñ.[™]Ù ‘& dñ	
ˆð ×#Ñ# I¨u°d·m±m×6TÑ6TÐV[Ø$GÈóPð 	P÷	ð 	ús   Á:;D:Ä:Ec                óº   — ddl m} d|vr(t        | j                  j                  dd«      }|�||d<    |j
                  ||fd| j                  j                  i|¤ŽS )z³Dispatch a tool call through the registry with the parent agent (when available)
        resolved automatically; returns the handler's JSON string. ``kwargs`` forward to dispatch.r   rl  Úparent_agentÚagentNr  )r}  r$  r<  r¸   r¸  Údispatchr  )r»   r¯  ÚargsÚkwargsr$  râ  s         r[   Údispatch_toolzPluginContext.dispatch_tool®  sa   € õ 	,à Ñ'Ü˜DŸM™M×2Ñ2°G¸TÓBˆEØÐ Ø).��~Ñ&Ø ˆx× Ñ  ¨DÑZ¸¿¹×8OÑ8OÐZÐSYÑZÐZr]   c           	     óî  ‡ ‡— ‰ j                   j                  �+t        j                  d‰ j                  j
                  «       yddlm} ‰ j                  ‰|d«      ry‰ j                   j                  }‰‰ j                   _        ‰ j                  d‰j
                  dt        ‰ j                   «      df‰|ˆˆ fd	„¬
«      }t        j                  d‰ j                  j
                  ‰j
                  «       |S )z Register the (single) ``agent.context_engine.ContextEngine`` replacing the built-in
        ContextCompressor; a second registration is rejected with a warning.NzyPlugin '%s' tried to register a context engine, but one is already registered. Only one context engine plugin is allowed.r   )ÚContextEnginezcontext engineÚcontext_engineÚmanager_valueÚ_context_enginec                ó>   •— ‰j                   j                  d‰| «      S )Nrë  )r¸   Ú_restore_value)r  Úenginer»   s    €€r[   r	  z7PluginContext.register_context_engine.<locals>.<lambda>Ê  s   ø€ ¨¯©×(DÑ(DÐEVÐX^Ð`kÓ(l€ r]   r
  z)Plugin '%s' registered context engine: %s)r¸   rë  rq   rÑ   r¦   rÆ   Úagent.context_enginerè  rí   r  r  r"  )r»   rî  rè  rü   r  s   ``   r[   Úregister_context_enginez%PluginContext.register_context_engine¹  sÏ   ù€ ð �=‰=×(Ñ(Ð4Ü�N‰Nð \àŸ=™=×-Ñ-ô/ð Ý6Ø×Ñ˜F MÐ3CÔDØØ—=‘=×0Ñ0ˆØ(.ˆ�‰Ô%Ø×(Ñ(Ø˜fŸk™k°Ä"ÀTÇ]Á]ÓBSÐUfÐ0gØ XÜlð )ó 
ˆô
 	�‰Ð?ÀÇÁ×ASÑASÐU[×U`ÑU`ÔaØˆr]   c                ó:  — ddl m}m} | j                  ||d«      ry	  ||«       t
        j                  d| j                  j                  |j                  «       y# t        $ r5}t
        j                  d| j                  j                  |«       Y d}~yd}~ww xY w)zÉRegister a :class:`agent.context_references.ContextReferenceProvider`; ``provider.prefix``
        defines ``@<prefix>:``. Built-in prefixes (diff, staged, file, folder, git, url) are
        rejected.r   )ÚContextReferenceProviderÚ#register_context_reference_providerzcontext reference providerNz5Plugin '%s' context reference registration failed: %sz.Plugin '%s' registered context reference: @%s:)Úagent.context_referencesrò  ró  rí   rÐ   rq   rÑ   r¦   rÆ   r"  Úprefix)r»   r#  Ú_CRPÚ	_registerr'  s        r[   Úregister_context_referencez(PluginContext.register_context_referenceÏ  s„   € ÷	
ð ×Ñ˜H dÐ,HÔIØð	Ù�hÔô 	�‰ÐDÀdÇmÁm×FXÑFXÐZb×ZiÑZiÕjøô ò 	Ü�N‰NÐRÐTX×TaÑTa×TfÑTfÐhkÔlÜûð	ús   žA Á	BÁ%+BÂBc           	     ó²   — ddl m} | j                  ||d«      ry|| _        t        j                  d| j                  j                  t        |dd«      «       y)zþRecord a memory provider (inert). Activation is owned by ``plugins/memory`` via
        ``memory.provider``; a provider reaching here was loaded by the general manager, and
        without this method its ``register()`` would fail on a missing attribute.r   )ÚMemoryProviderzmemory providerNz*Plugin '%s' registered memory provider: %srÆ   ú?)	Úagent.memory_providerrú  rí   Ú_memory_providerrq   rt   r¦   rÆ   r<  )r»   r#  rú  s      r[   Úregister_memory_providerz&PluginContext.register_memory_providerß  sL   € õ 	9Ø×Ñ˜H nÐ6GÔHØØ (ˆÔÜ�‰ÐAÀ4Ç=Á=×CUÑCUÜ˜X v¨sÓ3õ	5r]   c           
     ó°  ‡‡‡— ddl m} ddlm}mŠ | j                  ‰|d«      ryt        t        «       «      }| j                  j                  |k7  rLt        j                  d| j                  j                  ‰j                  | j                  j                  |«       y‰j                  Š	  |‰«       | j#                  d
‰ˆˆˆfd„d¬«      }t        j%                  d| j                  j                  ‰‰j&                  «       |S # t        t        f$ rA}t        j                  d| j                  j                  t!        ‰dd	«      |«       Y d}~yd}~ww xY w)zÛRegister a :class:`hermes_cli.dashboard_auth.DashboardAuthProvider` for the dashboard
        auth gate (non-loopback bind without ``--insecure``). Wrong type / duplicate name warn and
        are ignored, never raised.r   )ÚDashboardAuthProvider)Úregister_global_providerÚunregister_global_providerzdashboard-auth providerNz�Plugin '%s' tried to register dashboard-auth provider %r from profile scope %s; ignoring it because dashboard auth is owned by launch scope %s.z=Plugin '%s' failed to register dashboard-auth provider %r: %srÆ   rû  Údashboard_auth_providerc                 ó   •—  ‰‰‰ «      S rÅ   rd   )r#  r%  r  s   €€€r[   r	  z@PluginContext.register_dashboard_auth_provider.<locals>.<lambda>  s   ø€ Ñ%?ÀÈxÓ%X€ r]   Tró   z7Plugin '%s' registered dashboard-auth provider: %s (%s))Úhermes_cli.dashboard_authr   Ú"hermes_cli.dashboard_auth.registryr  r  rí   r   r   r¸   r  rq   rÑ   r¦   rÆ   r;  rÐ   r<  rù   r"  Údisplay_name)	r»   r#  r   r  Úlaunch_scopeÚer  r%  r  s	    `     @@r[   Ú register_dashboard_auth_providerz.PluginContext.register_dashboard_auth_providerê  s'  ú€ õ
 	DßkØ×Ñ˜HÐ&;Ð=VÔWØÜ&Ô'>Ó'@ÓAˆØ�=‰=×"Ñ" lÒ2Ü�N‰Nð/ð —‘×"Ñ"Ø—‘Ø—‘×'Ñ'Øôð Ø Ÿ™ˆð
	ñ % XÔ.ð
 —‘Ð6¸ÝXÐeið ó kˆä�‰ÐMÈtÏ}É}×OaÑOaØ! 8×#8Ñ#8ô	:àˆøô œ:Ð&ò 	Ü�N‰NÐZØŸ=™=×-Ñ-¬w°xÀÈÓ/MÈqôRäûð	ús   Â+D ÄEÄ7EÅEc                óH  ‡ ‡— ddl m}	m}
 |j                  d‰ j                  j
                  «        |
d‰|||||xs g |ddœ|¤Ž}‰ j                  j                  }|	j                  ‰|¬«      }|	j                  ||¬«       |	j                  ‰|¬«      }|d   |us|d   �y‰ j                  j                  j                  ‰«       ‰ j                  j                  ‰ j                  d	‰|	||ˆˆ fd
„¬«      }t        j                  d‰ j                  j
                  ‰«       |S )aý  Register a gateway platform adapter (``adapter_factory(PlatformConfig) -> BasePlatformAdapter``).
        ``check_fn`` is a PASSIVE "deps importable?" probe that must never install (status displays call
        it freely); an ACTIVE installer goes in ``ensure_deps_fn`` (called from ``create_adapter()`` when
        ``check_fn`` is False). Extra kwargs (``setup_fn``, ``emoji``, ``allowed_users_env``,
        ``platform_hint``, ``ensure_deps_fn``) forward to ``PlatformEntry``; unknown keys raise TypeError.r   )Úplatform_registryÚPlatformEntryÚplugin_namerÊ  )rÆ   rë   Úadapter_factoryro  Úvalidate_configÚrequired_envÚinstall_hintr†  r  é   NÚplatformc                 ó:   •— ‰j                   j                  ‰ «      S rÅ   )r¸   Ú _remove_platform_name_if_unownedrx  s   €€r[   r	  z1PluginContext.register_platform.<locals>.<lambda>/  s   ø€ ˜TŸ]™]×KÑKÈDÓQ€ r]   ry  z!Plugin %s registered platform: %srd   )Úgateway.platform_registryr  r  Ú
setdefaultr¦   rÆ   r¸   r  r  r  Ú_plugin_platform_namesr€  r!  rq   rt   )r»   rÆ   rë   r  ro  r  r  r  Úentry_kwargsr  r  rÚ   r  rü   rû   r  s   ``              r[   Úregister_platformzPluginContext.register_platform  s#  ù€ ÷ 	OØ×Ñ ¨t¯}©}×/AÑ/AÔBÙð 
Ø˜U°OÈhØ+¸,Ò:LÈ"Ø%¨hñ
ð ;Gñ
ˆð
 —‘×'Ñ'ˆØ$×:Ñ:¸4ÀuÐ:ÓMˆØ×"Ñ" 5°Ð"Ô6Ø#×9Ñ9¸$ÀeÐ9ÓLˆØ�1‰:˜UÑ" g¨a¡jÐ&<ØØ�‰×,Ñ,×0Ñ0°Ô6Ø—‘×9Ñ9Ø�M‰M˜: tÐ->ÀÈÜQð :ó 
ˆô 	�‰Ð8¸$¿-¹-×:LÑ:LÈdÔSØˆr]   c                óÂ  ‡ ‡‡— t        |«      s‰ j                  d«      ‚|� t        |t        «      r!|j	                  «       s‰ j                  d«      ‚||‰ j
                  j                  fŠ‰ j                  j                  Š‰j                  ‰«       ‰ j                  dt        |«      ˆˆˆ fd„«      }t        j                  d‰ j
                  j                  |«       |S )aP  Register a Slack Block Kit action handler, wired into ``slack_bolt.AsyncApp`` at connect.
        ``action_id`` is anything ``slack_bolt.App.action()`` accepts; ``callback`` is
        ``async def handler(ack, body, action)`` (``await ack()`` within 3s). Raises ``ValueError`` for
        a non-callable callback or empty ``action_id``.z3a Slack action handler with a non-callable callbackz.a Slack action handler with an empty action_idÚslack_action_handlerc                 ó<   •— ‰j                   j                  ‰‰ «      S rÅ   )r¸   Ú_remove_identity)rÚ   Úhandlersr»   s   €€€r[   r	  z=PluginContext.register_slack_action_handler.<locals>.<lambda>C  s   ø€  T§]¡]×%CÑ%CÀHÈeÓ%T€ r]   z-Plugin %s registered Slack action handler: %s)r:  rò   rè   ra  r  r¦   rÆ   r¸   Ú_slack_action_handlersÚappendrù   Úreprrq   rt   )r»   Ú	action_idr9  r  rÚ   r   s   `   @@r[   Úregister_slack_action_handlerz+PluginContext.register_slack_action_handler4  s²   ú€ ô ˜Ô!Ø—,‘,ÐTÓUÐUØÐ¤¨I´sÔ!;ÀIÇOÁOÔDUØ—,‘,ÐOÓPÐPØ˜H d§m¡m×&8Ñ&8Ð9ˆØ—=‘=×7Ñ7ˆØ�‰˜ÔØ—‘Ð3´T¸)³_ÝTóVˆä�‰ÐDÀdÇmÁm×FXÑFXÐZcÔdØˆr]   c                ó¼  — t        |«      s| j                  d«      ‚|xs dj                  «       j                  «       }|s| j                  d«      ‚| j                  j
                  j                  |g «      j                  || j                  j                  f«       t        j                  d| j                  j                  |t        |dt        |«      «      «       y)a]  Register ``factory(native, adapter)``, invoked at ``connect()`` before/as the core handlers
        register (``adapter`` read-only). ``native``: telegram PTB ``Application``, discord
        ``commands.Bot``, slack ``AsyncApp``, matrix client, teams ``App``, dingtalk
        ``DingTalkStreamClient``, line aiohttp ``web.Application``, others ``None``. Keep SDK imports
        inside the factory; exceptions are logged and the platform still connects. Scope handlers in
        first-match dispatch tables so core flows keep working. Raises ``ValueError`` when not callable
        or platform is empty.z6a platform handler factory with a non-callable factoryr{  z6a platform handler factory with an empty platform namez+Plugin %s registered %s handler factory: %sr`   N)r:  rò   r  rb  r¸   Ú_platform_handler_factoriesr  r"  r¦   rÆ   rq   rt   r<  r#  )r»   r  ÚfactoryrÈ   s       r[   Úregister_platform_handlerz'PluginContext.register_platform_handlerG  s°   € ô ˜Ô Ø—,‘,ÐWÓXÐXØŠ~˜2×$Ñ$Ó&×,Ñ,Ó.ˆÙØ—,‘,ÐWÓXÐXØ�‰×1Ñ1×<Ñ<¸SÀ"ÓE×LÑLÈgÐW[×WdÑWd×WiÑWiÐMjÔkÜ�‰ÐBÀDÇMÁM×DVÑDVÐX[Ü˜W j´$°w³-Ó@õ	Br]   c                ó(   — | j                  d|«       y)uý   ``register_platform_handler("telegram", factory)``. PTB dispatches only the FIRST matching
        handler per group and core registers a catch-all ``CallbackQueryHandler`` â€” always scope with
        ``pattern=`` or you swallow the core button flows.ÚtelegramN)r)  )r»   r(  s     r[   Úregister_telegram_handlerz'PluginContext.register_telegram_handlerX  s   € ð 	×&Ñ& z°7Õ;r]   )Údefaultsc               ó–  — | j                   j                  }|rt        |t        «      st	        d|› d|›�«      ‚t        d„ |D «       «      st	        d|› d|›d�«      ‚ddlm} ||D ���	ch c]  \  }}}	|’Œ
 c}	}}v rt	        d|› d|›d	|› d
|› d�	«      ‚| j                  }
| j                  j                  j                  |«      }|�8|j                  d«      |
k7  r$t	        d|› d|›d|j                  d«      › d�«      ‚|||dddddi dœ|xs i ¥|
|
dœ}| j                  d|| j                  j                  |d|||¬«      S c c}	}}w )a  Register an auxiliary LLM task with its own ``auxiliary.<key>`` config block (picker entry,
        ``AUXILIARY_<KEY>_*`` env bridge, defaults merged into loaded configs). ``defaults`` may
        override provider/model/base_url/api_key/timeout/extra_body (unknown keys kept verbatim).
        Raises ``ValueError`` for an empty/invalid key, a built-in key, or another plugin's key.rï   z4' tried to register auxiliary task with invalid key c              3  óJ   K  — | ]  }|j                  «       xs |d k(  –— Œ y­w)Ú_N)Úisalnum)rÇ   Úcs     r[   rÊ   z8PluginContext.register_auxiliary_task.<locals>.<genexpr>j  s"   è ø€ Ò8¨q�1—9‘9“;Ò* ! s¡(Ó*Ñ8ùs   ‚!#z' auxiliary task key z: must contain only alphanumeric characters and underscoresr   )Ú
_AUX_TASKSz!' cannot register auxiliary task uS    â€” that key is reserved for a built-in task. Pick a plugin-namespaced key (e.g. 'r0  z').rÊ  u#    â€” already registered by plugin 'ú'Úautor{  é<   )r#  ÚmodelÚbase_urlÚapi_keyr—  Ú
extra_body)rÈ   r  rr  r-  rÊ  rË  Úauxiliary_taskz,Plugin %s registered auxiliary task: %s (%s)r  )r¦   rÆ   rè   ra  rÐ   ÚallÚhermes_cli.main_provider_setupr3  rÂ   r¸   Ú
_aux_tasksrÖ   r  )r»   rÈ   r  rr  r-  ÚmeÚ_BUILTIN_AUX_TASKSÚkÚ_nameÚ_descÚowner_idÚexistingrÚ   s                r[   Úregister_auxiliary_taskz%PluginContext.register_auxiliary_task^  s¶  € ð �]‰]×ÑˆÙœ* S¬#Ô.Ü˜x¨ tÐ+_Ð`cÐ_fÐgÓhÐhÜÑ8°CÔ8Ô8Ü˜x¨ tÐ+@ÀÀð HYð Zó [ð [åSØÐ,>×?Ð?™˜˜E 5’1Ô?Ñ?Ü˜x¨ tÐ+LÈSÈGð TYØY[ÐX\Ð\]Ð^aÐ]bÐbeðgó hð hð —>‘>ˆØ—=‘=×+Ñ+×/Ñ/°Ó4ˆØÐ H§L¡L°Ó$:¸hÒ$FÜ˜x¨ tÐ+LÈSÈGð T+Ø+3¯<©<¸Ó+AÐ*BÀ!ðEó Fð Fð ¨À[Ø%+°bÀbÐUWÐdfØ')ñ?Ø.6ªn¸"ð?à¨hñ	
ˆð ×#Ñ#Ð$4°c¸4¿=¹=×;SÑ;SÐUZØ$RÐTWÐYeØ-5ð $ó 7ð 	7ùô! @s   Á+E
c                ó.  — ddl m} 	  ||d| j                  j                  › �¬«      }t
        j                  d| j                  j                  |«       |S # t        $ r5}t
        j                  d| j                  j                  |«       Y d}~yd}~ww xY w)aC  Additively register secret-token regexes with :mod:`agent.redact`; returns the count accepted.
        Plugins can over-redact, never weaken built-ins; ``security.redact_secrets: false`` applies
        equally. Each pattern must compile and start with >= 2 literal characters; invalid entries warn
        and are skipped.r   )Úregister_redaction_patternsr?  )r†  z5Plugin '%s' redaction pattern registration failed: %sNz,Plugin %s registered %d redaction pattern(s))Úagent.redactrH  r¦   rÆ   r5  rq   rÑ   rt   )r»   Úpatternsr÷  Úcountr'  s        r[   rH  z)PluginContext.register_redaction_patterns‚  s‚   € õ
 	Jð	Ù˜h°¸¿¹×9KÑ9KÐ8LÐ/MÔNˆEô 	�‰ÐCÀTÇ]Á]×EWÑEWÐY^Ô_Øˆøô	 ò 	Ü�N‰NÐRÐTX×TaÑTa×TfÑTfÐhkÔlÜûð	ús   ˆ!A Á	BÁ+BÂBc                ó\   — | j                  d||| j                  j                  t        «      S )zMRegister a lifecycle hook callback (unknown names warn but are still stored).Úhook)Ú_track_callbackr¸   Ú_hooksr¢   )r»   Ú	hook_namer9  s      r[   Úregister_hookzPluginContext.register_hook�  s&   € à×#Ñ# F¨I°xÀÇÁ×AUÑAUÔWbÓcÐcr]   c                ó\   — | j                  d||| j                  j                  t        «      S )z˜Register behavior-changing middleware (request kinds rewrite the payload, execution kinds
        wrap the callback). Unknown kinds warn but are stored.Ú
middleware)rN  r¸   Ú_middlewarer   )r»   r÷   r9  s      r[   Úregister_middlewarez!PluginContext.register_middleware”  s-   € ð ×#Ñ#Ø˜$ ¨$¯-©-×*CÑ*CÔEUó
ð 	
r]   c                ól  ‡ ‡‡‡— ‰|vrEt         j                  d‰ j                  j                  |‰dj	                  t        |«      «      «       ‰j                  ‰g «      j                  ‰«       ‰ j                  |‰ˆˆˆˆ fd„«      }t         j                  d‰ j                  j                  |‰«       |S )zUAppend ``callback`` under ``key`` (warning on unknown ``key``) and lease its removal.z2Plugin '%s' registered unknown %s '%s' (valid: %s)ú, c                 ó>   •— ‰j                   j                  ‰‰‰ «      S rÅ   )r¸   Ú_remove_callback)r9  rÈ   r  r»   s   €€€€r[   r	  z/PluginContext._track_callback.<locals>.<lambda>¤  s   ø€ °·±×0NÑ0NÈwÐX[Ð]eÓ0f€ r]   zPlugin %s registered %s: %s)
rq   rÑ   r¦   rÆ   ÚjoinÚsortedr  r"  rù   rt   )r»   r÷   rÈ   r9  r  Úvalidr  s   ` ```  r[   rN  zPluginContext._track_callback›  s�   û€ ð
 �eÑÜ�N‰NÐOÐQU×Q^ÑQ^×QcÑQcÐeiØ §	¡	¬&°«-Ó 8ô:à×Ñ˜3 Ó#×*Ñ*¨8Ô4Ø—‘˜T 3Ö(fÓgˆÜ�‰Ð2°D·M±M×4FÑ4FÈÈcÔRØˆr]   Úafter_memory)ÚpositionÚ	max_charsc          	     ót  — t        |«      st        d«      ‚t        |t        «      st	        |«      st        d«      ‚|t        vr*t        ddj                  t        t        «      «      z   «      ‚t        |t        «      s!t        |t        «      rd|cxk  r	t        k  sn t        dt        › �«      ‚| j                  j                  j                  |«      }|�t        d|›d|j                  ›�«      ‚t!        ||||| j"                  ¬	«      }| j%                  d
|| j                  j                  |d||¬«      S )z¬Register bounded context frozen into each new session prompt. Callables receive a
        read-only session-info mapping; the rendered prompt is persisted by core verbatim.zdsystem prompt section id must be 1-128 lowercase characters using letters, numbers, '.', '_', or '-'z:system prompt section content must be a string or callablez/system prompt section position must be one of: rW  r   z6system prompt section max_chars must be between 1 and zsystem prompt section z! is already registered by plugin )r  rµ  r^  r_  rÊ  Úsystem_prompt_sectionz.Plugin %s registered system prompt section: %sr  )rH   rÐ   rè   ra  r:  r;  r<   rZ  r[  r®   Úintr8   r¸   Ú_system_prompt_sectionsrÖ   rÊ  rD   rÂ   r  )r»   r  rµ  r^  r_  rE  Úsections          r[   Úregister_system_prompt_sectionz,PluginContext.register_system_prompt_section¨  s<  € ô 1°Ô4Üð Hó Ið Iä˜'¤3Ô'´¸Ô0AÜÐXÓYÐYØÔ:Ñ:ÜÐNØ#Ÿy™y¬Ô0OÓ)PÓQñRó Sð Sä�y¤$Ô'¬z¸)ÄSÔ/IØ˜9ÔGÔ(GÔGÜÐUÔVuÐUvÐwÓxÐxØ—=‘=×8Ñ8×<Ñ<¸RÓ@ˆØÐÜÐ5°b°VÐ;\Ð]e×]lÑ]lÐ\oÐpÓqÐqÜ+Ø˜7¨XÀÐSW×SaÑSaô
ˆð ×#Ñ#Ð$;¸RÀÇÁ×AfÑAfØ$+Ð-]Ð_aØ-5ð $ó 7ð 	7r]   c                ó�  — | j                   }|rt        |t        «      s&t        j	                  d||«       t        d|› d�«      ‚d|v r9t        j	                  d|||t        «       t        d|› d|› d|› dt        › d	�	«      ‚|�t        |t        «      st        d|› d
�«      ‚| j                  j                  |› d|› �|xs i «      S )a{  Publish bare *event* as ``<plugin_key>:<event>`` (namespace FORCED to this plugin); return
        the subscriber count scheduled. Any ``':'`` in the name (``hermes:x`` is reserved for core,
        foreign namespaces forbidden) raises ``ValueError``. Delivery is fire-and-forget via a
        single-worker queue: order preserved, a blocking subscriber cannot stall the emitter.z2Plugin '%s' tried to emit an invalid event name %rrï   z(' emit() requires a non-empty event nameú:uÐ   Plugin '%s' tried to emit namespaced/reserved event '%s' â€” a plugin may only emit bare event names under its own '%s:' namespace (the '%s:' prefix is reserved for core, and foreign namespaces are forbidden)z' may not emit 'z>': emit only the bare event name; the namespace is forced to 'z:' and the 'z:' prefix is reserved for corez'' emit() payload must be a dict or None)rÂ   rè   ra  rq   rÑ   rÐ   r7   r’  r;  r¸   Ú_dispatch_event)r»   ÚeventÚpayloadrË  s       r[   ÚemitzPluginContext.emitÃ  sî   € ð
 —^‘^ˆ
ÙœJ u¬cÔ2Ü�N‰NÐOÐQ[Ð]bÔcÜ˜x¨
 |Ð3[Ð\Ó]Ð]Ø�%‰<Ü�N‰Nð Mð & u¨jÔ:PôRô ˜x¨
 |Ð3CÀEÀ7ð K<Ø<F¸<À|ÔTjÐSkð l;ð<ó =ð =ð Ð¤z°'¼4Ô'@Ü˜h z lÐ2YÐZÓ[Ð[Ø�}‰}×,Ñ,°
¨|¸1¸U¸GÐ-DÀgÂmÐQSÓTÐTr]   c                ó  — |rt        |t        «      s#t        d| j                  j                  › d�«      ‚| j
                  j                  | j                  ||«       t        j                  d| j                  j                  |«       y)uª   Subscribe to a fully-qualified ``<plugin_key>:<event>`` name (unrestricted â€” only
        emitting is namespace-gated). Owner-tagged so unload removes zombie callbacks.rï   z-' subscribe() requires a non-empty event namez!Plugin %s subscribed to event: %sN)
rè   ra  rÐ   r¦   rÆ   r¸   Ú_subscribe_eventrÂ   rq   rt   )r»   ri  r9  s      r[   Ú	subscribezPluginContext.subscribeØ  se   € ñ œJ u¬cÔ2Ü˜x¨¯©×(:Ñ(:Ð';Ð;hÐiÓjÐjØ�‰×&Ñ& t§~¡~°u¸hÔGÜ�‰Ð8¸$¿-¹-×:LÑ:LÈeÕTr]   c           	     óp  — ddl m} d|v r&t        d|› d| j                  j                  › d�«      ‚|r|j                  |«      st        d|› d�«      ‚t        |«      }|j                  «       st        d	|› �«      ‚| j                  j                  xs | j                  j                  }|› d|› �}| j                  j                  r'|| j                  j                  v rt        d
|› d�«      ‚||| j                  ||t        |xs i «      dœ}| j                  d|| j                  j                  |d|«      S )u  Register a read-only skill resolvable as ``'<plugin_name>:<name>'`` via ``skill_view()``.
        Not in ``~/.hermes/skills/`` nor ``<available_skills>`` â€” explicit loads only. Raises
        ``ValueError`` (``':'``/invalid chars) or ``FileNotFoundError``.r   )Ú_NAMESPACE_RErg  zSkill name 'zG' must not contain ':' (the namespace is derived from the plugin name 'z' automatically).zInvalid skill name 'z'. Must match [a-zA-Z0-9_-]+.zSKILL.md not found at zPlugin skill 'z' is already registered)ÚpathrÊ  rË  Ú	bare_namerr  ÚfrontmatterÚskillzPlugin %s registered skill: %s)Úagent.skill_utilsrp  rÐ   r¦   rÆ   Úmatchr	   ÚexistsÚFileNotFoundErrorrà   Úportabler¸   Ú_plugin_skillsrÂ   r’  r  )	r»   rÆ   rq  rr  rs  rp  Ú	namespaceÚ	qualifiedrÚ   s	            r[   Úregister_skillzPluginContext.register_skillà  sB  € õ 	4Ø�$‰;Ü˜|¨D¨6ð 2-Ø-1¯]©]×-?Ñ-?Ð,@Ð@QðSó Tð Tá˜=×.Ñ.¨tÔ4ÜÐ3°D°6Ð9VÐWÓXÐXô �D‹zˆØ�{‰{Œ}Ü#Ð&<¸T¸FÐ$CÓDÐDØ—M‘M×1Ñ1ÒG°T·]±]×5GÑ5Gˆ	Ø �k  4 &Ð)ˆ	Ø�=‰=×!Ò! i°4·=±=×3OÑ3OÑ&OÜ˜~¨i¨[Ð8OÐPÓQÐQà I¸T¿^¹^ÐZ^Ø&´t¸KÒ<MÈ2Ó7Nñ
ˆð ×#Ñ# G¨Y¸¿¹×8TÑ8TÐV[Ø$DÀióQð 	Qr]   )r¦   r   r¼   z'PluginManager'©ÚreturnÚNone)r  ra  )rÂ   ra  r  r®   )rÈ   ra  r  ztuple[str, ...]rÅ   )rÈ   ra  rØ   r
   r  r
   )rÈ   ra  rÛ   r
   r  r€  )r  rK   )ræ   )
ré   r
   rê   Útyperë   ra  rì   ra  r  r®   )rñ   ra  r  rÐ   )
r÷   ra  rÈ   ra  rø   úCallable[[], None]rô   r®   r  rJ   )r÷   ra  rÈ   ra  r   Útuplerû   r
   rü   r
   rý   zCallable[[Any], bool]r  rJ   )r÷   ra  rÈ   ra  r  úDict[str, Any]rÚ   r
   rü   r
   r  rJ   )r÷   ra  rÈ   ra  r  r„  rÚ   r
   r  ra  r  r
   rü   r
   r  rJ   )r#  r
   r÷   ra  rê   r�  r$  r
   rë   ra  rì   ra  r  zOptional[Callable[[str], str]]r  zOptional[Callable[..., Any]]r  r°   r  úOptional[PluginRegistration])r  r
   )r9  r‚  r  rJ   )rÆ   r°   r  z'asyncio.Task')rÆ   ra  re  r   r  r€  )NNFr{  r{  F)rÆ   ra  rm  ra  rn  r’  rv   r   ro  úCallable | Nonerp  úlist | Nonerq  r®   rr  ra  rs  ra  rt  r®   r  r…  )r‡  ra  r  r®   )Né   )
r•  ra  ru  ra  r–  úOptional[Dict[str, Any]]r—  rŽ  r  r„  )r˜  r
   r  r„  )rÂ   ra  r  r©   )r¯  ra  r  r®   )r²  )rµ  ra  r¿  ra  r°  ú
str | Noner  r®   ©r  r®   )Nr{  )rÆ   ra  rÇ  ra  rÈ  r   rÉ  r†  rr  ra  r  rJ   )r{  r{  N)rÆ   ra  rv   r   rr  ra  r×  ra  rØ  rŠ  r  r…  )r¯  ra  rä  r’  r  ra  ©r  r…  )NNr{  )rÆ   ra  rë   ra  r  r   ro  r   r  r†  r  r‡  r  ra  r  r
   r  r…  )r$  r
   r9  r   r  rJ   )r  ra  r(  r   r  r€  )r(  r   r  r€  )
rÈ   ra  r  ra  rr  ra  r-  r‰  r  rJ   )r  rb  )rP  ra  r9  r   r  rJ   )r÷   ra  r9  r   r  rJ   )r÷   ra  rÈ   ra  r9  r   r  úDict[str, List[Callable]]r\  r¡   r  rJ   )
r  ra  rµ  z.Union[str, Callable[[Mapping[str, Any]], str]]r^  ra  r_  rb  r  rJ   )ri  ra  rj  zOptional[dict]r  rb  )ri  ra  r9  r   r  r€  )r{  N)
rÆ   ra  rq  r	   rr  ra  rs  zOptional[Mapping[str, Any]]r  rJ   )>r`   ra   rb   rc   r½   rÀ   ÚpropertyrÂ   rÎ   rÒ   rÜ   rÞ   r   rá   rå   rí   rò   rù   r  r×   r  r  r(  r,  r1  r6  r8  rO  ri  r4   r‚  rˆ  r™  rŸ  Úclassmethodr”  ÚstaticmethodrŒ  r|  rÃ  r¼  rÎ  rß  ræ  rð  rø  rþ  r
  r  r%  r)  r,  rF  rH  rQ  rU  rN  r6   re  rk  rn  r}  rd   r]   r[   r¶   r¶   æ   së  „ ÙGó%ó$ð ò+ó ð+ó	
óô
LóHð òJó ðJð ñ/ó ð/ôóVð
 W\ñkØðkØ!ðkØ,>ðkØOSðkà	ókð5Øð5Ø!ð5Ø,1ð5Ø<?ð5ØKNð5à&ð5ð 
ó5ð Y_ð
Øð
Ø!ð
Ø,:ð
ØCFð
ØRUð
à	ó
ð  ñØðØ!ðØ,:ðØCFðØQTðØadðàðð 
óð ÑH[Ø15ÐW[ñØðØ&)ðØ7;ðØGJðØSVðàðà'Eðð /ðð HUðð 
&ó	ð> òó ðð òDó ðDð òó ðóð 9=õ 
óXð2 ð ^cØAFð*Øð*Ø"%ð*Ø/3ð*Ø>Fð*à!ð*à8Cð*àVZð*ð ð*ð '*ð*ð ;?ð*ð 
&ò	*ó ð*óZEð MQØð'Øð'Ø!$ð'Ø1Ið'àð'ð 
ó'ð> !ÐàòJó ðJð* òXó ðXóWð: )/ðØMQñØðØ"%ðØ@Jðà	óóBjð àVZØðRØðRØ"ðRØ.6ðRØDSðRàðRð 
òRó ðRð àTVØ$(ðPØðPØ"*ðPØ9<ðPØNQðPà!ðPð 
&òPó ðPó6	[ð òó ðó*kó 	5ð ò'ó ð'ðR ð NRØðØðØ #ðØ6>ðØJRðà(ðà?Jðð ðð 14ðð 
&ò	ó ðð>ØðØ(0ðà	óó&Bó"<ð ð .2ñ!7Øð!7Ø),ð!7Ø;>ð!7à*ð!7ð 
ò!7ó ð!7óFódó
ðØðØ!ðØ-5ðØ@Yðàðð 
óð 'Ð9`ñ7Øð7Ø Nð7àð7à36ð7ð 
ó7ô6Uó*Uð à8:Ø37ðQØðQØ#ðQØ25ðQà0ðQð 
òQó ñQr]   r¶   Úregister_image_gen_providerÚimage_gen_providerzagent.image_gen_registryz)agent.image_gen_provider:ImageGenProviderzimage_gen providerzwRegister an :class:`agent.image_gen_provider.ImageGenProvider`; ``provider.name`` is matched by ``image_gen.provider``.rì   ÚanÚregister_video_gen_providerÚvideo_gen_providerzagent.video_gen_registryz)agent.video_gen_provider:VideoGenProviderzvideo_gen providerzwRegister an :class:`agent.video_gen_provider.VideoGenProvider`; ``provider.name`` is matched by ``video_gen.provider``.Úregister_web_search_providerÚweb_search_providerzagent.web_search_registryz+agent.web_search_provider:WebSearchProviderzweb providerz¥Register an :class:`agent.web_search_provider.WebSearchProvider`; ``provider.name`` is matched by ``web.search_backend`` / ``web.extract_backend`` / ``web.backend``.Úregister_browser_providerÚbrowser_providerzagent.browser_registryz&agent.browser_provider:BrowserProviderzbrowser providerz¸Register an :class:`agent.browser_provider.BrowserProvider`; ``provider.name`` is matched by ``browser.cloud_provider`` (consulted by ``tools.browser_tool_cloud._get_cloud_provider``).Ú&register_terminal_environment_providerÚterminal_environment_providerzagent.terminal_env_registryz7agent.terminal_env_provider:TerminalEnvironmentProviderzterminal environment provideru2  Register a :class:`agent.terminal_env_provider.TerminalEnvironmentProvider`; ``provider.name`` is matched by ``terminal.backend`` when no built-in backend has that name. Built-in names (local, docker, singularity, modal, daytona, vercel_sandbox, ssh) are rejected â€” plugins never shadow in-tree backends.rb  z6Plugin '%s' terminal environment provider rejected: %s)r  r  Úregister_secret_sourceÚsecret_sourcezagent.secret_sources.registryz&agent.secret_sources.base:SecretSourcezsecret sourceak  Register a :class:`agent.secret_sources.base.SecretSource`, run by ``load_hermes_dotenv()`` (after ``~/.hermes/.env``, before credentials are read) when ``secrets.<name>`` is enabled. The orchestrator owns ordering/precedence/provenance; the source only fetches. Since dotenv usually loads before discovery, the manager re-pulls enabled plugin sources afterwards.Úregister_sourcer†  )r  r  ÚparamÚregister_tts_providerÚtts_providerzagent.tts_registryzagent.tts_provider:TTSProviderzTTS providerzòRegister an :class:`agent.tts_provider.TTSProvider`; ``provider.name`` is matched by ``tts.provider`` unless it is a built-in name (rejected with a warning) or a ``tts.providers.<name>: type: command`` entry shares it (command-providers win).r  Úregister_transcription_providerÚtranscription_providerzagent.transcription_registryz2agent.transcription_provider:TranscriptionProviderztranscription providerz÷Register an :class:`agent.transcription_provider.TranscriptionProvider`; ``provider.name`` is matched by ``stt.provider`` unless it is a built-in name (rejected) or a ``stt.providers.<name>: type: command`` entry shares it (command-providers win).z?Tuple[Tuple[str, str, str, str, str, str, Dict[str, Any]], ...]Ú_SCOPED_PROVIDER_REGISTRARSc                ó"   — | j                  «       S rÅ   r  r  s    r[   r	  r	  5  s   € �q—w‘w“y€ r]   c                ó>   — | j                  «       j                  «       S rÅ   )r  rb  r  s    r[   r	  r	  5  s   € °Q·W±W³Y·_±_Ó5F€ r]   )r  rb  Nz3Dict[Optional[str], Optional[Callable[[str], str]]]Ú_NAME_NORMALIZERSc           	     ó.  ‡‡‡‡‡	‡
‡‡‡— |j                  d«      \  Š
Š	t        ‰j                  dd«         Š‰j                  d«      Šd
ˆ	ˆ
ˆˆˆˆˆˆfd„Šd
ˆfd„}‰j                  d«      dk(  r|n‰}| d	| › �|c|_        |_        |_        t        |«      S )z]Build one ``register_<category>_provider`` method from a ``_SCOPED_PROVIDER_REGISTRARS`` row.rg  r  r  r  c                óö   •— t        j                  ‰
«      }| j                  |‰t        t        j                  ‰«      ‰«      |‰‰j	                  dd«      ‰‰	rt        |‰	«      nd ‰j	                  d«      ¬«	      S )Nrì   ræ   r  )r÷   rê   r$  rë   rì   r  r  r  )Ú	importlibÚimport_moduler(  r<  rÖ   )r»   r#  r$  Ú	base_attrÚbase_modr÷   rë   Únormalize_fnrÖ  Úregister_nameÚregistry_mods      €€€€€€€€r[   r  z1_make_scoped_provider_registrar.<locals>.register?  su   ø€ Ü×*Ñ*¨<Ó8ˆØ×-Ñ-Ø˜4¬G´I×4KÑ4KÈHÓ4UÐW`Ó,aØ U°G·K±KÀ	È3Ó4OÐ[gÙ9F”W˜X }Ô5ÈDØ"Ÿ;™;Ð'7Ó8ð	 .ó 
ð 	
r]   c                ó   •—  ‰| |«      S rÅ   rd   )r»   r†  r  s     €r[   rž  z8_make_scoped_provider_registrar.<locals>.register_sourceH  s   ø€ Ù˜˜fÓ%Ð%r]   rŸ  r†  zPluginContext.rŒ  )Úsplitr§  rÖ   r`   rb   rc   r4   )Úmethod_namer÷   r°  Úbase_refrë   ÚdocrÖ  rž  Úmethodr¬  r­  r®  r  r¯  s    `` ` `  @@@@@r[   Ú_make_scoped_provider_registrarr·  9  sŽ   ÿø€ à"Ÿ.™.¨Ó-Ñ€HˆiÜ$ W§[¡[°¸gÓ%FÑG€LØ—K‘K 
Ó+€M÷
ô 
õ&ð !(§¡¨GÓ 4¸Ò @‰_Àh€FØ;FÈ.ÐYdÐXeÐHfÐhkÐ8€F„O�VÔ(¨&¬.Ü" 6Ó*Ð*r]   c                ó.   ‡ — t        ‰ «      ˆ fd„«       }|S )zçTurn a registrar into a no-op once the context's load timed out: the abandoned worker thread may
    still be executing register(), and a late registration would land in registries that the failure
    path already swept (#108139).c                ó¢   •— t        | dd«      r6t        j                  d| j                  j                  ‰j
                  «       y  ‰| g|¢­i |¤ŽS )Nrº   Fz9Plugin '%s' called %s() after its load timed out; ignored)r<  rq   rÑ   r¦   rÆ   r`   )r»   rä  rå  r¶  s      €r[   Úwrappedz-_ignore_after_abandoned_load.<locals>.wrappedY  sL   ø€ ä�4Ð*¨EÔ2Ü�N‰NØKÈTÏ]É]×M_ÑM_Ø—‘ôð Ù�dÐ,˜TÒ, VÑ,Ð,r]   ©r   )r¶  rº  s   ` r[   Ú_ignore_after_abandoned_loadr¼  U  s"   ø€ ô ˆ6ƒ]ó-ó ð-ð €Nr]   Ú	register_>   r8  rn  c                 ó²  — t         } 	 t        «       xs i j                  d«      }t        |t        «      r|j                  d«      €| S t        |d   «      }|dk  rt        j                  d|| «       | S |t        kD  r!t        j                  d|t        «       t        S |S # t        t        f$ r t        j                  d| «       | cY S t        $ r | cY S w xY w)a  Effective hook-callback timeout from ``plugins.hook_callback_timeout`` (default 30s; ``<= 0``
    disables the threaded path; clamped to ``_MAX_HOOK_CALLBACK_TIMEOUT_SECS``).

    ``invoke_hook`` calls this once per hook invocation; ``load_config_readonly()`` serves cache hits
    without ``_CONFIG_LOCK``, so this is a stat + dict lookup per call and needs no memo of its own.
    rT   Úhook_callback_timeoutz@plugins.hook_callback_timeout is not a number; using default %gsr   z?plugins.hook_callback_timeout=%g is negative; using default %gsz:plugins.hook_callback_timeout=%g exceeds max %gs; clamping)r?   r   rÖ   rè   r’  rŽ  r;  rÐ   rq   rÑ   r5  rA   )rØ   Úplugins_cfgr—  s      r[   Ú_resolve_hook_callback_timeoutrÁ  n  sÖ   € ô *€Gð	Ü+Ó-Ò3°×8Ñ8¸ÓCˆÜ˜+¤tÔ,°·±Ð@WÓ0XÐ0`ØˆNÜ˜Ð$;Ñ<Ó=ˆð �‚{Ü�‰ÐXÐZaÐcjÔkØˆØÔ0Ò0Ü�‰ÐSÐU\Ü6ô	8ä.Ð.Ø€Nøô ”zÐ"ò Ü�‰ÐYÐ[bÔcØŠÜò ØŠðús   ˆ?B  ÁB  Â 'CÃ	
CÃCc                  ó   — e Zd ZdZdd d„Zed!d„«       Zd"d„Zd#d„Zd$d„Z	d%d&d„Z
d'd	„Zd'd
„Zd'd„Zd(d„Z	 	 	 	 	 	 	 	 d)d„Zd*d„Zd+d„Zd,d„Zd-d„Z	 d	 	 	 	 	 	 	 d.d„Zd,d„Zd/d„Zd0d„Zd/d„Zd1d„Zd2d„Zd3d„Zd1d„Zd!d„Zd4d„Zd5d„Zd6d„Z y)7ÚPluginManagerz;Central manager that discovers, loads, and invokes plugins.Nc                óÒ  — |xs
 t        «       | _        t        | j                  «      | _        t	        j
                  «       | _        d| _        d | _        d | _	        d | _
        i | _        i | _        i | _        i | _        t        «       | _        t        «       | _        i | _        i | _        i | _        i | _        i | _        i | _        i | _        i | _        g | _        i | _        g | _        i | _        t	        j
                  «       | _        t	        j>                  | j<                  «      | _         d| _!        ddi| _"        tG        jH                  tJ        ¬«      | _&        d | _'        t	        jP                  «       | _)        i | _*        i | _+        i | _,        t	        jZ                  «       | _.        t^        | _0        t        «       | _1        i | _2        g | _3        g | _4        i | _5        i | _6        y )NFr   )Úmaxsize)7r   r  r	   r®  Ú	threadingÚRLockÚ_discovery_lockÚ_discoveredr¸  Ú_gateway_message_injectorrë  rÌ   rO  Ú_memory_hook_registrationsrT  Úsetr  r  rÍ  rÝ  rc  rz  Ú_portable_mcp_serversÚ_portable_mcp_server_pluginsr>  r`  r!  r'  Ú_plugin_loaded_listenersÚ_subscriptionsÚ_event_lockÚ	ConditionÚ_event_idleÚ_event_generationÚ_event_pending_by_generationÚqueueÚQueuer>   Ú_event_queueÚ_event_workerÚlocalÚ_emit_depthÚ_hook_running_callbacksÚ_hook_abandonedÚ_hook_timeout_suppressed_untilÚLockÚ_hook_timeout_lockr@   Ú!_hook_timeout_suppression_secondsÚ_hook_failures_reportedÚ_ownership_ledgerÚ_registration_orderÚ_persistent_carryoverÚ_predeclared_modulesÚ_predeclared_tools)r»   r  s     r[   r½   zPluginManager.__init__�  s¼  € ð #Ò7¤oÓ&7ˆŒÜ˜dŸn™nÓ-ˆŒÜ(Ÿ™Ó0ˆÔØ!&ˆÔØˆŒØIMˆÔ&Ø#ˆÔð
 24ˆŒØ13ˆŒà[]ˆÔ'Ø68ˆÔÜ,/«EˆÔÜ03³ˆÔ#Ø.0ˆÔØ13ˆÔØMOˆÔ$Ø9;ˆÔØ@BˆÔ"Ø<>ˆÔ)Ø57ˆŒØ46ˆÔ!Ø35ˆÔ#ØCEˆÔ(à8:ˆÔ%ð DFˆÔÜ$Ÿ?™?Ó,ˆÔÜ$×.Ñ.¨t×/?Ñ/?Ó@ˆÔØ!"ˆÔØ=>À¸FˆÔ)Ü.3¯k©kÔBTÔ.UˆÔØ9=ˆÔÜ$Ÿ?™?Ó,ˆÔð =?ˆÔ$Ø13ˆÔØBDˆÔ+Ü"+§.¡.Ó"2ˆÔÜ1RˆÔ.ä,/«EˆÔ$ð GIˆÔØ=?ˆÔ ð
 @BˆÔ"ð BDˆÔ!Ø8:ˆÕr]   c                ó   — | j                   duS )z@Return whether a live gateway can accept plugin-triggered turns.N©rÊ  r¿   s    r[   r½  z*PluginManager.has_gateway_message_injectorØ  s   € ð ×-Ñ-°TÐ9Ð9r]   c                ó   — ||f| _         y)z8Publish a live gateway injector and its lifecycle owner.Nré  )r»   rh  Úinjectors      r[   Úset_gateway_message_injectorz*PluginManager.set_gateway_message_injectorÝ  s   € à*/°Ð):ˆÕ&r]   c                óP   — | j                   �| j                   d   |u rd| _         yyy)z;Clear the injector only when it still belongs to ``owner``.Nr   ré  )r»   rh  s     r[   Úclear_gateway_message_injectorz,PluginManager.clear_gateway_message_injectorá  s3   € à×)Ñ)Ð5¸$×:XÑ:XÐYZÑ:[Ð_dÑ:dØ-1ˆDÕ*ð ;eÐ5r]   c                óN   — | j                   }|duxr t         |d   di |¤Ž«      S )z3Submit a plugin-triggered turn to the live gateway.Nr  rd   )rÊ  r®   )r»   rå  r�  s      r[   r¾  z$PluginManager.inject_gateway_messageæ  s0   € à×3Ñ3ˆ
Ø Ð%ÒG¬$¨}¨z¸!©}Ñ/F¸vÑ/FÓ*GÐGr]   c                óÖ  — | j                   r|st        «       ry| j                  5  t        | j                  «      5  | j                   r|s	 ddd«       ddd«       yt        d„ | j                  j                  «       D «       «      }|r| j                  «        t        d«      r.t        j                  d«       d| _         	 ddd«       ddd«       yd| _         	 | j                  «        | j                  «        | j                  «        |r| j                  «        ddd«       ddd«       | j#                  «       y# t         $ r	 d| _         ‚ w xY w# 1 sw Y   Œ8xY w# 1 sw Y   Œ<xY w)z£Scan all plugin sources and load each plugin found; ``force`` unloads first so config
        changes / new bundled backends become visible in long-lived sessions.Nc              3  óZ   K  — | ]#  \  }}|j                   rŒ|j                  rŒ |–— Œ% y ­wrÅ   )r±   r²   )rÇ   rA  Úps      r[   rÊ   z2PluginManager.discover_and_load.<locals>.<genexpr>ø  s&   è ø€ Ò%l©D¨A¨qÐQR×QXÓQXÐab×akÓak¤aÑ%lùs   ‚+—+¤+ÚHERMES_SAFE_MODEu/   HERMES_SAFE_MODE=1 â€” plugin discovery skippedTF)rÉ  r5   rÈ  r3   r®  Ú	frozensetrÌ   rÍ   Úunloadr   rq   r"  Ú_discover_and_load_innerÚ%_evict_stale_persistent_registrationsÚ'_refresh_secret_sources_after_discoveryÚ%_re_register_config_hooks_after_forceÚBaseExceptionÚ_notify_plugin_loaded)r»   ru   Úloaded_befores      r[   Údiscover_and_loadzPluginManager.discover_and_loadë  sH  € ð ×Ò¡EÔ.CÔ.Eð Ø×!Ñ!ñ $	Ô#5°d·n±nÓ#Eñ $	Ø×Ò©Ø÷$	÷ $	ð $	ô
 &Ñ%l°D·M±M×4GÑ4GÓ4IÔ%lÓlˆMÙØ—‘”ÜÐ1Ô2Ü—‘ÐMÔNØ#'�Ô Ø÷$	÷ $	ð $	ð  $ˆDÔðØ×-Ñ-Ô/ð ×:Ñ:Ô<ð ×<Ñ<Ô>Ùð
 ×>Ñ>Ô@÷C$	÷ $	ðL 	×"Ñ" =Õ1øô	 !ò Ø#(�Ô Øðú÷E$	ð $	ú÷ $	ð $	úsN   ¦E¼EÁEÁA$EÃEÃEÃAD>ÄEÄ>EÅEÅE	ÅEÅE(c                óº   — dD ])  \  }}	 t        j                  |«      j                  «        Œ+ y# t        $ r!}t        j                  d||«       Y d}~ŒRd}~ww xY w)z’Restore config-owned shell hooks/outbound webhooks after a force clear; each guarded
        independently so one failing does not skip the other.))z
shell-hookzagent.shell_hooks)zoutbound-webhookzagent.outbound_webhooksz'force-reload %s re-register skipped: %sN)rª  r«  Úre_register_config_hooksr5  rq   rt   )r»   rë   Úmodule_namer'  s       r[   rù  z3PluginManager._re_register_config_hooks_after_force  s`   € ð#Tò 	TÑˆE�;ðTÜ×'Ñ'¨Ó4×MÑMÕOñ	Tøô ò TÜ—‘ÐFÈÈs×SÑSûðTús   Š#0°	A¹AÁAc                ó  ‡— 	 ddl m} ddlm}m}  |«       }|sy	 ddlm}  |«       xs i j                  d«      xs i Šdˆfd„}|D �cg c]  } ||«      sŒt        |dd	«      ‘Œ }}|sy	 dd
l
m}	  |	«       }
 ||
«        ||
¬«       t        j                  ddj                  t        |«      «      «       y# t
        $ r Y yw xY w# t
        $ r i ŠY Œ–w xY wc c}w # t
        $ r }t        j                  d|«       Y d}~yd}~ww xY w)z»If any plugin secret source is enabled (per its own ``is_enabled(cfg)``, honoring custom
        activation), reset the cache and re-apply. Fail-open: never raises into discover_and_load.r   )Úlist_plugin_sources)Úload_hermes_dotenvÚreset_secret_source_cacheNr¦  Úsecretsc                óÄ   •— ‰j                  t        | dd«      «      }	 t        | j                  t	        |t
        «      r
|«      «      S i «      «      S # t        $ r Y yw xY w)NrÆ   r{  F)rÖ   r<  r®   Ú
is_enabledrè   r’  r5  )r†  rd  r  s     €r[   Ú_enabledzGPluginManager._refresh_secret_sources_after_discovery.<locals>._enabled6  s\   ø€ Ø—k‘k¤'¨&°&¸"Ó"=Ó>ˆGðÜ˜F×-Ñ-¼ÀGÌTÔ9R¨gÓ[Ó\Ð\ÐXZÓ[Ó\Ð\øÜò Ùðús   Ÿ)A Á		A Á	AÁArÆ   r{  ©r   )Úhermes_homez8Re-applied secret sources after plugin discovery for: %srW  z1secret source re-apply after discovery failed: %sr‹  )Úagent.secret_sources.registryr  Úhermes_cli.env_loaderr  r  r5  r©  r§  rÖ   r<  Úhermes_constantsr   rq   rt   rZ  r[  )r»   r  r  r  Úplugin_sourcesr§  r  ÚsÚenabled_namesr   Úhomer'  r  s               @r[   rø  z5PluginManager._refresh_secret_sources_after_discovery%  s
  ø€ ð	ÝIß[Ù0Ó2ˆNñ Øð	Ý5Ù"“}Ò*¨×/Ñ/°	Ó:Ò@¸bˆGõ	ð :HÖW°AÉ8ÐTUÍ;œ  F¨BÕ/ÐWˆÐWÙØð	Sõ 9Ù"Ó$ˆDÙ% dÔ+Ù¨4Õ0Ü�L‰LÐSØŸ™¤6¨-Ó#8Ó9õ;øô9 ò 	Ùð	ûô ò 	ØŠGð	üò Xøô ò 	SÜ�L‰LÐLÈc×RÑRûð	SúsG   ƒB: œ$C	 Á
CÁCÁ-AC Â:	CÃCÃ	CÃCÃ	DÃ(DÄDc           	     óÌ  — | j                  «       }|D �ch c]  }t        |«      ’Œ }}| j                  «       D �cg c]  }t        |«      |vsŒ|‘Œ }}t        j	                  dt        |«      «       |j                  |«       t        «       }t        «       }t        |«      }|r*t        j                  ddj                  |«      t        «       t        |«      }|j                  «       D �	�ci c]  \  }	}| j                  |||«      sŒ|	|“Œ }
}	}t!        |
«      D ]:  }|
|   }| j#                  |«       | j%                  |«       | j'                  |«       Œ< |rRt        j)                  dt        | j*                  «      t-        d„ | j*                  j/                  «       D «       «      «       | j1                  t3        |
j/                  «       «      «       yc c}w c c}w c c}}	w )u=   The actual discovery sweep â€” see :meth:`discover_and_load`.z  entrypoints: %d manifest(s)zqRemoved Hermes plugin %s is still listed in plugins.enabled; remove it and configure native Relay plugins with %srW  z/Plugin discovery complete: %d found, %d enabledc              3  ó:   K  — | ]  }|j                   sŒd –— Œ y­w)r  N)r¯   )rÇ   rò  s     r[   rÊ   z9PluginManager._discover_and_load_inner.<locals>.<genexpr>l  s   è ø€ ÒK !ÀÇÃœAÑKùs   ‚”N)Ú_collect_directory_manifestsr!   Ú_scan_entry_pointsrq   rt   r“  Úextendr'   r(   r   rÑ   rZ  r   r,   rÍ   Ú_gate_manifestr$   Ú_warn_python_dependenciesÚ_validate_plugin_config_schemaÚ_load_pluginr"  rÌ   ÚsumÚvaluesÚ_refresh_plugin_compat_reportr´   )r»   Ú	manifestsÚmÚdirectory_keysÚep_manifestsÚdisabledr¯   Ústale_relay_keysÚwinnersrA  Úto_loadÚ
lookup_keyr¦   s                r[   rö  z&PluginManager._discover_and_load_innerM  sž  € à*.×*KÑ*KÓ*Mˆ	ð 4=Ö=¨aœ, q�/Ð=ˆÐ=Ø#'×#:Ñ#:Ó#<Öf˜aÄÈQÃÐWeÒ@ešÐfˆÐfÜ�‰Ð4´c¸,Ó6GÔHØ×Ñ˜Ô&Ü(Ó*ˆÜ&Ó(ˆÜ3°GÓ<ÐÙÜ�N‰Nð RàŸ9™9Ð%5Ó6Ô8PôRô +¨9Ó5ˆØ$+§M¡M£O×a™D˜A˜q°t×7JÑ7JÈ1ÈhÐX_Õ7`�1�a‘4ÐaˆÑaÜ3°GÓ<ò 	(ˆJØ˜zÑ*ˆHØ×*Ñ*¨8Ô4Ø×/Ñ/°Ô9Ø×Ñ˜hÕ'ð		(ñ
 Ü�K‰KÐIÌ3ÈtÏ}É}ÓK]ÜÑK t§}¡}×';Ñ';Ó'=ÔKÓKôMà×*Ñ*¬4°·±Ó0@Ó+AÕBùò1 >ùÚfùó bs   •G»GÁGÃ-G Ä	G c                ó~   — 	 ddl m}  ||d¬«       y# t        $ r }t        j	                  d|«       Y d}~yd}~ww xY w)u¥  Refresh HERMES_HOME/.plugin-compat-report.json from this discovery pass (hermes_cli.plugin_compat).

        The Desktop boot modal has no Python runtime of its own and reads that file after the ``serve``
        backend is up, so the scan must run wherever plugins are discovered â€” not only under the CLI
        banner / doctor / update, which never run inside the Desktop's backend. Fail-open: never raises.
        r   )Úcompat_reportT©ru   z(plugin compat report refresh skipped: %sN)Úhermes_cli.plugin_compatr(  r5  rq   rt   )r»   r  r(  r'  s       r[   r  z+PluginManager._refresh_plugin_compat_reporto  s9   € ð	JÝ>Ù˜)¨4Ö0øÜò 	JÜ�L‰LÐCÀS×IÑIûð	Jús   ‚ “	<œ7·<c                ó‚  — t        |||«      }|j                  dk(  ry|j                  dk(  r| j                  |«       nY|j                  dk(  r| j                  |«       n8t	        ||j
                  |j                  ¬«      | j                  t        |«      <   |j                  rt        j                  |j                  Ž  y)zÝRoute one winning manifest per :func:`gate_manifest`: load now, defer, or record as
        skipped (introspection-only placeholder). Returns True only for plugins that go through the
        dependency-ordered load pass.ÚloadTÚload_nowÚdefer)r¦   r¯   r±   F)r+   Úactionr  Ú_register_deferred_platformr¥   r¯   r±   rÌ   r!   Úlogrq   )r»   r¦   r"  r¯   Úverdicts        r[   r  zPluginManager._gate_manifest|  s—   € ô   ¨(°GÓ<ˆØ�>‰>˜VÒ#ØØ�>‰>˜ZÒ'Ø×Ñ˜hÕ'Ø�^‰^˜wÒ&Ø×,Ñ,¨XÕ6ä4@Ø!¨7¯?©?À'Ç-Á-ô5QˆD�M‰Mœ, xÓ0Ñ1à�;Š;Ü�J‰J˜Ÿ™Ñ$Ør]   c          	     óú  — ddl m} t        |«      j                  «       j	                  «       }|dk(  rt        d«      ‚t        j                  d|«      st        d«      ‚t        |«      st        d«      ‚|| j                  v r*| j                  |   j                  }t        d|›d	|›�«      ‚ ||||t        t        «       j                  «       «      ¬
«      | j                  |<   t        j                  d||«       y)zµManager-level registration (public API kept for out-of-tree plugins); the PluginContext
        method is the tracked path plugins normally use. Same validation, no unload tracking.r   rQ  rS  rT  rU  rV  rW  rX  rY  rZ  r]  N)r_  rR  ra  r  rb  rÐ   rc  rd  r:  r;  r`  rÂ   r   rX   rq   r"  )r»   rÆ   re  rÂ   rR  rg  rh  s          r[   ri  z)PluginManager.register_approval_transport�  sç   € õ 	NÜ�D“	—‘Ó!×'Ñ'Ó)ˆØ�IÒÜÐLÓMÐMÜ�|‰|Ð7¸Ô?ÜÐZÓ[Ð[Ü˜
Ô#ÜÐLÓMÐMØ�D×-Ñ-Ñ-Ø×-Ñ-¨eÑ4×>Ñ>ˆEÜÐ2°5°)Ð;UÐV[ÐU^Ð_Ó`Ð`Ù+FØ 
°iÌcÔRaÓRc×RkÑRkÓRmÓNnô,
ˆ×!Ñ! %Ñ(ô 	�‰ÐAÀ9ÈeÕTr]   c                óè   — | j                   j                  t        |«      j                  «       j	                  «       «      }|�.|j
                  t        t        «       j                  «       «      k7  ry|S )z>Return a transport only inside the profile that registered it.N)r`  rÖ   ra  r  rb  r\  r   rX   )r»   rÆ   r�  s      r[   Úget_approval_transportz$PluginManager.get_approval_transport£  sY   € à×.Ñ.×2Ñ2´3°t³9·?±?Ó3D×3JÑ3JÓ3LÓMˆ
ØÐ ×!8Ñ!8¼CÄÓ@Q×@YÑ@YÓ@[Ó<\Ò!\ØØÐr]   c                ó   — t        «       S )zVDirectory manifests in full-discovery order (see :func:`collect_directory_manifests`).)r)   r¿   s    r[   r  z*PluginManager._collect_directory_manifestsª  s   € ä*Ó,Ð,r]   c                óX  — t        d«      ry|j                  d«      }t        |t        «      sydd„} ||j                  d«      «      } ||j                  dg «      «      }|sy| j	                  «       D �ci c]  }t        |«      |“Œ c}j                  «       D ]n  \  }}||j                  h}	|j                  r
|	|z  s|	|z  sŒ+	 ddl	m
}
  |
t        |j                  «      t        «       d	z  |j                  xs |z  g d¬
«      r yŒp yc c}w # t        t         t"        f$ r Y Œ�w xY w)z˜Probe enabled portable MCP packages without loading plugins (shares the full-discovery
        manifest collection so precedence/gating cannot diverge).ró  FrT   c                ó‚   — t        | t        «      r!| D �ch c]  }t        |t        «      sŒ|’Œ c}S t        «       S c c}w rÅ   )rè   r´   ra  rÌ  )rÛ   Úvs     r[   Ú_namesz6PluginManager.has_enabled_portable_mcp.<locals>._names·  s2   € Ü?IÈ%ÔQUÔ?V˜uÖ;˜!¬
°1´cÕ(:’AÒ;ÐaÔ\_Ó\aÐaùÒ;s   •<«<r¯   r"  r   )Ú_discover_mcpzplugin-data)Úcreate_dataT)rÛ   r
   r  r¡   )Ú_env_enabledrÖ   rè   r’  r  r!   rÍ   rÆ   ry  Úhermes_cli.agent_pluginsr;  r	   rq  r   rà   ÚOSErrorÚRuntimeErrorrÐ   )r»   Ú
raw_configÚplugins_configr:  r¯   r"  r  r&  r¦   Únamesr;  s              r[   Úhas_enabled_portable_mcpz&PluginManager.has_enabled_portable_mcp®  s5  € ô Ð*Ô+ØØ#Ÿ™¨	Ó2ˆÜ˜.¬$Ô/Øó	bñ ˜×+Ñ+¨IÓ6Ó7ˆÙ˜.×,Ñ,¨Z¸Ó<Ó=ˆÙØØAE×AbÑAbÓAdÖ$e¸A¤\°!£_°aÑ%7Ò$e×$kÑ$kÓ$mò 
	Ñ ˆJ˜Ø §¡Ð/ˆEØ×$Ò$¨°Ò(8ÀÈÂØðÝBÙ ¤ h§m¡mÓ!4´oÓ6GÈ-Ñ6WØ$,×$<Ñ$<Ò$JÀ
ñ7LØMOÐ]bõdáðdð
	ð ùò %føô œ\¬:Ð6ò Ùðús   Á7DÃADÄD)Ä(D)c                ó   — t        |||¬«      S )z9Read manifests under *path* (see :func:`scan_directory`).)Ú
skip_names)r-   )r»   rq  r†  rF  s       r[   Ú_scan_directoryzPluginManager._scan_directoryË  s   € ô ˜d F°zÔBÐBr]   c                ó   — t        «       S )zORead installed plugin entry points (see :func:`discover_entrypoint_manifests`).)r*   r¿   s    r[   r  z PluginManager._scan_entry_pointsÑ  s   € ä,Ó.Ð.r]   c                ó,   — t        | j                  «      S )zW``(action_id, callback, plugin_name)`` tuples for the Slack adapter to wire at connect.)r´   r!  r¿   s    r[   Úget_slack_action_handlersz'PluginManager.get_slack_action_handlersÕ  s   € ä�D×/Ñ/Ó0Ð0r]   c                óŒ   — t        | j                  j                  |xs dj                  «       j	                  «       g «      «      S )z¨``(factory, plugin_name)`` tuples for one platform; adapters call ``factory(native,
        adapter)`` at connect (see :meth:`PluginContext.register_platform_handler`).r{  )r´   r'  rÖ   r  rb  )r»   r  s     r[   Úget_platform_handler_factoriesz,PluginManager.get_platform_handler_factoriesÙ  s9   € ô �D×4Ñ4×8Ñ8¸(º.Àb×9OÑ9OÓ9Q×9WÑ9WÓ9YÐ[]Ó^Ó_Ð_r]   c                ó$   — | j                  d«      S )zEBack-compat alias for ``get_platform_handler_factories("telegram")``.r+  )rL  r¿   s    r[   Úget_telegram_handler_factoriesz,PluginManager.get_telegram_handler_factoriesÞ  s   € à×2Ñ2°:Ó>Ð>r]   c                óB  — t        | j                  j                  «       «      D ��cg c]ë  \  }}|j                  j                  t        |j                  «      |j                  j                  |j                  j                  |j                  j                  |j                  j                  |j                  t        |j                  «      t        |j                  «      t        |j                  «      t        |j                  «      |j                   dœ‘Œí c}}S c c}}w )z7Return a list of info dicts for all discovered plugins.)rÆ   rÈ   r÷   Úversionrr  r†  r¯   ÚtoolsÚhooksrS  Úcommandsr±   )r[  rÌ   rÍ   r¦   rÆ   r!   r÷   rP  rr  r†  r¯   r“  rª   r«   r¬   r­   r±   )r»   Ú_keyrò  s      r[   Úlist_pluginszPluginManager.list_pluginsâ  sÌ   € ô $ D§M¡M×$7Ñ$7Ó$9Ó:÷
ñ �$˜ð Ÿ
™
Ÿ™´¸Q¿Z¹ZÓ0HÐRS×R\ÑR\×RaÑRaØŸ:™:×-Ñ-¸a¿j¹j×>TÑ>TØŸ*™*×+Ñ+¸¿	¹	ÌCÐPQ×PbÑPbÓLcÜ˜Q×/Ñ/Ó0ÄÀA×D[ÑD[Ó@\Ü × 5Ñ 5Ó6ÀÇÁóó
ð 	
ùó 
s   §C0Dc                óJ   — | j                   j                  |«      }|r|d   S dS )z>Return the ``Path`` to a plugin skill's SKILL.md, or ``None``.rq  N)rz  rÖ   )r»   Úqualified_namerÚ   s      r[   Úfind_plugin_skillzPluginManager.find_plugin_skillî  s)   € à×#Ñ#×'Ñ'¨Ó7ˆÙ %ˆu�V‰}Ð/¨4Ð/r]   c                óf   ‡— |› d�Št        ˆfd„| j                  j                  «       D «       «      S )zCReturn sorted bare names of all skills registered by *plugin_name*.rg  c              3  óR   •K  — | ]  \  }}|j                  ‰«      sŒ|d    –— Œ  y­w)rr  N)Ú
startswith)rÇ   Úqnr	  rõ  s      €r[   rÊ   z3PluginManager.list_plugin_skills.<locals>.<genexpr>ö  s(   øè ø€ Òg©¨¨QÐQS×Q^ÑQ^Ð_eÕQf�a˜•nÑgùs   ƒ'�
')r[  rz  rÍ   )r»   r  rõ  s     @r[   Úlist_plugin_skillsz PluginManager.list_plugin_skillsó  s/   ø€ à�= Ð"ˆÜÓg°$×2EÑ2E×2KÑ2KÓ2MÔgÓgÐgr]   c                óè   — t        | j                  j                  «       «      D ��cg c]>  \  }}|t        |j	                  dd«      «      dt        |j	                  di «      «      dœ‘Œ@ c}}S c c}}w )zDReturn progressive-disclosure metadata for registered plugin skills.rr  r{  rÊ  rs  )rÆ   rr  Úcategoryrs  )r[  rz  rÍ   ra  rÖ   r’  )r»   r|  rÚ   s      r[   Úlist_plugin_skill_metadataz(PluginManager.list_plugin_skill_metadataø  sk   € ô '-¨T×-@Ñ-@×-FÑ-FÓ-HÓ&I÷	
ñ #�)˜Uð "´#°e·i±iÀÈrÓ6RÓ2SØ$´T¸%¿)¹)ÀMÐSUÓ:VÓ5Wóó
ð 	
ùó 
s   §AA.c                ó,   — t        | j                  «      S rÅ   )r®   rÍ  r¿   s    r[   Úhas_portable_mcp_serversz&PluginManager.has_portable_mcp_servers  s   € Ü�D×.Ñ.Ó/Ð/r]   c                ó|   — | j                   j                  «       D ��ci c]  \  }}|t        |«      “Œ c}}S c c}}w )z?Return a defensive copy of enabled portable MCP server configs.)rÍ  rÍ   r’  )r»   rÆ   rÕ   s      r[   Úget_portable_mcp_serversz&PluginManager.get_portable_mcp_servers  s2   € à7;×7QÑ7Q×7WÑ7WÓ7Y×Z¡| t¨V�”d˜6“lÑ"ÓZÐZùÓZs   ž8c                ó,   — t        | j                  «      S rÅ   )r’  rÎ  r¿   s    r[   Úget_portable_mcp_server_pluginsz-PluginManager.get_portable_mcp_server_plugins  s   € Ü�D×5Ñ5Ó6Ð6r]   c                ó<   — | j                   j                  |d«       y)z>Remove a stale registry entry (silently ignores missing keys).N)rz  Úpop)r»   rW  s     r[   Úremove_plugin_skillz!PluginManager.remove_plugin_skill  s   € à×Ñ×Ñ °Õ5r]   rÅ   )r  r°   r  r€  r‹  )rh  Úobjectrë  zCallable[..., bool]r  r€  )rh  rj  r  r€  )rå  r
   r  r®   ©F©ru   r®   r  r€  r~  )r  úList[PluginManifest]r  r€  )r¦   r   r"  r¡   r¯   úOptional[Set[str]]r  r®   )rÆ   ra  re  r   rÂ   ra  r  r€  )rÆ   ra  )r  rm  ©rA  úMapping[str, Any]r  r®   )rq  r	   r†  ra  rF  rn  r  rm  ©r  úList[tuple])r  ra  r  rr  ©r  zList[Dict[str, Any]])rW  ra  r  zOptional[Path])r  ra  r  r©   )r  zDict[str, Dict[str, Any]])r  zDict[str, str])rW  ra  r  r€  )!r`   ra   rb   rc   r½   rŽ  r½  rì  rî  r¾  rý  rù  rø  rö  r  r  ri  r5  r  rD  rG  r  rJ  rL  rN  rU  rX  r]  r`  rb  rd  rf  ri  rd   r]   r[   rÃ  rÃ  Š  sú   „ ÙEôI;ðV ò:ó ð:ó;ó2ó
Hô
.2ó`Tó&SóP CóDJðØ&ðØ2:ðØEWðà	óó(Uó&ó-óð< IMðCØðCØ"%ðCØ3EðCà	óCó/ó1ó`ó
?ó

ó0ó
hó

ó0ó[ó7ô6r]   rÃ  úOptional[PluginManager]Ú_plugin_managerzDict[Path, PluginManager]Ú_plugin_managers_by_homec                 óž   — 	 t        «       j                  «       j                  «       S # t        $ r t        «       j                  «       cY S w xY w)u·   Resolved active Hermes home â€” the key for per-profile plugin managers (plugins capture the
    home at registration, so a process serving several profiles cannot share one manager).)r   Ú
expanduserrX   r5  rd   r]   r[   Ú_plugin_home_keyry    sC   € ð.ÜÓ ×+Ñ+Ó-×5Ñ5Ó7Ð7øÜò .ÜÓ ×+Ñ+Ó-Ò-ð.ús   ‚%( ¨!AÁAc                ól  — | €yt        | di «      j                  «       D ]‡  }t        t        |dd«      dd«      }|r|j                  t        › d�«      sŒ6t	        |«       t
        5  t        j                  |«      | j                  k(  rt        j                  |d«       ddd«       Œ‰ y# 1 sw Y   Œ”xY w)uÇ   Purge ``sys.modules`` entries for this manager's directory plugins (package AND submodules â€”
    otherwise a same-slug plugin in another profile reuses the previous profile's submodule state).
    NrÌ   r§   r`   rð   )
r<  r  r[  r1   r2   r0   r/   rÖ   r  rh  )r¼   rÉ   r   s      r[   Ú_clear_plugin_submodulesr{  &  s¬   € ð €ØÜ˜' :¨rÓ2×9Ñ9Ó;ò :ˆÜœg f¨h¸Ó=¸zÈ4ÓPˆÙ +×"8Ñ"8¼J¸<ÀqÐ9IÔ"JØÜ�{Ô#Ü#ñ 	:Ü!×%Ñ% kÓ2°g×6GÑ6GÒGÜ"×&Ñ& {°DÔ9÷	:ð 	:ñ:÷
	:ð 	:ús   Á&9B*Â*B3	c                 ó8  — t        «       } t        5  t        �6t        t        j	                  «       vrt        t        | <   t        cddd«       S t        j                  | «      }|€t        t        | «      ¬«      }|t        | <   |a|cddd«       S # 1 sw Y   yxY w)z™Return the plugin manager for the active Hermes profile/home (cached per resolved home; a
    profile switch gets its own manager and plugin submodules).N)r  )ry  Ú_plugin_managers_lockru  rv  r  rÖ   rÃ  r   )Úcurrent_homer¼   s     r[   Úget_plugin_managerr  6  sŽ   € ô $Ó%€LÜ	ñ ô Ð&¬?ÔBZ×BaÑBaÓBcÑ+cÜ5DÔ$ \Ñ2Ü"÷ñ ô +×.Ñ.¨|Ó<ˆØˆ?Ü#¬o¸lÓ.KÔLˆGØ5<Ô$ \Ñ2Ø!ˆØ÷÷ ò ús   ‘3BÁ8BÂBc                 ó  — t         5  t        t        j                  t        j                  «       «      «      } t        �t        | vr| j                  t        «       | D ]  }t        |«       	 |j                  «        Œ  t        j                  «        daddd«       	 ddlm}  |«        y# t        $ r t        j                  dd¬«       Y Œpw xY w# 1 sw Y   Œ>xY w# t        $ r t        j                  dd¬«       Y yw xY w)zPTest-only: drop every cached manager and its submodules for a fully clean slate.Nz!test plugin-manager unload failedTr¶  r   )Úclear_providersz$dashboard-auth registry clear failed)r}  r´   r’  Úfromkeysrv  r  ru  r"  r{  rõ  r5  rq   rt   Úclearr  r�  )Úmanagersr¼   r�  s      r[   Ú _reset_plugin_managers_for_testsr…  I  sä   € ô 
ñ ÜœŸ™Ô&>×&EÑ&EÓ&GÓHÓIˆÜÐ&¬?À(Ñ+JØ�O‰OœOÔ,Øò 	QˆGÜ$ WÔ-ðQØ—‘Õ ð	Qô 	!×&Ñ&Ô(Øˆ÷ðLÝFÙÕøô ò QÜ—‘Ð@È4�ÖPðQú÷ð ûô" ò LÜ�‰Ð;ÀdˆÖKðLúsB   ‡A$CÁ,B+Á<CÂC Â+ CÃCÃCÃCÃCÃ D Ã?D c                ó4   — t        «       j                  | «      S )z�Whether config enables a portable package with MCP servers (manifest-only scan on a fresh
    manager; imports nothing, mutates no registry).)rÃ  rD  )rA  s    r[   Úhas_enabled_agent_plugin_mcpr‡  a  s   € ô ‹?×3Ñ3°JÓ?Ð?r]   c                óL   — t        «        t        «       j                  | ¬«       y)z�Discover and load all plugins (idempotent; ``force=True`` rescans). Joins an in-flight
    background discovery instead of racing a second scan.r)  N)Ú_join_background_discoveryr  rý  r)  s    r[   Údiscover_pluginsrŠ  g  s   € ô Ô ÜÓ×*Ñ*°Ð*Õ7r]   zOptional[threading.Thread]Ú_background_discovery_threadc                 ó  ‡— t        «       Š‰j                  ryt        5  t        �t        j	                  «       r
	 ddd«       ydˆfd„} t        j                  | dd¬«      at        j                  «        ddd«       y# 1 sw Y   yxY w)zäRun discovery in a daemon thread to overlap the rest of CLI startup (~150ms). Every
    synchronous consumer joins it via :func:`discover_plugins`, so no one sees a half-loaded
    registry. No-op when already done or in flight.Nc                 óˆ   •— 	 ‰ j                  «        t        «        y # t        $ r t        j	                  dd¬«       Y y w xY w)Nz"background plugin discovery failedTr¶  )rý  Ú_persist_plugin_toolset_keysr5  rq   rÑ   ©r¼   s   €r[   Ú_runz/start_background_plugin_discovery.<locals>._run~  s=   ø€ ðTØ×)Ñ)Ô+Ü,Õ.øÜò TÜ—‘ÐCÈd�ÖSðTús   ƒ ž AÁ Azplugin-discoveryT)ÚtargetrÆ   Údaemonr~  )r  rÉ  Ú_background_discovery_lockr‹  Úis_aliverÆ  ÚThreadÚstart)r�  r¼   s    @r[   Ú!start_background_plugin_discoveryr—  r  s{   ø€ ô
 !Ó"€GØ×ÒØÜ	#ñ -Ü'Ð3Ô8T×8]Ñ8]Ô8_Ø÷-ð -õ	Tô (1×'7Ñ'7¸tÐJ\ÐeiÔ'jÐ$Ü$×*Ñ*Ô,÷-÷ -ñ -ús   ŸA?Á2A?Á?BrŠ  c                óš   — t         }|�0|j                  «       r |t        j                  «       u s
t	        «       ry|j                  | ¬«       y)u    Wait for an in-flight background discovery (no-op from its own thread or a plugin-load worker it
    spawned â€” that worker's parent is blocked waiting on it).N©r—  )r‹  r”  rÆ  Úcurrent_threadr5   rZ  )r—  Úts     r[   r‰  r‰  ‰  s=   € ô 	%€AØ€y˜Ÿ
™
œ¨¬Y×-EÑ-EÓ-GÑ(GÔK`ÔKbØØ‡F�F�7€FÕr]   c                 ó"   — t        «       dz  dz  S )NÚcachezplugin_toolset_keys.jsonr	  rd   r]   r[   Ú_plugin_toolset_keys_cache_pathrž  ’  s   € ÜÓ˜wÑ&Ð)CÑCÐCr]   c            	     óL  — 	 ddl m}  t        t        «       D ��ch c]  \  }}}|’Œ
 c}}«      }	 t        t	        «       j                  «       «      } | t        «       ||dœdd¬«       yc c}}w # t        $ r g }Y Œ+w xY w# t        $ r t        j                  dd¬	«       Y yw xY w)
zJPersist discovered plugin toolset keys + portable MCP names (best-effort).r   )Úatomic_json_write)Útoolset_keysÚportable_mcpNi€  )ÚindentÚmodez!plugin toolset key persist failedTr¶  )
Úutilsr   r[  Úget_plugin_toolsetsr  rd  r5  rž  rq   rt   )r   Úts_keyr0  Úkeysry  s        r[   rŽ  rŽ  –  s¨   € ð	IÝ+ÜÔ2EÓ2G×H¡, &¨!¨Q’vÓHÓIˆð	ÜÔ0Ó2×KÑKÓMÓNˆHñ 	Ô9Ó;ÈdÐdlÑ=mÐvzð  BGö  	Hùó Iøô ò 	ØŠHð	ûô ò IÜ�‰Ð8À4ˆÖHðIúsD   ‚B  šA)
§B  °!A/ ÁB  Á)B  Á/A=Á:B  Á<A=Á=B  Â  B#Â"B#c                óö  — t        «       }t        }|duxr |j                  «       }|j                  r
|s ||«      S |ržt	        t
        «      5  t        j                  t        «       j                  d¬«      «      }t        |t        «      r|j                  | «      nd}t        |t        «      r&t        d„ |D «       «      rt        |«      cddd«       S ddd«       t!        «         ||«      S # 1 sw Y   ŒxY w)z\Shared body of the ``*_nowait`` probes: live registry, else last launch's cache, else block.Nzutf-8)Úencodingc              3  ó<   K  — | ]  }t        |t        «      –— Œ y ­wrÅ   )rè   ra  )rÇ   r9  s     r[   rÊ   z%_nowait_plugin_set.<locals>.<genexpr>¯  s   è ø€ Ò/SÀq´
¸1¼c×0BÑ/Sùs   ‚)r  r‹  r”  rÉ  r   r5  r   r¡  rž  Ú	read_textrè   r’  rÖ   r´   r<  rÌ  rŠ  )Úcache_fieldÚliver¼   r›  Ú	in_flightÚblobr  s          r[   Ú_nowait_plugin_setr±  ¤  sÌ   € ä Ó"€GÜ$€AØ˜�Ò. !§*¡*£,€IØ×Ò¡9Ù�G‹}ÐÙÜ”iÓ ñ 	#Ü—:‘:Ô=Ó?×IÑIÐSZÐIÓ[Ó\ˆDÜ.8¸¼tÔ.D�T—X‘X˜kÔ*È$ˆFÜ˜&¤$Ô'¬CÑ/SÈFÔ/SÔ,SÜ˜6“{÷		#÷ 	#ñ 	#ô
 ÔÙ�‹=Ð÷	#ð 	#ús   ÁA=C/Ã/C8c                 ó   — t        dd„ «      S )a  Plugin toolset keys without blocking on in-flight discovery: live registry when done, last
    launch's persisted set while a background scan runs (callers only EXCLUDE these keys, so a stale
    set is harmless and self-heals), else block via discover_plugins().r¡  c                óJ   — t        «       D ��ch c]  \  }}}|’Œ
 c}}S c c}}w rÅ   )r¦  )Ú_mr§  r0  s      r[   r	  z0get_plugin_toolset_keys_nowait.<locals>.<lambda>¹  s   € ÔUhÓUj×9kÁ\ÀVÈQÐPQº&Ó9k€ ùÓ9ks   Ž©r±  rd   r]   r[   Úget_plugin_toolset_keys_nowaitr¶  µ  s   € ô ˜nÑ.kÓlÐlr]   c                 ó   — t        dd„ «      S )zSPortable MCP server names; same contract as :func:`get_plugin_toolset_keys_nowait`.r¢  c                ó4   — t        | j                  «       «      S rÅ   )rÌ  rd  )r  s    r[   r	  z6get_portable_mcp_server_names_nowait.<locals>.<lambda>¾  s   € ¼¸A×<VÑ<VÓ<XÓ8Y€ r]   rµ  rd   r]   r[   Ú$get_portable_mcp_server_names_nowaitr¹  ¼  s   € ä˜nÑ.YÓZÐZr]   c                 óh   — t        «       } t        | dd«      st        «        | j                  «        | S )u†  Active manager, lazily discovering if it never ran â€” delivery must not depend on WHICH
    surface imported us (dashboards/TUI/cron never import model_tools). ``getattr`` default
    ``True`` leaves test doubles untouched.

    Hook/middleware delivery must not depend on WHICH surface imported us: dashboards, TUI slash workers,
    query mode, and cron delivery paths never import ``model_tools`` (whose import side-effect is the
    discovery trigger on the interactive CLI path), so hooks registered by user plugins were silently dead
    on those surfaces (#50776, #67597, #67890, #50937; tracking #64178 â€” salvaged from PR #64188).
    rÉ  T)r  r<  r‰  rý  r�  s    r[   Ú_delivery_managerr»  Á  s/   € ô !Ó"€GÜ�7˜M¨4Ô0Ü"Ô$Ø×!Ñ!Ô#Ø€Nr]   c                ó8   —  t        «       j                  | fi |¤ŽS )aó  Invoke a lifecycle hook (lazy-discovers first); return non-``None`` callback results.

    Hot-path / observer hooks in ``_HOOK_TIMEOUT_BOUNDED_HOOKS`` and the policy hook ``pre_tool_call`` are
    bounded by ``plugins.hook_callback_timeout`` (default 30s). On timeout the worker is abandoned (not
    joined) so we do not reintroduce the #6622 hang. Timed-out or still-running ``pre_tool_call`` callbacks
    fail closed with a block directive; other bounded hooks fail open (skip).
    Ensures plugins are discovered on first invocation so callers in processes that never explicitly call
    ``discover_plugins()`` (gateway platform events, TUI slash workers, query mode, cron) still fire
    callbacks registered by user plugins (tracking #64178).
    )r»  Úinvoke_hook©rP  rå  s     r[   r½  r½  Ò  s    € ð +ÔÓ×*Ñ*¨9Ñ?¸Ñ?Ð?r]   c              ‹  óT   K  —  t        «       j                  | fi |¤Žƒ d{  –—† S 7 Œ­w)z°:func:`invoke_hook` for callers on an event loop: ``async def`` callbacks are awaited
    there instead of bridged through a helper thread (see ``PluginManager.ainvoke_hook``).N)r»  Úainvoke_hookr¾  s     r[   rÀ  rÀ  à  s*   è ø€ ð 2Ô"Ó$×1Ñ1°)ÑF¸vÑF×FÐFÐFús   ‚(¡&¢(c                ó4   — t        «       j                  | «      S )z@Render plugin prompt sections after idempotent plugin discovery.)Ú_ensure_plugins_discoveredÚrender_system_prompt_sections)Úsession_infos    r[   rÃ  rÃ  æ  s   € ä%Ó'×EÑEÀlÓSÐSr]   c                ó8   —  t        «       j                  | fi |¤ŽS )uÐ   Invoke registered middleware callbacks (lazy-discovers like :func:`invoke_hook`).

    Lazy-discovers plugins on first use â€” same delivery-parity guarantee as :func:`invoke_hook` (tracking
    #64178).
    )r»  Úinvoke_middleware)r÷   rå  s     r[   rÆ  rÆ  ë  s    € ð 1ÔÓ×0Ñ0°Ñ@¸Ñ@Ð@r]   c                ó²   — t        «       }t        |dd«      }t        |«      rt         || «      «      S t        t        |di «      j	                  | «      «      S )aL  True when middleware is registered for ``kind``; lazy-discovers first since callers gate
    :func:`invoke_middleware` on it.

    Lazy-discovers first: callers use this as a gate before :func:`invoke_middleware`, so a pre-discovery
    ``False`` here would silently skip delivery on surfaces that never ran discovery (#64178).
    Úhas_middlewareNrT  )r»  r<  r:  r®   rÖ   )r÷   r¼   r¶  s      r[   rÈ  rÈ  ô  sQ   € ô  Ó!€GÜ�WÐ.°Ó5€FÜ�ÔÜ‘F˜4“LÓ!Ð!Ü”˜ °Ó3×7Ñ7¸Ó=Ó>Ð>r]   c                ó4   — t        «       j                  | «      S )uÏ   True when a loaded plugin handles a hook (lazy-discovers first, like :func:`has_middleware`).

    Lazy-discovers first â€” same gate-before-invoke rationale as :func:`has_middleware` (tracking #64178).
    )r»  Úhas_hook©rP  s    r[   rÊ  rÊ    s   € ô
 Ó×'Ñ'¨	Ó2Ð2r]   c                ó4   — t        «       j                  | «      S )z<Return a stable snapshot of callbacks registered for a hook.)r  Úiter_hook_callbacksrË  s    r[   rÍ  rÍ  
  s   € äÓ×3Ñ3°IÓ>Ð>r]   )r°  r  c           	     ó8  — 	 t        «       }|j                  d«      sy|j                  d| |||||¬«      }|D ]4  }t        |t        «      sŒd|v sd|v sŒt
        j                  d||| «       Œ6 y# t        $ r }	t
        j                  d|	«       Y d}	~	yd}	~	ww xY w)zžFire the observer-only ``pre_command`` hook; never raises. Directive-shaped returns are
    logged at debug so future block/rewrite adopters are discoverable.ry   N)ÚsurfacerÙ  Ú
alias_usedÚargs_rawr°  r  r/  Údecisionzžpre_command is observer-only in v1: ignoring directive %r for /%s (surface=%s). Block/rewrite will arrive with the command middleware variant (#64204/#64231).z0pre_command hook dispatch failed (non-fatal): %s)r  rÊ  r½  rè   r’  rq   rt   r5  )
rÏ  rÙ  rÐ  rÑ  r°  r  r¼   Úresultsrœ  r'  s
             r[   Úfire_pre_command_hookrÔ    s¯   € ðNÜ$Ó&ˆØ×Ñ Ô.ØØ×%Ñ%Ø 7°GÈ
Ø¨;Àð &ó 
ˆð ò 	7ˆFÜ˜&¤$Õ'¨X¸Ñ-?À:ÐQWÒCWÜ—‘ð nà# W¨gõ7ñ	7øô
 ò NÜ�‰ÐGÈ×MÑMûðNús(   ‚A0 ž-A0 ÁA0 ÁA0 Á0	BÁ9BÂBT)Úfrozenc                  óF   — e Zd ZU dZded<   dZded<   dZded<   dZded<   y)Ú_PreToolCallDirectiveNr°   r/  ÚmessageÚrule_keyr‰  Úmodified_args)r`   ra   rb   r/  r³   rØ  rÙ  rÚ  rd   r]   r[   r×  r×  )  s+   … à €FˆMÓ Ø!€Gˆ]Ó!Ø"€HˆmÓ"Ø.2€MÐ+Ô2r]   r×  c                ó0   — | t         _        |t         _        y rÅ   )Ú_thread_tool_whitelistÚallowedÚfmt)rÝ  Údeny_msg_fmts     r[   Úset_thread_tool_whitelistrà  1  s   € ð &-ÔÔ"Ø!-ÔÕr]   c                 ó   — d t         _        y rÅ   )rÜ  rÝ  rd   r]   r[   Úclear_thread_tool_whitelistrâ  9  s   € Ø%)ÔÕ"r]   r{  c                ó,  — t        t        dd«      }|�2| |vr.t        t        dd«      }	t        d|	j                  | ¬«      ¬«      S dd	lm}
  |
d
| t        |t        «      r|ni |||||t        |xs g «      ¬«	      }d}d}|D ]î  }t        |t        «      sŒ|j                  d«      }|dk(  r@|j                  d«      }t        |t        «      r|ri |�|nt        |t        «      r|ni ¥|¥}Œj|dvrŒo|j                  d«      }t        |t        «      r|r|nd}|dk(  r|sŒž|dk(  rt        d||¬«      c S |�Œ¶|j                  d«      }|t        |t        «      r|j                  «       xs dndf}Œð |�t        d|d   |d   |¬«      S t        |¬«      S )a  Check ``pre_tool_call`` hooks for ``{"action": "block", "message"}`` (veto; message becomes
    the tool result) or ``{"action": "approve", "message", "rule_key"?}`` (escalate ANY tool to the
    human-approval gate; ``rule_key`` picks the ``[a]lways`` allowlist grain). Precedence is
    ``block`` > ``approve`` > none, not registration order: any plugin's valid veto wins over an
    earlier plugin's request for human confirmation (#87420); among approves the first valid one
    wins. Irrelevant returns are ignored.rÝ  NrÞ  zTool '{tool_name}' deniedÚblock)r¯  )r/  rØ  r   )r½  r}   )r¯  rä  Útask_idÚ
session_idÚtool_call_idÚturn_idÚapi_request_idÚmiddleware_tracer/  Úmodifyrä  )rä  ÚapproverØ  )r/  rØ  rÚ  rÙ  rì  r  )r/  rØ  rÙ  rÚ  )rÚ  )r<  rÜ  r×  ÚformatÚhermes_cli.lifecycler½  rè   r’  r´   rÖ   ra  r  )r¯  rä  rå  ræ  rç  rè  ré  rê  rÝ  rÞ  Úinvoke_lifecycle_hookÚhook_resultsrÚ  Úfirst_approverœ  r/  ÚpartialrØ  rÙ  s                      r[   Ú$_get_pre_tool_call_directive_detailsró  =  sÎ  € ô Ô,¨i¸Ó>€GØÐ˜y°Ñ7ÜÔ,¨eÐ5PÓQˆÜ$¨G¸S¿Z¹ZÐR[¸ZÓ=\Ô]Ð]ÝIÙ(Ø 9¼:ÀdÌDÔ;Q±4ÐWYØ J¸\ÐSZØ%¼Ð=MÒ=SÐQSÓ8Tô€Lð
 /3€MØCG€MØò iˆÜ˜&¤$Ô'ØØ—‘˜HÓ%ˆð �XÒØ—j‘j Ó(ˆGÜ˜'¤4Ô(©Wð!Z°]Ð5N¡MÜ-7¸¼dÔ-C¡TÈð!ZØQXð!Z�àØÐ-Ñ-ØØ—*‘*˜YÓ'ˆÜ'¨´Ô5¹'‘'Àtˆà�WÒ¡WØØ�WÒÜ(°ÀÐXeÔfÒfàÑ Ø—z‘z *Ó-ˆHØ$ÄJÈxÔY\ÔD] x§~¡~Ó'7Ò'?¹4ÐcgÐh‰Mð3ið4 Ð Ü$¨I¸}ÈQÑ?OÐZgÐhiÑZjØ3@ôBð 	Bä ¨}Ô=Ð=r]   c                óL   — t        | |fi |¤Ž}|j                  |j                  fS )z»Back-compat: ``(directive, message)`` with directive ``"block"`` / ``"approve"`` / ``None``.
    ``hook_kwargs`` are the observability ids of :func:`_get_pre_tool_call_directive_details`.)ró  r/  rØ  )r¯  rä  Úhook_kwargsÚdetailss       r[   Úget_pre_tool_call_directiver÷  t  s(   € ô
 3°9¸dÑRÀkÑR€GØ�N‰N˜GŸO™OÐ,Ð,r]   c                ó4   — t        | |fi |¤Ž\  }}|dk(  r|S dS )zYDeprecated shim: only the ``block`` message (or ``None``); ``approve`` is invisible here.rä  N)r÷  )r¯  rä  rõ  Ú	directiverØ  s        r[   Úget_pre_tool_call_block_messagerú  }  s,   € ô 5°YÀÑTÈÑTÑ€IˆwØ 7Ò*ˆ7Ð4°Ð4r]   c                ó"   — t        | |fi |¤Žd   S )z´Resolve the pre_tool_call directive to a final block message (or ``None`` to proceed),
    running the human-approval gate for ``approve``. See :func:`_resolve_block_from_details`.r   )Ú_dispatch_pre_tool_call_hooks)r¯  rä  rõ  s      r[   Úresolve_pre_tool_blockrý  …  s   € ô
 )¨°DÑH¸KÑHÈÑKÐKr]   ©rè  rç  ræ  c               óz  — | j                   dk(  r| j                  S | j                   dk7  ry	 ddlm} ddlm}m} d}t        t        «      5   ||||¬«      }ddd«       	  ||| j                  xs d| j                  xs |¬	«      }	|� t        t        «      5   ||«       ddd«       |	j                  d«      s!t        |	j                  d«      xs d|› �«      S y# 1 sw Y   Œ†xY w# 1 sw Y   ŒHxY w# |�-t        t        «      5   ||«       ddd«       w # 1 sw Y   w xY ww xY w# t        $ r d
|› �cY S w xY w)z³The ONE place for the fail-closed approval logic: ``block`` blocks with its message; an
    ``approve`` whose gate errors, denies, or times out is blocked; anything else proceeds.rä  rì  Nr   )Úrequest_tool_approval)Ú#reset_current_observability_contextÚ!set_current_observability_contextrþ  r{  )rÙ  z)BLOCKED: plugin approval gate failed for ÚapprovedrØ  z&BLOCKED: plugin approval required for )r/  rØ  Útools.approvalr   Útools.approval_contextr  r  r   r5  rÙ  rÖ   ra  )
rö  r¯  rè  rç  ræ  r   r  r  Úapproval_tokensrœ  s
             r[   Ú_resolve_block_from_detailsr  �  sR  € ð ‡~�~˜Ò Ø�‰ÐØ‡~�~˜Ò"ØðGÝ8ßqØˆÜ”iÓ ñ 	SÙ?Ø¨lÀzôSˆO÷	Sð	IÙ*¨9°g·o±oÒ6KÈÐV]×VfÑVfÒVsÐjsÔtˆFàÐ*ÜœiÓ(ñ IÙ7¸ÔH÷Ið �:‰:�jÔ!Ü�6—:‘:˜iÓ(Ò`Ð.TÐU^ÐT_Ð,`ÓaÐaØ÷	Sð 	Sú÷Ið Iûð Ð*ÜœiÓ(ñ IÙ7¸ÔH÷I÷ Iñ Iúð +ûô ò Gð ;¸9¸+ÐFÒFðGúsq   ­D) ÁCÁD) Á!'C5 ÂD) Â	C)Â"D) ÃC&Ã"D) Ã)C2Ã.D) Ã5D&Ä	DÄ	D&ÄD"ÄD&Ä&D) Ä)D:Ä9D:c                óš   — t        | |fi |¤Ž}t        || fi dD �ci c]  }||j                  |d«      “Œ c}¤Ž}||j                  fS c c}w )u¾   Invoke ``pre_tool_call`` hooks once; return ``(block_message, modified_args)`` â€” the resolved
    block/approve message (``None`` to proceed) and merged ``modify`` args (``None`` if none).rþ  r{  )ró  r  rÖ   rÚ  )r¯  rä  rõ  rö  rA  Ú	block_msgs         r[   rü  rü  ­  s`   € ô
 3°9¸dÑRÀkÑR€GÜ+Ø�ñnØBkÖl¸Q˜q +§/¡/°!°RÓ"8Ñ8Òlñn€Ià�w×,Ñ,Ð-Ð-ùò ms   ›A©ræ  r  r7  ÚcodingÚattemptÚfinal_responseÚchanged_pathsc                óÆ  — t        d| |||||t        |xs g «      ¬«      }|D ]¼  }t        |t        «      sŒt	        |j                  d«      xs |j                  d«      xs d«      j                  «       j                  «       }	|j                  d«      xs |j                  d«      }
|	dv sŒŠt        |
t        «      sŒ›|
j                  «       sŒ¬|
j                  «       c S  y	)
a  Check ``pre_verify`` hooks for ``{"action": "continue", "message"}`` (or Claude-Code Stop
    ``{"decision": "block", "reason"}``) to keep the turn going; first non-empty message wins, any
    other return lets the turn finish. ``coding``/``attempt`` let hooks scope and self-throttle.rx   r
  r/  rÒ  r{  rØ  Úreason)Úcontinuerä  N)r½  r´   rè   r’  ra  rÖ   r  rb  )ræ  r  r7  r  r  r  r  rð  rœ  r/  rØ  s              r[   Úget_pre_verify_continue_messager  ¸  sÉ   € ô Ø °hÀeÐTZØ¨ÄdÈ=ÒK^Ð\^ÓF_ô€Lð ò #ˆÜ˜&¤$Ô'ØÜ�V—Z‘Z Ó)ÒI¨V¯Z©Z¸
Ó-CÒIÀrÓJ×PÑPÓR×XÑXÓZˆØ—*‘*˜YÓ'Ò?¨6¯:©:°hÓ+?ˆØÐ*Ò*¬z¸'Ä3Õ/GÈGÏMÉMÍOØ—=‘=“?Ò"ð#ð r]   ©r#  r7  Ústatus_codeÚ
error_typeÚ
error_codeÚerror_messageÚ
error_bodyr±   Úapprox_tokensÚcontext_lengthÚnum_messagesc                óH  ‡— ddl mŠ t        d| |||||t        |t        «      r|ni |||	|
¬«      }dˆfd„}|D �cg c]  } ||«      x}€Œ||f‘Œ }}|sy|d   \  }}d|i}dD ]  }||v sŒt        ||   «      ||<   Œ |j                  d	«      }t        |t        «      r&|j                  «       r|j                  «       dd
 |d	<   t        |j                  d«      t        «      r|d   |d<   t        |«      dkD  r"t        j                  dt        |«      dz
  «       |S c c}w )u¡  Consult ``transform_api_error_classification`` hooks BEFORE the built-in classifier.
    Run-all-then-pick-first: the first valid result in registration order wins, losing valid results
    warn (conflicts visible, not shadowed). Returns a sanitized dict (``reason`` -> ``FailoverReason``,
    hint flags -> bool, ``message`` capped at 500) or ``None``. Privacy: inputs may be unredacted.

    A callback returns ``None`` to decline, or a dict with a required ``"reason"`` (a
    :class:`agent.error_classifier.FailoverReason` member or its string name) plus optional recovery-hint
    overrides. Dispatch is run-all-then-pick-first: ``invoke_hook`` runs every registered callback with
    failures isolated, then the first result carrying a valid reason wins in registration order â€” mirroring
    :func:`get_pre_tool_call_block_message`, invalid or irrelevant returns are silently ignored so a
    misbehaving plugin degrades to a no-op. When more than one callback returns a valid classification, the
    losing results are skipped with a runtime warning (the #64714 skipped-transform rule) so conflicting
    provider plugins are visible in logs instead of silently shadowed.
    r   )ÚFailoverReasonr    r  c                ó  •— t        | t        «      r| j                  d«      nd }t        |t        «      r=t	        t
        «      5   ‰|j                  «       j                  «       «      cd d d «       S t        |‰«      r|S d S # 1 sw Y   y xY w)Nr  )rè   r’  rÖ   ra  r   rÐ   r  rb  )rœ  r  r  s     €r[   Ú_reasonz0get_plugin_error_classification.<locals>._reasonê  ss   ø€ Ü)3°F¼DÔ)A�—‘˜HÔ%ÀtˆÜ�fœcÔ"Üœ*Ó%ñ >Ù% f§l¡l£n×&:Ñ&:Ó&<Ó=÷>ñ >ô $ F¨NÔ;ˆvÐEÀÐE÷>àús   Á$BÂBNr  )Ú	retryableÚshould_compressÚshould_rotate_credentialÚshould_fallbackrØ  iô  Úerror_contextr  z‘transform_api_error_classification: skipped %d valid classification(s) after the first result in registration order won (run-all-then-pick-first)©rœ  r
   r  r
   )Úagent.error_classifierr  r½  rè   r’  r®   rÖ   ra  r  r“  rq   rÑ   )r#  r7  r  r  r  r  r  r±   r  r  r  rð  r  rœ  r  r\  ÚwinnerrÈ   rØ  r  s                      @r[   Úget_plugin_error_classificationr(  Í  sB  ø€ õ( 6ÜØ,°xÀuØ¨JÀ:Ø#¼jÈÔUYÔ>Z±
Ð`bØ =ÀØ!ô€LõFð -9Öd &ÁwÈvÃÐ=V¸VÑ<cˆf�fÒÐd€EÐdÙØØ˜1‘X�N€FˆFØ&¨Ð/€FØ^ò ,ˆØ�&Š=Ü˜v c™{Ó+ˆF�3ŠKð,ð �j‰j˜Ó#€GÜ�'œ3Ô G§M¡M¤OØ#ŸM™M›O¨D¨SÐ1ˆˆyÑÜ�&—*‘*˜_Ó-¬tÔ4Ø"(¨Ñ"9ˆˆÑÜ
ˆ5ƒz�A‚~Ü�‰ð ZÜ[^Ð_dÓ[eÐhiÑ[iô	kà€Mùò! es   »DÁDc                ó>   — t        «       }|j                  | ¬«       |S )zEReturn the global manager after idempotent (or ``force``d) discovery.r)  )r  rý  )ru   r¼   s     r[   rÂ  rÂ    s    € ä Ó"€GØ×Ñ EÐÔ*Ø€Nr]   c                 ó*   — t        «       j                  S )z5Return the plugin-registered context engine, or None.)rÂ  rë  rd   r]   r[   Úget_plugin_context_enginer+    s   € ä%Ó'×7Ñ7Ð7r]   c                óZ   — t        «       j                  j                  | «      }|r|d   S dS )zFReturn the handler for a plugin-registered slash command, or ``None``.rv   N)rÂ  rÝ  rÖ   )rÆ   rÚ   s     r[   Úget_plugin_command_handlerr-    s-   € ä&Ó(×9Ñ9×=Ñ=¸dÓC€EÙ$ˆ5�ÑÐ.¨$Ð.r]   c                óü  ‡ ‡‡‡— t        j                  ‰ «      s‰ S 	 t        j                  «        i Ši Št        j                  «       Šdˆˆˆˆ fd„}t        j                  t        j                  «       j
                  |fdd¬«      j                  «        ‰j                  t        ¬«      st        dt        d›d�«      ‚d	‰v r‰d	   ‚‰j                  d
«      S # t        $ r t        j
                  ‰ «      cY S w xY w)zÊResolve a plugin command result, awaiting async handlers: ``asyncio.run`` when no loop is
    running, else a helper thread with its own loop (30s bound so a hung handler cannot wedge the
    terminal).c                 ó¸   •— 	 t        j                  ‰«      ‰d<   ‰j                  «        y # t        $ r} | ‰d<   Y d } ~ Œ$d } ~ ww xY w# ‰j                  «        w xY w)NrÛ   r'  )rG  Úrunrú  rÌ  )r'  rB  ÚfailureÚoutcomerœ  s    €€€€r[   Ú_runnerz.resolve_plugin_command_result.<locals>._runner(  sM   ø€ ð	Ü&Ÿ{™{¨6Ó2ˆG�GÑð �H‰H�Jøô ò 	!Ø ˆG�EŽNûð	!ûð �H‰H�Jús#   ƒ, ¬	Aµ?ºA ¿AÁA ÁAzhermes-plugin-command-awaitT)r‘  rä  rÆ   r’  r™  z5Plugin command async handler did not complete within z.0fr  r'  rÛ   r~  )ÚinspectÚisawaitablerG  rI  r@  r0  rÆ  ÚEventr•  ÚcontextvarsÚcopy_contextr–  ÚwaitÚ"_PLUGIN_COMMAND_AWAIT_TIMEOUT_SECSÚTimeoutErrorrÖ   )rœ  r3  rB  r1  r2  s   ` @@@r[   Úresolve_plugin_command_resultr<    sï   û€ ô ×Ñ˜vÔ&Øˆð#Ü× Ñ Ô"ð !€GØ(*€GÜ�?‰?Ó€D÷ð ô ×ÑœK×4Ñ4Ó6×:Ñ:À'ÀØ7ÀôFßFKÁeÄgØ�9‰9Ô?ˆ9Ô@ÜÐRÜ@ÀÐEÀQðHó Ið 	Ià�ÑØ�e‰nÐØ�;‰;�wÓÐøô/ ò #Ü�{‰{˜6Ó"Ò"ð#ús   �C ÃC;Ã:C;c                 ó*   — t        «       j                  S )zYPlugin commands dict (name -> {handler, description, plugin}) after idempotent discovery.)rÂ  rÝ  rd   r]   r[   Úget_plugin_commandsr>  <  s   € ä%Ó'×8Ñ8Ð8r]   c                 ó€   — t        «       } t        | j                  «      D �cg c]  }| j                  |   ‘Œ c}S c c}w )zXPlugin auxiliary-task registration dicts sorted by ``key`` (after idempotent discovery).)rÂ  r[  r>  )r¼   rA  s     r[   Úget_plugin_auxiliary_tasksr@  A  s4   € ä(Ó*€GÜ+1°'×2DÑ2DÓ+EÖF aˆG×Ñ˜qÓ!ÒFÐFùÒFs   ¢;c            	     ó"  — t        «       } | j                  sg S 	 ddlm} i }| j                  D ]K  }|j                  |«      }|sŒ|j                  |j                  g «      j                  |j                  «       ŒM i }| j                  j                  «       D ]R  }|j                  D ]A  }|j                  |«      }|sŒ|j                  |v sŒ&|j                  |j                  |«       ŒC ŒT g }t        |«      D ]�  }|j                  |«      }	|	r|	j                  j                   ndxs dj#                  t        ||   «      «      }
|j                  |d|j%                  dd«      j'                  «       › �|
f«       Œƒ |S # t        $ r g cY S w xY w)zUPlugin toolsets as ``(key, label, description)`` tuples for the ``hermes tools`` TUI.r   rl  r{  rW  u   ðŸ”Œ r0  rÑ  )r  r  r}  r$  r5  r~  r  rm  r"  rÆ   rÌ   r  rª   r[  rÖ   r¦   rr  rZ  rÛ  Útitle)r¼   r$  Útoolset_toolsr¯  rÚ   Útoolset_pluginrÉ   rœ  r§  rÊ  Údescs              r[   r¦  r¦  G  sŠ  € ä Ó"€GØ×%Ò%Øˆ	ðÝ+ð
 +-€MØ×/Ñ/ò Kˆ	Ø×"Ñ" 9Ó-ˆÚØ×$Ñ$ U§]¡]°BÓ7×>Ñ>¸u¿z¹zÕJðKð /1€NØ×"Ñ"×)Ñ)Ó+ò AˆØ×0Ñ0ò 	AˆIØ×&Ñ& yÓ1ˆEÚ˜Ÿ™¨-Ò7Ø×)Ñ)¨%¯-©-¸Õ@ñ	AðAð
 €FÜ˜Ó'ò RˆØ×#Ñ# FÓ+ˆÙ/5�—‘×+Ò+¸2ÒjÀ$Ç)Á)ÌFÐS`ÐagÑShÓLiÓBjˆØ�‰�v  v§~¡~°c¸3Ó'?×'EÑ'EÓ'GÐ&HÐIÈ4ÐPÕQðRð €Møô) ò ØŠ	ðús   šF  Æ FÆF)ÚIterable)ÚType)Úcontextmanagerr»  c                 ó  — t        «       } | j                  5  | j                  j                  «       D ���ci c]   \  }}||D �cg c]  }|j                  ‘Œ c}“Œ" c}}}cddd«       S c c}w c c}}}w # 1 sw Y   yxY w)a_  Return the inter-plugin event bus subscription registry.

    Returns a snapshot mapping each fully-qualified event name
    (``<plugin_key>:<event>`` or ``hermes:<event>``) to subscriber callbacks in
    registration order. Owner ledger metadata stays private to the manager.
    Triggers idempotent plugin discovery before reading the snapshot.
    N)rÂ  rÑ  rÐ  rÍ   r9  )r¼   ri  ÚentriesrÚ   s       r[   Úget_plugin_subscriptionsrK  r  s{   € ô )Ó*€GØ	×	Ñ	ñ 
ð #*×"8Ñ"8×">Ñ">Ó"@÷
ð 
á��wð °Ö8 u�E—N“NÒ8Ñ8ô
÷
ñ 
ùâ8ùô
÷
ð 
ús.   —A5¶A.
ÁA)ÁA.
ÁA5Á)A.
Á.A5Á5A>c                óH   — t        «        t        «       j                  | «      S )zØUnload one plugin or all plugins from the process-global manager.

    Wait for background discovery first so teardown cannot race an in-flight
    registration sweep introduced by the warm-start discovery path.
    )r‰  r  rõ  )rÊ  s    r[   Úunload_pluginsrM  �  s   € ô Ô ÜÓ×&Ñ& vÓ.Ð.r]   )úhermes_cli.plugin_capabilitiesÚCAPABILITY_REGISTRY)zhermes_cli.plugins_discoveryÚENTRY_POINT_CAPABILITIES_GROUP)zhermes_cli.relay_plugin_cutoverÚLEGACY_RELAY_PLUGIN_KEYS)úhermes_cli.plugins_dispatchÚMAX_SYSTEM_PROMPT_SECTIONS)zhermes_cli.middlewareÚOBSERVER_SCHEMA_VERSION)rN  ÚVALID_CAPABILITY_IDS)zhermes_cli.configÚcfg_get)r¥  Úfast_safe_load)rR  Úformat_system_prompt_section)r  Úreset_hermes_home_override)r  Úset_hermes_home_override)rO  rP  rQ  rS  rT  rU  rV  rW  rX  rY  rZ  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Ö   ÚAttributeErrorr`   rª  r*  r\  r<  r«  )rÆ   r‘  rª  r\  s       r[   Ú__getattr__r_  œ  sh   € Ü ×$Ñ$ TÓ*€FØ€~Ü˜w¤x lÐ2DÀTÀHÐMÓNÐNÛÝ2ÙŒh˜Ð&˜vÓ&ÜÐ*�9×*Ñ*¨6°!©9Ó5°v¸a±yÓAÐAr]   )r  r	   rk  rl  )r  rŽ  )r¼   rt  r  r€  )r  rÃ  r~  ro  )rŠ  )r—  rŽ  r  r€  )r­  ra  r®  z%Callable[[PluginManager], 'set[str]']r  ú
'set[str]')r  r`  )rP  ra  rå  r
   r  ú	List[Any])rÄ  rp  r  z'List[RenderedPluginSystemPromptSection])r÷   ra  rå  r
   r  ra  )r÷   ra  r  r®   )rP  ra  r  r®   )rP  ra  r  ztuple[Callable, ...])rÏ  ra  rÙ  ra  rÐ  ra  rÑ  ra  r°  r°   r  r°   r  r€  )z>Tool '{tool_name}' denied: not in this thread's tool whitelist)rÝ  rn  rß  ra  r  r€  )r{  r{  r{  r{  r{  N)r¯  ra  rä  r‰  rå  ra  ræ  ra  rç  ra  rè  ra  ré  ra  rê  zOptional[List[Dict[str, Any]]]r  r×  )r¯  ra  rä  r‰  rõ  r
   r  z#tuple[Optional[str], Optional[str]])r¯  ra  rä  r‰  rõ  r
   r  r°   )rö  z'_PreToolCallDirective'r¯  ra  rè  ra  rç  ra  ræ  ra  r  r°   )r¯  ra  rä  r‰  rõ  r
   r  z.Tuple[Optional[str], Optional[Dict[str, Any]]])ræ  ra  r  ra  r7  ra  r  r®   r  rb  r  ra  r  zOptional[List[str]]r  r°   )r#  ra  r7  ra  r  zOptional[int]r  ra  r  ra  r  ra  r  r‰  r±   zOptional[BaseException]r  rb  r  rb  r  rb  r  r‰  )ru   r®   r  rÃ  )rÆ   ra  r  zOptional[Callable]r%  )r  zDict[str, dict]rs  rq  )r  r�  rÅ   )rÊ  z.Union[str, PluginManifest, LoadedPlugin, None]r  r®   )Ìrc   Ú
__future__r   rG  r7  Úimportlib.metadatarª  r4  r   ri   rU   rÖ  rc  rk   rÆ  ÚtypesÚ
contextlibr   Údataclassesr   r   Ú	functoolsr   r   Úpathlibr	   Útypingr
   r   r   r   r   r   r   r   r   r  r   r   r   Úregistration_lifecycler   r¥  r   r©  r   Úhermes_cli.middlewarer   Úhermes_cli.plugin_capabilitiesr   Úhermes_cli.relay_plugin_cutoverr   r   Úhermes_cli.plugins_manifestr   r   r   r    r!   r"   r#   r$   r%   Úhermes_cli.plugins_discoveryr&   r'   r(   r)   r*   r+   r,   r-   Úhermes_cli.plugins_loaderr.   r/   r0   r1   r2   r3   r4   r5   Úhermes_cli.plugins_dispatchr6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   Úhermes_cli.plugins_ledgerrI   rJ   Úhermes_cli.plugins_staterK   rL   rM   rN   rO   rP   rQ   r\   r�  r_   Ú	getLoggerr`   rq   rg   rh   rw   r¢   r³   r£   r=  rj  r×   r¥   r¶   r¤  r§  r·  Ú_rowÚsetattrr¼  r´   ÚvarsrÍ   rB  Ú_methodr:  r[  rÁ  rÃ  ru  rv  rÇ  r}  ry  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+  r-  r:  r<  r>  r@  r¦  rF  rG  rH  ÚcopyÚhashlibÚtimerK  rM  r]  r_  rd   r]   r[   ú<module>r|     sy  ðòõ #ã Û Û Û Û Û Û 	Û Û 	Û 
Û Û Ý ß (ß ,Ý ß R× RÕ Rç VÑ VÝ :Ý !Ý 2Ý 2Ý Dß ^÷÷ õ ÷
÷ ó ÷÷ ó ÷÷ ÷ ÷ ÷ ñ ÷ L÷÷ ñ ó>ôi˜oô ið 
ˆ×	Ñ	˜8Ó	$€ñ !Ð!7Ó8€Ø Ð ôXñ" Ô ò`€ˆXó `ðH &JÐ$JÐ ˜Ó Jà€Ù	‹€ð ÷ð ó ð÷WQñ WQð@ #Ð$8Ð:TØ0Ð2Fð?ØAJÈDÐ@QðSð #Ð$8Ð:TØ0Ð2Fð?Ø@BðDð $Ð%:Ð<WØ2°Nðkàð		ð
 !Ð"4Ð6NØ-Ð/Að:à;=ð	?ð
 .Ð/NØ"Ð$]Ø$ðð Ð.fÑgðið ˜Ð0OØ-¨ðWð Ð%6ÀÑJðLð ˜nÐ.BØ% ~ðXð �7Ððð 'Ð(@ÐB`Ø9Ð;Sð@àBMÈwÐAWð	YðQ-`Ð Ð\ó -ñ` !Ñ+FÈdñJÐ ÐFó ò
+ð. (ò L€DÙˆM˜4 ™7Ñ$CÀTÐ$JÕKðLàòñ& ™4 Ó.×4Ò4Ó6Ó7ò M�N€Eˆ7Ù�Õ˜e×.Ò.¨{Ô;¸uÐHbÒ?bÙ�˜uÑ&BÀ7Ó&KÕLðMð 
ˆ7óô8C6Ð%Ð':Ð<Mô C6ðT ,0€Ð(Ó /ð
 79Ð Ð3Ó 8Ø'˜	ŸšÓ)Ð ó.ó:ó ó&Ló0@ô8ð <@Ð Ð8Ó ?Ø+˜YŸ^š^Ó-Ð ó-ô.óDóIóó"mó[ó
ó"@óGóTó
Aó?ó3ó?ð "&ÀñNØðNØ!ðNØ/2ðNØ>AðNàðNà1>ðNð 
óNð. )˜ŸšÓ*Ð ñ �$Ô÷3ð 3ó ð3ð Yð.Øð.àð.ð 
ó.ó*ð
 Z\ØEGØ7;ð4>Øð4>Ø2ð4>Ø=@ð4>ØSVð4>àð4>à%(ð4>à?Bð4>ð 5ð4>ð ó	4>ðn-Øð-Ø2ð-ØCFð-à(ó-ð5Øð5Ø2ð5ØCFð5àó5ðLØðLØ2ðLØCFðLàóLð IKÐ`bØñØ$ðØ14ðØBEðØZ]ðàðð óð@.Øð.Ø2ð.ØCFð.à3ó.ð ¨R¸bÐQVØ¨BÐUYñØðØ'*ðØ8;ðØJNðàðà&)ðà?Rðð óð, ¨ÈÐacØ¨rÐZ^Ø%)ÀÐYZØñ	5Øð5Ø"%ð5Ø9Fð5Ø[^ð5àð5à),ð5à?Wð5ð #ð5ð ;>ð5ð TWð5ð ð	5ð
 ó5ôpò8ó
/ð &*Ð "ó óD9ó
GóõD Ý Ý %Û Û Û Û Ý ó
ð  >Bð	/Ø:ð	/à	ó	/ð UØ&hØ _Ø"_ØSØVØ/Ø1Ø$cØ"TØ PñÐ óBr]   