Files
gh-fcakyon-claude-codex-set…/hooks/scripts/validate_plugin_paths.py
2025-11-29 18:26:37 +08:00

94 lines
3.4 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Validate plugin paths alignment between marketplace.json and plugin structure.
Checks:
- .claude-plugin/plugin.json exists
- marketplace.json (if used at project root) paths match actual plugin directories
- Plugin name in plugin.json matches directory name
- Required plugin fields are present
"""
import json
import os
import sys
from pathlib import Path
def validate_plugin_paths():
"""Check plugin paths in marketplace and plugin structure."""
errors = []
plugin_root = Path(os.environ.get("CLAUDE_PLUGIN_ROOT", "."))
# Check .claude-plugin/plugin.json exists
plugin_json = plugin_root / ".claude-plugin" / "plugin.json"
if not plugin_json.exists():
errors.append(".claude-plugin directory or plugin.json not found")
print("❌ Plugin Path Validation Failed:")
for error in errors:
print(f"{error}")
return 1
try:
with open(plugin_json) as f:
plugin_config = json.load(f)
# Check required fields (only 'name' is required per Claude Code docs)
if "name" not in plugin_config:
errors.append(".claude-plugin/plugin.json: Missing 'name' field")
# Verify plugin name matches directory (if not at root)
plugin_name = plugin_config.get("name")
if plugin_name and plugin_root.name != ".":
dir_name = plugin_root.name
if plugin_name != dir_name:
errors.append(
f"Plugin name '{plugin_name}' in plugin.json does not match "
f"directory name '{dir_name}'"
)
except json.JSONDecodeError as e:
errors.append(f".claude-plugin/plugin.json: Invalid JSON - {e}")
# Check marketplace.json at project root if this is a plugin directory
marketplace_root = plugin_root.parent.parent / ".claude-plugin" / "marketplace.json"
if marketplace_root.exists():
try:
with open(marketplace_root) as f:
marketplace = json.load(f)
if "plugins" in marketplace:
plugin_name = plugin_config.get("name")
for plugin_entry in marketplace["plugins"]:
if plugin_entry.get("name") == plugin_name:
# Check path matches
path = plugin_entry.get("path")
if path:
# Resolve relative path
expected_path = plugin_root / "plugin.json"
if "${CLAUDE_PLUGIN_ROOT}" in path:
expected = path.replace("${CLAUDE_PLUGIN_ROOT}", str(plugin_root))
else:
expected = str(expected_path)
actual = plugin_root / ".claude-plugin" / "plugin.json"
if not actual.exists():
errors.append(
f"marketplace.json references path that doesn't exist: {path}"
)
except json.JSONDecodeError as e:
errors.append(f"marketplace.json: Invalid JSON - {e}")
if errors:
print("❌ Plugin Path Validation Failed:")
for error in errors:
print(f"{error}")
return 1
return 0
if __name__ == "__main__":
sys.exit(validate_plugin_paths())