
    Fj                    d   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	m
Z
 ddlmZmZ ddlmZ ddlmZ ddlmZ  ej        e          Z ej        d	
          dXd            Z G d de          Zd	ZdYdZdddZdZd[dZd\dZd]d Z d^d"Z!d_d%Z"d`d&Z#dad'Z$dbd(Z%dcd)Z&ddd,Z'	 	 dedfd/Z(dgd0Z)dgd1Z*dhd3Z+did5Z,dhd6Z-djd8Z.dgd9Z/dgd:Z0dkd;Z1dld=Z2dmd>Z3dnd@Z4dndAZ5dodBZ6dodCZ7dgdDZ8dgdEZ9dpdFZ:dpdGZ;dmdHZ<dI Z=dJ Z>dqdLZ?drdMZ@dsdNZAdtdOZBdudQZCdvdRZDdwdUZEdvdVZFdmdWZGdS )xuq  ``hermes plugins`` CLI subcommand — install, update, remove, and list plugins.

Plugins are installed from Git repositories into ``~/.hermes/plugins/``.
Supports full URLs and ``owner/repo`` shorthand (resolves to GitHub).

After install, if the plugin ships an ``after-install.md`` file it is
rendered with Rich Markdown.  Otherwise a default confirmation is shown.
    )annotationsN)Path)AnyOptional)get_hermes_home)cfg_get)masked_secret_prompt   )maxsizereturnOptional[str]c            
     8   t          j        d          } | r| S t          j        dk    rBt          j                            dd          }t          j                            dd          }t          j                            dd          }t          j                            |d	d
d          t          j                            |d	dd          t          j                            |d	d
d          t          j                            |d	dd          g}|rY|                    t          j                            |dd	d
d          t          j                            |dd	dd          f           ng d}|D ]'}|r#t          j        	                    |          r|c S (dS )zResolve a git binary for subprocess use when ``PATH`` may be minimal.

    Matches other Hermes subprocess resolution: :func:`shutil.which` first,
    then common Git for Windows install paths and POSIX defaults.
    gitntProgramFileszC:\Program FileszProgramFiles(x86)zC:\Program Files (x86)LOCALAPPDATA Gitcmdzgit.exebinPrograms)z/usr/bin/gitz/usr/local/bin/gitz/bin/gitN)
shutilwhichosnameenvirongetpathjoinextendisfile)foundprogprog_x86local
candidatescs         5/usr/local/lib/hermes-agent/hermes_cli/plugins_cmd.py_resolve_git_executabler)      ss    LE 	w$z~~n.ABB:>>"57PQQ
~r22GLLueY77GLLueY77GLL5%;;GLL5%;;	

  	GLL
E5)LLGLL
E5)LL   HGG
   	"" 	HHH4    c                      e Zd ZdZdS )PluginOperationErrorzHRecoverable plugin install/update failure (CLI exits; HTTP maps to 4xx).N)__name__
__module____qualname____doc__ r*   r(   r,   r,   ?   s        RRRRr*   r,   r   c                 V    t                      dz  } |                     dd           | S )z9Return the user plugins directory, creating it if needed.pluginsT)parentsexist_ok)r   mkdir)r3   s    r(   _plugins_dirr7   I   s-    )+GMM$M...Nr*   Fallow_subdirr   strplugins_dirr9   boolc                  | st          d          |r&|                     d          } | st          d          | dv rt          d|  d          |rdnd}|D ]}|| v rt          d|  d| d	          || z                                  }|                                }||k    rt          d|  d
          	 |                    |           n!# t           $ r t          d|  d          w xY w|S )a  Validate a plugin name and return the safe target path inside *plugins_dir*.

    Raises ``ValueError`` if the name contains path-traversal sequences or would
    resolve outside the plugins directory.

    ``allow_subdir=True`` permits a single forward slash inside *name* so
    category-namespaced plugin keys like ``observability/langfuse`` or
    ``image_gen/openai`` (the registry keys emitted by ``_discover_all_plugins``)
    can be looked up. ``..`` and backslash are still rejected, leading and
    trailing slashes are stripped, and the resolved target must still live
    inside *plugins_dir*. Install paths leave this at the default ``False``
    because a freshly-cloned plugin always lands top-level under
    ``~/.hermes/plugins/<name>/``.
    zPlugin name must not be empty./>   ...zInvalid plugin name 'z3': must not reference the plugins directory itself.)\r@   )r>   rA   r@   z': must not contain 'z'.z,': resolves to the plugins directory itself.z*': resolves outside the plugins directory.)
ValueErrorstripresolverelative_to)r   r;   r9   	bad_charsbadtargetplugins_resolveds          r(   _sanitize_plugin_namerJ   P   s|   (  ;9::: ?zz# 	?=>>>{]D]]]
 
 	

 !-C2CI Y Y$;;WTWWPSWWWXXX  D ))++F"**,,!!!VDVVV
 
 	

+,,,, 
 
 
TDTTT
 
 	


 Ms   ;C C/
identifierc                    |                      d          r| S |                     d                              d          }t          |          dk    r|\  }}d| d| dS t	          d|  d          )u  Turn an identifier into a cloneable Git URL.

    Accepted formats:
    - Full URL: https://github.com/owner/repo.git
    - Full URL: git@github.com:owner/repo.git
    - Full URL: ssh://git@github.com/owner/repo.git
    - Shorthand: owner/repo  →  https://github.com/owner/repo.git

    NOTE: ``http://`` and ``file://`` schemes are accepted but will trigger a
    security warning at install time.
    )zhttps://http://zgit@zssh://file://r>      zhttps://github.com/.gitzInvalid plugin identifier: 'z)'. Use a Git URL or owner/repo shorthand.)
startswithrC   splitlenrB   )rK   partsownerrepos       r(   _resolve_git_urlrW      s     QRR  S!!'',,E
5zzQt7U77T7777
	1z 	1 	1 	1  r*   urlc                   |                      d          }|                    d          r
|dd         }|                    dd          d         }d|v r6|                    dd          d                             dd          d         }|S )zCExtract the repo name from a Git URL for the plugin directory name.r>   rP   Nr
   :)rstripendswithrsplit)rX   r   s     r(   _repo_name_from_urlr`      s     ::c??D}}V CRCy;;sAr"D
