Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:20:28 +08:00
commit b727790a9e
65 changed files with 16412 additions and 0 deletions

View File

@@ -0,0 +1,331 @@
#!/usr/bin/env bash
# ============================================================================
# Field Checker Script
# ============================================================================
# Purpose: Verify required and recommended fields in plugin/marketplace configs
# Version: 1.0.0
# Usage: ./field-checker.sh <config-file> <type> [strict]
# Returns: 0=all required present, 1=missing required, 2=error
# ============================================================================
set -euo pipefail
# Source shared library
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/../../../scripts/validate-lib.sh"
# ====================
# Configuration
# ====================
readonly CONFIG_FILE="${1:-}"
readonly TYPE="${2:-}"
readonly STRICT="${3:-false}"
# ====================
# Field Definitions
# ====================
# Plugin required fields
PLUGIN_REQUIRED_FIELDS=(
"name"
"version"
"description"
"author"
"license"
)
# Plugin recommended fields
PLUGIN_RECOMMENDED_FIELDS=(
"repository"
"homepage"
"keywords"
"category"
)
# Marketplace required fields
MARKETPLACE_REQUIRED_FIELDS=(
"name"
"owner"
"owner.name"
"owner.email"
"plugins"
)
# Marketplace recommended fields
MARKETPLACE_RECOMMENDED_FIELDS=(
"version"
"metadata.description"
"metadata.homepage"
"metadata.repository"
)
# ====================
# Validation Functions
# ====================
check_field_exists() {
local file="$1"
local field="$2"
local value
# Use json_get from validate-lib.sh
value=$(json_get "${file}" ".${field}")
if [[ -n "${value}" && "${value}" != "null" ]]; then
return 0
else
return 1
fi
}
get_field_value() {
local file="$1"
local field="$2"
json_get "${file}" ".${field}"
}
check_field_empty() {
local value="$1"
if [[ -z "${value}" || "${value}" == "null" || "${value}" == '""' || "${value}" == "[]" || "${value}" == "{}" ]]; then
return 0 # Is empty
else
return 1 # Not empty
fi
}
# ====================
# Plugin Validation
# ====================
validate_plugin_fields() {
local file="$1"
local strict="$2"
local missing_required=0
local missing_recommended=0
print_section "Required Fields (${#PLUGIN_REQUIRED_FIELDS[@]})"
for field in "${PLUGIN_REQUIRED_FIELDS[@]}"; do
if check_field_exists "${file}" "${field}"; then
local value
value=$(get_field_value "${file}" "${field}")
# Check if empty
if check_field_empty "${value}"; then
print_error "${field}: Present but empty (REQUIRED)"
((missing_required++))
else
# Truncate long values for display
if [[ "${#value}" -gt 50 ]]; then
value="${value:0:47}..."
fi
print_success "${field}: \"${value}\""
fi
else
print_error "${field}: Missing (REQUIRED)"
((missing_required++))
fi
done
echo ""
print_section "Recommended Fields (${#PLUGIN_RECOMMENDED_FIELDS[@]})"
for field in "${PLUGIN_RECOMMENDED_FIELDS[@]}"; do
if check_field_exists "${file}" "${field}"; then
print_success "${field}: Present"
else
print_warning "${field}: Missing (improves quality)"
((missing_recommended++))
fi
done
echo ""
# Summary
if [[ ${missing_required} -eq 0 ]]; then
print_success "All required fields present"
else
print_error "Missing ${missing_required} required field(s)"
fi
if [[ ${missing_recommended} -gt 0 ]]; then
print_info "Missing ${missing_recommended} recommended field(s)"
fi
# Determine exit code
if [[ ${missing_required} -gt 0 ]]; then
return 1
elif [[ "${strict}" == "true" && ${missing_recommended} -gt 0 ]]; then
print_warning "Strict mode: Recommended fields are required"
return 1
else
return 0
fi
}
# ====================
# Marketplace Validation
# ====================
validate_marketplace_fields() {
local file="$1"
local strict="$2"
local missing_required=0
local missing_recommended=0
print_section "Required Fields (${#MARKETPLACE_REQUIRED_FIELDS[@]})"
for field in "${MARKETPLACE_REQUIRED_FIELDS[@]}"; do
if check_field_exists "${file}" "${field}"; then
local value
value=$(get_field_value "${file}" "${field}")
# Special handling for plugins array
if [[ "${field}" == "plugins" ]]; then
local count
count=$(get_json_array_length "${file}" ".plugins")
if [[ ${count} -gt 0 ]]; then
print_success "${field}: Array with ${count} entries"
else
print_error "${field}: Present but empty (REQUIRED)"
((missing_required++))
fi
elif check_field_empty "${value}"; then
print_error "${field}: Present but empty (REQUIRED)"
((missing_required++))
else
# Truncate long values
if [[ "${#value}" -gt 50 ]]; then
value="${value:0:47}..."
fi
print_success "${field}: \"${value}\""
fi
else
print_error "${field}: Missing (REQUIRED)"
((missing_required++))
fi
done
echo ""
print_section "Recommended Fields (${#MARKETPLACE_RECOMMENDED_FIELDS[@]})"
for field in "${MARKETPLACE_RECOMMENDED_FIELDS[@]}"; do
if check_field_exists "${file}" "${field}"; then
print_success "${field}: Present"
else
print_warning "${field}: Missing (improves quality)"
((missing_recommended++))
fi
done
echo ""
# Summary
if [[ ${missing_required} -eq 0 ]]; then
print_success "All required fields present"
else
print_error "Missing ${missing_required} required field(s)"
fi
if [[ ${missing_recommended} -gt 0 ]]; then
print_info "Missing ${missing_recommended} recommended field(s)"
fi
# Determine exit code
if [[ ${missing_required} -gt 0 ]]; then
return 1
elif [[ "${strict}" == "true" && ${missing_recommended} -gt 0 ]]; then
print_warning "Strict mode: Recommended fields are required"
return 1
else
return 0
fi
}
# ====================
# Main Logic
# ====================
main() {
# Validate arguments
if [[ -z "${CONFIG_FILE}" ]]; then
print_error "Usage: $0 <config-file> <type> [strict]"
print_info "Types: plugin, marketplace"
exit 2
fi
if [[ ! -f "${CONFIG_FILE}" ]]; then
print_error "Configuration file not found: ${CONFIG_FILE}"
exit 2
fi
if [[ -z "${TYPE}" ]]; then
print_error "Type required: plugin or marketplace"
exit 2
fi
# Validate JSON syntax first
if ! validate_json_syntax "${CONFIG_FILE}"; then
print_error "Invalid JSON syntax in ${CONFIG_FILE}"
print_info "Run JSON validation first to fix syntax errors"
exit 2
fi
# Print header
print_header "Required Fields Validation"
echo "Target: ${CONFIG_FILE}"
echo "Type: ${TYPE}"
echo "Strict Mode: ${STRICT}"
echo ""
# Validate based on type
case "${TYPE}" in
plugin)
if validate_plugin_fields "${CONFIG_FILE}" "${STRICT}"; then
echo ""
print_header "✅ PASS: All required fields present"
exit 0
else
echo ""
print_header "❌ FAIL: Missing required fields"
# Show remediation
echo ""
print_info "Action Required:"
echo " Add missing required fields to ${CONFIG_FILE}"
echo " Refer to plugin schema: .claude/docs/plugins/plugins-reference.md"
exit 1
fi
;;
marketplace)
if validate_marketplace_fields "${CONFIG_FILE}" "${STRICT}"; then
echo ""
print_header "✅ PASS: All required fields present"
exit 0
else
echo ""
print_header "❌ FAIL: Missing required fields"
# Show remediation
echo ""
print_info "Action Required:"
echo " Add missing required fields to ${CONFIG_FILE}"
echo " Refer to marketplace schema: .claude/docs/plugins/plugin-marketplaces.md"
exit 1
fi
;;
*)
print_error "Unknown type: ${TYPE}"
print_info "Valid types: plugin, marketplace"
exit 2
;;
esac
}
main "$@"

