fix: skill download to temp dir

This commit is contained in:
zhayujie
2026-03-09 18:43:28 +08:00
parent 08c69f5e9b
commit 71c8436e90
3 changed files with 25 additions and 14 deletions

View File

@@ -95,12 +95,14 @@ class SkillManager:
for name, entry in self.skills.items():
skill = entry.skill
prev = saved.get(name, {})
# category priority: persisted config (set by cloud) > default "skill"
category = prev.get("category", "skill")
merged[name] = {
"name": name,
"description": skill.description,
"source": skill.source,
"enabled": prev.get("enabled", True),
**( {"category": prev["category"]} if "category" in prev else {} ),
"category": category,
}
self.skills_config = merged

View File

@@ -82,21 +82,29 @@ class SkillService:
skill_dir = os.path.join(self.manager.custom_dir, name)
# Remove existing skill directory to ensure a clean overwrite
# Download to a temp directory first, then swap to avoid data loss on failure
tmp_dir = skill_dir + ".tmp"
if os.path.exists(tmp_dir):
shutil.rmtree(tmp_dir)
os.makedirs(tmp_dir, exist_ok=True)
try:
for file_info in files:
url = file_info.get("url")
rel_path = file_info.get("path")
if not url or not rel_path:
logger.warning(f"[SkillService] add: skip invalid file entry {file_info}")
continue
dest = os.path.join(tmp_dir, rel_path)
self._download_file(url, dest)
except Exception:
shutil.rmtree(tmp_dir, ignore_errors=True)
raise
# All files downloaded successfully, replace the old directory
if os.path.exists(skill_dir):
shutil.rmtree(skill_dir)
logger.info(f"[SkillService] add: removed existing skill directory for overwrite: {skill_dir}")
os.makedirs(skill_dir, exist_ok=True)
for file_info in files:
url = file_info.get("url")
rel_path = file_info.get("path")
if not url or not rel_path:
logger.warning(f"[SkillService] add: skip invalid file entry {file_info}")
continue
dest = os.path.join(skill_dir, rel_path)
self._download_file(url, dest)
os.rename(tmp_dir, skill_dir)
# Reload to pick up the new skill and sync config
self.manager.refresh_skills()

View File

@@ -275,6 +275,7 @@ Write the YAML frontmatter with `name`, `description`, and optional `metadata`:
- `requires.anyBins`: Alternative binaries — at least one must be present
- `always`: Set to `true` to always load regardless of requirements
- `emoji`: Skill icon (optional)
- Do NOT set `category` — it defaults to `skill` and is managed by the system
**API Key Requirements**: