2626
2727@plugin_app .command ("list" )
2828def list_plugins (
29+ marketplace : Optional [str ] = typer .Argument (
30+ None ,
31+ help = "Marketplace name to browse (from 'cam plugin repos'). If not specified, shows all plugins from all marketplaces." ,
32+ ),
2933 show_all : bool = typer .Option (
3034 False ,
3135 "--all" ,
32- help = "Show all plugins from marketplaces (not just enabled)" ,
36+ help = "Show all plugins from marketplaces (not just enabled). Deprecated: use without marketplace argument instead. " ,
3337 ),
3438 app_type : Optional [str ] = typer .Option (
3539 None ,
3640 "--app" ,
3741 "-a" ,
3842 help = f"App type to show plugins for ({ ', ' .join (VALID_APP_TYPES )} ). Shows all apps if not specified." ,
3943 ),
44+ query : Optional [str ] = typer .Option (
45+ None ,
46+ "--query" ,
47+ "-q" ,
48+ help = "Filter plugins by name or description" ,
49+ ),
50+ category : Optional [str ] = typer .Option (
51+ None ,
52+ "--category" ,
53+ "-c" ,
54+ help = "Filter plugins by category" ,
55+ ),
56+ limit : int = typer .Option (
57+ 50 ,
58+ "--limit" ,
59+ "-n" ,
60+ help = "Maximum number of plugins to show" ,
61+ ),
4062):
41- """List installed/enabled plugins."""
63+ """List installed and available plugins from configured marketplaces.
64+
65+ Without arguments: Shows installed plugins for all apps plus available plugins from all marketplaces.
66+ With marketplace name: Shows plugins from the specified marketplace.
67+ Use --query to search by name/description, --category to filter by category.
68+ """
4269 from code_assistant_manager .plugins import VALID_APP_TYPES , get_handler
70+ from code_assistant_manager .plugins .fetch import fetch_repo_info
71+ from code_assistant_manager .cli .plugins .plugin_discovery_commands import (
72+ _filter_plugins ,
73+ _display_plugin ,
74+ _display_marketplace_header ,
75+ _display_marketplace_footer ,
76+ _resolve_marketplace_repo ,
77+ _display_marketplace_not_found ,
78+ )
79+
80+ # Handle marketplace-specific browsing (replaces browse functionality)
81+ if marketplace :
82+ from code_assistant_manager .cli .option_utils import resolve_single_app
83+
84+ app = resolve_single_app (app_type or "claude" , VALID_APP_TYPES , default = "claude" )
85+ manager = PluginManager ()
86+ handler = get_handler (app )
87+
88+ # Resolve marketplace to repo info
89+ repo_owner , repo_name , repo_branch = _resolve_marketplace_repo (
90+ manager , handler , marketplace
91+ )
4392
93+ if not repo_owner or not repo_name :
94+ _display_marketplace_not_found (manager , handler , marketplace )
95+ raise typer .Exit (1 )
96+
97+ # Fetch plugins
98+ typer .echo (f"{ Colors .CYAN } Fetching plugins from { marketplace } ...{ Colors .RESET } " )
99+ info = fetch_repo_info (repo_owner , repo_name , repo_branch )
100+
101+ if not info or not info .plugins :
102+ typer .echo (f"{ Colors .RED } ✗ Could not fetch plugins from repo.{ Colors .RESET } " )
103+ raise typer .Exit (1 )
104+
105+ # Filter and display
106+ plugins = _filter_plugins (info .plugins , query , category )
107+ total = len (plugins )
108+ plugins = plugins [:limit ]
109+
110+ _display_marketplace_header (info , query , category , total )
111+ typer .echo (f"\n { Colors .BOLD } Plugins:{ Colors .RESET } \n " )
112+
113+ for plugin in plugins :
114+ _display_plugin (plugin )
115+
116+ _display_marketplace_footer (info , marketplace , total , limit )
117+ return
118+
119+ # Show both installed and available plugins (default behavior)
44120 if app_type :
45- # Show plugins for specific app (original behavior)
121+ # Show plugins for specific app
46122 if app_type not in VALID_APP_TYPES :
47123 typer .echo (
48124 f"{ Colors .RED } ✗ Invalid app type: { app_type } . Valid: { ', ' .join (VALID_APP_TYPES )} { Colors .RESET } "
49125 )
50126 raise typer .Exit (1 )
51127
52128 handler = get_handler (app_type )
53- _show_app_plugins (app_type , handler , show_all )
129+ _show_app_plugins (app_type , handler , True , query , category , limit ) # Always show available now
54130 else :
55- # Show plugins for all apps
131+ # Show plugins for all apps plus available plugins
132+ manager = PluginManager ()
133+
56134 typer .echo (f"{ Colors .BOLD } Plugin Status Across All Apps:{ Colors .RESET } \n " )
57135
58136 apps_with_plugins = []
@@ -61,22 +139,18 @@ def list_plugins(
61139 enabled_plugins = handler .get_enabled_plugins ()
62140 if enabled_plugins :
63141 apps_with_plugins .append (current_app )
64- _show_app_plugins (current_app , handler , show_all , show_header = False )
142+ _show_app_plugins (current_app , handler , True , query , category , limit , show_header = False )
65143 typer .echo () # Add spacing between apps
66144
67145 if not apps_with_plugins :
68146 typer .echo (f"{ Colors .YELLOW } No plugins installed in any app.{ Colors .RESET } " )
69147 typer .echo (f"Use 'cam plugin install <plugin>' to install one." )
70148
71- # Show available built-in repos
72- if BUILTIN_PLUGIN_REPOS :
73- typer .echo (f"\n { Colors .CYAN } Available built-in plugins:{ Colors .RESET } " )
74- for name , repo in BUILTIN_PLUGIN_REPOS .items ():
75- typer .echo (f" • { name } : { repo .description or 'No description' } " )
76- typer .echo (f"\n Install with: cam plugin install <name>" )
149+ # Show available plugins from all marketplaces
150+ _show_available_plugins (manager , query , category , limit )
77151
78152
79- def _show_app_plugins (app_name : str , handler , show_all : bool , show_header : bool = True ):
153+ def _show_app_plugins (app_name : str , handler , show_all : bool , query : Optional [ str ] = None , category : Optional [ str ] = None , limit : int = 50 , show_header : bool = True ):
80154 """Show plugins for a specific app."""
81155 # Get enabled plugins from settings
82156 enabled_plugins = handler .get_enabled_plugins ()
@@ -116,6 +190,16 @@ def _show_app_plugins(app_name: str, handler, show_all: bool, show_header: bool
116190 # Scan plugins from marketplaces
117191 plugins = handler .scan_marketplace_plugins ()
118192 if plugins :
193+ # Apply filtering if specified
194+ if query or category :
195+ plugins = [p for p in plugins if
196+ (not query or query .lower () in p .name .lower () or
197+ (p .description and query .lower () in p .description .lower ())) and
198+ (not category or category .lower () in (p .category or "" ).lower ())]
199+
200+ # Apply limit
201+ plugins = plugins [:limit ]
202+
119203 typer .echo (
120204 f"{ Colors .BOLD } Available Plugins from Marketplaces ({ app_name } ):{ Colors .RESET } \n "
121205 )
@@ -136,6 +220,103 @@ def _show_app_plugins(app_name: str, handler, show_all: bool, show_header: bool
136220 typer .echo ()
137221
138222
223+ def _show_available_plugins (manager : PluginManager , query : Optional [str ] = None , category : Optional [str ] = None , limit : int = 50 ):
224+ """Show available plugins from all configured marketplaces."""
225+ from code_assistant_manager .plugins .fetch import fetch_repo_info
226+ from code_assistant_manager .cli .plugins .plugin_discovery_commands import _filter_plugins , _display_plugin
227+
228+ all_repos = manager .get_all_repos ()
229+ if not all_repos :
230+ return
231+
232+ typer .echo (f"{ Colors .BOLD } Available Plugins from All Marketplaces:{ Colors .RESET } " )
233+
234+ all_plugins = []
235+ repo_sources = {} # Track which repo each plugin comes from
236+
237+ for repo_name , repo in all_repos .items ():
238+ if not repo .repo_owner or not repo .repo_name :
239+ continue
240+
241+ # Fetch repo info
242+ info = fetch_repo_info (
243+ repo .repo_owner , repo .repo_name , repo .repo_branch or "main"
244+ )
245+ if not info :
246+ continue
247+
248+ if info .type == "marketplace" :
249+ # Add plugins from marketplace with their source
250+ for plugin in info .plugins :
251+ plugin ["marketplace" ] = repo_name
252+ repo_sources [f"{ plugin .get ('name' , '' )} @{ repo_name } " ] = repo_name
253+ all_plugins .extend (info .plugins )
254+ else :
255+ # Single plugin repository
256+ plugin_name = info .name
257+ all_plugins .append (
258+ {
259+ "name" : plugin_name ,
260+ "version" : info .version or "" ,
261+ "description" : info .description or "" ,
262+ "category" : "" ,
263+ "marketplace" : repo_name ,
264+ }
265+ )
266+ repo_sources [f"{ plugin_name } @{ repo_name } " ] = repo_name
267+
268+ if not all_plugins :
269+ typer .echo (f" { Colors .YELLOW } No plugins found in configured repositories{ Colors .RESET } " )
270+ return
271+
272+ # Filter and display
273+ plugins = _filter_plugins (all_plugins , query , category )
274+ total = len (plugins )
275+ plugins = plugins [:limit ]
276+
277+ if query or category :
278+ typer .echo (f" Showing { len (plugins )} of { total } matching plugins\n " )
279+ else :
280+ typer .echo (f" Showing { len (plugins )} plugins\n " )
281+
282+ # Organize plugins by marketplace
283+ plugins_by_marketplace = {}
284+ for plugin in plugins :
285+ marketplace_name = plugin .get ("marketplace" , "Unknown" )
286+ if marketplace_name not in plugins_by_marketplace :
287+ plugins_by_marketplace [marketplace_name ] = []
288+ plugins_by_marketplace [marketplace_name ].append (plugin )
289+
290+ # Display plugins organized by marketplace
291+ displayed_count = 0
292+ for marketplace_name in sorted (plugins_by_marketplace .keys ()):
293+ marketplace_plugins = plugins_by_marketplace [marketplace_name ]
294+ typer .echo (f"{ Colors .BOLD } { marketplace_name } :{ Colors .RESET } " )
295+
296+ for plugin in marketplace_plugins :
297+ if displayed_count >= limit :
298+ break
299+ _display_plugin (plugin )
300+ displayed_count += 1
301+
302+ if displayed_count >= limit :
303+ break
304+
305+ if total > limit :
306+ typer .echo (f"\n ... and { total - limit } more plugins" )
307+
308+ categories = {p .get ("category" ) for p in all_plugins if p .get ("category" )}
309+ if categories :
310+ typer .echo (
311+ f"\n { Colors .CYAN } Categories:{ Colors .RESET } { ', ' .join (sorted (categories ))} "
312+ )
313+
314+ typer .echo (
315+ f"\n { Colors .CYAN } Install with:{ Colors .RESET } cam plugin install <marketplace>:<plugin-name>"
316+ )
317+ typer .echo ()
318+
319+
139320@plugin_app .command ("repos" )
140321def list_repos ():
141322 """List available plugin repositories and marketplaces (built-in + user)."""
0 commit comments