d{{{{3""2&--c155b9Kr*   
plugin_dirdictc                0   | dz  }|                                 si S 	 ddl}t          |d          5 }|                    |          pi cddd           S # 1 swxY w Y   dS # t          $ r(}t
                              d| |           i cY d}~S d}~ww xY w)z;Read plugin.yaml and return the parsed dict, or empty dict.plugin.yamlr   Nutf-8encodingz$Failed to read plugin.yaml in %s: %s)existsyamlopen	safe_load	Exceptionloggerwarning)ra   manifest_fileri   fes        r(   _read_manifestrr      s    .M!! 	-'222 	+a>>!$$*	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+ 	+   =z1MMM						s@   A# A	A# AA# AA# #
B-B
BBNonec                T   |                      d          D ]}|j        }| |z  }|                                so	 t          j        ||           |                    d| d|j         d           Z# t          $ r*}|                    d|j         d|            Y d}~d}~ww xY wdS )zCopy any .example files to their real names if they don't already exist.

    For example, ``config.yaml.example`` becomes ``config.yaml``.
    Skips files that already exist to avoid overwriting user config on reinstall.
    z	*.examplez[dim]  Created z from [/dim]z)[yellow]Warning:[/yellow] Failed to copy : N)globstemrh   r   copy2printr   OSError)ra   consoleexample_file	real_name	real_pathrq   s         r(   _copy_example_filesr      s    #44   %	*	!! 		\9555PiPP|7HPPP       X@QXXUVXX       		 s   6A00
B$: BB$manifest	list[str]c                H   |                      d          pg }|sg S ddlm g }|D ]n}t          |t                    r|                    d|i           /t          |t                    r*|                     d          r|                    |           ofd|D             S )zLReturn declared ``requires_env`` names that are unset in ``~/.hermes/.env``.requires_envr   )get_env_valuer   c                l    g | ]0}|                     d            |d                    (|d          1S r   )r   .0sr   s     r(   
<listcomp>z/_missing_requires_env_names.<locals>.<listcomp>   sB    [[[!AEE&MM[--PQRXPYBZBZ[AfI[[[r*   )r   hermes_cli.configr   
isinstancer:   appendrb   )r   r   	env_specsentryr   s       @r(   _missing_requires_env_namesr      s    <<//52L 	//////I $ $eS!! 	$fe_----t$$ 	$6):): 	$U###[[[[y[[[[r*   c                   |                      d          pg }|sdS ddlmm} ddlm} g }|D ]n}t          |t                    r|                    d|i           /t          |t                    r*|                     d          r|                    |           ofd|D             }|sdS |                      dd          }|
                    d	| d
           |D ]y}	|	d         }
|	                     dd          }|	                     dd          }|	                     dd          }d|
 }|r|d| z  }|
                    |           |r|
                    d| d           	 |r&t          d|
 d                                          }n%t          d|
 d                                          }n:# t          t          f$ r& |
                    d |             d           Y  dS w xY w|r> ||
|           |t           j        |
<   |
                    d |             d           U|
                    d|
 d |             d           {|
                                 dS )a  Prompt for required environment variables declared in plugin.yaml.

    ``requires_env`` accepts two formats:

    Simple list (backwards-compatible)::

        requires_env:
          - MY_API_KEY

    Rich list with metadata::

        requires_env:
          - name: MY_API_KEY
            description: "API key for Acme service"
            url: "https://acme.com/keys"
            secret: true

    Already-set variables are skipped.  Values are saved to the user's ``.env``.
    r   Nr   )r   save_env_value)display_hermes_homer   c                6    g | ]} |d                    |S r   r1   r   s     r(   r   z+_prompt_plugin_env_vars.<locals>.<listcomp>  s,    DDDQ==6+C+CDqDDDr*   zthis pluginz
[bold]z6[/bold] requires the following environment variables:
descriptionr   rX   secretF      — z  [dim]Get yours at: ru   rv   z,
[dim]  Skipped (you can set these later in z/.env)[/dim]u     [green]✓[/green] Saved to z/.envz  [dim]  Skipped (set z in z/.env later)[/dim])r   r   r   r   hermes_constantsr   r   r:   r   rb   rz   r	   rC   inputEOFErrorKeyboardInterruptr   r   )r   r|   r   r   r   r   r   missingplugin_namespecr   descrX   r   labelvaluer   s                   @r(   _prompt_plugin_env_varsr      s   ( <<//52L ????????444444 I $ $eS!! 	$fe_----t$$ 	$6):): 	$U### EDDD)DDDG ,,v}55KMMa[aaabbb h hF|xxr**hhub!!(E**T 	$^T^^#Ee 	?MM=#===>>>	 5,]$]]];;AACCm4mmm,,2244+, 	 	 	MMmJ]J]J_J_mmmnnnFFF	  	hN4'''$BJtMMW;N;N;P;PWWWXXXXMMf4ff=P=P=R=RfffggggMMOOOOOs   .AF<<2G32G3c                   ddl m} ddlm} ddlm}  |            }| dz  }|                                rl|                    d          } ||          }|                                 |                     ||dd	
                     |                                 dS |                                 |                     |d| d|  ddd	                     |                                 dS )z@Show after-install.md if it exists, otherwise a default message.r   Console)Markdown)Panelafter-install.mdre   rf   greenF)border_styleexpandz![green bold]Plugin installed:[/] z
