Skip to content

Commit 9174a38

Browse files
committed
Fix: Correct plugin browse help text in install command
Replace incorrect 'cam plugin search --marketplace' with the correct 'cam plugin browse' command in plugin installation help text. This fixes the misleading help output that was shown after successfully installing a marketplace.
1 parent b325254 commit 9174a38

27 files changed

+1028
-174
lines changed

code_assistant_manager/agents/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,20 @@
33
This package provides functionality to manage agents for AI coding assistants.
44
Agents are markdown files that define custom agent behaviors and are installed to:
55
- Claude: ~/.claude/agents/
6+
- Codex: ~/.codex/agents/
7+
- Gemini: ~/.gemini/agents/
8+
- Droid: ~/.factory/agents/
9+
- CodeBuddy: ~/.codebuddy/agents/
610
711
Reference: https://github.com/iannuttall/claude-agents
812
"""
913

1014
from .base import BaseAgentHandler
1115
from .claude import ClaudeAgentHandler
16+
from .codebuddy import CodebuddyAgentHandler
17+
from .codex import CodexAgentHandler
18+
from .droid import DroidAgentHandler
19+
from .gemini import GeminiAgentHandler
1220
from .manager import VALID_APP_TYPES, AgentManager
1321
from .models import Agent, AgentRepo
1422

@@ -18,5 +26,9 @@
1826
"AgentManager",
1927
"BaseAgentHandler",
2028
"ClaudeAgentHandler",
29+
"CodexAgentHandler",
30+
"GeminiAgentHandler",
31+
"DroidAgentHandler",
32+
"CodebuddyAgentHandler",
2133
"VALID_APP_TYPES",
2234
]

code_assistant_manager/agents/claude.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
"""Claude-specific agent handler."""
1+
"""Claude agent handler."""
22

33
from pathlib import Path
44

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""CodeBuddy agent handler."""
2+
3+
from pathlib import Path
4+
5+
from .base import BaseAgentHandler
6+
7+
8+
class CodebuddyAgentHandler(BaseAgentHandler):
9+
"""Agent handler for CodeBuddy CLI."""
10+
11+
@property
12+
def app_name(self) -> str:
13+
return "codebuddy"
14+
15+
@property
16+
def _default_agents_dir(self) -> Path:
17+
return Path.home() / ".codebuddy" / "agents"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""Codex agent handler."""
2+
3+
from pathlib import Path
4+
5+
from .base import BaseAgentHandler
6+
7+
8+
class CodexAgentHandler(BaseAgentHandler):
9+
"""Agent handler for OpenAI Codex CLI."""
10+
11+
@property
12+
def app_name(self) -> str:
13+
return "codex"
14+
15+
@property
16+
def _default_agents_dir(self) -> Path:
17+
return Path.home() / ".codex" / "agents"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""Droid agent handler."""
2+
3+
from pathlib import Path
4+
5+
from .base import BaseAgentHandler
6+
7+
8+
class DroidAgentHandler(BaseAgentHandler):
9+
"""Agent handler for Factory.ai Droid CLI."""
10+
11+
@property
12+
def app_name(self) -> str:
13+
return "droid"
14+
15+
@property
16+
def _default_agents_dir(self) -> Path:
17+
return Path.home() / ".factory" / "agents"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"""Gemini agent handler."""
2+
3+
from pathlib import Path
4+
5+
from .base import BaseAgentHandler
6+
7+
8+
class GeminiAgentHandler(BaseAgentHandler):
9+
"""Agent handler for Google Gemini CLI."""
10+
11+
@property
12+
def app_name(self) -> str:
13+
return "gemini"
14+
15+
@property
16+
def _default_agents_dir(self) -> Path:
17+
return Path.home() / ".gemini" / "agents"

code_assistant_manager/agents/manager.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212

1313
from .base import BaseAgentHandler
1414
from .claude import ClaudeAgentHandler
15+
from .codebuddy import CodebuddyAgentHandler
16+
from .codex import CodexAgentHandler
17+
from .droid import DroidAgentHandler
18+
from .gemini import GeminiAgentHandler
1519
from .models import Agent, AgentRepo
1620

1721
logger = logging.getLogger(__name__)
@@ -56,6 +60,10 @@ def _load_builtin_agent_repos() -> List[Dict]:
5660
# Registry of available handlers
5761
AGENT_HANDLERS: Dict[str, Type[BaseAgentHandler]] = {
5862
"claude": ClaudeAgentHandler,
63+
"codex": CodexAgentHandler,
64+
"gemini": GeminiAgentHandler,
65+
"droid": DroidAgentHandler,
66+
"codebuddy": CodebuddyAgentHandler,
5967
}
6068

6169
# Valid app types for agents

code_assistant_manager/cli/agents_commands.py

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
AgentManager,
1313
AgentRepo,
1414
)
15+
from code_assistant_manager.cli.option_utils import resolve_app_targets
1516
from code_assistant_manager.menu.base import Colors
1617
from code_assistant_manager.plugins.fetch import parse_github_url
1718

