from __future__ import annotations import json import shutil from pathlib import Path def resolve_plugin_paths() -> dict[str, Path]: """ 解析插件的实际安装路径。 顺序: 1) 环境变量 AIRPLAN_HOME > 2) ~/.airplan > 3) 相对脚本位置推测 """ # 1. 环境变量 if "AIRPLAN_HOME" in __import__("os").environ: return {"root": Path(__import__("os").environ["AIRPLAN_HOME"])} # 2. ~/.airplan 默认 home = Path.home() default = home / ".airplan" if default.exists(): return {"root": default} # 3. 尝试从当前脚本位置推测 # 脚本位于 {root}/scripts/airplan.py import sys script_root = Path(sys.argv[0]).resolve().parent if sys.argv else None if script_root and (script_root.name == "scripts"): plugin_root = script_root.parent if (plugin_root / ".claude-plugin").exists(): return {"root": plugin_root} # 4. 从本模块位置推测 # 本模块位于 {root}/lib/air_runtime/installer.py module_root = Path(__file__).resolve().parent.parent.parent # lib/air_runtime/installer -> lib/air_runtime -> lib -> root if (module_root / ".claude-plugin").exists(): return {"root": module_root} raise FileNotFoundError("Cannot locate plugin installation directory") def get_plugin_meta() -> dict: """读取 plugin.json 元数据""" paths = resolve_plugin_paths() meta_path = paths["root"] / ".claude-plugin" / "plugin.json" if not meta_path.exists(): raise FileNotFoundError(f"plugin.json not found at {meta_path}") return json.loads(meta_path.read_text()) def post_install_verify() -> dict: """ 安装后验证:检查所有依赖工具是否存在。 返回 {tool: bool} 映射,False 表示缺失。 """ required_tools = [ "git", # 版本控制 "cmake", # 构建 "ffmpeg", # XDB 截图 "xvfb-run", # XDB 虚拟显示 ] result = {"ok": True, "missing": []} for tool in required_tools: found = shutil.which(tool) is not None result[tool] = found if not found: result["ok"] = False result["missing"].append(tool) # 检查 Python 依赖 try: import yaml result["pyyaml"] = True except ImportError: result["pyyaml"] = False result["ok"] = False result["missing"].append("pyyaml") # 检查目录结构 paths = resolve_plugin_paths() for subdir in ["lib", "scripts", "skills", "commands"]: p = paths["root"] / subdir result[f"dir_{subdir}"] = p.exists() if not p.exists(): result["ok"] = False result["missing"].append(f"dir:{subdir}") return result def verify_plugin_json_paths() -> dict: """ 验证 plugin.json 里的路径是否可解析。 设计原文 P0-9 指出硬编码 $HOME 是问题,这里修复它。 """ meta = get_plugin_meta() issues = [] # 检查 scripts 路径 entry = meta.get("entry", {}) if isinstance(entry, dict): script_path_str = entry.get("args", [""])[0] if entry.get("args") else "" else: script_path_str = str(entry) if "$HOME" in script_path_str: # 尝试解析 resolved = script_path_str.replace("$HOME", str(Path.home())) if not Path(resolved).exists(): issues.append(f"script path not found: {resolved}") else: # 修复:改用相对路径或 AIRPLAN_HOME 变量 issues.append(f"script uses $HOME: {script_path_str} (should use relative path)") # 检查 marketplace 路径 market_path = meta.get("marketplace", "") if "$HOME" in market_path: issues.append(f"marketplace uses $HOME: {market_path}") return { "issues": issues, "resolved_paths": resolve_plugin_paths(), }