[dim]Location:[/] u   ✓ Installed)r   titler   N)	rich.consoler   rich.markdownr   
rich.panelr   rh   	read_textrz   )	ra   rK   r   r   r   r|   after_installcontentmds	            r(   _display_after_installr   4  s9   $$$$$$&&&&&&      giiG!33M ))7);;XgeeBWUCCCDDDE2J 2 2%/2 2$%  	
 	
 	
 	r*   c                    ddl m}  |            }|                                 |                    d|  d|            |                                 dS )z*Show confirmation after removing a plugin.r   r   u   [red]✗[/red] Plugin [bold]z[/bold] removed from N)r   r   rz   )r   r;   r   r|   s       r(   _display_removedr   Q  s`    $$$$$$giiGMMOOOMMYYYKYYZZZMMOOOOOr*   c                   t          | |d          }|                                sed                    d |                                D                       pd}|                    d|  d| d|            t          j        d	           |S )
zUReturn the plugin path if it exists, or exit with an error listing installed plugins.Tr8   z, c              3  L   K   | ]}|                                 |j        V   d S )N)is_dirr   )r   ds     r(   	<genexpr>z,_require_installed_plugin.<locals>.<genexpr>_  s1      RRqxxzzRafRRRRRRr*   z(none)[red]Error:[/red] Plugin 'z' not found in z.
Installed plugins: r
   )rJ   rh   r   iterdirrz   sysexit)r   r;   r|   rH   	installeds        r(   _require_installed_pluginr   [  s    "44HHHF==?? IIRRk.A.A.C.CRRRRR^V^	. . .k . ."+. .	
 	
 	
 	Mr*   forcetuple[Path, dict, str]c                  ddl }	 t          |           }n/# t          $ r"}t          t	          |                    |d}~ww xY wt                      }|                                5 }t          |          dz  }t                      }|st          d          	 t          j
        |ddd|t	          |          gddd	
          }	nD# t          $ r}t          d          |d}~wt          j        $ r}t          d          |d}~ww xY w|	j        dk    r4|	j        p|	j        pd                                }
t          d|
           t#          |          }|                    d          pt'          |          }	 t)          ||          }n/# t          $ r"}t          t	          |                    |d}~ww xY w|                    d          }|x	 t+          |          }n,# t          t,          f$ r t          d| d| d          dw xY w|t.          k    r0ddlm} t          d| d| dt.           d |             d	          d|                                r,|st          d| d| d          t7          j        |           t7          j        t	          |          t	          |                     ddd           n# 1 swxY w Y   |dz                                  p|dz                                  }|s2|dz                                  st<                              d|           ddl m!} tE          | |                       t#          |          }|                    d          p|j#        }|||fS )zClone Git plugin into ``~/.hermes/plugins``.

    Returns ``(target_dir, installed_manifest, canonical_name)``.
    Raises ``PluginOperationError`` on failure.
    r   Nplugin$git is not installed or not in PATH.clonez--depth1T<   )capture_outputtexttimeoutz%Git clone timed out after 60 seconds.r   zGit clone failed:
r   manifest_versionPlugin 'z ' has invalid manifest_version 'z' (expected an integer).)recommended_update_commandz' requires manifest_version z), but this installer only supports up to z. Run z to update Hermes.zD' already exists. Use force reinstall or run `hermes plugins update z`.rd   
plugin.yml__init__.pyz>%s has no plugin.yaml / __init__.py; may not be a valid pluginr   )$tempfilerW   rB   r,   r:   r7   TemporaryDirectoryr   r)   
subprocessrunFileNotFoundErrorTimeoutExpired
returncodestderrstdoutrC   rr   r   r`   rJ   int	TypeError_SUPPORTED_MANIFEST_VERSIONr   r   rh   r   rmtreemoverm   rn   r   r   r   r   )rK   r   r   git_urlrq   r;   tmp
tmp_targetgit_exeresulterrr   r   rH   mvmv_intr   has_yamlr   installed_manifestinstalled_names                        r(   _install_plugin_corer   m  s    OOO2":.. 2 2 2"3q66**12 ..K		$	$	&	& =2##YY)
)++ 	O&'MNNN	^'9c7C
OOL#	  FF ! 	 	 	&6  ( 	 	 	&7 	
 !!=7FM7R>>@@C&'BS'B'BCCC!*--ll6**J.A'.J.J	6*;DDFF 	6 	6 	6&s1vv..A5	6 \\,-->R	*   *5{ 5 55 5 5  
 333HHHHHH*L{ L L L L>YL L5577L L L  	 ==?? 	" *E{ E E5@E E E   M&!!!C
OOS[[111{=2 =2 =2 =2 =2 =2 =2 =2 =2 =2 =2 =2 =2 =2 =2~ &..00TVl5J4R4R4T4TH 
Vm3;;== 
L	
 	
 	

 %$$$$$		***'//'++F33Bv{N%~55s    
A=A'2K+CK
DC  D2DDA5K=FK
F:F55F::KG%$K%)HB-KKKenableOptional[bool]c                   ddl m}  |            }	 t          |           }nC# t          $ r6}|                    d|            t          j        d           Y d}~nd}~ww xY w|                    d          r|                    d           |                    d| d	           	 t          | |
          \  }}}	nC# t          $ r6}|                    d|            t          j        d           Y d}~nd}~ww xY w|dz  
                                sG|dz  
                                s0|dz  
                                s|                    d|	 d           t          ||           t          ||            |}
|
t
          j                                        rtt
          j                                        rV	 t!          d|	 d                                                                          }|dv }
n# t&          t(          f$ r d}
Y nw xY wd}
|
r~t+                      }t-                      }|                    |	           |                    |	           t3          |           t5          |           |                    d|	 d           n|                    d|	 d           |                    d           |                    d           |                                 dS )zInstall a plugin from a Git URL or owner/repo shorthand.

    After install, prompt "Enable now? [y/N]" unless *enable* is provided
    (True = auto-enable without prompting, False = install disabled).
    r   r   [red]Error:[/red] r
   NrM   rN   zs[yellow]Warning:[/yellow] Using insecure/local URL scheme. Consider using https:// or git@ for production installs.z[dim]Cloning 	...[/dim]r   rd   r   r   z[yellow]Warning:[/yellow] zQ doesn't contain plugin.yaml or __init__.py. It may not be a valid Hermes plugin.z
  Enable 'z' now? [y/N]: >   yyesF    [green]✓[/green] Plugin [bold]z[/bold] enabled.zB[dim]Plugin installed but not enabled. Run `hermes plugins enable z` to activate.[/dim]z=[dim]Restart the gateway for the plugin to take effect:[/dim]z#[dim]  hermes gateway restart[/dim])r   r   rW   rB   rz   r   r   rQ   r   r,   rh   r   r   stdinisattyr   r   rC   lowerr   r   _get_enabled_set_get_disabled_setadddiscard_save_enabled_set_save_disabled_set)rK   r   r   r   r|   r   rq   rH   r   r   should_enableanswerenableddisableds                 r(   cmd_installr    s    %$$$$$giiG":..   .1../// 011 
G	
 	
 	

 MM4'4445555I6
 6
 6
2"NN     .1../// ]"**,, 
f|6K5S5S5U5U 
fhh
 	D D D D	
 	
 	

 .8886:...M9 		"#*"3"3"5"5 		"&???? %''%%''  !', 6/0 & & & %& "M 
"$$$&&N###((('"""8$$$O~OOO	
 	
 	
 	
 	O*8O O O	
 	
 	

 MMQRRRMM7888MMOOOOOs>   " 
A",AA")B? ?
C?	,C::C?;G= =HHc                   ddl m}  |            }t                      }	 t          | ||          }nC# t          $ r6}|                    d|            t          j        d           Y d}~nd}~ww xY w|dz                                  s-|                    d|  d           t          j        d           |                    d	|  d
           t          |          \  }}|s,|                    d|            t          j        d           t          ||           |                                }d|v r|                    d|  d           dS |                    d|  d           |                    d| d           dS )zAUpdate an installed plugin by pulling latest from its git remote.r   r   r   r
   NrP   r   z@' was not installed from git (no .git directory). Cannot update.z[dim]Updating r   Already up to dater   z[/bold] is already up to date.z[/bold] updated.z[dim]ru   )r   r   r7   r   rB   rz   r   r   rh   _git_pull_plugin_dirr   rC   )	r   r   r|   r;   rH   rq   okoutputouts	            r(   
