Skip to content

Commit 22ba317

Browse files
committed
Feature: Make marketplace argument optional in browse command to show all plugins
When 'cam plugin browse' is run without a marketplace name, it now: - Fetches plugins from all configured marketplaces and standalone plugins - Aggregates all plugins into a single list - Supports filtering with --query and --category across all sources - Shows total count and available categories - Maintains backward compatibility with specific marketplace browsing Examples: cam plugin browse # Show all 565+ plugins cam plugin browse anthropic-agent-skills # Show specific marketplace cam plugin browse -q 'document' # Filter all plugins by query
1 parent 85437d5 commit 22ba317

1 file changed

Lines changed: 93 additions & 5 deletions

File tree

code_assistant_manager/cli/plugin_commands.py

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -826,9 +826,9 @@ def _display_marketplace_footer(info, marketplace: str, total: int, limit: int)
826826

827827
@plugin_app.command("browse")
828828
def browse_marketplace(
829-
marketplace: str = typer.Argument(
830-
...,
831-
help="Marketplace name to browse (from 'cam plugin repos')",
829+
marketplace: Optional[str] = typer.Argument(
830+
None,
831+
help="Marketplace name to browse (from 'cam plugin repos'). If not specified, shows all plugins from all marketplaces.",
832832
),
833833
query: Optional[str] = typer.Option(
834834
None,
@@ -855,9 +855,10 @@ def browse_marketplace(
855855
help=f"App type ({', '.join(VALID_APP_TYPES)})",
856856
),
857857
):
858-
"""Browse plugins in a configured marketplace.
858+
"""Browse plugins in configured marketplaces or a specific one.
859859
860-
Fetches the marketplace manifest from GitHub and lists all available plugins.
860+
Without a marketplace name: Shows all plugins from all marketplaces and standalone plugins.
861+
With a marketplace name: Fetches the marketplace manifest from GitHub and lists available plugins.
861862
Use --query to search by name/description, --category to filter by category.
862863
"""
863864
from code_assistant_manager.plugins.fetch import fetch_repo_info
@@ -866,6 +867,93 @@ def browse_marketplace(
866867
manager = PluginManager()
867868
handler = _get_handler(app)
868869

870+
# If no marketplace specified, show all plugins from all repos
871+
if not marketplace:
872+
typer.echo(
873+
f"{Colors.CYAN}Fetching all plugins from all marketplaces and plugins...{Colors.RESET}\n"
874+
)
875+
876+
all_repos = manager.get_all_repos()
877+
if not all_repos:
878+
typer.echo(
879+
f"{Colors.YELLOW}No plugin repositories configured{Colors.RESET}"
880+
)
881+
return
882+
883+
all_plugins = []
884+
repo_sources = {} # Track which repo each plugin comes from
885+
886+
for repo_name, repo in all_repos.items():
887+
if not repo.repo_owner or not repo.repo_name:
888+
continue
889+
890+
# Fetch repo info
891+
info = fetch_repo_info(
892+
repo.repo_owner, repo.repo_name, repo.repo_branch or "main"
893+
)
894+
if not info:
895+
typer.echo(
896+
f" {Colors.YELLOW}{Colors.RESET} {repo_name} (failed to fetch)"
897+
)
898+
continue
899+
900+
if info.type == "marketplace":
901+
# Add plugins from marketplace with their source
902+
for plugin in info.plugins:
903+
plugin["marketplace"] = repo_name
904+
repo_sources[f"{plugin.get('name', '')}@{repo_name}"] = repo_name
905+
all_plugins.extend(info.plugins)
906+
else:
907+
# Single plugin repository
908+
plugin_name = info.name
909+
all_plugins.append(
910+
{
911+
"name": plugin_name,
912+
"version": info.version or "",
913+
"description": info.description or "",
914+
"category": "",
915+
"marketplace": repo_name,
916+
}
917+
)
918+
repo_sources[f"{plugin_name}@{repo_name}"] = repo_name
919+
920+
if not all_plugins:
921+
typer.echo(
922+
f"{Colors.YELLOW}No plugins found in configured repositories{Colors.RESET}"
923+
)
924+
return
925+
926+
# Filter and display
927+
plugins = _filter_plugins(all_plugins, query, category)
928+
total = len(plugins)
929+
plugins = plugins[:limit]
930+
931+
typer.echo(f"{Colors.BOLD}All Available Plugins:{Colors.RESET}")
932+
typer.echo(f"Total: {total} plugins\n")
933+
934+
if query or category:
935+
typer.echo(f"Matching: {total}\n")
936+
937+
typer.echo(f"{Colors.BOLD}Plugins:{Colors.RESET}\n")
938+
939+
for plugin in plugins:
940+
_display_plugin(plugin)
941+
942+
if total > limit:
943+
typer.echo(f"\n ... and {total - limit} more")
944+
945+
categories = {p.get("category") for p in all_plugins if p.get("category")}
946+
if categories:
947+
typer.echo(
948+
f"\n{Colors.CYAN}Categories:{Colors.RESET} {', '.join(sorted(categories))}"
949+
)
950+
951+
typer.echo(
952+
f"\n{Colors.CYAN}Filter by marketplace:{Colors.RESET} cam plugin browse <marketplace-name>"
953+
)
954+
typer.echo()
955+
return
956+
869957
# Resolve marketplace to repo info
870958
repo_owner, repo_name, repo_branch = _resolve_marketplace_repo(
871959
manager, handler, marketplace

0 commit comments

Comments
 (0)