
    (Gjk                      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
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	
          dwd            Z G d de          Zd	ZdxdZdddydZh dZdzdZ d{d Z!d|d"Z"d}d%Z#d~d'Z$dd*Z%dd+Z&dd,Z'dd-Z(dd.Z)dd1Z*	 	 ddd4Z+dd5Z,dd6Z-dd8Z.dd:Z/dd;Z0dd=Z1dd>Z2dd@Z3ddDZ4dddFZ5ddGZ6ddHZ7ddIZ8ddLZ9ddSZ:ddUZ;dddWZ<dd[Z=ddd]Z>dd_Z?dd`Z@ddaZAddbZBddcZCdddZDddeZEddfZFddgZGdh ZHdi ZIddkZJddlZKddmZLddnZMddpZNddqZOddtZPdduZQddvZRdS )uq  ``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         </home/rurouni/.hermes/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   J   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   Q   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/>
   blobpulltreewikipullscommitissuesactionscommitsreleases
identifiertuple[str, Optional[str]]c                ^   |                      d          r|                      d          r7| t          d          d         }|                    dd          d                             dd          d                             d          }|                    d          }t          |          d	k    rt	          |dd
                   r|d
         t
          v r|d                             d          }d}|d
         dk    rOt          |          dk    r<d                    d |dd         D                                           d          pd}d|d          d| d|fS d| v r2|                     d          \  }}}||                    d          pdfS d}| 	                    |          }	|	dk    rM| d|	t          d          z            }| |	t          |          z   d                             d          }||pdfS | dfS d |                     d                              d          D             }t          |          d
