feat: P1-19 P1-20 实现 - 边界测试强制 + 高风险审计 + UI Skill 路由

P1-19.1: Arc 边界测试强制
- TaskNode 新增 test_required 字段
- _inject_boundary_tests() 为每个模块注入接口测试和单元测试任务
- Done When 验证必须包含"测试通过"

P1-19.2: AirRvr 高风险审计
- 新增 HighRiskAudit, HighRiskFinding 数据类
- ReviewReport 新增 highRiskAudit 字段,含 lifecycle/nullPointer/danglingPointer/exceptionSafety/concurrency + overallRisk + deliveryVerdict
- 序列化/反序列化支持

P1-19.3: block-release 集成
- dispatch_worker_group() 派发前扫描最新审查报告
- deliveryVerdict=block-release 时阻止所有后续派发
- 记录 eng.blocked 事件

P1-20: frontend-design Skill 集成
- is_ui_task() UI 任务检测
- ensure_frontend_design_skill() 自动安装 Skill
- route_ui_task() UI 任务路由决策
- enter_worker() 集成 UI 检测,skill 不可用时阻止执行
- commands/do.md 更新 UI 处理说明
- SKILL.md 新增 INV-12/INV-13/INV-14

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
AirLongDian
2026-06-10 17:06:48 +08:00
commit e73a4da354
54 changed files with 6054 additions and 0 deletions

View File

@@ -0,0 +1,121 @@
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(),
}