Compare commits
28 Commits
8f450c0e7b
...
v5.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 34227126c2 | |||
| ef94602eba | |||
| 155e7be399 | |||
| 1fb9e6cece | |||
| f2cf082ba8 | |||
| d580464f4a | |||
| fe6b354ee2 | |||
| ec965dc8ee | |||
| cb07a382ea | |||
| 48ce693bb5 | |||
| bc0282b5f8 | |||
| db67d3cc76 | |||
| a933edeef1 | |||
| 1df9573f7a | |||
| 35d5f14003 | |||
| 5321b2929e | |||
| 05aa50d409 | |||
| 54e8e694b1 | |||
| 8ec7cbb1e9 | |||
| 3519a96d06 | |||
| f809c672b5 | |||
| 5d205c9c13 | |||
| efb83e0f28 | |||
| 7bedfa2c65 | |||
| 42ab4f13cf | |||
| 77dc122079 | |||
| ce774bcc6f | |||
| b3abe863af |
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Project management plugins with Gitea and NetBox integrations",
|
||||
"version": "4.1.0"
|
||||
"version": "5.0.0"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
@@ -181,6 +181,22 @@
|
||||
"category": "visualization",
|
||||
"tags": ["dash", "plotly", "mantine", "charts", "dashboards", "theming", "dmc"],
|
||||
"license": "MIT"
|
||||
},
|
||||
{
|
||||
"name": "contract-validator",
|
||||
"version": "1.0.0",
|
||||
"description": "Cross-plugin compatibility validation and Claude.md agent verification",
|
||||
"source": "./plugins/contract-validator",
|
||||
"author": {
|
||||
"name": "Leo Miranda",
|
||||
"email": "leobmiranda@gmail.com"
|
||||
},
|
||||
"homepage": "https://gitea.hotserv.cloud/personal-projects/leo-claude-mktplace/src/branch/main/plugins/contract-validator/README.md",
|
||||
"repository": "https://gitea.hotserv.cloud/personal-projects/leo-claude-mktplace.git",
|
||||
"mcpServers": ["./.mcp.json"],
|
||||
"category": "development",
|
||||
"tags": ["validation", "contracts", "compatibility", "agents", "interfaces", "cross-plugin"],
|
||||
"license": "MIT"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ All notable changes to the Leo Claude Marketplace will be documented in this fil
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [Unreleased]
|
||||
## [5.0.0] - 2026-01-26
|
||||
|
||||
### Added
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ See `docs/DEBUGGING-CHECKLIST.md` for details on cache timing.
|
||||
## Project Overview
|
||||
|
||||
**Repository:** leo-claude-mktplace
|
||||
**Version:** 4.1.0
|
||||
**Version:** 5.0.0
|
||||
**Status:** Production Ready
|
||||
|
||||
A plugin marketplace for Claude Code containing:
|
||||
@@ -67,6 +67,7 @@ A plugin marketplace for Claude Code containing:
|
||||
| `cmdb-assistant` | NetBox CMDB integration for infrastructure management | 1.0.0 |
|
||||
| `data-platform` | pandas, PostgreSQL, and dbt integration for data engineering | 1.0.0 |
|
||||
| `viz-platform` | DMC validation, Plotly charts, and theming for dashboards | 1.0.0 |
|
||||
| `contract-validator` | Cross-plugin compatibility validation and agent verification | 1.0.0 |
|
||||
| `project-hygiene` | Post-task cleanup automation via hooks | 0.1.0 |
|
||||
|
||||
## Quick Start
|
||||
@@ -93,6 +94,7 @@ A plugin marketplace for Claude Code containing:
|
||||
| **Config** | `/config-analyze`, `/config-optimize` |
|
||||
| **Data** | `/ingest`, `/profile`, `/schema`, `/explain`, `/lineage`, `/run` |
|
||||
| **Visualization** | `/component`, `/chart`, `/dashboard`, `/theme`, `/theme-new`, `/theme-css` |
|
||||
| **Validation** | `/validate-contracts`, `/check-agent`, `/list-interfaces` |
|
||||
| **Debug** | `/debug-report`, `/debug-review` |
|
||||
|
||||
## Repository Structure
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Leo Claude Marketplace - v4.1.0
|
||||
# Leo Claude Marketplace - v5.0.0
|
||||
|
||||
A collection of Claude Code plugins for project management, infrastructure automation, and development workflows.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
**This file defines ALL valid paths in this repository. No exceptions. No inference. No assumptions.**
|
||||
|
||||
Last Updated: 2026-01-26 (v4.1.0)
|
||||
Last Updated: 2026-01-26 (v5.0.0)
|
||||
|
||||
---
|
||||
|
||||
@@ -49,6 +49,15 @@ leo-claude-mktplace/
|
||||
│ │ │ └── dbt_tools.py
|
||||
│ │ ├── requirements.txt
|
||||
│ │ └── .venv/
|
||||
│ ├── contract-validator/ # Contract validation MCP (NEW v5.0.0)
|
||||
│ │ ├── mcp_server/
|
||||
│ │ │ ├── server.py
|
||||
│ │ │ ├── parse_tools.py
|
||||
│ │ │ ├── validation_tools.py
|
||||
│ │ │ └── report_tools.py
|
||||
│ │ ├── tests/
|
||||
│ │ ├── requirements.txt
|
||||
│ │ └── .venv/
|
||||
│ └── viz-platform/ # Visualization MCP (NEW v4.1.0)
|
||||
│ ├── mcp_server/
|
||||
│ │ ├── server.py
|
||||
@@ -135,6 +144,14 @@ leo-claude-mktplace/
|
||||
│ │ ├── agents/
|
||||
│ │ ├── hooks/
|
||||
│ │ └── claude-md-integration.md
|
||||
│ ├── contract-validator/ # NEW in v5.0.0
|
||||
│ │ ├── .claude-plugin/
|
||||
│ │ ├── .mcp.json
|
||||
│ │ ├── mcp-servers/
|
||||
│ │ │ └── contract-validator -> ../../../mcp-servers/contract-validator # SYMLINK
|
||||
│ │ ├── commands/
|
||||
│ │ ├── agents/
|
||||
│ │ └── claude-md-integration.md
|
||||
│ └── viz-platform/ # NEW in v4.1.0
|
||||
│ ├── .claude-plugin/
|
||||
│ ├── .mcp.json
|
||||
@@ -269,6 +286,7 @@ plugins/cmdb-assistant/mcp-servers/netbox -> ../../../mcp-servers/netbox
|
||||
plugins/pr-review/mcp-servers/gitea -> ../../../mcp-servers/gitea
|
||||
plugins/data-platform/mcp-servers/data-platform -> ../../../mcp-servers/data-platform
|
||||
plugins/viz-platform/mcp-servers/viz-platform -> ../../../mcp-servers/viz-platform
|
||||
plugins/contract-validator/mcp-servers/contract-validator -> ../../../mcp-servers/contract-validator
|
||||
```
|
||||
|
||||
---
|
||||
@@ -277,6 +295,7 @@ plugins/viz-platform/mcp-servers/viz-platform -> ../../../mcp-servers/viz-platfo
|
||||
|
||||
| Date | Change | By |
|
||||
|------|--------|-----|
|
||||
| 2026-01-26 | v5.0.0: Added contract-validator plugin and MCP server | Claude Code |
|
||||
| 2026-01-26 | v4.1.0: Added viz-platform plugin and MCP server | Claude Code |
|
||||
| 2026-01-25 | v4.0.0: Added data-platform plugin and MCP server | Claude Code |
|
||||
| 2026-01-20 | v3.0.0: MCP servers moved to root with symlinks | Claude Code |
|
||||
|
||||
1
mcp-servers/contract-validator/tests/__init__.py
Normal file
1
mcp-servers/contract-validator/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Tests for contract-validator MCP server
|
||||
193
mcp-servers/contract-validator/tests/test_parse_tools.py
Normal file
193
mcp-servers/contract-validator/tests/test_parse_tools.py
Normal file
@@ -0,0 +1,193 @@
|
||||
"""
|
||||
Unit tests for parse tools.
|
||||
"""
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def parse_tools():
|
||||
"""Create ParseTools instance"""
|
||||
from mcp_server.parse_tools import ParseTools
|
||||
return ParseTools()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_readme(tmp_path):
|
||||
"""Create a sample README.md for testing"""
|
||||
readme = tmp_path / "README.md"
|
||||
readme.write_text("""# Test Plugin
|
||||
|
||||
A test plugin for validation.
|
||||
|
||||
## Features
|
||||
|
||||
- **Feature One**: Does something
|
||||
- **Feature Two**: Does something else
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/test-cmd` | Test command |
|
||||
| `/another-cmd` | Another test command |
|
||||
|
||||
## Agents
|
||||
|
||||
| Agent | Description |
|
||||
|-------|-------------|
|
||||
| `test-agent` | A test agent |
|
||||
|
||||
## Tools Summary
|
||||
|
||||
### Category A (3 tools)
|
||||
`tool_a`, `tool_b`, `tool_c`
|
||||
|
||||
### Category B (2 tools)
|
||||
`tool_d`, `tool_e`
|
||||
""")
|
||||
return str(tmp_path)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_claude_md(tmp_path):
|
||||
"""Create a sample CLAUDE.md for testing"""
|
||||
claude_md = tmp_path / "CLAUDE.md"
|
||||
claude_md.write_text("""# CLAUDE.md
|
||||
|
||||
## Project Overview
|
||||
|
||||
### Four-Agent Model (test)
|
||||
|
||||
| Agent | Personality | Responsibilities |
|
||||
|-------|-------------|------------------|
|
||||
| **Planner** | Thoughtful | Planning via `create_issue`, `search_lessons` |
|
||||
| **Executor** | Focused | Implementation via `write`, `edit` |
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Planner creates issues
|
||||
2. Executor implements code
|
||||
""")
|
||||
return str(claude_md)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_plugin_interface_basic(parse_tools, sample_readme):
|
||||
"""Test basic plugin interface parsing"""
|
||||
result = await parse_tools.parse_plugin_interface(sample_readme)
|
||||
|
||||
assert "error" not in result
|
||||
# Plugin name extraction strips "Plugin" suffix
|
||||
assert result["plugin_name"] == "Test"
|
||||
assert "A test plugin" in result["description"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_plugin_interface_commands(parse_tools, sample_readme):
|
||||
"""Test command extraction from README"""
|
||||
result = await parse_tools.parse_plugin_interface(sample_readme)
|
||||
|
||||
commands = result["commands"]
|
||||
assert len(commands) == 2
|
||||
assert commands[0]["name"] == "/test-cmd"
|
||||
assert commands[1]["name"] == "/another-cmd"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_plugin_interface_agents(parse_tools, sample_readme):
|
||||
"""Test agent extraction from README"""
|
||||
result = await parse_tools.parse_plugin_interface(sample_readme)
|
||||
|
||||
agents = result["agents"]
|
||||
assert len(agents) == 1
|
||||
assert agents[0]["name"] == "test-agent"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_plugin_interface_tools(parse_tools, sample_readme):
|
||||
"""Test tool extraction from README"""
|
||||
result = await parse_tools.parse_plugin_interface(sample_readme)
|
||||
|
||||
tools = result["tools"]
|
||||
tool_names = [t["name"] for t in tools]
|
||||
assert "tool_a" in tool_names
|
||||
assert "tool_b" in tool_names
|
||||
assert "tool_e" in tool_names
|
||||
assert len(tools) >= 5
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_plugin_interface_categories(parse_tools, sample_readme):
|
||||
"""Test tool category extraction"""
|
||||
result = await parse_tools.parse_plugin_interface(sample_readme)
|
||||
|
||||
categories = result["tool_categories"]
|
||||
assert "Category A" in categories
|
||||
assert "Category B" in categories
|
||||
assert "tool_a" in categories["Category A"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_plugin_interface_features(parse_tools, sample_readme):
|
||||
"""Test feature extraction"""
|
||||
result = await parse_tools.parse_plugin_interface(sample_readme)
|
||||
|
||||
features = result["features"]
|
||||
assert "Feature One" in features
|
||||
assert "Feature Two" in features
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_plugin_interface_not_found(parse_tools, tmp_path):
|
||||
"""Test error when README not found"""
|
||||
result = await parse_tools.parse_plugin_interface(str(tmp_path / "nonexistent"))
|
||||
|
||||
assert "error" in result
|
||||
assert "not found" in result["error"].lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_claude_md_agents(parse_tools, sample_claude_md):
|
||||
"""Test agent extraction from CLAUDE.md"""
|
||||
result = await parse_tools.parse_claude_md_agents(sample_claude_md)
|
||||
|
||||
assert "error" not in result
|
||||
assert result["agent_count"] == 2
|
||||
|
||||
agents = result["agents"]
|
||||
agent_names = [a["name"] for a in agents]
|
||||
assert "Planner" in agent_names
|
||||
assert "Executor" in agent_names
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_claude_md_tool_refs(parse_tools, sample_claude_md):
|
||||
"""Test tool reference extraction from agents"""
|
||||
result = await parse_tools.parse_claude_md_agents(sample_claude_md)
|
||||
|
||||
agents = {a["name"]: a for a in result["agents"]}
|
||||
planner = agents["Planner"]
|
||||
|
||||
assert "create_issue" in planner["tool_refs"]
|
||||
assert "search_lessons" in planner["tool_refs"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_claude_md_not_found(parse_tools, tmp_path):
|
||||
"""Test error when CLAUDE.md not found"""
|
||||
result = await parse_tools.parse_claude_md_agents(str(tmp_path / "CLAUDE.md"))
|
||||
|
||||
assert "error" in result
|
||||
assert "not found" in result["error"].lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_parse_plugin_with_direct_file(parse_tools, sample_readme):
|
||||
"""Test parsing with direct file path instead of directory"""
|
||||
readme_path = Path(sample_readme) / "README.md"
|
||||
result = await parse_tools.parse_plugin_interface(str(readme_path))
|
||||
|
||||
assert "error" not in result
|
||||
# Plugin name extraction strips "Plugin" suffix
|
||||
assert result["plugin_name"] == "Test"
|
||||
261
mcp-servers/contract-validator/tests/test_report_tools.py
Normal file
261
mcp-servers/contract-validator/tests/test_report_tools.py
Normal file
@@ -0,0 +1,261 @@
|
||||
"""
|
||||
Unit tests for report tools.
|
||||
"""
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def report_tools():
|
||||
"""Create ReportTools instance"""
|
||||
from mcp_server.report_tools import ReportTools
|
||||
return ReportTools()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_marketplace(tmp_path):
|
||||
"""Create a sample marketplace structure"""
|
||||
import json
|
||||
|
||||
plugins_dir = tmp_path / "plugins"
|
||||
plugins_dir.mkdir()
|
||||
|
||||
# Plugin 1
|
||||
plugin1 = plugins_dir / "plugin-one"
|
||||
plugin1.mkdir()
|
||||
plugin1_meta = plugin1 / ".claude-plugin"
|
||||
plugin1_meta.mkdir()
|
||||
(plugin1_meta / "plugin.json").write_text(json.dumps({"name": "plugin-one"}))
|
||||
(plugin1 / "README.md").write_text("""# plugin-one
|
||||
|
||||
First test plugin.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/cmd-one` | Command one |
|
||||
|
||||
## Tools Summary
|
||||
|
||||
### Tools (2 tools)
|
||||
`tool_a`, `tool_b`
|
||||
""")
|
||||
|
||||
# Plugin 2
|
||||
plugin2 = plugins_dir / "plugin-two"
|
||||
plugin2.mkdir()
|
||||
plugin2_meta = plugin2 / ".claude-plugin"
|
||||
plugin2_meta.mkdir()
|
||||
(plugin2_meta / "plugin.json").write_text(json.dumps({"name": "plugin-two"}))
|
||||
(plugin2 / "README.md").write_text("""# plugin-two
|
||||
|
||||
Second test plugin.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/cmd-two` | Command two |
|
||||
|
||||
## Tools Summary
|
||||
|
||||
### Tools (2 tools)
|
||||
`tool_c`, `tool_d`
|
||||
""")
|
||||
|
||||
# Plugin 3 (with conflict)
|
||||
plugin3 = plugins_dir / "plugin-three"
|
||||
plugin3.mkdir()
|
||||
plugin3_meta = plugin3 / ".claude-plugin"
|
||||
plugin3_meta.mkdir()
|
||||
(plugin3_meta / "plugin.json").write_text(json.dumps({"name": "plugin-three"}))
|
||||
(plugin3 / "README.md").write_text("""# plugin-three
|
||||
|
||||
Third test plugin with conflict.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/cmd-one` | Conflicting command |
|
||||
|
||||
## Tools Summary
|
||||
|
||||
### Tools (1 tool)
|
||||
`tool_e`
|
||||
""")
|
||||
|
||||
return str(tmp_path)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def marketplace_no_plugins(tmp_path):
|
||||
"""Create marketplace with no plugins"""
|
||||
plugins_dir = tmp_path / "plugins"
|
||||
plugins_dir.mkdir()
|
||||
return str(tmp_path)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def marketplace_no_dir(tmp_path):
|
||||
"""Create path without plugins directory"""
|
||||
return str(tmp_path)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_report_json_format(report_tools, sample_marketplace):
|
||||
"""Test JSON format report generation"""
|
||||
result = await report_tools.generate_compatibility_report(
|
||||
sample_marketplace, "json"
|
||||
)
|
||||
|
||||
assert "error" not in result
|
||||
assert "generated_at" in result
|
||||
assert "summary" in result
|
||||
assert "plugins" in result
|
||||
assert result["summary"]["total_plugins"] == 3
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_report_markdown_format(report_tools, sample_marketplace):
|
||||
"""Test markdown format report generation"""
|
||||
result = await report_tools.generate_compatibility_report(
|
||||
sample_marketplace, "markdown"
|
||||
)
|
||||
|
||||
assert "error" not in result
|
||||
assert "report" in result
|
||||
assert "# Contract Validation Report" in result["report"]
|
||||
assert "## Summary" in result["report"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_report_finds_conflicts(report_tools, sample_marketplace):
|
||||
"""Test that report finds command conflicts"""
|
||||
result = await report_tools.generate_compatibility_report(
|
||||
sample_marketplace, "json"
|
||||
)
|
||||
|
||||
assert "error" not in result
|
||||
assert result["summary"]["errors"] > 0
|
||||
assert result["summary"]["total_issues"] > 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_report_counts_correctly(report_tools, sample_marketplace):
|
||||
"""Test summary counts are correct"""
|
||||
result = await report_tools.generate_compatibility_report(
|
||||
sample_marketplace, "json"
|
||||
)
|
||||
|
||||
summary = result["summary"]
|
||||
assert summary["total_plugins"] == 3
|
||||
assert summary["total_commands"] == 3 # 3 commands total
|
||||
assert summary["total_tools"] == 5 # a, b, c, d, e
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_report_no_plugins(report_tools, marketplace_no_plugins):
|
||||
"""Test error when no plugins found"""
|
||||
result = await report_tools.generate_compatibility_report(
|
||||
marketplace_no_plugins, "json"
|
||||
)
|
||||
|
||||
assert "error" in result
|
||||
assert "no plugins" in result["error"].lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_report_no_plugins_dir(report_tools, marketplace_no_dir):
|
||||
"""Test error when plugins directory doesn't exist"""
|
||||
result = await report_tools.generate_compatibility_report(
|
||||
marketplace_no_dir, "json"
|
||||
)
|
||||
|
||||
assert "error" in result
|
||||
assert "not found" in result["error"].lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_issues_all(report_tools, sample_marketplace):
|
||||
"""Test listing all issues"""
|
||||
result = await report_tools.list_issues(sample_marketplace, "all", "all")
|
||||
|
||||
assert "error" not in result
|
||||
assert "issues" in result
|
||||
assert result["total_issues"] > 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_issues_filter_by_severity(report_tools, sample_marketplace):
|
||||
"""Test filtering issues by severity"""
|
||||
all_result = await report_tools.list_issues(sample_marketplace, "all", "all")
|
||||
error_result = await report_tools.list_issues(sample_marketplace, "error", "all")
|
||||
|
||||
# Error count should be less than or equal to all
|
||||
assert error_result["total_issues"] <= all_result["total_issues"]
|
||||
|
||||
# All issues should have error severity
|
||||
for issue in error_result["issues"]:
|
||||
sev = issue.get("severity", "")
|
||||
if hasattr(sev, 'value'):
|
||||
sev = sev.value
|
||||
assert "error" in str(sev).lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_issues_filter_by_type(report_tools, sample_marketplace):
|
||||
"""Test filtering issues by type"""
|
||||
result = await report_tools.list_issues(
|
||||
sample_marketplace, "all", "interface_mismatch"
|
||||
)
|
||||
|
||||
# All issues should have matching type
|
||||
for issue in result["issues"]:
|
||||
itype = issue.get("issue_type", "")
|
||||
if hasattr(itype, 'value'):
|
||||
itype = itype.value
|
||||
assert "interface_mismatch" in str(itype).lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_list_issues_combined_filters(report_tools, sample_marketplace):
|
||||
"""Test combined severity and type filters"""
|
||||
result = await report_tools.list_issues(
|
||||
sample_marketplace, "error", "interface_mismatch"
|
||||
)
|
||||
|
||||
assert "error" not in result
|
||||
# Should have command conflict errors
|
||||
assert result["total_issues"] > 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_report_markdown_has_all_sections(report_tools, sample_marketplace):
|
||||
"""Test markdown report contains all expected sections"""
|
||||
result = await report_tools.generate_compatibility_report(
|
||||
sample_marketplace, "markdown"
|
||||
)
|
||||
|
||||
report = result["report"]
|
||||
assert "## Summary" in report
|
||||
assert "## Plugins" in report
|
||||
# Compatibility section only if there are checks
|
||||
assert "Plugin One" in report or "plugin-one" in report.lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_report_includes_suggestions(report_tools, sample_marketplace):
|
||||
"""Test that issues include suggestions"""
|
||||
result = await report_tools.generate_compatibility_report(
|
||||
sample_marketplace, "json"
|
||||
)
|
||||
|
||||
issues = result.get("all_issues", [])
|
||||
# Find an issue with a suggestion
|
||||
issues_with_suggestions = [
|
||||
i for i in issues
|
||||
if i.get("suggestion")
|
||||
]
|
||||
assert len(issues_with_suggestions) > 0
|
||||
256
mcp-servers/contract-validator/tests/test_validation_tools.py
Normal file
256
mcp-servers/contract-validator/tests/test_validation_tools.py
Normal file
@@ -0,0 +1,256 @@
|
||||
"""
|
||||
Unit tests for validation tools.
|
||||
"""
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def validation_tools():
|
||||
"""Create ValidationTools instance"""
|
||||
from mcp_server.validation_tools import ValidationTools
|
||||
return ValidationTools()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def plugin_a(tmp_path):
|
||||
"""Create first test plugin"""
|
||||
plugin_dir = tmp_path / "plugin-a"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / ".claude-plugin").mkdir()
|
||||
|
||||
readme = plugin_dir / "README.md"
|
||||
readme.write_text("""# Plugin A
|
||||
|
||||
Test plugin A.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/setup-a` | Setup A |
|
||||
| `/shared-cmd` | Shared command |
|
||||
|
||||
## Tools Summary
|
||||
|
||||
### Core (2 tools)
|
||||
`tool_one`, `tool_two`
|
||||
""")
|
||||
return str(plugin_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def plugin_b(tmp_path):
|
||||
"""Create second test plugin"""
|
||||
plugin_dir = tmp_path / "plugin-b"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / ".claude-plugin").mkdir()
|
||||
|
||||
readme = plugin_dir / "README.md"
|
||||
readme.write_text("""# Plugin B
|
||||
|
||||
Test plugin B.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/setup-b` | Setup B |
|
||||
| `/shared-cmd` | Shared command (conflict!) |
|
||||
|
||||
## Tools Summary
|
||||
|
||||
### Core (2 tools)
|
||||
`tool_two`, `tool_three`
|
||||
""")
|
||||
return str(plugin_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def plugin_no_conflict(tmp_path):
|
||||
"""Create plugin with no conflicts"""
|
||||
plugin_dir = tmp_path / "plugin-c"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / ".claude-plugin").mkdir()
|
||||
|
||||
readme = plugin_dir / "README.md"
|
||||
readme.write_text("""# Plugin C
|
||||
|
||||
Test plugin C.
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/unique-cmd` | Unique command |
|
||||
|
||||
## Tools Summary
|
||||
|
||||
### Core (1 tool)
|
||||
`unique_tool`
|
||||
""")
|
||||
return str(plugin_dir)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def claude_md_with_agents(tmp_path):
|
||||
"""Create CLAUDE.md with agent definitions"""
|
||||
claude_md = tmp_path / "CLAUDE.md"
|
||||
claude_md.write_text("""# CLAUDE.md
|
||||
|
||||
### Four-Agent Model
|
||||
|
||||
| Agent | Personality | Responsibilities |
|
||||
|-------|-------------|------------------|
|
||||
| **TestAgent** | Careful | Uses `tool_one`, `tool_two`, `missing_tool` |
|
||||
| **ValidAgent** | Thorough | Uses `tool_one` only |
|
||||
| **EmptyAgent** | Unknown | General tasks |
|
||||
""")
|
||||
return str(claude_md)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_compatibility_command_conflict(validation_tools, plugin_a, plugin_b):
|
||||
"""Test detection of command name conflicts"""
|
||||
result = await validation_tools.validate_compatibility(plugin_a, plugin_b)
|
||||
|
||||
assert "error" not in result
|
||||
assert result["compatible"] is False
|
||||
|
||||
# Find the command conflict issue
|
||||
error_issues = [i for i in result["issues"] if i["severity"].value == "error"]
|
||||
assert len(error_issues) > 0
|
||||
assert any("/shared-cmd" in str(i["message"]) for i in error_issues)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_compatibility_tool_overlap(validation_tools, plugin_a, plugin_b):
|
||||
"""Test detection of tool name overlaps"""
|
||||
result = await validation_tools.validate_compatibility(plugin_a, plugin_b)
|
||||
|
||||
assert "tool_two" in result["shared_tools"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_compatibility_unique_tools(validation_tools, plugin_a, plugin_b):
|
||||
"""Test identification of unique tools per plugin"""
|
||||
result = await validation_tools.validate_compatibility(plugin_a, plugin_b)
|
||||
|
||||
assert "tool_one" in result["a_only_tools"]
|
||||
assert "tool_three" in result["b_only_tools"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_compatibility_no_conflict(validation_tools, plugin_a, plugin_no_conflict):
|
||||
"""Test compatible plugins"""
|
||||
result = await validation_tools.validate_compatibility(plugin_a, plugin_no_conflict)
|
||||
|
||||
assert "error" not in result
|
||||
assert result["compatible"] is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_compatibility_missing_plugin(validation_tools, plugin_a, tmp_path):
|
||||
"""Test error when plugin not found"""
|
||||
result = await validation_tools.validate_compatibility(
|
||||
plugin_a,
|
||||
str(tmp_path / "nonexistent")
|
||||
)
|
||||
|
||||
assert "error" in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_agent_refs_with_missing_tools(validation_tools, claude_md_with_agents, plugin_a):
|
||||
"""Test detection of missing tool references"""
|
||||
result = await validation_tools.validate_agent_refs(
|
||||
"TestAgent",
|
||||
claude_md_with_agents,
|
||||
[plugin_a]
|
||||
)
|
||||
|
||||
assert "error" not in result
|
||||
assert result["valid"] is False
|
||||
assert "missing_tool" in result["tool_refs_missing"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_agent_refs_valid_agent(validation_tools, claude_md_with_agents, plugin_a):
|
||||
"""Test valid agent with all tools found"""
|
||||
result = await validation_tools.validate_agent_refs(
|
||||
"ValidAgent",
|
||||
claude_md_with_agents,
|
||||
[plugin_a]
|
||||
)
|
||||
|
||||
assert "error" not in result
|
||||
assert result["valid"] is True
|
||||
assert "tool_one" in result["tool_refs_found"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_agent_refs_empty_agent(validation_tools, claude_md_with_agents, plugin_a):
|
||||
"""Test agent with no tool references"""
|
||||
result = await validation_tools.validate_agent_refs(
|
||||
"EmptyAgent",
|
||||
claude_md_with_agents,
|
||||
[plugin_a]
|
||||
)
|
||||
|
||||
assert "error" not in result
|
||||
# Should have info issue about undocumented references
|
||||
info_issues = [i for i in result["issues"] if i["severity"].value == "info"]
|
||||
assert len(info_issues) > 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_agent_refs_agent_not_found(validation_tools, claude_md_with_agents, plugin_a):
|
||||
"""Test error when agent not found"""
|
||||
result = await validation_tools.validate_agent_refs(
|
||||
"NonexistentAgent",
|
||||
claude_md_with_agents,
|
||||
[plugin_a]
|
||||
)
|
||||
|
||||
assert "error" in result
|
||||
assert "not found" in result["error"].lower()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_data_flow_valid(validation_tools, tmp_path):
|
||||
"""Test data flow validation with valid flow"""
|
||||
claude_md = tmp_path / "CLAUDE.md"
|
||||
claude_md.write_text("""# CLAUDE.md
|
||||
|
||||
### Four-Agent Model
|
||||
|
||||
| Agent | Personality | Responsibilities |
|
||||
|-------|-------------|------------------|
|
||||
| **DataAgent** | Analytical | Load with `read_csv`, analyze with `describe`, export with `to_csv` |
|
||||
""")
|
||||
|
||||
result = await validation_tools.validate_data_flow("DataAgent", str(claude_md))
|
||||
|
||||
assert "error" not in result
|
||||
assert result["valid"] is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_validate_data_flow_missing_producer(validation_tools, tmp_path):
|
||||
"""Test data flow with consumer but no producer"""
|
||||
claude_md = tmp_path / "CLAUDE.md"
|
||||
claude_md.write_text("""# CLAUDE.md
|
||||
|
||||
### Four-Agent Model
|
||||
|
||||
| Agent | Personality | Responsibilities |
|
||||
|-------|-------------|------------------|
|
||||
| **BadAgent** | Careless | Just runs `describe`, `head`, `tail` without loading |
|
||||
""")
|
||||
|
||||
result = await validation_tools.validate_data_flow("BadAgent", str(claude_md))
|
||||
|
||||
assert "error" not in result
|
||||
# Should have warning about missing producer
|
||||
warning_issues = [i for i in result["issues"] if i["severity"].value == "warning"]
|
||||
assert len(warning_issues) > 0
|
||||
156
plugins/contract-validator/README.md
Normal file
156
plugins/contract-validator/README.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# contract-validator Plugin
|
||||
|
||||
Cross-plugin compatibility validation and CLAUDE.md agent verification for Claude Code plugin marketplaces.
|
||||
|
||||
## Problem Statement
|
||||
|
||||
As plugin marketplaces grow, several compatibility issues emerge:
|
||||
|
||||
- **Command conflicts**: Multiple plugins defining the same slash command (e.g., `/initial-setup`)
|
||||
- **Tool name overlaps**: Different plugins using identical tool names with incompatible interfaces
|
||||
- **Undocumented dependencies**: Agents referencing tools that don't exist
|
||||
- **Broken data flows**: Agent sequences that expect outputs not produced by prior steps
|
||||
|
||||
Contract-validator solves these by parsing plugin interfaces and validating compatibility before runtime.
|
||||
|
||||
## Features
|
||||
|
||||
- **Interface Parsing**: Extract commands, agents, and tools from plugin README.md files
|
||||
- **Agent Extraction**: Parse CLAUDE.md Four-Agent Model tables and Agents sections
|
||||
- **Compatibility Checks**: Pairwise validation between all plugins in a marketplace
|
||||
- **Data Flow Validation**: Verify agent tool sequences have valid data producers/consumers
|
||||
- **Comprehensive Reports**: Markdown or JSON reports with actionable suggestions
|
||||
|
||||
## Installation
|
||||
|
||||
This plugin is part of the leo-claude-mktplace. Install via:
|
||||
|
||||
```bash
|
||||
# From marketplace
|
||||
claude plugins install leo-claude-mktplace/contract-validator
|
||||
|
||||
# Setup MCP server venv
|
||||
cd ~/.claude/plugins/marketplaces/leo-claude-mktplace/mcp-servers/contract-validator
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/validate-contracts` | Full marketplace compatibility validation |
|
||||
| `/check-agent` | Validate single agent definition |
|
||||
| `/list-interfaces` | Show all plugin interfaces |
|
||||
|
||||
## Agents
|
||||
|
||||
| Agent | Description |
|
||||
|-------|-------------|
|
||||
| `full-validation` | Complete cross-plugin compatibility validation |
|
||||
| `agent-check` | Single agent definition verification |
|
||||
|
||||
## Tools Summary
|
||||
|
||||
### Parse Tools (2)
|
||||
- `parse_plugin_interface` - Extract interface from plugin README.md
|
||||
- `parse_claude_md_agents` - Extract agents from CLAUDE.md
|
||||
|
||||
### Validation Tools (3)
|
||||
- `validate_compatibility` - Check two plugins for conflicts
|
||||
- `validate_agent_refs` - Verify agent tool references exist
|
||||
- `validate_data_flow` - Check data flow through agent sequences
|
||||
|
||||
### Report Tools (2)
|
||||
- `generate_compatibility_report` - Full marketplace validation report
|
||||
- `list_issues` - Filter issues by severity or type
|
||||
|
||||
## Example Workflow
|
||||
|
||||
```
|
||||
/validate-contracts ~/claude-plugins-work
|
||||
|
||||
# Output:
|
||||
# Contract Validation Report
|
||||
#
|
||||
# | Metric | Count |
|
||||
# |------------|-------|
|
||||
# | Plugins | 12 |
|
||||
# | Commands | 39 |
|
||||
# | Tools | 32 |
|
||||
# | **Issues** | **7** |
|
||||
# | - Errors | 3 |
|
||||
# | - Warnings | 0 |
|
||||
# | - Info | 4 |
|
||||
#
|
||||
# ## Issues Found
|
||||
# [ERROR] Command conflict: projman and data-platform both define /initial-setup
|
||||
# [ERROR] Command conflict: projman and pr-review both define /initial-setup
|
||||
# ...
|
||||
```
|
||||
|
||||
```
|
||||
/check-agent Planner ./CLAUDE.md
|
||||
|
||||
# Output:
|
||||
# Agent: Planner
|
||||
# Status: VALID
|
||||
#
|
||||
# Tool References Found (3):
|
||||
# - create_issue ✓
|
||||
# - search_lessons ✓
|
||||
# - get_execution_order ✓
|
||||
#
|
||||
# Data Flow: No issues detected
|
||||
```
|
||||
|
||||
## Issue Types
|
||||
|
||||
| Type | Severity | Description |
|
||||
|------|----------|-------------|
|
||||
| `interface_mismatch` | ERROR | Command name conflict between plugins |
|
||||
| `missing_tool` | ERROR | Agent references non-existent tool |
|
||||
| `interface_mismatch` | WARNING | Tool name overlap (different plugins) |
|
||||
| `optional_dependency` | WARNING | Agent uses tool from non-required plugin |
|
||||
| `undeclared_output` | INFO | Agent has no documented tool references |
|
||||
|
||||
## Parsed Interface Structure
|
||||
|
||||
When parsing a plugin README.md, the following structure is extracted:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugin_name": "data-platform",
|
||||
"description": "Data engineering tools...",
|
||||
"commands": [
|
||||
{"name": "/ingest", "description": "Load data..."}
|
||||
],
|
||||
"agents": [
|
||||
{"name": "data-analysis", "description": "..."}
|
||||
],
|
||||
"tools": [
|
||||
{"name": "read_csv", "category": "pandas"}
|
||||
],
|
||||
"tool_categories": {
|
||||
"pandas": ["read_csv", "to_csv", ...],
|
||||
"PostgreSQL": ["pg_query", ...]
|
||||
},
|
||||
"features": ["pandas Operations", "PostgreSQL/PostGIS", ...]
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Plugin Authors
|
||||
|
||||
1. **Use unique command names**: Prefix with plugin name if generic (e.g., `/data-setup` vs `/initial-setup`)
|
||||
2. **Document all tools**: Include tool names in README.md with backticks
|
||||
3. **Specify tool categories**: Use `### Category (N tools)` headers
|
||||
4. **Declare agent tools**: List tools used by agents in their definitions
|
||||
|
||||
### For Marketplace Maintainers
|
||||
|
||||
1. **Run validation before merging**: Use `/validate-contracts` in CI/CD
|
||||
2. **Review warnings**: Tool overlaps may indicate design issues
|
||||
3. **Track issues over time**: Use JSON format for programmatic tracking
|
||||
90
plugins/contract-validator/agents/agent-check.md
Normal file
90
plugins/contract-validator/agents/agent-check.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# Agent Check Agent
|
||||
|
||||
You are an agent definition validator. Your role is to verify that a specific agent's tool references and data flow are valid.
|
||||
|
||||
## Capabilities
|
||||
|
||||
- Parse agent definitions from CLAUDE.md
|
||||
- Validate tool references against available plugins
|
||||
- Verify data flow patterns through agent sequences
|
||||
- Provide detailed validation feedback
|
||||
|
||||
## Available Tools
|
||||
|
||||
### Parsing
|
||||
- `parse_claude_md_agents` - Extract all agents from CLAUDE.md
|
||||
- `parse_plugin_interface` - Extract interface from plugin (for available tools)
|
||||
|
||||
### Validation
|
||||
- `validate_agent_refs` - Check agent tool references exist
|
||||
- `validate_data_flow` - Verify data flow through agent sequence
|
||||
|
||||
### Reporting
|
||||
- `list_issues` - Filter issues for this agent
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Locate the agent**:
|
||||
- Use `parse_claude_md_agents` on specified CLAUDE.md
|
||||
- Find agent by name (case-insensitive match)
|
||||
- If not found, list available agents
|
||||
|
||||
2. **Gather available tools**:
|
||||
- Scan plugins directory for available plugins
|
||||
- For each plugin, use `parse_plugin_interface`
|
||||
- Build set of all available tool names
|
||||
|
||||
3. **Validate tool references**:
|
||||
- Use `validate_agent_refs` with agent name and plugin paths
|
||||
- Report found tools (valid references)
|
||||
- Report missing tools (errors)
|
||||
- Suggest corrections for typos
|
||||
|
||||
4. **Validate data flow**:
|
||||
- Use `validate_data_flow` to check sequence
|
||||
- Verify data producers precede consumers
|
||||
- Check for orphaned data references
|
||||
- Identify potential flow issues
|
||||
|
||||
5. **Report findings**:
|
||||
- Agent name and source file
|
||||
- Responsibilities extracted
|
||||
- Tool references: found vs missing
|
||||
- Data flow validation results
|
||||
- Suggestions for improvement
|
||||
|
||||
## Validation Rules
|
||||
|
||||
### Tool Reference Rules
|
||||
- All referenced tools must exist in available plugins
|
||||
- Tool names are case-sensitive
|
||||
- Partial matches suggest typos
|
||||
|
||||
### Data Flow Rules
|
||||
- Data producers (read_csv, pg_query, etc.) should precede consumers
|
||||
- Data consumers (describe, head, to_csv, etc.) need valid data_ref
|
||||
- Workflow steps should have logical sequence
|
||||
|
||||
## Issue Severities
|
||||
|
||||
- **ERROR**: Tool reference not found - agent will fail
|
||||
- **WARNING**: Data flow issue - agent may produce unexpected results
|
||||
- **INFO**: Undocumented reference - consider adding documentation
|
||||
|
||||
## Example Interaction
|
||||
|
||||
**User**: /check-agent Orchestrator
|
||||
|
||||
**Agent**:
|
||||
1. Parses CLAUDE.md, finds Orchestrator agent
|
||||
2. Extracts responsibilities: "Sprint execution, parallel batching, Git operations"
|
||||
3. Finds tool refs: create_issue, update_issue, search_lessons
|
||||
4. Validates against plugins: all tools found in projman/gitea
|
||||
5. Validates data flow: no data producers/consumers used
|
||||
6. Reports: "Agent Orchestrator: VALID - all 3 tool references found"
|
||||
|
||||
**User**: /check-agent InvalidAgent
|
||||
|
||||
**Agent**:
|
||||
1. Parses CLAUDE.md, agent not found
|
||||
2. Reports: "Agent 'InvalidAgent' not found. Available agents: Planner, Orchestrator, Executor, Code Reviewer"
|
||||
87
plugins/contract-validator/agents/full-validation.md
Normal file
87
plugins/contract-validator/agents/full-validation.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Full Validation Agent
|
||||
|
||||
You are a contract validation specialist. Your role is to perform comprehensive cross-plugin compatibility validation for the entire marketplace.
|
||||
|
||||
## Capabilities
|
||||
|
||||
- Parse plugin interfaces from README.md files
|
||||
- Parse agent definitions from CLAUDE.md files
|
||||
- Validate cross-plugin compatibility
|
||||
- Identify interface mismatches and conflicts
|
||||
- Generate detailed validation reports
|
||||
|
||||
## Available Tools
|
||||
|
||||
### Parsing
|
||||
- `parse_plugin_interface` - Extract interface from plugin README.md
|
||||
- `parse_claude_md_agents` - Extract agents from CLAUDE.md
|
||||
|
||||
### Validation
|
||||
- `validate_compatibility` - Check two plugins for conflicts
|
||||
- `validate_agent_refs` - Verify agent tool references exist
|
||||
- `validate_data_flow` - Check data flow through agent sequences
|
||||
|
||||
### Reporting
|
||||
- `generate_compatibility_report` - Full marketplace report
|
||||
- `list_issues` - Filter issues by severity/type
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Discover plugins**:
|
||||
- Locate marketplace plugins directory
|
||||
- Identify plugins by `.claude-plugin/` marker
|
||||
- Build list of all plugins to validate
|
||||
|
||||
2. **Parse all interfaces**:
|
||||
- For each plugin, use `parse_plugin_interface`
|
||||
- Extract commands, agents, tools from README.md
|
||||
- Track tool categories and features
|
||||
|
||||
3. **Run pairwise compatibility checks**:
|
||||
- For each pair of plugins, use `validate_compatibility`
|
||||
- Check for command name conflicts (ERROR)
|
||||
- Check for tool name overlaps (WARNING)
|
||||
- Identify interface mismatches
|
||||
|
||||
4. **Validate CLAUDE.md agents** (if present):
|
||||
- Use `parse_claude_md_agents` on project CLAUDE.md
|
||||
- For each agent, use `validate_agent_refs`
|
||||
- Use `validate_data_flow` to check sequences
|
||||
|
||||
5. **Generate comprehensive report**:
|
||||
- Use `generate_compatibility_report`
|
||||
- Format: markdown for human review, JSON for programmatic use
|
||||
- Include summary statistics and detailed findings
|
||||
|
||||
## Report Structure
|
||||
|
||||
### Summary
|
||||
- Total plugins scanned
|
||||
- Total commands, agents, tools found
|
||||
- Issue counts by severity (error/warning/info)
|
||||
|
||||
### Compatibility Matrix
|
||||
- Plugin pairs with conflicts
|
||||
- Shared tools between plugins
|
||||
- Unique tools per plugin
|
||||
|
||||
### Issues List
|
||||
- ERROR: Command name conflicts (must fix)
|
||||
- WARNING: Tool name overlaps (review needed)
|
||||
- INFO: Undocumented references (improve docs)
|
||||
|
||||
### Recommendations
|
||||
- Actionable suggestions per issue
|
||||
- Priority order for fixes
|
||||
|
||||
## Example Interaction
|
||||
|
||||
**User**: /validate-contracts ~/claude-plugins-work
|
||||
|
||||
**Agent**:
|
||||
1. Discovers 12 plugins in marketplace
|
||||
2. Parses all README.md files
|
||||
3. Runs 66 pairwise compatibility checks
|
||||
4. Finds 3 errors, 4 warnings
|
||||
5. Reports: "Command conflict: projman and data-platform both define /initial-setup"
|
||||
6. Suggests: "Rename one command to avoid ambiguity"
|
||||
152
plugins/contract-validator/claude-md-integration.md
Normal file
152
plugins/contract-validator/claude-md-integration.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# contract-validator Plugin - CLAUDE.md Integration
|
||||
|
||||
Add this section to your marketplace or project's CLAUDE.md to enable contract validation features.
|
||||
|
||||
## Suggested CLAUDE.md Section
|
||||
|
||||
```markdown
|
||||
## Contract Validation
|
||||
|
||||
This marketplace uses the contract-validator plugin for cross-plugin compatibility checks.
|
||||
|
||||
### Available Commands
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `/validate-contracts` | Full marketplace compatibility validation |
|
||||
| `/check-agent` | Validate single agent definition |
|
||||
| `/list-interfaces` | Show all plugin interfaces |
|
||||
|
||||
### Validation Workflow
|
||||
|
||||
Run before merging plugin changes:
|
||||
|
||||
1. `/validate-contracts` - Check for conflicts
|
||||
2. Review errors (must fix) and warnings (should review)
|
||||
3. Fix issues before merging
|
||||
|
||||
### Interface Documentation Standards
|
||||
|
||||
For plugins to be validated correctly, document interfaces in README.md:
|
||||
|
||||
**Commands Section:**
|
||||
```markdown
|
||||
## Commands
|
||||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `/my-command` | What it does |
|
||||
```
|
||||
|
||||
**Tools Section:**
|
||||
```markdown
|
||||
## Tools Summary
|
||||
|
||||
### Category (N tools)
|
||||
`tool_a`, `tool_b`, `tool_c`
|
||||
```
|
||||
|
||||
**Agents Section:**
|
||||
```markdown
|
||||
## Agents
|
||||
|
||||
| Agent | Description |
|
||||
|-------|-------------|
|
||||
| `my-agent` | What it does |
|
||||
```
|
||||
```
|
||||
|
||||
## Declaring Agent Tool References
|
||||
|
||||
For agent validation to work, document tool usage in CLAUDE.md:
|
||||
|
||||
### Option 1: Four-Agent Model Table
|
||||
|
||||
```markdown
|
||||
### Four-Agent Model
|
||||
|
||||
| Agent | Personality | Responsibilities |
|
||||
|-------|-------------|------------------|
|
||||
| **Planner** | Methodical | Planning via `create_issue`, `search_lessons` |
|
||||
```
|
||||
|
||||
### Option 2: Agent Sections
|
||||
|
||||
```markdown
|
||||
### Planner Agent
|
||||
|
||||
Uses these tools:
|
||||
- `create_issue` - Create planning issues
|
||||
- `search_lessons` - Find relevant lessons
|
||||
```
|
||||
|
||||
## Best Practices for Plugin Authors
|
||||
|
||||
### Unique Command Names
|
||||
|
||||
Avoid generic names that may conflict:
|
||||
|
||||
```markdown
|
||||
# BAD - Will conflict with other plugins
|
||||
| `/setup` | Setup wizard |
|
||||
|
||||
# GOOD - Plugin-specific prefix
|
||||
| `/data-setup` | Data platform setup wizard |
|
||||
```
|
||||
|
||||
### Document All Tools
|
||||
|
||||
Ensure every MCP tool is listed in README.md:
|
||||
|
||||
```markdown
|
||||
## Tools Summary
|
||||
|
||||
### pandas (14 tools)
|
||||
`read_csv`, `read_parquet`, `read_json`, `to_csv`, `to_parquet`,
|
||||
`describe`, `head`, `tail`, `filter`, `select`, `groupby`, `join`,
|
||||
`list_data`, `drop_data`
|
||||
```
|
||||
|
||||
### Specify Dependencies
|
||||
|
||||
If agents depend on tools from other plugins, document it:
|
||||
|
||||
```markdown
|
||||
## Dependencies
|
||||
|
||||
This agent uses tools from:
|
||||
- `projman` - Issue management (`create_issue`, `update_issue`)
|
||||
- `data-platform` - Data loading (`read_csv`, `describe`)
|
||||
```
|
||||
|
||||
## Typical Workflows
|
||||
|
||||
### Pre-Merge Validation
|
||||
|
||||
```
|
||||
# Before merging new plugin
|
||||
/validate-contracts
|
||||
|
||||
# Check specific agent after changes
|
||||
/check-agent Orchestrator
|
||||
```
|
||||
|
||||
### Plugin Development
|
||||
|
||||
```
|
||||
# See what interfaces exist
|
||||
/list-interfaces
|
||||
|
||||
# After adding new command, verify no conflicts
|
||||
/validate-contracts
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
Add to your pipeline:
|
||||
|
||||
```yaml
|
||||
- name: Validate Plugin Contracts
|
||||
run: |
|
||||
claude --skill contract-validator:validate-contracts --args "${{ github.workspace }}"
|
||||
```
|
||||
Reference in New Issue
Block a user