mirror of
https://github.com/wshobson/agents
synced 2026-06-21 14:13:58 +00:00
feat(plugin-eval): scaffold project with uv, ruff, ty
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# plugin-eval
|
||||
|
||||
Three-layer quality evaluation framework for Claude Code plugins.
|
||||
@@ -0,0 +1,56 @@
|
||||
[project]
|
||||
name = "plugin-eval"
|
||||
version = "0.1.0"
|
||||
description = "Three-layer quality evaluation framework for Claude Code plugins"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"pydantic>=2.0",
|
||||
"typer>=0.15",
|
||||
"rich>=13.0",
|
||||
"pyyaml>=6.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
llm = [
|
||||
"claude-agent-sdk>=0.1.50",
|
||||
]
|
||||
api = [
|
||||
"anthropic>=0.45",
|
||||
]
|
||||
dev = [
|
||||
"pytest>=8.0",
|
||||
"pytest-asyncio>=0.24",
|
||||
"pytest-cov>=6.0",
|
||||
"ruff>=0.9",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
plugin-eval = "plugin_eval.cli:app"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/plugin_eval"]
|
||||
|
||||
[tool.ruff]
|
||||
target-version = "py312"
|
||||
line-length = 100
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E4", "E7", "E9", "F", "B", "I", "UP", "SIM"]
|
||||
ignore = ["E501"]
|
||||
|
||||
[tool.ruff.format]
|
||||
quote-style = "double"
|
||||
|
||||
[tool.ty.rules]
|
||||
possibly-unresolved-reference = "error"
|
||||
possibly-missing-attribute = "error"
|
||||
possibly-missing-import = "error"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
asyncio_mode = "auto"
|
||||
@@ -0,0 +1,3 @@
|
||||
"""PluginEval — Quality evaluation framework for Claude Code plugins."""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
@@ -0,0 +1,79 @@
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fixtures_dir() -> Path:
|
||||
return Path(__file__).parent / "fixtures"
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_skill_dir(tmp_path: Path) -> Path:
|
||||
"""Create a minimal valid skill directory."""
|
||||
skill_dir = tmp_path / "test-skill"
|
||||
skill_dir.mkdir()
|
||||
skill_md = skill_dir / "SKILL.md"
|
||||
skill_md.write_text(
|
||||
"---\n"
|
||||
"name: test-skill\n"
|
||||
'description: "Test skill for evaluation. Use when testing plugin-eval."\n'
|
||||
"---\n\n"
|
||||
"# Test Skill\n\n"
|
||||
"## Overview\n\n"
|
||||
"This is a test skill for evaluation purposes.\n\n"
|
||||
"## Usage\n\n"
|
||||
"```python\nprint('hello')\n```\n\n"
|
||||
"## Troubleshooting\n\n"
|
||||
"Check the logs.\n"
|
||||
)
|
||||
refs_dir = skill_dir / "references"
|
||||
refs_dir.mkdir()
|
||||
(refs_dir / "guide.md").write_text("# Guide\n\nDetailed reference content.\n")
|
||||
return skill_dir
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_plugin_dir(tmp_path: Path, sample_skill_dir: Path) -> Path:
|
||||
"""Create a minimal valid plugin directory."""
|
||||
plugin_dir = tmp_path / "test-plugin"
|
||||
plugin_dir.mkdir()
|
||||
claude_dir = plugin_dir / ".claude-plugin"
|
||||
claude_dir.mkdir()
|
||||
(claude_dir / "plugin.json").write_text('{"name": "test-plugin"}')
|
||||
|
||||
skills_dir = plugin_dir / "skills"
|
||||
skills_dir.mkdir()
|
||||
import shutil
|
||||
dest = skills_dir / "test-skill"
|
||||
shutil.copytree(sample_skill_dir, dest)
|
||||
|
||||
agents_dir = plugin_dir / "agents"
|
||||
agents_dir.mkdir()
|
||||
(agents_dir / "test-agent.md").write_text(
|
||||
"---\n"
|
||||
"name: test-agent\n"
|
||||
'description: "Test agent. Use PROACTIVELY for testing."\n'
|
||||
"model: sonnet\n"
|
||||
"tools: Read, Grep, Glob\n"
|
||||
"---\n\n"
|
||||
"You are a test agent.\n"
|
||||
)
|
||||
return plugin_dir
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def poor_skill_dir(tmp_path: Path) -> Path:
|
||||
"""Create a skill with multiple anti-patterns."""
|
||||
skill_dir = tmp_path / "poor-skill"
|
||||
skill_dir.mkdir()
|
||||
skill_md = skill_dir / "SKILL.md"
|
||||
lines = ["---\n", "name: poor-skill\n", 'description: "A skill."\n', "---\n\n"]
|
||||
lines.append("# Poor Skill\n\n")
|
||||
for i in range(100):
|
||||
lines.append(f"You MUST follow rule {i}. You ALWAYS do this. NEVER skip.\n")
|
||||
skill_md.write_text("".join(lines))
|
||||
refs = skill_dir / "references"
|
||||
refs.mkdir()
|
||||
(refs / "orphan.md").write_text("# Orphan\n\nNot referenced from SKILL.md.\n")
|
||||
return skill_dir
|
||||
Generated
+1065
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user