k    rO|d         |d         }}
d                    |d
d                                       d          }d|
 d| d}||pdfS t          d|  d          )u  Turn an identifier into a cloneable Git URL and optional subdirectory.

    Returns ``(git_url, subdir)`` where ``subdir`` is the path within the
    cloned repository that contains the plugin (``None`` when the plugin lives
    at the repo root).

    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
    - Browser URL: https://github.com/owner/repo/tree/main/path
      →  (https://github.com/owner/repo.git, "path")
    - Shorthand: owner/repo  →  https://github.com/owner/repo.git
    - Shorthand w/ subdir: owner/repo/path/to/plugin
      →  (https://github.com/owner/repo.git, "path/to/plugin")
    - Full URL w/ subdir (``.git`` boundary):
      https://github.com/owner/repo.git/path/to/plugin
      →  (https://github.com/owner/repo.git, "path/to/plugin")
    - Any URL w/ explicit subdir fragment (works for every scheme, incl.
      ``file://`` and ssh): <url>#path/to/plugin
      →  (<url>, "path/to/plugin")

    NOTE: ``http://`` and ``file://`` schemes are accepted but will trigger a
    security warning at install time.
    )zhttps://http://zgit@zssh://file://zhttps://github.com/N?r
   r   #r>         .gitrM      c              3     K   | ]}||V  	d S Nr1   .0ps     r(   	<genexpr>z#_resolve_git_url.<locals>.<genexpr>   s'      %@%@Aa%@a%@%@%@%@%@%@r*      z.git/c                    g | ]}||S r1   r1   rb   s     r(   
<listcomp>z$_resolve_git_url.<locals>.<listcomp>   s    >>>1A>Q>>>r*   zInvalid plugin identifier: 'zi'. Use a Git URL or 'owner/repo' shorthand (optionally with a subdirectory: 'owner/repo/path/to/plugin').)
startswithlensplitrC   all_GITHUB_BROWSER_SEGMENTSremovesuffixr   	partitionfindrB   )rU   r   partsreposubdirgit_url_fragmarkeridxowners              r(   _resolve_git_urlr{      s   6 QRR    !677 		Kc"788::;D::c1%%a(..sA66q9??DDDJJsOOE5zzQ3uRaRy>>eAhBZ6Z6ZQx,,V448v%%#e**// XX%@%@qrr%@%@%@@@FFsKKStFBU1XBBBBBFJJ *)33C88GQTZZ__455oof%%"99 !43V#4!45Gc&kk 1 3 34::3??FV^t,,4 ?>
((--33C88>>>E
5zzQAhat%)$$**3//::::::4((
	(z 	( 	( 	(  r*   
clone_rootrt   c                <   |                                  } | |z                                   }|| k    r| |j        vrt          d| d          |                                st          d| d          |                                st          d| d          |S )aI  Resolve ``subdir`` inside ``clone_root``, rejecting path traversal.

    Guards against ``..`` segments, absolute paths, and symlinks that would
    escape the cloned repository. Returns the resolved directory path.
    Raises ``PluginOperationError`` if the path escapes the clone, doesn't
    exist, or is not a directory.
    zPlugin subdirectory 'z' escapes the repository.z#' does not exist in the repository.z' is not a directory.)rD   r4   r,   existsis_dir)r|   rt   	candidates      r(   _resolve_subdir_withinr      s     ##%%Jf$--//I J:Y5F#F#F"EFEEE
 
 	
  
"OFOOO
 
 	
  
"AFAAA
 
 	
 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>   r^   Nr
   rg   :)rstripendswithrsplit)r   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)r~   yamlopen	safe_load	Exceptionloggerwarning)r   manifest_filer   fes        r(   _read_manifestr     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stemr~   r   copy2printr   OSError)r   consoleexample_file	real_name	real_pathr   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   rc   sr   s     r(   ri   z/_missing_requires_env_names.<locals>.<listcomp>9  sB    [[[!AEE&MM[--PQRXPYBZBZ[AfI[[[r*   )r   hermes_cli.configr   
isinstancer:   appendr   )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(   ri   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   r   secretF      — z  [dim]Get yours at: r   r   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   r   r   r	   rC   inputEOFErrorKeyboardInterruptr   r   )r   r   r   r   r   r   r   missingplugin_namespecr   descr   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.mdr   r   greenF)border_styleexpandz![green bold]Plugin installed:[/] z
[dim]Location:[/] u   ✓ Installed)r   titler   N)	rich.consoler   rich.markdownr   
rich.panelr   r~   	read_textr   )	r   rU   r   r   r   r   after_installcontentmds	            r(   _display_after_installr     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   r   )r   r;   r   r   s       r(   _display_removedr     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 ra   )r   r   )rc   ds     r(   re   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   r~   r   iterdirr   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|           |rt#          ||          }n|}t%          |          }|                    d          p?|r/|                    d                              dd          d         nt-          |          }	 t/          ||          }n/# t          $ r"}t          t	          |                    |d}~ww xY w|                    d          }|x	 t1          |          }n,# t          t2          f$ r t          d| d| d          dw xY w|t4          k    r0ddlm} t          d| d| dt4           d |             d	          d|                                r,|st          d| d| d          t=          j        |           t=          j         t	          |          t	          |                     ddd           n# 1 swxY w Y   |dz                                  p|dz                                  }|s2|dz                                  stB          "                    d |           dd!l#m$} tK          | |                       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   r>   r
   rg   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`.r   
plugin.yml__init__.pyz>%s has no plugin.yaml / __init__.py; may not be a valid pluginr   )'tempfiler{   rB   r,   r:   r7   TemporaryDirectoryr   r)   
subprocessrunFileNotFoundErrorTimeoutExpired
returncodestderrstdoutrC   r   r   r   r   r   r   rJ   int	TypeError_SUPPORTED_MANIFEST_VERSIONr   r   r~   r   rmtreemover   r   r   r   r   r   )rU   r   r   ru   rt   r   r;   tmp	tmp_clonegit_exeresulterr
tmp_targetr   r   rH   mvmv_intr   has_yamlr   installed_manifestinstalled_names                          r(   _install_plugin_corer    s    OOO2*:66 2 2 2"3q66**12 ..K		$	$	&	& E2#II(	)++ 	O&'MNNN	^'9c7C	NNK#	  FF ! 	 	 	&6  ( 	 	 	&7 	
 !!=7FM7R>>@@C&'BS'B'BCCC  	#/	6BBJJ"J!*--ll6** 
5;]FMM#%%c1--b11ATU\A]A] 		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1KE2 E2 E2 E2 E2 E2 E2 E2 E2 E2 E2 E2 E2 E2 E2N &..00TVl5J4R4R4T4TH 
Vm3;;== 
L	
 	
 	

 %$$$$$		***'//'++F33Bv{N%~55s    
AA  A*2L+C	L	
D
C##D
5DD

B;LGL
H!G>>HLH.-L.)IB-LLL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           |r|                    d| d	| d
           n|                    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rX   rY   zs[yellow]Warning:[/yellow] Using insecure/local URL scheme. Consider using https:// or git@ for production installs.z[dim]Cloning z
 (subdir: z
)...[/dim]	...[/dim]r   r   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   r{   rB   r   r   r   rj   r  r,   r~   r   r   stdinisattyr   r   rC   lowerr   r   _get_enabled_set_get_disabled_setadddiscard_save_enabled_set_save_disabled_set)rU   r   r  r   r   ru   _subdirr   rH   r  r  should_enableanswerenableddisableds                  r(   cmd_installr*  %  s    %$$$$$giiG+J77   .1../// 011 
G	
 	
 	

  :LgLLLLLMMMM8g888999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%C! !
D!+,DD!#;H H54H5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
   Nr^   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.[dim]r   )r   r   r7   r   rB   r   r   r   r~   _git_pull_plugin_dirr   rC   )	r   r   r   r;   rH   r   okoutputouts	            r(   
cmd_updater2  {  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   r   r   r   r   r  r   )r   r   r   r;   rH   r   s         r(   
cmd_remover5    s    $$$$$$giiG..K*4gFF   .1../// M&T;'''''r3  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   r9  r   r   listr6  r   )r9  configr)  s      r(   r   r     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   r9  save_configr3   r)  Nr   r9  r@  sorted)r)  r9  r@  r=  s       r(   r$  r$    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   r8  r3   r(  )r   r9  r   r   r   r6  r<  r   )r9  r=  plugins_cfgr(  s       r(   r  r    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(  NrA  )r(  r9  r@  r=  s       r(   r#  r#    se    ::::::::[]]Fy#)'??F9i Kr*   c                     t                      }|D ]$} |d         k    s |d         k    r
|d         c S % fd|D             }t          |          dk    r|d         S dS )u]  Resolve a user-supplied plugin identifier to its canonical registry key.

    Accepts either the bare manifest name (``nemo_relay``), the directory
    name, or the full path-derived key (``observability/nemo_relay``) and
    returns the canonical key the loader gates on (``manifest.key`` or, for a
    flat plugin, the bare name). Returns ``None`` when no plugin matches.

    This is the single normalization point so ``hermes plugins enable`` /
    ``disable`` write the same key that ``PluginManager`` matches against —
    nested category plugins (e.g. ``observability/nemo_relay``) included.
    r_   r   c                j    g | ]/}|d                               d          d         k    '|d          0S )r_   r>   rg   rl   rc   r   r   s     r(   ri   z'_resolve_plugin_key.<locals>.<listcomp>  s=    UUUTU1X^^C=P=PQS=T5T5TE!H5T5T5Tr*   r
   N_discover_all_pluginsrk   r   entriesr   leaf_matchess   `   r(   _resolve_plugin_keyrO    s     $%%G  58tuQx//8OOO  0
 VUUU'UUUL
<AA4r*   Optional[tuple]c                     t                      }|D ],} |d         k    s |d         k    r|d         |d         fc S - fd|D             }t          |          dk    r|d         S dS )a3  Resolve *name* to ``(canonical_key, source)`` or ``None`` if no match.

    Mirrors :func:`_resolve_plugin_key`'s normalization but also returns the
    plugin's source (``"bundled"``, ``"user"``, ``"project"``, ...) so the
    enable path can tell whether a built-in-override consent prompt is needed.
    r_   r   r\   c                z    g | ]7}|d                               d          d         k    '|d          |d         f8S )r_   r>   rg   r\   rH  rI  s     r(   ri   z2_resolve_plugin_key_and_source.<locals>.<listcomp>  sP       !&58>>#&&r*** 
