lllin000_PaperForge/paperforge/services/skill_deploy.py

89 lines
2.8 KiB
Python

"""Skill deployment service — deploys the unified paperforge skill to the vault.
Used by both setup wizard (install) and update worker (update).
All deployments are vault-local only.
"""
from __future__ import annotations
import shutil
from pathlib import Path
# ── Agent platform → vault-local skill directory ──
AGENT_SKILL_DIRS: dict[str, str] = {
"opencode": ".opencode/skills",
"claude": ".claude/skills",
"codex": ".codex/skills",
"cursor": ".cursor/skills",
"windsurf": ".windsurf/skills",
"github_copilot": ".github/skills",
"gemini": ".gemini/skills",
"cline": ".clinerules",
"augment": ".augment/skills",
"trae": ".trae/skills",
}
def _resolve_source_root() -> Path:
"""Resolve the paperforge package root (where skills/ lives)."""
import paperforge
return Path(paperforge.__file__).parent
def deploy_skills(
vault: Path,
agent_key: str = "opencode",
overwrite: bool = False,
) -> dict:
"""Deploy paperforge skill and AGENTS.md to the vault.
Args:
vault: Obsidian vault root.
agent_key: Agent platform key (opencode, claude, etc.).
overwrite: If True, overwrite existing files (used by update).
Returns:
dict with 'skill_deployed', 'agents_md', 'errors' keys.
"""
errors: list[str] = []
# ── Deploy paperforge skill ──
skill_deployed = False
source_root = _resolve_source_root()
src_skill = source_root / "skills" / "paperforge"
if src_skill.exists():
skill_dir_name = AGENT_SKILL_DIRS.get(agent_key)
if skill_dir_name:
dst_skill = vault / skill_dir_name / "paperforge"
try:
if overwrite and dst_skill.exists():
shutil.rmtree(dst_skill, ignore_errors=True)
dst_skill.parent.mkdir(parents=True, exist_ok=True)
shutil.copytree(src_skill, dst_skill, dirs_exist_ok=True)
skill_deployed = True
except Exception as e:
errors.append(f"Skill deploy failed: {e}")
else:
errors.append(f"Unknown agent: {agent_key}")
else:
errors.append("Skills source not found in package")
# ── Deploy AGENTS.md (only if it does not exist — users customise it) ──
agents_ok = False
agents_src = source_root.parent / "AGENTS.md"
if agents_src.exists():
try:
agents_dst = vault / "AGENTS.md"
if not agents_dst.exists():
shutil.copy2(agents_src, agents_dst)
agents_ok = True
except Exception as e:
errors.append(f"AGENTS.md deploy failed: {e}")
return {
"skill_deployed": skill_deployed,
"agents_md": agents_ok,
"errors": errors,
}