View File

@@ -0,0 +1,448 @@
#!/usr/bin/env python3
# ============================================================================
# Format Validator Script
# ============================================================================
# Purpose: Validate format compliance for semver, URLs, emails, naming
# Version: 1.0.0
# Usage: ./format-validator.py --file <path> --type <plugin|marketplace> [--strict]
# Returns: 0=all valid, 1=format violations, 2=error
# ============================================================================
import json
import sys
import argparse
import re
from pathlib import Path
from typing import Dict, List, Tuple, Optional
# ====================
# Color Support
# ====================
class Colors:
"""ANSI color codes for terminal output"""
RED = '\033[0;31m'
GREEN = '\033[0;32m'
YELLOW = '\033[1;33m'
BLUE = '\033[0;34m'
CYAN = '\033[0;36m'
BOLD = '\033[1m'
NC = '\033[0m'
@classmethod
def disable(cls):
"""Disable colors for non-TTY output"""
cls.RED = cls.GREEN = cls.YELLOW = cls.BLUE = cls.CYAN = cls.BOLD = cls.NC = ''
if not sys.stdout.isatty():
Colors.disable()
# ====================
# Format Patterns
# ====================
# Semantic versioning: X.Y.Z
SEMVER_PATTERN = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?(\+[a-zA-Z0-9.]+)?$')
# Lowercase-hyphen naming: plugin-name
LOWERCASE_HYPHEN_PATTERN = re.compile(r'^[a-z0-9]+(-[a-z0-9]+)*$')
# Email: RFC 5322 simplified
EMAIL_PATTERN = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
# URL: http or https
URL_PATTERN = re.compile(r'^https?://')
# HTTPS only
HTTPS_PATTERN = re.compile(r'^https://')
# SPDX License Identifiers (common ones)
SPDX_LICENSES = [
'MIT', 'Apache-2.0', 'GPL-3.0', 'GPL-2.0', 'LGPL-3.0', 'LGPL-2.1',
'BSD-2-Clause', 'BSD-3-Clause', 'ISC', 'MPL-2.0', 'AGPL-3.0',
'Unlicense', 'CC0-1.0', 'Proprietary'
]
# Approved categories (10 standard)
APPROVED_CATEGORIES = [
'development', 'testing', 'deployment', 'documentation', 'security',
'database', 'monitoring', 'productivity', 'quality', 'collaboration'
]
# ====================
# Validation Functions
# ====================
class FormatValidator:
"""Format validation logic"""
def __init__(self, strict_https: bool = False):
self.strict_https = strict_https
self.errors: List[Tuple[str, str, str]] = []
self.warnings: List[Tuple[str, str]] = []
self.passed: List[Tuple[str, str]] = []
def validate_semver(self, field: str, value: str) -> bool:
"""Validate semantic versioning"""
if not value:
return True # Skip empty (handled by required fields check)
if SEMVER_PATTERN.match(value):
self.passed.append((field, f'"{value}" (semver)'))
return True
else:
error = (
field,
f'"{value}"',
'Invalid: Must use semantic versioning (X.Y.Z)\n'
' Pattern: MAJOR.MINOR.PATCH\n'
' Example: 1.0.0, 2.1.5'
)
self.errors.append(error)
return False
def validate_lowercase_hyphen(self, field: str, value: str) -> bool:
"""Validate lowercase-hyphen naming"""
if not value:
return True
if LOWERCASE_HYPHEN_PATTERN.match(value):
self.passed.append((field, f'"{value}" (lowercase-hyphen)'))
return True
else:
error = (
field,
f'"{value}"',
'Invalid: Must use lowercase-hyphen format\n'
' Pattern: ^[a-z0-9]+(-[a-z0-9]+)*$\n'
' Example: my-plugin, test-tool, plugin123'
)
self.errors.append(error)
return False
def validate_email(self, field: str, value: str) -> bool:
"""Validate email address"""
if not value:
return True
if EMAIL_PATTERN.match(value):
self.passed.append((field, f'"{value}" (valid email)'))
return True
else:
error = (
field,
f'"{value}"',
'Invalid: Must be valid email address\n'
' Pattern: user@domain.tld\n'
' Example: developer@example.com'
)
self.errors.append(error)
return False
def validate_url(self, field: str, value: str) -> bool:
"""Validate URL format"""
if not value:
return True
if self.strict_https and not HTTPS_PATTERN.match(value):
error = (
field,
f'"{value}"',
'Invalid: HTTPS required in strict mode\n'
f' Current: {value}\n'
f' Required: {value.replace("http://", "https://", 1)}'
)
self.errors.append(error)
return False
elif URL_PATTERN.match(value):
if value.startswith('http://'):
self.warnings.append((
field,
f'"{value}" - Consider using HTTPS for security'
))
self.passed.append((field, f'"{value}" (valid URL)'))
return True
else:
error = (
field,
f'"{value}"',
'Invalid: Must be valid URL\n'
' Pattern: https://domain.tld/path\n'
' Example: https://github.com/user/repo'
)
self.errors.append(error)
return False
def validate_license(self, field: str, value: str) -> bool:
"""Validate SPDX license identifier"""
if not value:
return True
if value in SPDX_LICENSES:
self.passed.append((field, f'"{value}" (SPDX identifier)'))
return True
else:
error = (
field,
f'"{value}"',
'Invalid: Must be SPDX license identifier\n'
' Common: MIT, Apache-2.0, GPL-3.0, BSD-3-Clause, ISC\n'
' See: https://spdx.org/licenses/'
)
self.errors.append(error)
return False
def validate_category(self, field: str, value: str) -> bool:
"""Validate category against approved list"""
if not value:
return True
if value in APPROVED_CATEGORIES:
self.passed.append((field, f'"{value}" (approved category)'))
return True
else:
error = (
field,
f'"{value}"',
'Invalid: Must be one of 10 approved categories\n'
' Valid: development, testing, deployment, documentation,\n'
' security, database, monitoring, productivity,\n'
' quality, collaboration'
)
self.errors.append(error)
return False
def validate_description_length(self, field: str, value: str) -> bool:
"""Validate description length (50-200 chars recommended)"""
if not value:
return True
length = len(value)
if 50 <= length <= 200:
self.passed.append((field, f'Valid length ({length} chars)'))
return True
elif length < 50:
self.warnings.append((
field,
f'Short description ({length} chars) - consider 50-200 characters for clarity'
))
return True
else:
self.warnings.append((
field,
f'Long description ({length} chars) - consider keeping under 200 characters'
))
return True
# ====================
# Plugin Validation
# ====================
def validate_plugin_formats(data: Dict, validator: FormatValidator) -> int:
"""Validate plugin format compliance"""
print(f"{Colors.CYAN}Format Checks:{Colors.NC}\n")
# name: lowercase-hyphen
if 'name' in data:
validator.validate_lowercase_hyphen('name', data['name'])
# version: semver
if 'version' in data:
validator.validate_semver('version', data['version'])
# description: length check
if 'description' in data:
validator.validate_description_length('description', data['description'])
# license: SPDX
if 'license' in data:
validator.validate_license('license', data['license'])
# homepage: URL
if 'homepage' in data:
validator.validate_url('homepage', data['homepage'])
# repository: URL or object
if 'repository' in data:
repo = data['repository']
if isinstance(repo, str):
validator.validate_url('repository', repo)
elif isinstance(repo, dict) and 'url' in repo:
validator.validate_url('repository.url', repo['url'])
# category: approved list
if 'category' in data:
validator.validate_category('category', data['category'])
# author: email if object
if 'author' in data:
author = data['author']
if isinstance(author, dict) and 'email' in author:
validator.validate_email('author.email', author['email'])
return 0 if not validator.errors else 1
# ====================
# Marketplace Validation
# ====================
def validate_marketplace_formats(data: Dict, validator: FormatValidator) -> int:
"""Validate marketplace format compliance"""
print(f"{Colors.CYAN}Format Checks:{Colors.NC}\n")
# name: lowercase-hyphen
if 'name' in data:
validator.validate_lowercase_hyphen('name', data['name'])
# owner.email: email
if 'owner' in data and isinstance(data['owner'], dict):
if 'email' in data['owner']:
validator.validate_email('owner.email', data['owner']['email'])
# version: semver (if present)
if 'version' in data:
validator.validate_semver('version', data['version'])
# metadata fields
if 'metadata' in data and isinstance(data['metadata'], dict):
metadata = data['metadata']
if 'description' in metadata:
validator.validate_description_length('metadata.description', metadata['description'])
if 'homepage' in metadata:
validator.validate_url('metadata.homepage', metadata['homepage'])
if 'repository' in metadata:
validator.validate_url('metadata.repository', metadata['repository'])
return 0 if not validator.errors else 1
# ====================
# Output Formatting
# ====================
def print_results(validator: FormatValidator):
"""Print validation results"""
print()
# Passed checks
if validator.passed:
for field, msg in validator.passed:
print(f" {Colors.GREEN}{field}: {msg}{Colors.NC}")
# Errors
if validator.errors:
print()
for field, value, msg in validator.errors:
print(f" {Colors.RED}{field}: {value}{Colors.NC}")
for line in msg.split('\n'):
print(f" {line}")
print()
# Warnings
if validator.warnings:
print()
for field, msg in validator.warnings:
print(f" {Colors.YELLOW}⚠️ {field}: {msg}{Colors.NC}")
# Summary
print()
print(f"{Colors.BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{Colors.NC}")
total = len(validator.passed) + len(validator.errors)
passed_count = len(validator.passed)
if validator.errors:
print(f"{Colors.RED}Failed: {len(validator.errors)}{Colors.NC}")
if validator.warnings:
print(f"{Colors.YELLOW}Warnings: {len(validator.warnings)}{Colors.NC}")
print(f"Status: {Colors.RED}FAIL{Colors.NC}")
else:
print(f"Passed: {passed_count}/{total}")
if validator.warnings:
print(f"{Colors.YELLOW}Warnings: {len(validator.warnings)}{Colors.NC}")
print(f"Status: {Colors.GREEN}PASS{Colors.NC}")
# ====================
# Main Logic
# ====================
def main():
"""CLI entry point"""
parser = argparse.ArgumentParser(
description='Validate format compliance for plugin and marketplace configurations',
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
'--file',
type=str,
required=True,
help='Path to configuration file (plugin.json or marketplace.json)'
)
parser.add_argument(
'--type',
type=str,
choices=['plugin', 'marketplace'],
required=True,
help='Configuration type'
)
parser.add_argument(
'--strict',
action='store_true',
help='Enforce HTTPS for all URLs'
)
args = parser.parse_args()
# Load configuration file
try:
with open(args.file, 'r', encoding='utf-8') as f:
data = json.load(f)
except FileNotFoundError:
print(f"{Colors.RED}❌ File not found: {args.file}{Colors.NC}", file=sys.stderr)
return 2
except json.JSONDecodeError as e:
print(f"{Colors.RED}❌ Invalid JSON: {e}{Colors.NC}", file=sys.stderr)
print(f"{Colors.BLUE} Run JSON validation first{Colors.NC}", file=sys.stderr)
return 2
# Print header
print(f"{Colors.BOLD}{Colors.BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{Colors.NC}")
print(f"{Colors.BOLD}Format Validation{Colors.NC}")
print(f"{Colors.BOLD}{Colors.BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{Colors.NC}")
print(f"Target: {args.file}")
print(f"Type: {args.type}")
if args.strict:
print(f"Strict HTTPS: {Colors.GREEN}Enforced{Colors.NC}")
print()
# Create validator
validator = FormatValidator(strict_https=args.strict)
# Validate based on type
if args.type == 'plugin':
result = validate_plugin_formats(data, validator)
else:
result = validate_marketplace_formats(data, validator)
# Print results
print_results(validator)
return result
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,263 @@
#!/usr/bin/env python3
# ============================================================================
# JSON Validator Script
# ============================================================================
# Purpose: Multi-backend JSON syntax validation with detailed error reporting
# Version: 1.0.0
# Usage: ./json-validator.py --file <path> [--verbose]
# Returns: 0=valid, 1=invalid, 2=error
# Backends: jq (preferred), python3 json module (fallback)
# ============================================================================
import json
import sys
import argparse
import subprocess
import shutil
from pathlib import Path
# ====================
# Color Support
# ====================
class Colors:
"""ANSI color codes for terminal output"""
RED = '\033[0;31m'
GREEN = '\033[0;32m'
YELLOW = '\033[1;33m'
BLUE = '\033[0;34m'
CYAN = '\033[0;36m'
BOLD = '\033[1m'
NC = '\033[0m'
@classmethod
def disable(cls):
"""Disable colors for non-TTY output"""
cls.RED = cls.GREEN = cls.YELLOW = cls.BLUE = cls.CYAN = cls.BOLD = cls.NC = ''
if not sys.stdout.isatty():
Colors.disable()
# ====================
# Backend Detection
# ====================
def detect_backend():
"""Detect available JSON validation backend"""
if shutil.which('jq'):
return 'jq'
elif sys.version_info >= (3, 0):
return 'python3'
else:
return 'none'
def print_backend_info():
"""Print detected backend information"""
backend = detect_backend()
if backend == 'jq':
print(f"{Colors.GREEN}✅ Backend: jq (preferred){Colors.NC}")
elif backend == 'python3':
print(f"{Colors.YELLOW}⚠️ Backend: python3 (fallback){Colors.NC}")
else:
print(f"{Colors.RED}❌ No JSON validator available{Colors.NC}")
print(f"{Colors.BLUE} Install jq for better error messages: apt-get install jq{Colors.NC}")
return backend
# ====================
# JQ Backend
# ====================
def validate_with_jq(file_path, verbose=False):
"""Validate JSON using jq (provides better error messages)"""
try:
result = subprocess.run(
['jq', 'empty', file_path],
capture_output=True,
text=True,
check=False
)
if result.returncode == 0:
print(f"{Colors.GREEN}✅ Valid JSON: {file_path}{Colors.NC}")
print(f"Backend: jq")
return 0
else:
# Parse jq error message
error_msg = result.stderr.strip()
print(f"{Colors.RED}❌ Invalid JSON: {file_path}{Colors.NC}")
if verbose:
print(f"{Colors.BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{Colors.NC}")
print(f"{Colors.RED}Error Details:{Colors.NC}")
print(f" {error_msg}")
print()
print(f"{Colors.YELLOW}Remediation:{Colors.NC}")
print(" - Check for missing commas between object properties")
print(" - Verify bracket matching: [ ] { }")
print(" - Ensure proper string quoting")
print(" - Use a JSON formatter/linter in your editor")
else:
# Extract line number if available
if "parse error" in error_msg.lower():
print(f"Error: {error_msg}")
return 1
except FileNotFoundError:
print(f"{Colors.RED}❌ File not found: {file_path}{Colors.NC}", file=sys.stderr)
return 2
except Exception as e:
print(f"{Colors.RED}❌ Error running jq: {e}{Colors.NC}", file=sys.stderr)
return 2
# ====================
# Python3 Backend
# ====================
def validate_with_python(file_path, verbose=False):
"""Validate JSON using Python's json module (universal fallback)"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# Attempt to parse JSON
json.loads(content)
print(f"{Colors.GREEN}✅ Valid JSON: {file_path}{Colors.NC}")
print(f"Backend: python3")
return 0
except FileNotFoundError:
print(f"{Colors.RED}❌ File not found: {file_path}{Colors.NC}", file=sys.stderr)
return 2
except json.JSONDecodeError as e:
print(f"{Colors.RED}❌ Invalid JSON: {file_path}{Colors.NC}")
if verbose:
print(f"{Colors.BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{Colors.NC}")
print(f"{Colors.RED}Error Details:{Colors.NC}")
print(f" Line: {e.lineno}")
print(f" Column: {e.colno}")
print(f" Issue: {e.msg}")
print()
# Show problematic section
try:
lines = content.split('\n')
start = max(0, e.lineno - 3)
end = min(len(lines), e.lineno + 2)
print(f"Problematic Section (lines {start+1}-{end}):")
for i in range(start, end):
line_num = i + 1
marker = "" if line_num == e.lineno else " "
print(f" {marker} {line_num:3d} | {lines[i]}")
print()
except:
pass
print(f"{Colors.YELLOW}Remediation:{Colors.NC}")
print(" - Check for missing commas between array elements or object properties")
print(" - Verify bracket matching: [ ] { }")
print(" - Ensure all strings are properly quoted")
print(" - Use a JSON formatter/linter in your editor")
else:
print(f"Error: {e.msg} at line {e.lineno}, column {e.colno}")
return 1
except Exception as e:
print(f"{Colors.RED}❌ Error reading file: {e}{Colors.NC}", file=sys.stderr)
return 2
# ====================
# Main Validation
# ====================
def validate_json(file_path, verbose=False):
"""Main validation function with backend selection"""
backend = detect_backend()
if backend == 'none':
print(f"{Colors.RED}❌ No JSON validation backend available{Colors.NC}", file=sys.stderr)
print(f"{Colors.BLUE} Install jq or ensure python3 is available{Colors.NC}", file=sys.stderr)
return 2
if backend == 'jq':
return validate_with_jq(file_path, verbose)
else:
return validate_with_python(file_path, verbose)
# ====================
# CLI Interface
# ====================
def main():
"""CLI entry point"""
parser = argparse.ArgumentParser(
description='Validate JSON file syntax with multi-backend support',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
Examples:
./json-validator.py --file plugin.json
./json-validator.py --file marketplace.json --verbose
./json-validator.py --detect
Backends:
- jq (preferred): Fast, excellent error messages
- python3 (fallback): Universal availability
Exit codes:
0: Valid JSON
1: Invalid JSON
2: File error or backend unavailable
'''
)
parser.add_argument(
'--file',
type=str,
help='Path to JSON file to validate'
)
parser.add_argument(
'--verbose',
action='store_true',
help='Show detailed error information and remediation'
)
parser.add_argument(
'--detect',
action='store_true',
help='Detect and display available backend'
)
args = parser.parse_args()
# Handle backend detection
if args.detect:
print_backend_info()
return 0
# Validate required arguments
if not args.file:
parser.print_help()
return 2
# Perform validation
return validate_json(args.file, args.verbose)
if __name__ == '__main__':
sys.exit(main())

View File

@@ -0,0 +1,265 @@
#!/usr/bin/env bash
# ============================================================================
# Schema Differ Script
# ============================================================================
# Purpose: Compare configuration against reference schemas and validate plugin entries
# Version: 1.0.0
# Usage: ./schema-differ.sh <marketplace-file> [index]
# Returns: 0=all valid, 1=validation errors, 2=error
# ============================================================================
set -euo pipefail
# Source shared library
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/../../../scripts/validate-lib.sh"
# ====================
# Configuration
# ====================
readonly MARKETPLACE_FILE="${1:-}"
readonly INDEX="${2:-all}"
# ====================
# Plugin Entry Validation
# ====================
validate_plugin_entry() {
local index=$1
local entry_json=$2
local strict=${3:-false}
local has_errors=0
local has_warnings=0
# Extract fields using json_get would be complex here, so use jq/python inline
local name version source description author keywords license
name=$(echo "${entry_json}" | jq -r '.name // empty' 2>/dev/null || echo "")
version=$(echo "${entry_json}" | jq -r '.version // empty' 2>/dev/null || echo "")
source=$(echo "${entry_json}" | jq -r '.source // empty' 2>/dev/null || echo "")
description=$(echo "${entry_json}" | jq -r '.description // empty' 2>/dev/null || echo "")
author=$(echo "${entry_json}" | jq -r '.author // empty' 2>/dev/null || echo "")
keywords=$(echo "${entry_json}" | jq -r '.keywords // empty' 2>/dev/null || echo "")
license=$(echo "${entry_json}" | jq -r '.license // empty' 2>/dev/null || echo "")
echo ""
print_section "Entry ${index}: ${name:-<unnamed>}"
# Required fields
echo " Required (3):"
# name (required, lowercase-hyphen)
if [[ -z "${name}" ]]; then
print_error " name: Missing (REQUIRED)"
((has_errors++))
elif ! validate_name_format "${name}"; then
print_error " name: \"${name}\" - Invalid format"
print_info " Expected: lowercase-hyphen (my-plugin)"
((has_errors++))
else
print_success " name: \"${name}\""
fi
# source (required, valid format)
if [[ -z "${source}" ]]; then
print_error " source: Missing (REQUIRED)"
((has_errors++))
elif ! validate_source_format "${source}"; then
print_error " source: \"${source}\" - Invalid format"
print_info " Valid: ./path, github:user/repo, https://url"
((has_errors++))
else
print_success " source: \"${source}\""
fi
# description (required, non-empty)
if [[ -z "${description}" ]]; then
print_error " description: Missing (REQUIRED)"
((has_errors++))
else
# Truncate for display
local desc_display="${description}"
if [[ ${#description} -gt 50 ]]; then
desc_display="${description:0:47}..."
fi
print_success " description: \"${desc_display}\""
fi
echo ""
echo " Recommended (4):"
# version (recommended, semver)
if [[ -z "${version}" ]]; then
print_warning " version: Missing"
((has_warnings++))
elif ! validate_semver "${version}"; then
print_warning " version: \"${version}\" - Invalid semver"
((has_warnings++))
else
print_success " version: \"${version}\""
fi
# author (recommended)
if [[ -z "${author}" || "${author}" == "null" ]]; then
print_warning " author: Missing"
((has_warnings++))
else
print_success " author: Present"
fi
# keywords (recommended)
if [[ -z "${keywords}" || "${keywords}" == "null" || "${keywords}" == "[]" ]]; then
print_warning " keywords: Missing"
((has_warnings++))
else
local keyword_count
keyword_count=$(echo "${entry_json}" | jq '.keywords | length' 2>/dev/null || echo "0")
print_success " keywords: ${keyword_count} items"
fi
# license (recommended, SPDX)
if [[ -z "${license}" ]]; then
print_warning " license: Missing"
((has_warnings++))
elif ! validate_license "${license}"; then
print_warning " license: \"${license}\" - Unknown SPDX identifier"
((has_warnings++))
else
print_success " license: \"${license}\""
fi
# Entry status
echo ""
if [[ ${has_errors} -eq 0 ]]; then
if [[ ${has_warnings} -eq 0 ]]; then
print_success "Status: PASS (no issues)"
else
print_info "Status: PASS with ${has_warnings} warning(s)"
fi
return 0
else
print_error "Status: FAIL (${has_errors} critical issues, ${has_warnings} warnings)"
return 1
fi
}
# ====================
# Main Logic
# ====================
main() {
# Validate arguments
if [[ -z "${MARKETPLACE_FILE}" ]]; then
print_error "Usage: $0 <marketplace-file> [index]"
exit 2
fi
if [[ ! -f "${MARKETPLACE_FILE}" ]]; then
print_error "Marketplace file not found: ${MARKETPLACE_FILE}"
exit 2
fi
# Validate JSON syntax
if ! validate_json_syntax "${MARKETPLACE_FILE}"; then
print_error "Invalid JSON in ${MARKETPLACE_FILE}"
print_info "Run JSON validation first to fix syntax errors"
exit 2
fi
# Print header
print_header "Plugin Entries Validation"
echo "Marketplace: ${MARKETPLACE_FILE}"
echo ""
# Get plugins array length
local plugin_count
plugin_count=$(get_json_array_length "${MARKETPLACE_FILE}" ".plugins")
if [[ ${plugin_count} -eq 0 ]]; then
print_warning "No plugin entries found in marketplace"
print_info "The plugins array is empty"
exit 0
fi
echo "Total Entries: ${plugin_count}"
# Determine which entries to validate
local entries_to_check=()
if [[ "${INDEX}" == "all" ]]; then
for ((i=0; i<plugin_count; i++)); do
entries_to_check+=("$i")
done
elif [[ "${INDEX}" =~ ^[0-9]+$ ]]; then
if [[ ${INDEX} -ge ${plugin_count} ]]; then
print_error "Invalid index: ${INDEX} (valid range: 0-$((plugin_count-1)))"
exit 2
fi
entries_to_check=("${INDEX}")
else
print_error "Invalid index: ${INDEX} (must be number or 'all')"
exit 2
fi
# Validate each entry
local failed_count=0
local total_errors=0
local total_warnings=0
for idx in "${entries_to_check[@]}"; do
# Extract plugin entry
local entry_json
if command -v jq &> /dev/null; then
entry_json=$(jq ".plugins[${idx}]" "${MARKETPLACE_FILE}" 2>/dev/null)
else
# Fallback to python
entry_json=$(python3 <<EOF 2>/dev/null
import json
with open('${MARKETPLACE_FILE}') as f:
data = json.load(f)
print(json.dumps(data['plugins'][${idx}]))
EOF
)
fi
# Validate entry
if ! validate_plugin_entry "${idx}" "${entry_json}" "false"; then
((failed_count++))
fi
done
# Summary
echo ""
print_header "Summary"
local passed_count=$((${#entries_to_check[@]} - failed_count))
local pass_percentage=$((passed_count * 100 / ${#entries_to_check[@]}))
echo "Total Entries: ${#entries_to_check[@]}"
if [[ ${passed_count} -gt 0 ]]; then
print_success "Passed: ${passed_count} (${pass_percentage}%)"
fi
if [[ ${failed_count} -gt 0 ]]; then
print_error "Failed: ${failed_count} ($((100 - pass_percentage))%)"
fi
echo ""
if [[ ${failed_count} -eq 0 ]]; then
print_header "✅ PASS: All plugin entries valid"
exit 0
else
print_header "❌ FAIL: ${failed_count} plugin entries have errors"
echo ""
print_info "Action Required:"
echo " Fix validation errors in plugin entries"
echo " Ensure all required fields are present"
echo " Use correct formats for names, versions, and sources"
exit 1
fi
}
main "$@"

View File

@@ -0,0 +1,241 @@
## Operation: Check Plugin Entries
Validate plugin entries in marketplace configuration for completeness and format compliance.
### Parameters from $ARGUMENTS
- **marketplace**: Path to marketplace.json file (required)
- **strict**: Require all recommended fields in plugin entries (optional, default: false)
- **index**: Validate specific plugin entry by index (optional, validates all if not specified)
### Workflow
1. **Load Marketplace Configuration**
```
Locate marketplace.json:
- Direct path: <marketplace>
- Relative: <marketplace>/marketplace.json
- Claude plugin: <marketplace>/.claude-plugin/marketplace.json
Validate JSON syntax first
```
2. **Extract Plugin Entries**
```
Parse plugins array from marketplace.json
Count total entries
Determine which entries to validate (all or specific index)
```
3. **Validate Each Plugin Entry**
```
For each plugin entry, execute .scripts/schema-differ.sh
Check required fields:
- name (string, lowercase-hyphen)
- source (string, valid format: ./path, github:, https://)
- description (string, non-empty)
Check recommended fields:
- version (string, semver)
- author (string or object)
- keywords (array, 3-7 items)
- license (string, SPDX identifier)
Validate field formats:
- name: lowercase-hyphen pattern
- version: semantic versioning
- source: valid source format
- license: SPDX identifier
```
4. **Aggregate Results**
```
Per-entry summary:
- Entry index
- Plugin name
- Status: PASS/FAIL
- Missing required fields
- Missing recommended fields
- Format violations
Overall summary:
- Total entries
- Passed count
- Failed count
- Total issues
```
### Plugin Entry Required Fields
- `name`: Unique plugin identifier (lowercase-hyphen)
- `source`: Where to locate plugin (./path, github:user/repo, https://url)
- `description`: Brief plugin description (non-empty)
### Plugin Entry Recommended Fields
- `version`: Plugin version (semver)
- `author`: Plugin author (string or object)
- `keywords`: Search keywords (array of 3-7 strings)
- `license`: License identifier (SPDX)
- `homepage`: Documentation URL
- `repository`: Source code URL
### Source Format Validation
**Relative Path**:
- Pattern: `./` or `../`
- Example: `./plugins/my-plugin`
**GitHub Format**:
- Pattern: `github:owner/repo`
- Example: `github:anthropics/claude-plugin`
**Git URL**:
- Pattern: `https://...git`
- Example: `https://github.com/user/plugin.git`
**Archive URL**:
- Pattern: `https://....(zip|tar.gz|tgz)`
- Example: `https://example.com/plugin.zip`
### Examples
```bash
# Validate all plugin entries in marketplace
/schema-validation entries marketplace:./test-marketplace
# Validate with strict mode (require recommended fields)
/schema-validation entries marketplace:marketplace.json strict:true
# Validate specific plugin entry by index
/schema-validation entries marketplace:marketplace.json index:0
```
### Error Handling
- **Marketplace not found**: Show searched paths
- **Invalid JSON**: Suggest running json validation
- **No plugins array**: Error - required field
- **Empty plugins array**: Warning - marketplace has no plugins
- **Invalid index**: Error with valid range
### Output Format
**Success (all entries valid)**:
```
✅ Plugin Entries Validation: PASS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Marketplace: ./test-marketplace/marketplace.json
Total Entries: 3
Entry 0: code-review ✅
Required (3/3):
✅ name: "code-review"
✅ source: "./plugins/code-review"
✅ description: "Automated code review..."
Recommended (4/4):
✅ version: "2.0.0"
✅ author: Present
✅ keywords: 3 items
✅ license: "MIT"
Entry 1: deploy-tools ✅
Required (3/3):
✅ name: "deploy-tools"
✅ source: "github:company/deploy"
✅ description: "Deployment automation..."
Recommended (3/4):
✅ version: "1.5.0"
✅ author: Present
⚠️ keywords: Missing
Entry 2: security-scan ✅
Required (3/3):
✅ name: "security-scan"
✅ source: "https://example.com/plugin.zip"
✅ description: "Security vulnerability scanning..."
Summary:
Total: 3 entries
Passed: 3 (100%)
Failed: 0
Warnings: 1 (non-blocking)
Status: PASS
```
**Failure (validation errors)**:
```
❌ Plugin Entries Validation: FAIL
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Marketplace: marketplace.json
Total Entries: 2
Entry 0: my-plugin ❌
Required (2/3):
❌ name: "My-Plugin"
Invalid: Must use lowercase-hyphen format
Expected: my-plugin
❌ source: Missing (REQUIRED)
✅ description: "My awesome plugin"
Recommended (1/4):
✅ version: "1.0.0"
❌ author: Missing
❌ keywords: Missing
❌ license: Missing
Issues: 5 (2 critical, 3 warnings)
Entry 1: test-tool ✅
Required (3/3):
✅ name: "test-tool"
✅ source: "./plugins/test-tool"
✅ description: "Testing utilities"
Recommended (2/4):
⚠️ version: Missing
⚠️ author: Missing
Summary:
Total: 2 entries
Passed: 1 (50%)
Failed: 1 (50%)
Critical Issues: 2
Warnings: 5
Status: FAIL
Action Required:
Fix plugin entry #0 (my-plugin):
- Change name to lowercase-hyphen: "my-plugin"
- Add source field: "./plugins/my-plugin"
- Consider adding: author, keywords, license
```
**Empty Marketplace**:
```
⚠️ Plugin Entries Validation: WARNING
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Marketplace: marketplace.json
⚠️ No plugin entries found
- plugins array is empty
- Add at least one plugin entry to marketplace
Status: WARNING (empty marketplace)
```
### Integration
This operation is called by:
- `full-schema-validation.md` - When validating marketplace type
- `validation-orchestrator` - Marketplace comprehensive validation
- Direct user invocation for plugin entry checking
**Request**: $ARGUMENTS

View File

@@ -0,0 +1,183 @@
## Operation: Check Required Fields
Verify all required fields are present and non-empty in plugin or marketplace configuration.
### Parameters from $ARGUMENTS
- **path**: Path to plugin directory or marketplace file (required)
- **type**: Target type: `plugin` or `marketplace` (required)
- **strict**: Fail on missing recommended fields (optional, default: false)
### Workflow
1. **Detect Target Type**
```
IF type not specified:
Auto-detect based on path structure:
- Has plugin.json → plugin
- Has marketplace.json or .claude-plugin/marketplace.json → marketplace
- Otherwise → error
```
2. **Locate Configuration File**
```
For plugin:
Check: <path>/plugin.json
For marketplace:
Check: <path>/marketplace.json
OR: <path>/.claude-plugin/marketplace.json
IF not found:
Return error with searched paths
```
3. **Execute Field Validation**
```
Execute .scripts/field-checker.sh "$config_file" "$type" "$strict"
Returns:
- List of required fields: present ✅ or missing ❌
- List of recommended fields: present ✅ or missing ⚠️
- Overall status: PASS or FAIL
```
4. **Aggregate Results**
```
Count:
- Required missing: critical errors
- Recommended missing: warnings
IF any required missing:
Exit with status 1
IF strict mode AND any recommended missing:
Exit with status 1
Otherwise:
Exit with status 0
```
### Required Fields by Type
**Plugin** (from plugin.json):
- `name` (string, lowercase-hyphen format)
- `version` (string, semver X.Y.Z)
- `description` (string, 50-200 characters)
- `author` (string or object with name field)
- `license` (string, SPDX identifier)
**Marketplace** (from marketplace.json):
- `name` (string, lowercase-hyphen format)
- `owner` (object with name field)
- `owner.name` (string)
- `owner.email` (string, valid email format)
- `plugins` (array, at least one entry)
### Recommended Fields
**Plugin**:
- `repository` (object or string, source code location)
- `homepage` (string, documentation URL)
- `keywords` (array, 3-7 relevant keywords)
- `category` (string, one of 10 approved categories)
**Marketplace**:
- `version` (string, marketplace version)
- `metadata.description` (string, marketplace purpose)
- `metadata.homepage` (string, marketplace documentation)
- `metadata.repository` (string, marketplace source)
### Examples
```bash
# Check plugin required fields
/schema-validation fields path:. type:plugin
# Check marketplace with strict mode (fail on missing recommended)
/schema-validation fields path:./test-marketplace type:marketplace strict:true
# Auto-detect type
/schema-validation fields path:.
```
### Error Handling
- **File not found**: List all searched paths
- **Invalid JSON**: Suggest running json validation first
- **Unknown type**: Show valid types (plugin, marketplace)
- **Empty field**: Report which field is present but empty
### Output Format
**Success (all required present)**:
```
✅ Required Fields Validation: PASS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: plugin.json
Type: plugin
Required Fields (5/5):
✅ name: "my-plugin"
✅ version: "1.0.0"
✅ description: "My awesome plugin"
✅ author: "Developer Name"
✅ license: "MIT"
Recommended Fields (3/4):
✅ repository: Present
✅ homepage: Present
✅ keywords: Present
⚠️ category: Missing (improves discoverability)
Status: PASS
Warnings: 1 (non-blocking)
```
**Failure (missing required)**:
```
❌ Required Fields Validation: FAIL
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: plugin.json
Type: plugin
Required Fields (3/5):
✅ name: "my-plugin"
❌ version: Missing (REQUIRED - use semver X.Y.Z)
✅ description: "My plugin"
❌ license: Missing (REQUIRED - use MIT, Apache-2.0, etc.)
✅ author: "Developer"
Critical Issues: 2
Status: FAIL
Action Required:
Add missing required fields to plugin.json:
- version: "1.0.0"
- license: "MIT"
```
**Marketplace Example**:
```
✅ Required Fields Validation: PASS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: marketplace.json
Type: marketplace
Required Fields (5/5):
✅ name: "my-marketplace"
✅ owner.name: "DevTools Team"
✅ owner.email: "devtools@example.com"
✅ plugins: Array with 3 entries
Status: PASS
```
### Integration
This operation is called by:
- `full-schema-validation.md` - Second validation step after JSON syntax
- `validation-orchestrator` - Comprehensive validation checks
- Direct user invocation for field checking
**Request**: $ARGUMENTS

View File

@@ -0,0 +1,313 @@
## Operation: Full Schema Validation
Execute complete schema validation workflow: JSON syntax → Required fields → Format compliance → Plugin entries (if marketplace).
### Parameters from $ARGUMENTS
- **path**: Path to plugin directory or marketplace (required)
- **type**: Target type: `plugin` or `marketplace` (optional, auto-detect)
- **strict**: Fail on warnings and missing recommended fields (optional, default: false)
- **verbose**: Show detailed error information (optional, default: false)
### Workflow
1. **Detect Target Type**
```
IF type not specified:
Auto-detect based on path structure:
- Has plugin.json at root → plugin
- Has marketplace.json → marketplace
- Otherwise → error
Locate configuration file:
Plugin: <path>/plugin.json
Marketplace: <path>/marketplace.json or <path>/.claude-plugin/marketplace.json
```
2. **Phase 1: JSON Syntax Validation**
```
Read validate-json.md instructions
Execute: .scripts/json-validator.py --file "$config" --verbose "$verbose"
On failure:
- Report JSON syntax errors
- Stop validation (cannot proceed with invalid JSON)
- Exit with status 1
On success:
- Continue to Phase 2
```
3. **Phase 2: Required Fields Check**
```
Read check-required-fields.md instructions
Execute: .scripts/field-checker.sh "$config" "$type" "$strict"
Collect results:
- Required fields: present/missing
- Recommended fields: present/missing
- Critical errors count
- Warnings count
On failure:
- Report missing required fields
- Continue to Phase 3 (show all issues)
On success:
- Continue to Phase 3
```
4. **Phase 3: Format Validation**
```
Read validate-formats.md instructions
Execute: .scripts/format-validator.py --file "$config" --type "$type" --strict "$strict"
Validate:
- Semantic versioning
- Lowercase-hyphen naming
- URL formats
- Email addresses
- License identifiers
- Category names (if present)
Collect results:
- Format violations count
- Warnings count
```
5. **Phase 4: Plugin Entries Validation (Marketplace Only)**
```
IF type == "marketplace":
Read check-plugin-entries.md instructions
Execute: .scripts/schema-differ.sh "$config" "all"
Validate each plugin entry:
- Required fields (name, source, description)
- Recommended fields (version, author, license, keywords)
- Format compliance
Collect results:
- Total plugin entries
- Passed entries
- Failed entries
- Total issues per entry
```
6. **Aggregate Results**
```
Compile all validation phases:
Phase 1: JSON Syntax [PASS/FAIL]
Phase 2: Required Fields [PASS/FAIL]
Phase 3: Format Compliance [PASS/FAIL]
Phase 4: Plugin Entries [PASS/FAIL] (marketplace only)
Calculate overall status:
IF any phase FAIL: Overall FAIL
IF strict mode AND any warnings: Overall FAIL
ELSE: Overall PASS
Generate summary report:
- Total checks performed
- Critical errors
- Warnings
- Overall status
- Publication readiness
```
### Exit Codes
- **0**: All validation passed (or warnings only in non-strict mode)
- **1**: Validation failed (critical errors or strict mode with warnings)
- **2**: Error (file not found, invalid arguments, etc.)
### Examples
```bash
# Full validation with auto-detect
/schema-validation full-schema path:.
# Full plugin validation with strict mode
/schema-validation full-schema path:. type:plugin strict:true
# Full marketplace validation with verbose output
/schema-validation full-schema path:./test-marketplace type:marketplace verbose:true
# Validate specific plugin in subdirectory
/schema-validation full-schema path:./plugins/my-plugin type:plugin
```
### Integration
This operation is the primary entry point for complete schema validation and is called by:
- `validation-orchestrator` comprehensive validation
- Marketplace submission workflows
- CI/CD validation pipelines
- Direct user invocation for thorough checking
### Output Format
**Success (all phases pass)**:
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FULL SCHEMA VALIDATION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: plugin.json
Type: plugin
Mode: Standard
Phase 1: JSON Syntax ✅
Status: Valid JSON
Backend: jq
Phase 2: Required Fields ✅
Required: 5/5 present
Recommended: 3/4 present
Missing: category (non-critical)
Phase 3: Format Compliance ✅
Checks: 7/7 passed
Version: 1.0.0 (valid semver)
Name: my-plugin (valid lowercase-hyphen)
License: MIT (valid SPDX)
URLs: All valid HTTPS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VALIDATION SUMMARY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Overall Status: ✅ PASS
Checks Performed: 15
Critical Errors: 0
Warnings: 1
Passed: 14
Publication Readiness: READY ✅
Your plugin meets all required standards
Consider adding: category field for better discoverability
Quality Score: 95/100 ⭐⭐⭐⭐⭐
```
**Failure (multiple phases fail)**:
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FULL SCHEMA VALIDATION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: plugin.json
Type: plugin
Mode: Standard
Phase 1: JSON Syntax ✅
Status: Valid JSON
Backend: python3
Phase 2: Required Fields ❌
Required: 3/5 present
Missing:
❌ version (REQUIRED - use semver X.Y.Z)
❌ license (REQUIRED - use MIT, Apache-2.0, etc.)
Phase 3: Format Compliance ❌
Checks: 4/6 passed
Violations:
❌ name: "My-Plugin" - must use lowercase-hyphen
❌ homepage: "example.com" - must be valid URL
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VALIDATION SUMMARY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Overall Status: ❌ FAIL
Checks Performed: 11
Critical Errors: 4
Warnings: 0
Passed: 7
Publication Readiness: NOT READY ❌
Fix 4 critical issues before submission
Priority Actions:
1. Add version field: "1.0.0"
2. Add license field: "MIT"
3. Fix name format: "my-plugin"
4. Fix homepage URL: "https://example.com"
Quality Score: 45/100 ⭐⭐
Rating: Needs Improvement
Next Steps:
1. Fix all critical errors above
2. Re-run validation: /schema-validation full-schema path:.
3. Aim for quality score 90+ for publication
```
**Marketplace Example (with plugin entries)**:
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
FULL SCHEMA VALIDATION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: marketplace.json
Type: marketplace
Mode: Standard
Phase 1: JSON Syntax ✅
Status: Valid JSON
Phase 2: Required Fields ✅
Required: 5/5 present
Recommended: 4/4 present
Phase 3: Format Compliance ✅
Checks: 4/4 passed
Phase 4: Plugin Entries ✅
Total Entries: 3
Passed: 3 (100%)
Failed: 0
Entry 0: code-review ✅
Entry 1: deploy-tools ✅
Entry 2: security-scan ✅
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
VALIDATION SUMMARY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Overall Status: ✅ PASS
Checks Performed: 23
Critical Errors: 0
Warnings: 0
Passed: 23
Publication Readiness: READY ✅
Your marketplace meets all standards
All 3 plugin entries are valid
Quality Score: 100/100 ⭐⭐⭐⭐⭐
Rating: Excellent
```
### Error Handling
- **File not found**: List searched paths, suggest creating configuration
- **Invalid JSON**: Stop at Phase 1, show syntax errors
- **Auto-detect failure**: Suggest specifying type explicitly
- **Script execution error**: Show script path and error message
### Performance
- **Plugin**: 1-2 seconds (3 phases)
- **Marketplace**: 2-5 seconds (4 phases, depends on plugin entry count)
- **Large Marketplace**: 5-10 seconds (50+ plugin entries)
**Request**: $ARGUMENTS

View File

@@ -0,0 +1,76 @@
---
description: Validate JSON schemas, required fields, and format compliance for marketplaces and plugins
---
You are the Schema Validation coordinator, ensuring structural integrity and format compliance.
## Your Mission
Parse `$ARGUMENTS` to determine the requested schema validation operation and route to the appropriate sub-command.
## Available Operations
Parse the first word of `$ARGUMENTS` to determine which operation to execute:
- **json** → Read `.claude/commands/schema-validation/validate-json.md`
- **fields** → Read `.claude/commands/schema-validation/check-required-fields.md`
- **formats** → Read `.claude/commands/schema-validation/validate-formats.md`
- **entries** → Read `.claude/commands/schema-validation/check-plugin-entries.md`
- **full-schema** → Read `.claude/commands/schema-validation/full-schema-validation.md`
## Argument Format
```
/schema-validation <operation> [parameters]
```
### Examples
```bash
# Validate JSON syntax
/schema-validation json file:plugin.json
# Check required fields
/schema-validation fields path:. type:plugin
# Validate formats (semver, URLs, naming)
/schema-validation formats path:.
# Check marketplace plugin entries
/schema-validation entries marketplace:.claude-plugin/marketplace.json
# Run complete schema validation
/schema-validation full-schema path:. type:plugin
```
## Validation Scope
**For Plugins**:
- Required: name, version, description, author, license
- Formats: semver (version), lowercase-hyphen (name), valid license
- Optional: keywords, category, homepage, repository
**For Marketplaces**:
- Required: name, owner, plugins
- Plugin entries: name, version, source, description, author, license
- Formats: valid source (github:, URL, path)
## Error Handling
If the operation is not recognized:
1. List all available operations
2. Show validation scope
3. Provide usage examples
## Base Directory
Base directory for this skill: `.claude/commands/schema-validation/`
## Your Task
1. Parse `$ARGUMENTS` to extract operation and parameters
2. Read the corresponding operation file
3. Execute schema validation with multi-backend support (jq, python3)
4. Return detailed validation results with line numbers for errors
**Current Request**: $ARGUMENTS

View File

@@ -0,0 +1,195 @@
## Operation: Validate Formats
Validate format compliance for semver, URLs, email addresses, and naming conventions.
### Parameters from $ARGUMENTS
- **path**: Path to plugin directory or marketplace file (required)
- **type**: Target type: `plugin` or `marketplace` (optional, auto-detect)
- **strict**: Enforce HTTPS for all URLs (optional, default: false)
### Workflow
1. **Locate Configuration File**
```
Auto-detect or use specified type:
Plugin: plugin.json
Marketplace: marketplace.json or .claude-plugin/marketplace.json
```
2. **Execute Format Validation**
```
Execute .scripts/format-validator.py --file "$config" --type "$type" --strict "$strict"
Validates:
- Semantic versioning (X.Y.Z)
- Lowercase-hyphen naming (^[a-z0-9]+(-[a-z0-9]+)*$)
- URL formats (http/https)
- Email addresses (RFC 5322 compliant)
- License identifiers (SPDX)
- Category names (10 approved categories)
```
3. **Report Results**
```
For each field:
✅ Valid format
❌ Invalid format with specific error and remediation
Summary:
- Total fields checked
- Passed count
- Failed count
- Exit code: 0 (all pass) or 1 (any fail)
```
### Format Validation Rules
**Semantic Versioning (version field)**:
- Pattern: `X.Y.Z` where X, Y, Z are non-negative integers
- Valid: `1.0.0`, `2.5.3`, `10.20.30`
- Invalid: `1.0`, `v1.0.0`, `1.0.0-beta` (pre-release allowed but optional)
**Lowercase-Hyphen Naming (name field)**:
- Pattern: `^[a-z0-9]+(-[a-z0-9]+)*$`
- Valid: `my-plugin`, `test-marketplace`, `plugin123`
- Invalid: `My-Plugin`, `test_plugin`, `plugin.name`, `-plugin`, `plugin-`
**URL Format (homepage, repository fields)**:
- Must start with `http://` or `https://`
- Strict mode: Only `https://` allowed
- Valid: `https://example.com`, `http://localhost:3000`
- Invalid: `example.com`, `www.example.com`, `ftp://example.com`
**Email Format (owner.email, author.email fields)**:
- RFC 5322 compliant pattern
- Valid: `user@example.com`, `name.surname@company.co.uk`
- Invalid: `user@`, `@example.com`, `user example.com`
**License Identifier (license field)**:
- SPDX identifier or "Proprietary"
- Common: MIT, Apache-2.0, GPL-3.0, BSD-3-Clause
- Valid: `MIT`, `Apache-2.0`, `ISC`, `Proprietary`
- Invalid: `mit`, `Apache 2.0`, `BSD`
**Category (category field)**:
- One of 10 approved categories
- Valid: development, testing, deployment, documentation, security, database, monitoring, productivity, quality, collaboration
- Invalid: coding, devops, tools, utilities
### Examples
```bash
# Validate plugin formats
/schema-validation formats path:.
# Validate marketplace with strict HTTPS enforcement
/schema-validation formats path:./test-marketplace type:marketplace strict:true
# Validate specific plugin
/schema-validation formats path:./my-plugin type:plugin
```
### Error Handling
- **File not found**: Show expected locations
- **Invalid JSON**: Suggest running json validation first
- **Format violation**: Specific error with correct pattern
- **Unknown field**: Warn but don't fail
### Output Format
**Success (all formats valid)**:
```
✅ Format Validation: PASS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: plugin.json
Type: plugin
Format Checks (7/7):
✅ name: "my-plugin" (lowercase-hyphen)
✅ version: "1.0.0" (semver)
✅ description: Valid length (73 chars)
✅ license: "MIT" (SPDX identifier)
✅ homepage: "https://example.com" (valid URL)
✅ repository: "https://github.com/user/repo" (valid URL)
✅ category: "development" (approved category)
Status: PASS
```
**Failure (format violations)**:
```
❌ Format Validation: FAIL
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: plugin.json
Type: plugin
Format Checks (4/7):
❌ name: "My-Plugin"
Invalid: Must use lowercase-hyphen format
Pattern: ^[a-z0-9]+(-[a-z0-9]+)*$
Example: my-plugin, test-tool, plugin123
❌ version: "1.0"
Invalid: Must use semantic versioning (X.Y.Z)
Expected: Three version numbers separated by dots
Example: 1.0.0, 2.1.5
✅ description: Valid (80 characters)
❌ license: "Apache 2.0"
Invalid: Must be SPDX identifier
Expected: Apache-2.0
Valid identifiers: MIT, Apache-2.0, GPL-3.0, BSD-3-Clause
⚠️ homepage: "http://example.com"
Warning: Consider using HTTPS for security
Current: http://example.com
Recommended: https://example.com
✅ repository: "https://github.com/user/repo"
❌ category: "coding"
Invalid: Must be one of 10 approved categories
Valid: development, testing, deployment, documentation,
security, database, monitoring, productivity,
quality, collaboration
Failed: 4
Warnings: 1
Status: FAIL
Action Required:
Fix format violations:
- name: Convert to lowercase-hyphen (my-plugin)
- version: Use semver format (1.0.0)
- license: Use SPDX identifier (Apache-2.0)
- category: Choose approved category (development)
```
**Marketplace Example**:
```
✅ Format Validation: PASS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: marketplace.json
Type: marketplace
Format Checks (4/4):
✅ name: "enterprise-marketplace" (lowercase-hyphen)
✅ owner.email: "devtools@company.com" (valid email)
✅ metadata.homepage: "https://company.com/plugins" (valid HTTPS URL)
✅ metadata.repository: "https://github.com/company/plugins" (valid HTTPS URL)
Status: PASS
Strict HTTPS: Enforced ✅
```
### Integration
This operation is called by:
- `full-schema-validation.md` - Third validation step after fields check
- `best-practices` skill - Naming and versioning validation
- Direct user invocation for format checking
**Request**: $ARGUMENTS

View File

@@ -0,0 +1,110 @@
## Operation: Validate JSON Syntax
Validate JSON file syntax with multi-backend support (jq + python3 fallback).
### Parameters from $ARGUMENTS
- **file**: Path to JSON file (required)
- **verbose**: Show detailed error information (optional, default: false)
### Workflow
1. **Parse Arguments**
```
Extract file path from $ARGUMENTS
Check if verbose mode requested
```
2. **Validate File Exists**
```
IF file does not exist:
Return error with file path
Exit with status 1
```
3. **Detect JSON Tool**
```
Execute .scripts/json-validator.py --detect
Primary: jq (faster, better error messages)
Fallback: python3 (universal availability)
```
4. **Validate JSON Syntax**
```
Execute .scripts/json-validator.py --file "$file" --verbose "$verbose"
On success:
- Print success message with file path
- Return 0
On failure:
- Print error message with line number and details
- Show problematic JSON section
- Return 1
```
### Examples
```bash
# Basic JSON validation
/schema-validation json file:plugin.json
# Verbose validation with details
/schema-validation json file:marketplace.json verbose:true
# Validate multiple files (call multiple times)
/schema-validation json file:plugin1.json
/schema-validation json file:plugin2.json
```
### Error Handling
- **File not found**: Clear message with expected path
- **Invalid JSON**: Line number, character position, error description
- **No JSON tool available**: Instruction to install jq or python3
- **Permission denied**: File access error with remediation
### Output Format
**Success**:
```
✅ Valid JSON: plugin.json
Backend: jq
```
**Failure (basic)**:
```
❌ Invalid JSON: marketplace.json
Error: Unexpected token at line 15
```
**Failure (verbose)**:
```
❌ Invalid JSON: marketplace.json
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Error Details:
Line: 15
Position: 8
Issue: Expected ',' or ']' but got '}'
Problematic Section (lines 13-17):
13 | "plugins": [
14 | {
15 | "name": "test"
16 | }
17 | }
Remediation:
- Check for missing commas between array elements
- Verify bracket matching: [ ] { }
- Use a JSON formatter/linter in your editor
```
### Integration
This operation is called by:
- `full-schema-validation.md` - First validation step
- `validation-orchestrator` - Quick validation checks
- Direct user invocation for single file checks
**Request**: $ARGUMENTS