q58***r*   r
   NrJ  rL  s   `   r(   _resolve_plugin_key_and_sourcerS    s     $%%G ( (58tuQx//!HeAh''''  0   *1  L <AA4r*   	plugin_idkeyr   c                   ddl m}m}  |            }|                    di           }t	          |t
                    si }||d<   |                    di           }t	          |t
                    si }||d<   |                    | i           }t	          |t
                    si }||| <   t          |          ||<    ||           dS )zEWrite ``plugins.entries.<plugin_id>.<key> = value`` into config.yaml.r   r?  r3   rM  N)r   r9  r@  
setdefaultr   r   r<   )	rT  rU  r   r9  r@  r=  rD  rM  r   s	            r(   _set_plugin_entry_flagrX    s    ::::::::[]]F##Ir22Kk4(( ('y$$Y33Ggt$$ )!(Iy"--EeT"" #"	eE#JKr*   allow_tool_overridec                   ddl m}  |            }t          |           }|-|                    d|  d           t	          j        d           |\  }}t                      }t                      }||v o||v}	|	s|                    |           |	                    |           |
                    d          d         }
|
|k    r|	                    |
           t          |           t          |           |                    d	| d
           n|                    d| d           |dk    rdS t          |||           dS )a  Add a plugin to the enabled allow-list (and remove it from disabled).

    For non-bundled plugins, prompt the operator about granting the
    privileged ``allow_tool_override`` capability (replacing built-in tools
    like ``shell_exec`` / ``write_file``). ``allow_tool_override`` is a
    tri-state: ``True`` grants without prompting, ``False`` declines without
    prompting, ``None`` (default) asks interactively. Bundled plugins are
    trusted and never prompted.
    r   r   N[red]Plugin '$' is not installed or bundled.[/red]r
   r>   rg   r  z.[/bold] enabled. Takes effect on next session.[dim]Plugin 'z' is already enabled.[/dim]bundled)r   r   rS  r   r   r   r  r   r!  r"  rl   r#  r$  _resolve_tool_override_grant)r   rY  r   r   resolvedrU  sourcer(  r)  already_enabledbares              r(   
cmd_enablerd  -  s    %$$$$$giiG .d33HPdPPPQQQKC  G ""HWn<H)<O HCyy~~b!3;;T"""'"""8$$$,s , , ,	
 	
 	
 	

 	FcFFFGGG  #/BCCCCCr*   c                \   |Zd}	 |                      |                                                                          }n# t          t          f$ r d}Y nw xY w|dv }|}t          |d|           |r|                     d| d| d           dS |                     d	| d
| d           dS )zResolve and persist the ``allow_tool_override`` grant for a plugin.

    ``allow_tool_override`` tri-state: True grants, False declines, None
    prompts interactively (defaulting to deny on a non-interactive stdin).
    Nz[yellow]Allow this plugin to replace built-in tools (e.g. shell_exec, write_file)?[/yellow]
  This is a privileged capability: an override can intercept everything the agent routes through that tool.
  Grant it? [y/N] r   >   r  r  rY  u!   [green]✓[/green] Granted [bold]zD[/bold] permission to override built-in tools ([dim]plugins.entries.z".allow_tool_override: true[/dim]).r-  z@ may not override built-in tools. Re-run `hermes plugins enable z2 --allow-tool-override` to grant this later.[/dim])r   rC   r  r   r   rX  r   )r   rU  rY  promptr'  rT  s         r(   r_  r_  _  s(    "! 		]]6**002288::FF+, 	 	 	FFF	$4I9&;=PQQQ 
S S S%.S S S	
 	
 	
 	
 	
 	 C    &)     	
 	
 	
 	
 	
s   9A   AAc                N   ddl m}  |            }t          |           }|-|                    d|  d           t	          j        d           t                      }t                      }||vr||v r|                    d| d           dS |                    |           |	                    d	          d
         }||k    r|                    |           |
                    |           t          |           t          |           |                    d| d           dS )zBRemove a plugin from the enabled allow-list (and add to disabled).r   r   Nr[  r\  r
   r]  z' is already disabled.[/dim]r>   rg   u"   [yellow]⊘[/yellow] Plugin [bold]z/[/bold] disabled. Takes effect on next session.)r   r   rO  r   r   r   r  r   r"  rl   r!  r#  r$  )r   r   r   rU  r(  r)  rc  s          r(   cmd_disablerh    sO   $$$$$$giiG
d
#
#C
{PdPPPQQQ  G ""H
'cXooGcGGGHHHOOC 99S>>"Ds{{LLgx   MM	( 	( 	( 	(    r*   c                $    t          |           duS )z>Return True if a plugin with *name* (bare name or key) exists.N)rO  r   s    r(   _plugin_existsrj    s    t$$D00r*   r   prefixc                   | dz  }|                                 s| dz  }|                                 sdS 	 ddl}n# t          $ r d}Y nw xY w| 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|}	||||	fS )z|Read a plugin.yaml manifest and return (name, version, description, key).

    Returns None if no manifest file exists.
    r   r   Nr   r   r   r   r   versionr   r>   )r~   r   ImportErrorr   r   r   r   r   )
r   rk  r   r   r   rm  r   r   r   rU  s
             r(   _read_manifest_inforo    s   
 %M!! )L(!! t   6DGK 	mg666 3!>>!,,23 3 3 3 3 3 3 3 3 3 3 3 3 3 3<<//Dll9b11G",,}b99KK 	 	 	D	"(
2V

af


dC+s**sF   ; A
	A
C# ,BC# BC# BA
C# #
C0/C0basera  
skip_namesdepthr  seenc           	        |                                  sdS t          |                                           D ]}|                                 s|dk    r|r
|j        |v r)t	          ||          }|?|\  }}	}
}||v r|dk    rM|}|dk    r|dz                                  rd}||	|
|||f||<   z|dk    r|r| d|j         n|j        }t          ||t                      ||dz   |           dS )	zRecursive directory scan matching PluginManager._scan_directory_level.

    Populates *seen* with key -> (name, version, description, source, dir, key).
    Nr   r^  userr^   r   r
   r>   )r   rB  r   r   ro  r~   _scan_levelr6  )rp  ra  rq  rk  rr  rs  r   infor   rm  r   rU  	src_label
sub_prefixs                 r(   rv  rv    sA    ;;== DLLNN## C Cxxzz 	A::*::)=)="1f--.2+D';d{{v22IQZ$7$7$9$9!	wY3GDIA::-3?)))))
Avsuuj%!)TBBBB%C Cr*   r<  c            	         i } ddl m}  |            }|dddhft                      dt                      ffD ]\  }}}t	          |||dd|            t          |                                           S )u0  Return a list of (name, version, description, source, dir_path, key) for
    every plugin the loader can see — user + bundled + project.

    Matches the ordering/dedup of ``PluginManager.discover_and_load``:
    bundled first, then user, then project; user overrides bundled on
    key collision.
    r   get_bundled_plugins_dirr^  memorycontext_engineru  r   )hermes_cli.pluginsr|  r7   r6  rv  r<  values)rs  r|  repo_pluginsrp  ra  skips         r(   rK  rK    s     D ;:::::**,,L	y8-=">?	' 5 5fd 	D&$At4444r*   r   c                .    | |v s||v rdS | |v s||v rdS dS )zAReturn the user-facing activation state for a plugin name or key.r)  r(  znot enabledr1   )r   r(  r)  rU  s       r(   _plugin_statusr    s5    x3(??zw#..y=r*   rM  argsr   c                    | }t          |dd          st          |dd          rd |D             }t          |dd          rfd|D             }|S )z*Apply ``hermes plugins list`` CLI filters.
no_bundledFru  c                *    g | ]}|d          dk    |S )r\   r^  r1   )rc   r   s     r(   ri   z*_filter_plugin_entries.<locals>.<listcomp>  s&    IIIe58y3H3HE3H3H3Hr*   r(  c           	     Z    g | ]'}t          |d          |d                   dk    %|(S )r   r_   rU  r(  )r  )rc   r   r)  r(  s     r(   ri   z*_filter_plugin_entries.<locals>.<listcomp>  sG     
 
 
eAhuQxHHHIUU UUUr*   )getattr)rM  r  r(  r)  filtereds     `` r(   _filter_plugin_entriesr    s    Ht\5)) JWT65-I-I JIIxIIItY&& 

 
 
 
 
'
 
 
 Or*   
Any | Nonec           
     J   ddl m} ddlm}  |            }t	                      }|s,|                    d           |                    d           dS t                      t                      t          ||           }t          | dd          r4fd	|D             }t          t          j        |d
                     dS t          | dd          rK|D ]F\  }}}}	}
}t          ||          }t          |dd|	ddt          |          dd|            GdS |s|                    d           dS  |dd          }|                    dd           |                    d           |                    dd           |                    d           |                    dd           |D ]V\  }}}}	}
}t          ||          }|dk    rd}n|dk    rd}nd }|                    ||t          |          ||	           W|                                 |                    |           |                                 |                    d!           |                    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jsonFc           	     j    g | ]/\  }}}}}}|t          ||           t          |          ||d0S )r  )r   statusrm  r   ra  )r  r:   )	rc   r   rm  r   ra  _dirrU  r)  r(  s	          r(   ri   zcmd_list.<locals>.<listcomp>)  sd     	
 	
 	
 >g{FD# (wcJJJw<<*  	
 	
 	
r*   r]   )indentplainr  12 8z3[dim]No plugins matched the selected filters.[/dim]Plugins)r   
show_linesNamebold)styleStatusVersiondimDescriptionSourcer)  z[red]disabled[/red]r(  z[green]enabled[/green]z[yellow]not enabled[/yellow]zA[dim]Compact view:[/dim] hermes plugins list --plain --no-bundledz-[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.tabler  rK  r   r  r   r  r  r  dumpsr  r:   
add_columnadd_row)r  r   r  r   rM  payloadr   rm  _descriptionra  r  rU  r  tabler   status_namer)  r(  s                   @@r(   cmd_listr    s3   $$$$$$      giiG#%%G 8999RSSS  G ""H$WdGXFFGtVU## 	
 	
 	
 	
 	
 BI	
 	
 	
 	dj+++,,,tWe$$ >E 	E 	E:D'<s#D'8EEEFVCCCCCCCLLCCCTCCDDDD KLLLE	e444E	V6***	X	Ye,,,	]###	XU+++9@ G G5g{FD#$T7H#FFF*$$*FFI%%-FF3FdFCLL+vFFFFMMOOOMM%MMOOOMMUVVV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   )rc   r   r   _avails       r(   ri   z._discover_memory_providers.<locals>.<listcomp>c  s#    SSS!3tVtSSSr*   )plugins.memoryr  r   r  s    r(   _discover_memory_providersr  _  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)r6  plugins.context_enginer  r   r!  r   r  r  r  r  r   )	enginesrs  r  r   r   r  r  r  plugin_engines	            r(   _discover_context_enginesr  h  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   r8  r}  providerr   r:  r   r9  r   r   r9  r=  s     r(   _get_current_memory_providerr    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   r8  contextengine
compressorr:  r  r  s     r(   _get_current_context_enginer    sb    111111vy(LIIIY\Y   ||r  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?  r}  r  Nr   r9  r@  r   r9  r@  r=  s       r(   _save_memory_providerr    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?  r  r  Nr  r  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  r  r  r   rk   r  )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)r  r   r
   r  zContext Engine (select one)r  TF)r  r  r  r  r   rk   r  )r  r  r  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            	        ddl m}   |             }t                      }t                      }t	                      }g }g }t                      }t          |          D ]q\  }\  }	}
}}}}|r|	 d| n|	}|dk    r| d}|                    |	           |                    |           |	|v s||v r|	|vr||vr|                    |           rt                      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   r^  z
 [bundled]built-inzMemory ProviderzContext EnginezE[dim]No plugins installed and no provider categories available.[/dim]r  Nz0[dim]Interactive mode requires a terminal.[/dim])r   r   rK  r  r   r6  	enumerater   r!  r  r  r  r  r<   r   r   r  r  curses_run_composite_uirn  _run_composite_fallback)r   r   rM  enabled_setdisabled_setplugin_namesplugin_labelsplugin_selectedir   _versionr   ra  _drU  r   current_memorycurrent_context
categorieshas_pluginshas_categoriesr  s                         r(   
cmd_toggler    si   $$$$$$giiG $%%G"$$K$&&LLMeeO=Fw=O=O # #99D(KS2=G4.....4Y(((ED!!!U###K3+#5#54|;S;SX[coXoXo""" 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 G G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    rF||dz
  k     rf	 j        }                                r|                    d          z  }|                     |dd|dz
  |           n# j        $ r Y nw xY w|dz  }|}	t#          |t%          |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        t3          d          hv r!dk    r|dz
  !z  }nm|j        t3          d          hv r!dk    r|dz   !z  }nE|j        t3          d          hv r/!dk    r't#          !dz
  |t%          d|dz
            z             }n|j        t3          d          hv r,!dk    r$t%          d|t%          d|dz
            z
            }n|j        k    rd}n|j        k    rt%          d!dz
            }n|t3          d          k    r|k     r                    |h           nY|z
  }d|cxk    rk     r~n nB                                  |         \  }}} |            }|r/d d<   ||dk    rtC                      pdntE                      |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tC                      pdntE                      |f|<   #                                } $                                 %                                 | &                    d                                           r                                                                                      dj        d                               dj        d                               dj        d                               dj        dk    rdnj	        d                                d           n|dt3          d           hv rd d<   d S )!Nr   r
   rg   r]   r\   rf      Tr  uV     ↑↓/j/k navigate  PgUp/PgDn page  SPACE toggle  ENTER configure/confirm  ESC donez  General Pluginsu   ✓r  u   → [z] z  Provider Pluginsz   z<24u    ▸ kjr   r_   br  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minmaxrangeA_NORMALr  refreshgetchKEY_UPordKEY_DOWN	KEY_NPAGE	KEY_PPAGEKEY_HOMEKEY_ENDsymmetric_difference_updateendwinr  r  initscrnoechocbreakkeypad	KEY_ENTER)"stdscrcursorscroll_offsetmax_ymax_xhattrvisible_rowsr  sattrplugin_startplugin_stopr  checkarrowlineattrcicat_namecat_current_cat_fncat_idxrU  	_cat_name_cat_curcat_fnchangedr  chosenr  n_categories	n_pluginsr  result_holdertotal_itemss"                             r(   _drawz _run_composite_ui.<locals>._drawG  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~	LLNNN!??,,LE5$$&& 2V..q111Eq!Y	5AAAqlAIv|   
 <    !19L%% &=<777 & 5 9A 1}}uqy== &!,,.. :!V%6%6q%9%99Eq!-@%!)USSSS!<   FA,!)]Sq=Q=Q-QRR|[99  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)3s88444?? q&3q%!);L;L2LMMF)3s88444?? FSEAI->->$>??F''&&Qa00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}~	s]   A0E2 2
E?>E?4AH 
HH=K
K'&K'AM   
M-,M-4P
PP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  r6  rk   wrapperr  r!  r"  r  r#  r$  r   r  r  )r  r  r  r  r)  r  r   r  rC  new_enablednew_disabledr  r   prev_enabledenabled_changeddisabled_changed
new_memorynew_contextr>  r?  r@  rA  rB  s   ` `  `            @@@@@r(   r  r  9  s    100000!!FL!!I z??Ll*K(-EJJMJ J J J J J J J J J J JX 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): r]   )hermes_cli.colorsrM  rN  r   YELLOWr6  DIMr  GREENr   rC   r  rk   r   rB   r   r   r!  r"  r  r#  r$  )r  r  r  r)  r  r   rM  rN  r>  r  r   rx   valry   rE  rF  r   rG  r5  r6  r7  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               r   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(  )r{   rj   r   rB   r  r,   r:   r   r  r   r!  r"  r#  r$  r~   )rU   r   r  rX  ru   r%  rH   r  r  excrY  endishintaps                  r(   dashboard_install_pluginr`  z  s    H+J77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/   <A 
AAA( (
B2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)r  get_plugin_managerr{  provides_tools)tools.registryrb  r   r  r  rc  _pluginsr  r   r   tools_registered	get_entrytoolsetr|  r7   r   r   r   )r   rb  r  rc  manager_keyloaded	tool_namer   r|  rp  r   r   s                r(   _get_plugin_toolset_keyrn    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)rn  r   r9  r@  r   r   r   r  r<  r   remove)
r   r  toolset_keyr9  r@  r=  rp  r=  platformts_lists
             r(   _toggle_plugin_toolsetrv    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.rW  T)r/  r   	unchanged)r  )rj  r  r   r!  r"  r#  r$  rv  )r   r(  r\  r]  s       r(   "dashboard_set_agent_plugin_enabledry    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?   rW  r^   z-' is not a git checkout; cannot pull updates.r   r   r,  T)r/  r   r0  rx  )r|  r7   r~   r.  r   r   r   )r   rH   r/  msgr   rx  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   rL   z	--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.  D  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.r^  Fz5Bundled plugins cannot be removed from the dashboard.rW  Nr   r~  r?   T)r/  r   )r7   rK  r|  r   r  )	r   r;   n_verr  src_pathrk  rH   s	            r(   dashboard_remove_user_pluginr  [  s    ..K)>)@)@ c c%4S%99	))*abbbbb'--F~JJJKJJJ
 
 	

 M&%%%r*   c                   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    rAd}t          | dd          rd}nt          | dd          rd}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>   rmrr  	uninstallrY  no_allow_tool_override)rY  disable>   lsr<  r   r   z[red]Unknown plugins action: z[/red]r
   )r  r*  rU   r2  r   r5  rd  rh  r  r  r   r   r   r   r   )r  action
