"""路径与 Agent 目标定义。""" from __future__ import annotations from pathlib import Path HOME = Path.home() PREFERRED_POUCH_HOME = HOME / ".pouch" LEGACY_POUCH_HOME = HOME / ".skills" PROJECT_MANIFEST = ".pouch.yaml" LEGACY_PROJECT_MANIFEST = ".skills.yaml" def _first_existing_dir(*candidates: Path, default: Path) -> Path: for path in candidates: if path.is_dir(): return path return default def _first_existing_file(*candidates: Path, default: Path) -> Path: for path in candidates: if path.is_file(): return path return default POUCH_HOME = _first_existing_dir( PREFERRED_POUCH_HOME, LEGACY_POUCH_HOME, default=PREFERRED_POUCH_HOME, ) SKILLS_DIR = POUCH_HOME / "skills" TEMPLATE_DIR = SKILLS_DIR / "_template" DRAFTS_DIR = POUCH_HOME / ".drafts" CATALOG_FILE = POUCH_HOME / "catalog.yaml" LEGACY_REGISTRY_FILE = POUCH_HOME / "registry.yaml" CATALOG_CACHE_DIR = _first_existing_dir( HOME / ".local" / "share" / "pouch" / "externals", HOME / ".local" / "share" / "skills" / "externals", default=HOME / ".local" / "share" / "pouch" / "externals", ) CONFIG_FILE = _first_existing_file( HOME / ".config" / "pouch" / "config.yaml", HOME / ".config" / "skiff" / "config.yaml", default=HOME / ".config" / "pouch" / "config.yaml", ) SOURCES_DIR = _first_existing_dir( HOME / ".local" / "share" / "pouch" / "sources", HOME / ".local" / "share" / "skiff" / "sources", default=HOME / ".local" / "share" / "pouch" / "sources", ) AGENT_GLOBAL: dict[str, Path] = { "cursor": HOME / ".cursor" / "skills", "claude": HOME / ".claude" / "skills", "codex": HOME / ".codex" / "skills", # agents 标准目录:OMP 原生 canonical(agents provider),cursor/codex 项目级同路径 "agents": HOME / ".agents" / "skills", } AGENT_PROJECT: dict[str, str] = { "cursor": ".agents/skills", "claude": ".claude/skills", "codex": ".agents/skills", # 与 cursor/codex 共用 .agents/skills;软链幂等,同路径只写一次 "agents": ".agents/skills", } ALL_TARGETS = ("cursor", "claude", "codex", "agents") def project_manifest(root: Path) -> Path: """项目清单路径:优先 .pouch.yaml,否则沿用 .skills.yaml。""" preferred = root / PROJECT_MANIFEST legacy = root / LEGACY_PROJECT_MANIFEST if preferred.is_file(): return preferred if legacy.is_file(): return legacy return preferred def resolve_targets(target: str | None) -> list[str]: if target is None or target == "all": return list(ALL_TARGETS) if target not in ALL_TARGETS: raise ValueError(f"未知 target: {target!r},可选: {', '.join(ALL_TARGETS)}, all") return [target] def agent_skill_dir(target: str, *, project_root: Path | None = None) -> Path: if project_root is None: return AGENT_GLOBAL[target] return project_root / AGENT_PROJECT[target] def ensure_pouch_home() -> None: if not POUCH_HOME.is_dir(): raise SystemExit( "~/.pouch 不存在。请将本仓库克隆到 ~/.pouch。" "若仍是 ~/.skills,先执行: mv ~/.skills ~/.pouch" )