cmd_updater    s   $$$$$$giiG..K*4gFF   .1../// VO##%% 3 3 3 3	
 	
 	
 	MM24222333%f--JB 3633444 (((
,,..Cs""StSSS	
 	
 	
 	
 	
 	OOOOPPP)c)))*****   2 
A2,A--A2c                6   ddl m}  |            }t                      }	 t          | ||          }nC# t          $ r6}|                    d|            t          j        d           Y d}~nd}~ww xY wt          j	        |           t          | |           dS )z#Remove an installed plugin by name.r   r   r   r
   N)r   r   r7   r   rB   rz   r   r   r   r   r   )r   r   r|   r;   rH   rq   s         r(   
cmd_remover  E  s    $$$$$$giiG..K*4gFF   .1../// M&T;'''''r  setc                     	 ddl m}   |             }t          |ddg           }t          |t                    rt          |          nt                      S # t          $ r t                      cY S w xY w)zRead the disabled plugins set from config.yaml.

    An explicit deny-list. A plugin name here never loads, even if also
    listed in ``plugins.enabled``.
    r   load_configr3   r  default)r   r  r   r   listr  rl   )r  configr  s      r(   r   r   V  s    11111169j"EEE *8T : :Es8}}}E   uus   AA A21A2r  c                    ddl m}m}  |            }d|vri |d<   t          |           |d         d<    ||           dS )z/Write the disabled plugins list to config.yaml.r   r  save_configr3   r  Nr   r  r  sorted)r  r  r  r  s       r(   r   r   e  sg    ::::::::[]]Fy$*8$4$4F9j!Kr*   c                 b   	 ddl m}   |             }|                    di           }t          |t                    st                      S |                    dg           }t          |t                    rt          |          nt                      S # t          $ r t                      cY S w xY w)zRead the enabled plugins allow-list from config.yaml.

    Plugins are opt-in: only names here are loaded. Returns ``set()`` if
    the key is missing (same behaviour as "nothing enabled yet").
    r   r  r3   r  )r   r  r   r   rb   r  r  rl   )r  r  plugins_cfgr  s       r(   r   r   o  s    	111111jjB//+t,, 	55L//)R00)'488Cs7|||ceeC   uus   AB AB B.-B.r  c                    ddl m}m}  |            }d|vri |d<   t          |           |d         d<    ||           dS )z.Write the enabled plugins list to config.yaml.r   r  r3   r  Nr  )r  r  r  r  s       r(   r   r     se    ::::::::[]]Fy#)'??F9i Kr*   c                   ddl m}  |            }t          |           s-|                    d|  d           t	          j        d           t                      }t                      }| |v r| |vr|                    d|  d           dS |                    |            |	                    |            t          |           t          |           |                    d	|  d
           dS )zEAdd a plugin to the enabled allow-list (and remove it from disabled).r   r   [red]Plugin '$' is not installed or bundled.[/red]r
   [dim]Plugin 'z' is already enabled.[/dim]Nr   z.[/bold] enabled. Takes effect on next session.)r   r   _plugin_existsrz   r   r   r   r   r   r   r   r   r   r   r|   r  r  s        r(   
cmd_enabler&    s   $$$$$$giiG$ PdPPPQQQ  G ""Hw4x//GdGGGHHHKKTgx   MM	(4 	( 	( 	(    r*   c                   ddl m}  |            }t          |           s-|                    d|  d           t	          j        d           t                      }t                      }| |vr| |v r|                    d|  d           dS |                    |            |	                    |            t          |           t          |           |                    d	|  d
           dS )zBRemove a plugin from the enabled allow-list (and add to disabled).r   r   r!  r"  r
   r#  z' is already disabled.[/dim]Nu"   [yellow]⊘[/yellow] Plugin [bold]z/[/bold] disabled. Takes effect on next session.)r   r   r$  rz   r   r   r   r   r   r   r   r   r%  s        r(   cmd_disabler(    s   $$$$$$giiG$ PdPPPQQQ  G ""H7tx//HdHHHIIIOODLLgx   MM	( 	( 	( 	(    r*   c                   t                      }|                                rp|| z                                  rdS |                                D ]B}|                                st          |          }|                    d          | k    r dS Cddlm}  |            }|                                rI|| z  }|                                r0|dz                                  s|dz                                  rdS dS )zCReturn True if a plugin with *name* is installed (user) or bundled.Tr   r   get_bundled_plugins_dirrd   r   F)r7   r   r   rr   r   hermes_cli.pluginsr+  rh   )r   user_dirchildr   r+  repo_plugins	candidates          r(   r$  r$    s,    ~~H tO##%% 	4%%'' 	 	E<<>> %e,,H||F##t++tt , ;:::::**,,L  4'	 	&..00	L(0022	 45r*   r  c                     	 ddl n# t          $ r dY nw xY wi dfdddlm}    |             ddd            t	                      ddd           t                                                    S )ux  Return a list of (key, version, description, source, dir_path) for
    every plugin the loader can see — user + bundled.

    Mirrors :meth:`PluginManager._scan_directory_level` so category-namespaced
    plugins (``observability/langfuse``, ``image_gen/openai``) surface here
    just like flat ones (``disk-cleanup``). A subdirectory with no
    ``plugin.yaml`` of its own is treated as a category and recursed into
    one level deeper (depth capped at 2, same as the loader).

    The returned ``key`` is the path-derived registry key — the value the
    user types into ``hermes plugins enable <key>``. For category-namespaced
    plugins that's ``<category>/<dirname>``; for flat plugins it's the
    manifest's ``name`` (or the directory name if the manifest omits it).

    User entries override bundled on key collision, matching
    ``PluginManager.discover_and_load``.
    r   Nbaser   sourcer:   prefixdepthr   r   rs   c                \   |                                  sd S t          |                                           D ]q}|                                 s|dk    r|dk    r
|j        dv r.|dz  }|                                s|dz  }|                                r|j        }d}d}r	 t          |d          5 }	                    |	          pi }
d d d            n# 1 swxY w Y   |
                    d	|j                  }|
                    d
d          }|
                    dd          }n# t          $ r Y nw xY w|r| d|j         n|}|}|dk    r|dz                                  rd}|||||f|<   C|dk    rK|r| d|j         n|j        } ||||dz              sd S )Nr   bundled>   memorycontext_enginerd   r   r   re   rf   r   versionr   r>   userrP   r   r
   )	r   r  r   r   rh   rj   rk   r   rl   )r2  r3  r4  r5  r   ro   manifest_namer:  r   rp   r   key	src_label