enable_argallow_overrider   s        r(   plugins_commandr  m  s   T+T22F
45)) 	JJT;.. 	JO$//	
 	
 	
 	
 	
 	

 
8		49	0	0	049	8		 4.66 	#!NNT3U;; 	#"N49.AAAAAA	9		DI	>	!	!	((((((		FFFFGGGr*   )r   r   )r   r   )r   r:   r;   r   r9   r<   r   r   )rU   r:   r   rV   )r|   r   rt   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   rU   r:   r   r   )r   r:   r;   r   r   r   )r   r:   r;   r   r   r   )rU   r:   r   r<   r   r   )FN)rU   r:   r   r<   r  r  r   r   )r   r:   r   r   )r   r6  )r)  r6  r   r   )r(  r6  r   r   )r   r:   r   r   )r   r:   r   rP  )rT  r:   rU  r:   r   r<   r   r   ra   )r   r:   rY  r  r   r   )rU  r:   rY  r  r   r   )r   r:   r   r<   )r   r   rk  r:   )rp  r   ra  r:   rq  r6  rk  r:   rr  r  rs  r   r   r   )r   r<  )r   )
r   r:   r(  r6  r)  r6  rU  r:   r   r:   )
rM  r<  r  r   r(  r6  r)  r6  r   r<  )r  r  r   r   )r   r  )r   r:   )r   r<   )r   r   )rU   r:   r   r<   r  r<   r   rU  )r   r:   r  r<   r   r   )r   r:   r(  r<   r   rU  )r   r:   r   rz  )r   r:   r   rU  )rH   r   r   r  )Sr0   
__future__r   	functoolsr  loggingr   r   r   r   pathlibr   typingr   r   r   r   r   r   hermes_cli.secret_promptr	   	getLoggerr-   r   	lru_cacher)   r   r,   r  r7   rJ   rn   r{   r   r   r   r   r   r   r   r   r   r  r*  r2  r5  r   r$  r  r#  rO  rS  rX  rd  r_  rh  rj  ro  rv  rK  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r`  rn  rv  ry  r|  r  r.  r  r  r1   r*   r(   <module>r     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   @ @ @ @F   :         *\ \ \ \$H H H HV   :   
 
 
 
$b6 b6 b6 b6N !S S S S Sl%+ %+ %+ %+P( ( ( ("         $      6   *   (/D /D /D /D /Dd%
 %
 %
 %
P   @1 1 1 1
+ + + +< C  C  C  CF   *    
 
 
 
?_ ?_ ?_ ?_ ?_N      @            # # # #L# # # #V5C 5C 5C 5CpB B BJ9 9 9x. . . .b+ + + +\# # # #L: : : :B/ / / /M M M M4' ' ' '.& & & &$' ' ' ' ' 'r*   