Ctrl K
ComunidadGuías…

scout/plugins/skill_manager.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""第三方技能包管理 — 支持安装、卸载与版本隔离."""

import json
import shutil
from pathlib import Path
from typing import List, Optional

from scout.config.settings import ScoutConfig


class SkillPackage:
    """技能包元数据."""
    def __init__(self, name: str, version: str, description: str = "", author: str = ""):
        self.name = name
        self.version = version
        self.description = description
        self.author = author

    def to_dict(self):
        return {
            "name": self.name,
            "version": self.version,
            "description": self.description,
            "author": self.author,
        }

    @classmethod
    def from_dict(cls, data: dict):
        return cls(**data)


class SkillManager:
    """管理第三方技能包的生命周期."""
    
    def __init__(self, config: ScoutConfig):
        self.config = config
        self.skills_dir = config.skills_dir
        self.manifest_file = self.skills_dir / "installed_skills.json"
        self._ensure_manifest()

    def _ensure_manifest(self):
        if not self.manifest_file.exists():
            self.manifest_file.write_text(json.dumps([]))

    def install(self, source_path: str, package: SkillPackage) -> bool:
        """从源码路径安装技能包."""
        target_dir = self.skills_dir / package.name
        if target_dir.exists():
            # 简单的版本覆盖逻辑,实际可扩展为多版本共存
            shutil.rmtree(target_dir)
        
        shutil.copytree(source_path, target_dir)
        
        # 更新清单
        installed = self.list_installed()
        installed.append(package.to_dict())
        self.manifest_file.write_text(json.dumps(installed, indent=2))
        return True

    def uninstall(self, name: str) -> bool:
        """卸载技能包."""
        target_dir = self.skills_dir / name
        if not target_dir.exists():
            return False
        
        shutil.rmtree(target_dir)
        
        installed = [s for s in self.list_installed() if s["name"] != name]
        self.manifest_file.write_text(json.dumps(installed, indent=2))
        return True

    def list_installed(self) -> List[dict]:
        """列出已安装的包."""
        try:
            return json.loads(self.manifest_file.read_text())
        except (json.JSONDecodeError, FileNotFoundError):
            return []

    def get_skill_path(self, name: str) -> Optional[Path]:
        """获取技能包的运行时路径."""
        path = self.skills_dir / name
        return path if path.exists() else None