sub_prefix_scanseenri   s                 r(   r@  z$_discover_all_plugins.<locals>._scan  s\   {{}} 	F'' .	4 .	4A88:: 

i''F:::-M '')) 1 !L 0##%%  !  !-'BBB ?a'+~~a'8'8'>BH? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(0VQV(D(D"*,,y""="=&.ll="&E&E$    /5G**!&***-"	V##V(;(;(=(=# %I !';	1ES	 zz17CF--QV---QVJE!VZ3333].	4 .	4s7   'D/8CD/C 	 D/#C 	$A
D//
D<;D<r*  r7  r   r;  )
r2  r   r3  r:   r4  r:   r5  r   r   rs   )ri   ImportErrorr,  r+  r7   r  values)r+  r@  rA  ri   s    @@@r(   _discover_all_pluginsrD    s    $    D14 14 14 14 14 14 14 14f ;:::::	E
!
!
#
#YA666	E,..&"a(((s   
 c                 T   ddl m}  ddlm}  |             }t	                      }|s,|                    d           |                    d           dS t                      }t                      } |dd	          }|                    d
d           |                    d           |                    dd           |                    d           |                    dd           |D ]>\  }}}	}
}||v rd}n	||v rd}nd}|	                    ||t          |          |	|
           ?|                                 |                    |           |                                 |                    d           |                    d           |                    d           dS )z>List all plugins (bundled + user) with enabled/disabled state.r   r   )Tablez [dim]No plugins installed.[/dim]:[dim]Install with:[/dim] hermes plugins install owner/repoNPluginsF)r   
