1919logger = logging .getLogger (__name__ )
2020
2121skill_app = typer .Typer (
22- help = "Manage skills for AI assistants (Claude, Codex, Copilot, Gemini, Droid, CodeBuddy)" ,
22+ help = "Manage skills for AI assistants (Claude, Codex, Copilot, Gemini, Droid, CodeBuddy, Qwen )" ,
2323 no_args_is_help = True ,
2424)
2525
@@ -35,7 +35,13 @@ def list_skills(
3535 "claude" ,
3636 "--app" ,
3737 "-a" ,
38- help = "App type(s) to check installed status (claude, codex, copilot, gemini, all)" ,
38+ help = "App type(s) to check installed status (claude, codex, copilot, gemini, qwen, all)" ,
39+ ),
40+ query : Optional [str ] = typer .Option (
41+ None ,
42+ "--query" ,
43+ "-q" ,
44+ help = "Filter skills by repository name (e.g., 'BrownFineSecurity/iothackbot')" ,
3945 ),
4046):
4147 """List all skills."""
@@ -48,21 +54,47 @@ def list_skills(
4854
4955 skills = manager .get_all ()
5056
57+ # Filter skills by query if provided
58+ if query and isinstance (query , str ):
59+ filtered_skills = {}
60+ query_lower = query .lower ()
61+ for skill_key , skill in skills .items ():
62+ if skill .repo_owner and skill .repo_name :
63+ repo_full_name = f"{ skill .repo_owner } /{ skill .repo_name } " .lower ()
64+ if query_lower in repo_full_name :
65+ filtered_skills [skill_key ] = skill
66+ skills = filtered_skills
67+
5168 if not skills :
52- typer .echo (
53- f"{ Colors .YELLOW } No skills found. Run 'cam skill fetch' to discover skills from repositories.{ Colors .RESET } "
54- )
69+ if query and isinstance (query , str ):
70+ typer .echo (
71+ f"{ Colors .YELLOW } No skills found matching query '{ query } '. Run 'cam skill fetch' to discover skills from repositories.{ Colors .RESET } "
72+ )
73+ else :
74+ typer .echo (
75+ f"{ Colors .YELLOW } No skills found. Run 'cam skill fetch' to discover skills from repositories.{ Colors .RESET } "
76+ )
5577 return
5678
5779 context = ", " .join (target_apps )
58- typer .echo (f"\n { Colors .BOLD } Skills (for { context } ):{ Colors .RESET } \n " )
80+ if query and isinstance (query , str ):
81+ typer .echo (f"\n { Colors .BOLD } Skills matching '{ query } ' (for { context } ):{ Colors .RESET } \n " )
82+ else :
83+ typer .echo (f"\n { Colors .BOLD } Skills (for { context } ):{ Colors .RESET } \n " )
5984 for skill_key , skill in sorted (skills .items ()):
6085 status = (
6186 f"{ Colors .GREEN } ✓{ Colors .RESET } "
6287 if skill .installed
6388 else f"{ Colors .RED } ✗{ Colors .RESET } "
6489 )
65- typer .echo (f"{ status } { Colors .BOLD } { skill .name } { Colors .RESET } ({ skill_key } )" )
90+ # Create simplified install key: repo_owner/repo_name:directory
91+ # This matches the simplified keys that are also stored in the skills dict
92+ if skill .repo_owner and skill .repo_name :
93+ install_key = f"{ skill .repo_owner } /{ skill .repo_name } :{ skill .directory } "
94+ else :
95+ install_key = skill_key
96+
97+ typer .echo (f"{ status } { Colors .BOLD } { skill .name } { Colors .RESET } ({ install_key } )" )
6698 if skill .description :
6799 typer .echo (f" { Colors .CYAN } Description:{ Colors .RESET } { skill .description } " )
68100 typer .echo (f" { Colors .CYAN } Directory:{ Colors .RESET } { skill .directory } " )
@@ -344,7 +376,7 @@ def install_skill(
344376 "claude" ,
345377 "--app" ,
346378 "-a" ,
347- help = "App type(s) to install to (claude, codex, gemini, all)" ,
379+ help = "App type(s) to install to (claude, codex, gemini, qwen, all)" ,
348380 ),
349381):
350382 """Install a skill to one or more app skills directories."""
@@ -372,7 +404,7 @@ def uninstall_skill(
372404 "claude" ,
373405 "--app" ,
374406 "-a" ,
375- help = "App type(s) to uninstall from (claude, codex, gemini, all)" ,
407+ help = "App type(s) to uninstall from (claude, codex, gemini, qwen, all)" ,
376408 ),
377409):
378410 """Uninstall a skill from one or more app skills directories."""
@@ -504,7 +536,7 @@ def skill_status(
504536 None ,
505537 "--app" ,
506538 "-a" ,
507- help = "App type(s) to show (claude, codex, gemini, all). Default shows all." ,
539+ help = "App type(s) to show (claude, codex, gemini, qwen, all). Default shows all." ,
508540 ),
509541):
510542 """Show skill installation status across apps (alias: installed)."""
@@ -517,7 +549,7 @@ def list_installed_skills(
517549 None ,
518550 "--app" ,
519551 "-a" ,
520- help = "App type(s) to show (claude, codex, gemini, all). Default shows all." ,
552+ help = "App type(s) to show (claude, codex, gemini, qwen, all). Default shows all." ,
521553 ),
522554):
523555 """Show installed skills for each app."""
@@ -574,7 +606,7 @@ def uninstall_all_skills(
574606 ...,
575607 "--app" ,
576608 "-a" ,
577- help = "App type(s) to uninstall all skills from (claude, codex, gemini, all)" ,
609+ help = "App type(s) to uninstall all skills from (claude, codex, gemini, qwen, all)" ,
578610 ),
579611 force : bool = typer .Option (False , "--force" , "-f" , help = "Skip confirmation" ),
580612):
0 commit comments