@@ -231,10 +232,18 @@ def install_agent(
231232
"claude",
232233
"--app",
233234
"-a",
234-
help="App type to install to (currently only 'claude' supported)",
235+
help="App type to install to (claude, codex, gemini, droid, codebuddy)",
235236
),
236237
):
237238
"""Install an agent to an app's agents directory."""
239+
# Validate app type
240+
if app_type not in VALID_APP_TYPES:
241+
typer.echo(
242+
f"{Colors.RED}✗ Invalid value '{app_type}' for --app. "
243+
f"Valid: {', '.join(VALID_APP_TYPES)}{Colors.RESET}"
244+
)
245+
raise typer.Exit(1)
246+
238247
manager = _get_agent_manager()
239248

240249
try:
@@ -254,11 +263,19 @@ def uninstall_agent(
254263
"claude",
255264
"--app",
256265
"-a",
257-
help="App type to uninstall from (currently only 'claude' supported)",
266+
help="App type to uninstall from (claude, codex, gemini, droid, codebuddy)",
258267
),
259268
force: bool = typer.Option(False, "--force", "-f", help="Skip confirmation"),
260269
):
261270
"""Uninstall an agent from an app's agents directory."""
271+
# Validate app type
272+
if app_type not in VALID_APP_TYPES:
273+
typer.echo(
274+
f"{Colors.RED}✗ Invalid value '{app_type}' for --app. "
275+
f"Valid: {', '.join(VALID_APP_TYPES)}{Colors.RESET}"
276+
)
277+
raise typer.Exit(1)
278+
262279
manager = _get_agent_manager()
263280
agent = manager.get(agent_key)
264281

@@ -350,57 +367,59 @@ def remove_repo(
350367

351368
@agent_app.command("installed")
352369
def list_installed_agents(
353-
app_type: str = typer.Option(
354-
"claude",
370+
app_type: Optional[str] = typer.Option(
371+
None,
355372
"--app",
356373
"-a",
357-
help="App type to show installed agents for",
374+
help="App type(s) to show (claude, codex, gemini, droid, codebuddy, all). Default shows all.",
358375
),
359376
):
360-
"""Show installed agents."""
377+
"""Show installed agents for each app."""
361378
manager = _get_agent_manager()
362-
363-
try:
364-
handler = manager.get_handler(app_type)
365-
except ValueError as e:
366-
typer.echo(f"{Colors.RED}✗ Error: {e}{Colors.RESET}")
367-
raise typer.Exit(1)
368-
369-
agents_dir = handler.agents_dir
370-
typer.echo(
371-
f"\n{Colors.BOLD}{app_type.capitalize()} Agents ({agents_dir}):{Colors.RESET}"
372-
)
373-
374-
if not agents_dir.exists():
375-
typer.echo(f" {Colors.YELLOW}No agents installed{Colors.RESET}")
376-
return
377-
378-
installed = list(agents_dir.glob("*.md"))
379-
if not installed:
380-
typer.echo(f" {Colors.YELLOW}No agents installed{Colors.RESET}")
381-
return
382-
383379
all_agents = manager.get_all()
384380

385-
for agent_file in sorted(installed):
386-
filename = agent_file.name
387-
388-
# Find matching agent in database
389-
agent_key = None
390-
for key, agent in all_agents.items():
391-
if agent.filename.lower() == filename.lower():
392-
agent_key = key
393-
break
394-
395-
if agent_key:
396-
agent = all_agents[agent_key]
397-
typer.echo(
398-
f" {Colors.GREEN}{Colors.RESET} {agent.name} ({Colors.CYAN}{agent_key}{Colors.RESET})"
399-
)
400-
else:
401-
typer.echo(f" {Colors.GREEN}{Colors.RESET} {filename}")
381+
target_apps = resolve_app_targets(
382+
app_type,
383+
VALID_APP_TYPES,
384+
default=None,
385+
fallback_to_all_if_none=True,
386+
)
402387

403-
typer.echo()
388+
for app in target_apps:
389+
try:
390+
handler = manager.get_handler(app)
391+
except ValueError:
392+
continue
393+
394+
agents_dir = handler.agents_dir
395+
typer.echo(f"\n{Colors.BOLD}{app.capitalize()} ({agents_dir}):{Colors.RESET}")
396+
397+
if not agents_dir.exists():
398+
typer.echo(f" {Colors.YELLOW}No agents installed{Colors.RESET}")
399+
continue
400+
401+
installed = list(agents_dir.glob("*.md"))
402+
if not installed:
403+
typer.echo(f" {Colors.YELLOW}No agents installed{Colors.RESET}")
404+
continue
405+
406+
for agent_file in sorted(installed):
407+
filename = agent_file.name
408+
409+
# Find matching agent in database
410+
agent_key = None
411+
for key, agent in all_agents.items():
412+
if agent.filename.lower() == filename.lower():
413+
agent_key = key
414+
break
415+
416+
if agent_key:
417+
agent = all_agents[agent_key]
418+
typer.echo(
419+
f" {Colors.GREEN}{Colors.RESET} {agent.name} ({Colors.CYAN}{agent_key}{Colors.RESET})"
420+
)
421+
else:
422+
typer.echo(f" {Colors.GREEN}{Colors.RESET} {filename}")
404423

405424

406425
@agent_app.command("uninstall-all")

0 commit comments

Comments
 (0)