show_linesNamebold)styleStatusVersiondimDescriptionSourcez[red]disabled[/red]z[green]enabled[/green]z[yellow]not enabled[/yellow]z-[dim]Interactive toggle:[/dim] hermes pluginsz?[dim]Enable/disable:[/dim] hermes plugins enable/disable <name>uI   [dim]Plugins are opt-in by default — only 'enabled' plugins load.[/dim])r   r   
rich.tablerF  rD  rz   r   r   
add_columnadd_rowr:   )r   rF  r|   entriesr  r  tabler   r:  r   r3  _dirstatuss                r(   cmd_listrY  -  s   $$$$$$      giiG#%%G 8999RSSS  G ""HE	e444E	V6***	X	Ye,,,	]###	XU+++4; G G0g{FD8*FFW__-FF3FdFCLL+vFFFFMMOOOMM%MMOOOMMABBBMMSTTTMM]^^^^^r*   list[tuple[str, str]]c                 \    	 ddl m}  d  |             D             S # t          $ r g cY S w xY w)zAReturn [(name, description), ...] for available memory providers.r   discover_memory_providersc                    g | ]
\  }}}||fS r1   r1   )r   r   r   _avails       r(   r   z._discover_memory_providers.<locals>.<listcomp>]  s#    SSS!3tVtSSSr*   )plugins.memoryr]  rl   r\  s    r(   _discover_memory_providersra  Y  s[    <<<<<<SS7P7P7R7RSSSS   			s    ++c                    g } t                      }	 ddlm}  |            D ]6\  }}}||vr,|                     ||f           |                    |           7n# t
          $ r Y nw xY w	 ddlm}m}  |              |            }|r6t          |dd          r%|j
        |vr|                     |j
        df           n# t
          $ r Y nw xY w| S )aZ  Return [(name, description), ...] for available context engines.

    Includes repo-shipped engines from ``plugins/context_engine/`` AND
    plugin-registered engines (third-party engines installed as Hermes
    plugins via ``ctx.register_context_engine``). Repo-shipped descriptions
    win when a plugin-registered engine collides on name.
    r   )discover_context_engines)discover_pluginsget_plugin_context_enginer   Nzinstalled plugin)r  plugins.context_enginerc  r   r   rl   r,  rd  re  getattrr   )	enginesrA  rc  r   r   r_  rd  re  plugin_engines	            r(   _discover_context_enginesrj  b  sH    &(GUUDCCCCCC":":"<"< 	 	D$4d|,,,	    RRRRRRRR1133 	EW]FDAA 	EmFX`dFdFdNNM.0BCDDD    Ns%   AA 
A'&A'+AC   
CCc                 p    	 ddl m}   |             }t          |ddd          pdS # t          $ r Y dS w xY w)zBReturn the current memory.provider from config (empty = built-in).r   r  r8  providerr   r  r   r  r   rl   r  r  s     r(   _get_current_memory_providerro    sb    111111vxR@@@FBF   rr   $' 
55c                 p    	 ddl m}   |             }t          |ddd          pdS # t          $ r Y dS w xY w)z.Return the current context.engine from config.r   r  contextengine
compressorr  rm  rn  s     r(   _get_current_context_engineru    sb    111111vy(LIIIY\Y   ||rp  c                h    ddl m}m}  |            }d|vri |d<   | |d         d<    ||           dS )z'Persist memory.provider to config.yaml.r   r  r8  rl  Nr   r  r  r   r  r  r  s       r(   _save_memory_providerry    s_    ::::::::[]]Fvx#'F8Z Kr*   c                h    ddl m}m}  |            }d|vri |d<   | |d         d<    ||           dS )z&Persist context.engine to config.yaml.r   r  rr  rs  Nrw  rx  s       r(   _save_context_enginer{    s_    ::::::::[]]Fy"&F9hKr*   c                    ddl m}  t                      }t                      }dg}dg}d}|D ]R\  }}|                    |           |r| d| n|}|                    |           ||k    rt          |          dz
  }S|rC||vr?|                    |           |                    | d           t          |          dz
  } | d||	          }	||	         }
|
|k    rt          |
           d
S dS )zDLaunch a radio picker for memory providers. Returns True if changed.r   curses_radiolistzbuilt-in (default)r   r   r
    (not found)zMemory Provider (select one)r   itemsselectedTF)hermes_cli.curses_uir~  ro  ra  r   rS   ry  )r~  current	providersr  namesr  r   r   r   choicenew_providers              r(   _configure_memory_providerr    sK   555555*,,G*,,I ""EDEH & &
dT+/94'''''TU7??5zzA~H  "7%''W---...u::>,  F =Lwl+++t5r*   c                    ddl m}  t                      }t                      }dg}dg}d}|D ]R\  }}|                    |           |r| d| n|}|                    |           ||k    rt          |          dz
  }S|dk    rC||vr?|                    |           |                    | d           t          |          dz
  } | d||	          }	||	         }
|
|k    rt          |
           d
S dS )zCLaunch a radio picker for context engines. Returns True if changed.r   r}  zcompressor (default)rt  r   r
   r  zContext Engine (select one)r  TF)r  r~  ru  rj  r   rS   r{  )r~  r  rh  r  r  r  r   r   r   r  
new_engines              r(   _configure_context_enginer    sN   555555)++G'))G $$ENEH & &
dT+/94'''''TU7??5zzA~H ,7%#7#7W---...u::>+  F vJWZ(((t5r*   c            	     v   ddl m}   |             }t                      }t                      }t	                      }g }g }t                      }t          |          D ]h\  }\  }	}
}}}|r|	 d| n|	}|dk    r| d}|                    |	           |                    |           |	|v r|	|vr|                    |           it                      pd}t                      }d|t          fd|t          fg}t          |          }t          |          }|s.|s,|                    d	           |                    d
           dS t          j                                        s|                    d           dS 	 ddl}t'          |||||||           dS # t(          $ r t+          ||||||           Y dS w xY w)uJ   Interactive composite UI — general plugins + provider plugin categories.r   r   r   r7  z
 [bundled]built-inzMemory ProviderzContext EnginezE[dim]No plugins installed and no provider categories available.[/dim]rG  Nz0[dim]Interactive mode requires a terminal.[/dim])r   r   rD  r   r   r  	enumerater   r   ro  ru  r  r  r<   rz   r   r   r   curses_run_composite_uirB  _run_composite_fallback)r   r|   rU  enabled_setdisabled_setplugin_namesplugin_labelsplugin_selectedir   _versionr   r3  _dr   current_memorycurrent_context
categorieshas_pluginshas_categoriesr  s                        r(   
cmd_toggler    sQ   $$$$$$giiG $%%G"$$K$&&LLMeeO8A'8J8J # #44D(K2=G4.....4Y(((ED!!!U###;4|#;#;""" 233AzN133O	N,FG	?,EFJ
 |$$K*%%N ~ ]^^^RSSS 9 HIIIC&,&
G	= 	= 	= 	= 	= C C Cm_ ,j'	C 	C 	C 	C 	C 	CCs   ;F F87F8c           	          ddl m} t          |          t          |          t                    z   ddd fd}                     |            |             t                      }	t          |          }
t          |          D ]I\  }}|v r+|	                    |           |
                    |           4|
                    |           Jt                      }|	|k    }|
|k    }|s|ret          |	           t          |
           |                    dt          |	           dt          |          t          |	          z
   d           ndk    r|                    d	           d
         r:t                      pd}t                      }|                    d| d| d           dk    sd
         r|                    d           |                                 dS )z<Custom curses screen with checkboxes + category action rows.r   )flush_stdinF)plugins_changedproviders_changedc                                        d                                           r                                                                                      dj        d                               dj        d                               dj        d                               dj        dk    rdnj	        d           d}d}	 | 
                                 |                                 \  }}	 j        }                                r|                    d          z  }|                     ddd	|dz
  |           |                     ddd
|dz
  j                   n# j        $ r Y nw xY w|dz
  }||k     r|}n|||z   k    r||z
  dz   }d}dk    r"||dz
  k     rf	 j        }                                r|                    d          z  }|                     |dd|dz
  |           n# j        $ r Y nw xY w|dz  }t#                    D ]}	||dz
  k    r n|	v rdnd}
|	|k    rdnd}d| d|
 d|	          }j        }|	|k    r3j        }                                r|                    d          z  }	 |                     |d||dz
  |           n# j        $ r Y nw xY w|dz  }||dz
  k     r|dz  }dk    r"||dz
  k     r	 j        }                                r|                    d          z  }|                     |dd|dz
  |           n# j        $ r Y nw xY w|dz  }t'                    D ]\  }\  }}}||dz
  k    r n|z   }||k    rdnd}d| d|dd| }j        }||k    r3j        }                                r|                    d          z  }	 |                     |d||dz
  |           n# j        $ r Y nw xY w|dz  }|                                  |                                 }|j        t/          d          hv rdk    r|dz
  z  }n|j        t/          d          hv rdk    r|dz   z  }n|t/          d          k    r|k     r                    |h           nY|z
  }d|cxk    rk     r~n nB                                 |         \  }}} |            }|r/dd<   ||dk    rt7                      pdnt9                      |f|<                                   }                                                                   |                      d                                           r                                                                                      dj        d                               dj        d                               dj        d                               dj        dk    rdnj	        d                                d           n|j!        ddhv r|k     rdd<   d S |z
  }d|cxk    rk     r~n n                                 |         \  }}} |            }|r/dd<   ||dk    rt7                      pdnt9                      |f|<                                   }                                                                   |                      d                                           r                                                                                      dj        d                               dj        d                               dj        d                               dj        dk    rdnj	        d                                d           n|dt/          d          hv rdd<   d S 3)Nr   r
   r[   rO            TrH  uB     ↑↓ navigate  SPACE toggle  ENTER configure/confirm  ESC donez  General Pluginsu   ✓ u   → [z] z  Provider Pluginsz   z<24u    ▸ kjr  r  
      r     q)"curs_set
has_colorsstart_coloruse_default_colors	init_pairCOLOR_GREENCOLOR_YELLOW
COLOR_CYANCOLORSCOLOR_WHITEcleargetmaxyxA_BOLD
color_pairaddnstrA_DIMerrorrangeA_NORMALr  refreshgetchKEY_UPordKEY_DOWNsymmetric_difference_updateendwinro  ru  initscrnoechocbreakkeypad	KEY_ENTER) stdscrcursorscroll_offsetmax_ymax_xhattrvisible_rowsr   sattrr  checkarrowlineattrcicat_namecat_current_cat_fncat_idxr=  	_cat_name_cat_curcat_fnchangedr  chosenr  n_categories	n_pluginsr  result_holdertotal_itemss                            r(   _drawz _run_composite_ui.<locals>._drawA  s	    	T   %%'''Q 2B777Q 3R888Q 12666QV]Q%6%6F<NPRSSSr	LLNNN!??,,LE5$$&& 2V..q111Eq!Y	5AAAq^AIv|   
 <    !19L%% &=<777 & 5 9A 1}}uqy== &!,,.. :!V%6%6q%9%99Eq!-@%!)USSSS!<   FAy))  AEAI~~()VHHE()VHHECuCCCCq1ACCD!?DF{{%}!,,.. 9 F$5$5a$8$88Dq!T519dCCCC!<   FAA 519}}Q aA	MM"ME((** 6!2!21!5!55NN1a)=uqy%PPPP|   DQ<Ej<Q<Q  8B8;EAI~~'"nG(/6(9(9HHsELuLLLLL{LLD!?D&((%}!,,.. 9 F$5$5a$8$88Dq!T519dCCCC!<   FAANN,,..Cv}c#hh///??$qjK7F#c((333??$qjK7FCI%%66x@@@@  )+BB---------6@n3	8V"(&((" AEM*=> !*PRVWPWPW < > > L*%@%B%B &	.JrN "(!1!1d+++!,,.. d"..000"55777",,Q0BBGGG",,Q0CRHHH",,Q0A2FFF",,QV]Q5F5FFL^`bccc***)2r222I%%7;M"34F  )+BB---------6@n3	8V"(&((" AEM*=> )PRVWPWPW < > > L*%@%B%B &	.JrN "(!1!1d+++!,,.. d"..000"55777",,Q0BBGGG",,Q0CRHHH",,Q0A2FFF",,QV]Q5F5FFL^`bccc***SXX&&37/0er	s]   A0E2 2
E?>E?4AH 
HHJ66
KK,AL< <
M	M	O--
O:9O:u%   
[green]✓[/green] General plugins: z
 enabled, z
 disabled.z&
[dim]General plugins unchanged.[/dim]r  r  u*   [green]✓[/green] Memory provider: [bold]z[/bold]  Context engine: [bold]z[/bold]z/[dim]Changes take effect on next session.[/dim]N)r  r  r  rS   wrapperr  r   r   r   r   r   rz   ro  ru  )r  r  r  r  r  r  r|   r  r  new_enablednew_disabledr  r   prev_enabledenabled_changeddisabled_changed
new_memorynew_contextr  r  r  r  r  s   ` `  `            @@@@@r(   r  r  3  s    100000!!FL!!I z??Ll*K(-EJJM~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~@ NN5KMMM uuKHL\** # #4;;OOD!!!  &&&&T""""#%%L!\1O#x/ A* A+&&&<(((@K8H8H @ @<  3{#3#33@ @ @	
 	
 	
 	
 
Q?@@@() 
133Az
133:J : :%0: : :	
 	
 	

 1}}&9:}GHHHMMOOOOOr*   c           
     T   ddl m}m} t           |d|j                             | rt          |          }t           |d|j                             t           |d|j                             	 t          |          D ]8\  }	}
