fix: backfill official optional skill provenance

This commit is contained in:
wysie 2026-05-27 18:32:03 +08:00 committed by kshitij
parent a38e283395
commit f040710d04
4 changed files with 414 additions and 2 deletions

View file

@ -12569,6 +12569,31 @@ Examples:
help="Skip confirmation prompt when using --restore",
)
skills_repair_official = skills_subparsers.add_parser(
"repair-official",
help="Backfill or restore official optional skills from repo source",
description=(
"Repair official optional skill provenance. By default, only backfills "
"hub metadata for exact matches. Pass --restore to replace missing or "
"mutated active copies from optional-skills/, moving existing copies to "
"a restore backup first. Use name 'all' to repair every optional skill."
),
)
skills_repair_official.add_argument(
"name", help="Official optional skill folder/frontmatter name, or 'all'"
)
skills_repair_official.add_argument(
"--restore",
action="store_true",
help="Restore from official optional source, backing up existing matching copies",
)
skills_repair_official.add_argument(
"--yes",
"-y",
action="store_true",
help="Skip confirmation prompt when using --restore",
)
skills_publish = skills_subparsers.add_parser(
"publish", help="Publish a skill to a registry"
)

View file

@ -1041,6 +1041,48 @@ def do_reset(name: str, restore: bool = False,
c.print("[dim]Use /reset to start a new session now, or --now to apply immediately (invalidates prompt cache).[/]\n")
def do_repair_official(name: str, restore: bool = False,
console: Optional[Console] = None,
skip_confirm: bool = False,
invalidate_cache: bool = True) -> None:
"""Backfill or restore official optional skills from repo source."""
from tools.skills_sync import restore_official_optional_skill
c = console or _console
if restore and not skip_confirm:
c.print(f"\n[bold]Restore official optional skill '{name}' from repo source?[/]")
c.print("[dim]Existing matching active copies will be moved to a restore backup before copying the official source.[/]")
try:
answer = input("Confirm [y/N]: ").strip().lower()
except (EOFError, KeyboardInterrupt):
answer = "n"
if answer not in {"y", "yes"}:
c.print("[dim]Cancelled.[/]\n")
return
result = restore_official_optional_skill(name, restore=restore)
if not result.get("ok"):
c.print(f"[bold red]Error:[/] {result.get('message', 'Repair failed')}\n")
return
c.print(f"[bold green]{result['message']}[/]")
if result.get("restored"):
c.print(f"[dim]Restored: {', '.join(result['restored'])}[/]")
if result.get("backfilled"):
c.print(f"[dim]Backfilled provenance: {', '.join(result['backfilled'])}[/]")
if result.get("backed_up"):
c.print(f"[dim]Backed up: {', '.join(result['backed_up'])}[/]")
c.print(f"[dim]Backup dir: {result.get('backup_dir')}[/]")
c.print()
if invalidate_cache:
try:
from agent.prompt_builder import clear_skills_system_prompt_cache
clear_skills_system_prompt_cache(clear_snapshot=True)
except Exception:
pass
def do_tap(action: str, repo: str = "", console: Optional[Console] = None) -> None:
"""Manage taps (custom GitHub repo sources)."""
from tools.skills_hub import TapsManager
@ -1372,6 +1414,9 @@ def skills_command(args) -> None:
elif action == "reset":
do_reset(args.name, restore=getattr(args, "restore", False),
skip_confirm=getattr(args, "yes", False))
elif action == "repair-official":
do_repair_official(args.name, restore=getattr(args, "restore", False),
skip_confirm=getattr(args, "yes", False))
elif action == "publish":
do_publish(
args.skill_path,