···326326 backend_instance = get_backend(backend_name)
327327 skills_dir = backend_instance.get_skills_dir(Scope.LOCAL)
328328329329- console.print(
330330- f"Syncing to [cyan]{backend_name}[/cyan] -> [dim]{skills_dir}[/dim]\n"
331331- )
332332-333329 # Discover available skills from pixi environment
334330 available_skills = discover_local_skills(env)
335331 available_names = {s.name for s in available_skills}
···342338 to_install = [s for s in available_skills if s.name not in installed_names]
343339 to_remove = [name for name in installed_names if name not in available_names]
344340345345- if not to_install and not to_remove:
346346- console.print(f"[dim]Already in sync ({len(available_skills)} skill(s))[/dim]")
347347- raise typer.Exit(0)
341341+ # Header
342342+ console.print(
343343+ f"\n[bold]Syncing[/bold] [cyan]{backend_name}[/cyan] -> {skills_dir}\n"
344344+ )
348345349349- # Show summary of changes
350350- if available_skills:
351351- console.print(f"[dim]Available in env: {len(available_skills)} skill(s)[/dim]")
352352- else:
353353- console.print(f"[dim]No skills in .pixi/envs/{env}/share/agent-skills/[/dim]")
354354-355355- if installed_names:
356356- console.print(f"[dim]Installed: {len(installed_names)} skill(s)[/dim]")
357357- else:
358358- console.print("[dim]Installed: 0 skill(s)[/dim]")
359359-360360- # Install new skills
361361- installed_count = 0
362362- for skill in sorted(to_install, key=lambda s: s.name):
363363- try:
364364- symlink_path = backend_instance.install(skill)
365365- console.print(f"[green]+[/green] {skill.name} -> {symlink_path}")
366366- installed_count += 1
367367- except ValueError as e:
368368- console.print(f"[red]✗ {skill.name}: {e}[/red]")
346346+ # Show all skills with status
347347+ all_skill_names = available_names | installed_names
348348+ for name in sorted(all_skill_names):
349349+ if name in to_remove:
350350+ console.print(f" [red]-[/red] {name} [dim](removed)[/dim]")
351351+ elif name in {s.name for s in to_install}:
352352+ skill = next(s for s in to_install if s.name == name)
353353+ try:
354354+ backend_instance.install(skill)
355355+ console.print(f" [green]+[/green] {name} [dim](installed)[/dim]")
356356+ except ValueError as e:
357357+ console.print(f" [red]✗[/red] {name} [dim]({e})[/dim]")
358358+ else:
359359+ console.print(f" [dim] {name}[/dim]")
369360370370- # Remove skills no longer available
371371- removed_count = 0
361361+ # Handle removals
372362 for name in sorted(to_remove):
373373- if backend_instance.uninstall(name, Scope.LOCAL):
374374- console.print(f"[red]-[/red] {name}")
375375- removed_count += 1
376376- else:
377377- console.print(f"[yellow]?[/yellow] {name} (not found)")
363363+ backend_instance.uninstall(name, Scope.LOCAL)
378364379365 # Summary
380380- changes = []
381381- if installed_count:
382382- changes.append(f"installed {installed_count}")
383383- if removed_count:
384384- changes.append(f"removed {removed_count}")
385385-386386- if changes:
387387- console.print(f"\n[green]Synced: {', '.join(changes)} skill(s)[/green]")
366366+ console.print()
367367+ if to_install or to_remove:
368368+ parts = []
369369+ if to_install:
370370+ parts.append(f"[green]+{len(to_install)}[/green]")
371371+ if to_remove:
372372+ parts.append(f"[red]-{len(to_remove)}[/red]")
373373+ console.print(
374374+ f" [{'/'.join(parts)}] [bold]{len(available_names)} skill(s)[/bold]"
375375+ )
376376+ else:
377377+ console.print(f" [dim]no changes, {len(available_names)} skill(s)[/dim]")
388378389389- # Show final state
390390- final_count = len(available_names)
391391- console.print(f"[dim]Result: {final_count} skill(s) in {skills_dir}[/dim]")
379379+ # Show tip if no skills
380380+ if not available_skills:
381381+ console.print(
382382+ f"\n[dim]Add skills to .pixi/envs/{env}/share/agent-skills/ to sync[/dim]"
383383+ )
392384393385394386if __name__ == "__main__":