|	|v r |d|j                  nd}t          d	| d
|	dz   dd|
            9t                       	 t           |d|j                            
                                }|snst          |          dz
  }d|cxk    rt          |           k     rn n|                    |h           n# t          t          t           f$ r Y dS w xY wt                       t                      }t          |          }t          |           D ]I\  }	}|	|v r+|                    |           |                    |           4|                    |           Jt'                      }||k    s||k    rt)          |           t+          |           |rt           |d|j                             t          |          D ]%\  }\  }}}t          d	|dz    d| d| d           &t                       	 t           |d|j                            
                                }|rEt          |          dz
  }d|cxk    rt          |          k     rn n ||         d                      n# t          t          t           f$ r Y nw xY wt                       dS )z1Text-based fallback for the composite plugins UI.r   )Colorscolorz

  Pluginsz
  General Pluginsz&  Toggle by number, Enter to confirm.
Tu   [✓]z[ ]r   r  r
   z>2z. z"  Toggle # (or Enter to confirm): Nz
  Provider Pluginsr  ]z"  Configure # (or Enter to skip): rO   )hermes_cli.colorsr  r  rz   YELLOWr  DIMr  GREENr   rC   r   rS   r  rB   r   r   r   r   r   r   r   )r  r  r  r  r  r|   r  r  r  r  r   markervalidxr  r  r   r  r  r  r  r  s                         r(   r  r  ,  s    0///////	%%v}
-
-...   -_%%ee)6=99:::ee=vzJJKKK	%m44 9 95<=KKz6<888U7677AE777778888GGGEE"F
SSTTZZ\\ #hhl////c,///////66u=== 18<   GGG	  55MM .. 	' 	'GAtF{{%%%$$T****  &&&&')),&&,(*B*Bk***|,,,  ee*FM::;;;3<Z3H3H 	= 	=/B/;;rAv;;;;[;;;<<<<	BFJOOPPVVXXC (XX\,,,,S__,,,,,%JrN1%'''-x8 	 	 	D	 
GGGGGs,   2E  AE E! E!A7K= =LLdict[str, Any]c               l   g }	 t          |           }|                    d          r|                    d           n# t          $ r Y nw xY w	 t	          | |          \  }}}n)# t
          $ r}dt          |          dcY d}~S d}~ww xY wt          |          }	|rdt                      }
t                      }|

                    |           |                    |           t          |
           t          |           d}|dz  }|                                rt          |          }d|||	||d	S )
zPNon-interactive install for the web dashboard. Returns a JSON-serializable dict.r   zEInsecure URL scheme; prefer https:// or git@ for production installs.r   Fr	  r  Nr   T)r	  r   warningsmissing_envafter_install_pathr  )rW   rQ   r   rB   r   r,   r:   r   r   r   r   r   r   r   rh   )rK   r   r   r  r   rH   r   r   excr  endishintaps                 r(   dashboard_install_pluginr	  h  s    H":..455 	OOW      05I6
 6
 6
2"NN   0 0 0c#hh////////0 ..@AAK  !!
~N###"3D	$	$B	yy{{ 2ww %""  s-   9> 
A
AA% %
B/B BBc                   	 ddl m} n# t          $ r Y dS w xY w	 ddlm}m}  |              |            }|j                                        D ]P\  }}|j        j	        | k    s|| k    r5|j
        D ]+}|                    |          }|r|j        r|j        c c S , nQn# t          $ r Y nw xY w	 ddlm}	  |	            t                      fD ]}
|
                                s|
| z  }|                                rRt!          |          }|                    d          pg D ]+}|                    |          }|r|j        r|j        c c S ,n# t          $ r Y nw xY wdS )u!  Return the toolset key a plugin registers its tools under, or None.

    Queries the live tool registry — the plugin must already be loaded.
    Falls back to reading ``provides_tools`` from plugin.yaml and looking
    up the toolset from the registry for the first tool name found.
    r   )registryN)rd  get_plugin_managerr*  provides_tools)tools.registryr  rl   r,  rd  r  _pluginsr  r   r   tools_registered	get_entrytoolsetr+  r7   r   rr   r   )r   r  rd  r  manager_keyloaded	tool_namer   r+  r2  r0  r   s                r(   _get_plugin_toolset_keyr    s(   +++++++   ttKKKKKKKK$$&&#,2244 	 	LD&#t++tt||!'!8 - -I$..y99E - -$},,,,, 0<    >>>>>>,,..? 		- 		-D;;== tI!! -))44!).>!?!?!E2 - -I$..y99E - -$},,,,,		-     4s=   	 
BB" B" "
B/.B/3BE E 
E"!E"c                  t          |           }|sdS ddlm}m}  |            }|                    d          }t          |t                    si }||d<   d}|                                D ]T\  }}	t          |	t                    s|r||	vr|		                    |           d}9||	v r|	
                    |           d}U|r|s
|s|g|d<   d}|r ||           dS dS )zAdd or remove a plugin's toolset from platform_toolsets for all platforms.

    Only acts if the plugin actually provides tools (has a toolset key).
    Nr   r  platform_toolsetsFTcli)r  r   r  r  r   r   rb   r  r  r   remove)
r   r   toolset_keyr  r  r  r  r  platformts_lists
             r(   _toggle_plugin_toolsetr    sS   
 *$//K ::::::::[]]F

#677'.. 8&7"#G.4466 	 	''4(( 	 	')){+++G##NN;'''G  g &7 $/=%  F r*   c               "   t          |           s	dd|  ddS t                      }t                      }|rm| |v r
| |vrd| ddS |                    |            |                    |            t          |           t          |           t          | d           d| ddS | |vr
| |v rd| ddS |                    |            |                    |            t          |           t          |           t          | d           d| ddS )zEnable or disable a plugin in ``config.yaml`` (runtime allow/deny lists).

    For plugins that provide tools (toolsets), also toggles the toolset in
    ``platform_toolsets`` so the agent actually sees the tools in sessions.
    Fr   z' is not installed or bundled.r   T)r	  r   	unchanged)r   )r$  r   r   r   r   r   r   r  )r   r  r  r  s       r(   "dashboard_set_agent_plugin_enabledr"    sO    $ W&U&U&U&UVVV			B


C >2::$c//4@@@
tD"3tD1111Du===2~~$#++Dt<<<JJtGGDMMMbs4....5999r*   Optional[Path]c                    t                      }	 t          | |d          }n# t          $ r Y dS w xY w|                                r|ndS )z>Resolved path under ``~/.hermes/plugins/<name>`` if it exists.Tr8   N)r7   rJ   rB   r   )r   r;   rH   s      r(   _user_installed_plugin_dirr%    s_    ..K&t[tLLL   tt]]__.66$.s   # 
11c                   t          |           }|dd|  dt                       ddS |dz                                  s	dd|  ddS t          |          \  }}|sd|dS d	d
lm} t          | |                       d|v }d| ||dS )z1``git pull`` inside ``~/.hermes/plugins/<name>``.NFr   ' was not found under r?   r   rP   z-' is not a git checkout; cannot pull updates.r   r   r  T)r	  r   r
  r!  )r%  r7   rh   r  r   r   r   )r   rH   r	  msgr   r!  s         r(   dashboard_update_user_pluginr)    s    '--F~MMMLNNMMM
 
 	

 VO##%% 
SSSS
 
 	

 #6**GB +c***$$$$$$		***$+I)LLLr*   rH   tuple[bool, str]c           	        t                      }|sdS 	 t          j        |ddgdddt          |                     }n"# t          $ r Y dS t          j        $ r Y dS w xY w|j        dk    r:|j        pd	                                p|j	                                        }d
|pdfS d|j	                                        fS )N)Fr   pullz	--ff-onlyTr   )r   r   r   cwd)Fz$Git pull timed out after 60 seconds.r   r   Fzgit pull failed.)
r)   r   r   r:   r   r   r   r   rC   r   )rH   r   r   r   s       r(   r  r  2  s    %''G =<<=fk*F
 
 
  = = =<<<$ = = =<<<= A}"))++Dv}/B/B/D/Dc////$$&&&&s   )> 
AAAc                    t                      }t                      D ]\  }}}}}|| k    r|dk    rdddc S t          |           }|dd|  d| ddS t          j        |           d	| d
S )z7Delete a plugin tree under ``~/.hermes/plugins/`` only.r7  Fz5Bundled plugins cannot be removed from the dashboard.r   Nr   r'  r?   T)r	  r   )r7   rD  r%  r   r   )r   r;   n_verr  src_pathrH   s           r(   dashboard_remove_user_pluginr3  I  s    ..K#8#:#: c c4S%99	))*abbbbb'--F~JJJKJJJ
 
 	

 M&%%%r*   c                t   t          | dd          }|dk    rQd}t          | dd          rd}nt          | dd          rd}t          | j        t          | dd          |	           dS |d
k    rt          | j                   dS |dv rt          | j                   dS |dk    rt          | j                   dS |dk    rt          | j                   dS |dv rt                       dS |t                       dS ddl
m}  |                                d| d           t          j        d           dS )z$Dispatch hermes plugins subcommands.plugins_actionNinstallr   FT	no_enabler   )r   r   update>   rmr  	uninstalldisable>   lsr  r   r   z[red]Unknown plugins action: z[/red]r
   )rg  r  rK   r  r   r  r&  r(  rY  r  r   r   rz   r   r   )argsaction
enable_argr   s       r(   plugins_commandr@  [  s   T+T22F
45)) 	JJT;.. 	JO$//	
 	
 	
 	
 	
 	

 
8		49	0	0	049	8		49	9		DI	>	!	!




	((((((		FFFFGGGr*   )r   r   )r   r   )r   r:   r;   r   r9   r<   r   r   )rK   r:   r   r:   )rX   r:   r   r:   )ra   r   r   rb   )ra   r   r   rs   )r   rb   r   r   )r   rb   r   rs   )ra   r   rK   r:   r   rs   )r   r:   r;   r   r   rs   )r   r:   r;   r   r   r   )rK   r:   r   r<   r   r   )FN)rK   r:   r   r<   r   r   r   rs   )r   r:   r   rs   )r   r  )r  r  r   rs   )r  r  r   rs   )r   r:   r   r<   )r   r  )r   rs   )r   rZ  )r   r:   )r   r<   )rK   r:   r   r<   r   r<   r   r  )r   r:   r   r   )r   r:   r   r<   r   rs   )r   r:   r  r<   r   r  )r   r:   r   r#  )r   r:   r   r  )rH   r   r   r*  )Hr0   
__future__r   	functoolsloggingr   r   r   r   pathlibr   typingr   r   r   r   r   r   hermes_cli.secret_promptr	   	getLoggerr-   rm   	lru_cacher)   rl   r,   r   r7   rJ   rW   r`   rr   r   r   r   r   r   r   r   r  r  r  r   r   r   r   r&  r(  r$  rD  rY  ra  rj  ro  ru  ry  r{  r  r  r  r  r  r	  r  r  r"  r%  r)  r  r3  r@  r1   r*   r(   <module>rI     s    # " " " " "      				      



                       , , , , , , % % % % % % 9 9 9 9 9 9		8	$	$ Q    DS S S S S9 S S S       	6 6 6 6 6 6r   8         *\ \ \ \$H H H HV   :   
 
 
 
$Z6 Z6 Z6 Z6~ !P P P P Pf%+ %+ %+ %+P( ( ( ("         $      6   4   4P P P Pf$_ $_ $_ $_X      @            # # # #L# # # #V5C 5C 5C 5Cpv v vr9 9 9x. . . .b+ + + +\# # # #L: : : :B/ / / /M M M M4' ' ' '.& & & &$           r*   