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,254 @@
#!/usr/bin/env bash
# ============================================================================
# CHANGELOG Validator
# ============================================================================
# Purpose: Validate CHANGELOG.md format compliance (Keep a Changelog)
# Version: 1.0.0
# Usage: ./changelog-validator.sh <changelog-path> [--strict] [--json]
# Returns: 0=success, 1=error, JSON output to stdout if --json
# ============================================================================
set -euo pipefail
# Default values
STRICT_MODE=false
JSON_OUTPUT=false
REQUIRE_UNRELEASED=true
# Valid change categories per Keep a Changelog
VALID_CATEGORIES=("Added" "Changed" "Deprecated" "Removed" "Fixed" "Security")
# Parse arguments
CHANGELOG_PATH="${1:-CHANGELOG.md}"
shift || true
while [[ $# -gt 0 ]]; do
case "$1" in
--strict)
STRICT_MODE=true
shift
;;
--json)
JSON_OUTPUT=true
shift
;;
--no-unreleased)
REQUIRE_UNRELEASED=false
shift
;;
*)
shift
;;
esac
done
# Initialize results
declare -a issues=()
declare -a version_entries=()
declare -a categories_used=()
has_title=false
has_unreleased=false
compliance_score=100
# Check if file exists
if [[ ! -f "$CHANGELOG_PATH" ]]; then
if $JSON_OUTPUT; then
cat <<EOF
{
"error": "CHANGELOG not found",
"path": "$CHANGELOG_PATH",
"present": false,
"score": 0,
"status": "warning",
"issues": ["CHANGELOG.md not found"]
}
EOF
else
echo "⚠️ WARNING: CHANGELOG not found at $CHANGELOG_PATH"
echo "CHANGELOG is recommended but not required for initial submission."
fi
exit 1
fi
# Read content
content=$(<"$CHANGELOG_PATH")
# Check for title
if echo "$content" | grep -qiE "^#\s*(changelog|change.?log)"; then
has_title=true
else
issues+=("Missing title 'Changelog' or 'Change Log'")
((compliance_score-=10)) || true
fi
# Check for Unreleased section
if echo "$content" | grep -qE "^##\s*\[Unreleased\]"; then
has_unreleased=true
else
if $REQUIRE_UNRELEASED; then
issues+=("Missing [Unreleased] section")
((compliance_score-=15)) || true
fi
fi
# Extract version headers
while IFS= read -r line; do
if [[ $line =~ ^##[[:space:]]*\[([0-9]+\.[0-9]+\.[0-9]+)\][[:space:]]*-[[:space:]]*([0-9]{4}-[0-9]{2}-[0-9]{2}) ]]; then
version="${BASH_REMATCH[1]}"
date="${BASH_REMATCH[2]}"
version_entries+=("$version|$date")
elif [[ $line =~ ^##[[:space:]]*\[?([0-9]+\.[0-9]+\.[0-9]+)\]? ]] && [[ ! $line =~ \[Unreleased\] ]]; then
# Invalid format detected
issues+=("Invalid version header format: '$line' (should be '## [X.Y.Z] - YYYY-MM-DD')")
((compliance_score-=10)) || true
fi
done <<< "$content"
# Check for valid change categories
for category in "${VALID_CATEGORIES[@]}"; do
if echo "$content" | grep -qE "^###[[:space:]]*$category"; then
categories_used+=("$category")
fi
done
# Detect invalid categories
while IFS= read -r line; do
if [[ $line =~ ^###[[:space:]]+(.*) ]]; then
cat_name="${BASH_REMATCH[1]}"
is_valid=false
for valid_cat in "${VALID_CATEGORIES[@]}"; do
if [[ "$cat_name" == "$valid_cat" ]]; then
is_valid=true
break
fi
done
if ! $is_valid; then
issues+=("Non-standard category: '### $cat_name' (should be one of: ${VALID_CATEGORIES[*]})")
((compliance_score-=5)) || true
fi
fi
done <<< "$content"
# Check date formats in version headers
for entry in "${version_entries[@]}"; do
date_part="${entry#*|}"
if [[ ! $date_part =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
issues+=("Invalid date format in version entry: $date_part (should be YYYY-MM-DD)")
((compliance_score-=5)) || true
fi
done
# Ensure score doesn't go negative
if ((compliance_score < 0)); then
compliance_score=0
fi
# Determine status
status="pass"
if ((compliance_score < 60)); then
status="fail"
elif ((compliance_score < 80)); then
status="warning"
fi
# Output results
if $JSON_OUTPUT; then
# Build JSON output
cat <<EOF
{
"present": true,
"path": "$CHANGELOG_PATH",
"has_title": $has_title,
"has_unreleased": $has_unreleased,
"version_count": ${#version_entries[@]},
"version_entries": [
$(IFS=,; for entry in "${version_entries[@]}"; do
version="${entry%|*}"
date="${entry#*|}"
echo " {\"version\": \"$version\", \"date\": \"$date\"}"
done | paste -sd, -)
],
"categories_used": [
$(IFS=,; for cat in "${categories_used[@]}"; do
echo " \"$cat\""
done | paste -sd, -)
],
"compliance_score": $compliance_score,
"status": "$status",
"issues": [
$(IFS=,; for issue in "${issues[@]}"; do
# Escape quotes in issue text
escaped_issue="${issue//\"/\\\"}"
echo " \"$escaped_issue\""
done | paste -sd, -)
]
}
EOF
else
# Human-readable output
echo ""
echo "CHANGELOG Validation Results"
echo "========================================"
echo "File: $CHANGELOG_PATH"
echo "Compliance Score: $compliance_score/100"
echo ""
if $has_title; then
echo "✓ Title present"
else
echo "✗ Title missing"
fi
if $has_unreleased; then
echo "✓ [Unreleased] section present"
else
if $REQUIRE_UNRELEASED; then
echo "✗ [Unreleased] section missing"
else
echo "⚠ [Unreleased] section missing (not required)"
fi
fi
echo ""
echo "Version Entries: ${#version_entries[@]}"
for entry in "${version_entries[@]}"; do
version="${entry%|*}"
date="${entry#*|}"
echo " • [$version] - $date"
done
if [[ ${#categories_used[@]} -gt 0 ]]; then
echo ""
echo "Change Categories Used:"
for cat in "${categories_used[@]}"; do
echo "$cat"
done
fi
if [[ ${#issues[@]} -gt 0 ]]; then
echo ""
echo "Issues Found: ${#issues[@]}"
for issue in "${issues[@]}"; do
echo "$issue"
done
fi
echo ""
if [[ "$status" == "pass" ]]; then
echo "Overall: ✓ PASS"
elif [[ "$status" == "warning" ]]; then
echo "Overall: ⚠ WARNINGS"
else
echo "Overall: ✗ FAIL"
fi
echo ""
fi
# Exit with appropriate code
if [[ "$status" == "fail" ]]; then
exit 1
else
exit 0
fi

View File

@@ -0,0 +1,325 @@
#!/usr/bin/env bash
# ============================================================================
# Example Validator
# ============================================================================
# Purpose: Validate example quality and detect placeholder patterns
# Version: 1.0.0
# Usage: ./example-validator.sh <path> [--no-placeholders] [--recursive] [--json]
# Returns: 0=success, 1=warning, JSON output to stdout if --json
# ============================================================================
set -euo pipefail
# Default values
NO_PLACEHOLDERS=true
RECURSIVE=true
JSON_OUTPUT=false
EXTENSIONS="md,txt,json,sh,py,js,ts,yaml,yml"
# Parse arguments
TARGET_PATH="${1:-.}"
shift || true
while [[ $# -gt 0 ]]; do
case "$1" in
--no-placeholders)
NO_PLACEHOLDERS=true
shift
;;
--allow-placeholders)
NO_PLACEHOLDERS=false
shift
;;
--recursive)
RECURSIVE=true
shift
;;
--non-recursive)
RECURSIVE=false
shift
;;
--json)
JSON_OUTPUT=true
shift
;;
--extensions)
EXTENSIONS="$2"
shift 2
;;
*)
shift
;;
esac
done
# Initialize counters
files_checked=0
example_count=0
placeholder_count=0
todo_count=0
declare -a issues=()
declare -a files_with_issues=()
# Build find command based on recursiveness
if $RECURSIVE; then
FIND_DEPTH=""
else
FIND_DEPTH="-maxdepth 1"
fi
# Build extension pattern
ext_pattern=""
IFS=',' read -ra EXT_ARRAY <<< "$EXTENSIONS"
for ext in "${EXT_ARRAY[@]}"; do
if [[ -z "$ext_pattern" ]]; then
ext_pattern="-name '*.${ext}'"
else
ext_pattern="$ext_pattern -o -name '*.${ext}'"
fi
done
# Find files to check
mapfile -t files < <(eval "find '$TARGET_PATH' $FIND_DEPTH -type f \( $ext_pattern \) 2>/dev/null" || true)
# Placeholder patterns to detect
declare -a PLACEHOLDER_PATTERNS=(
'TODO[:\)]'
'FIXME[:\)]'
'XXX[:\)]'
'HACK[:\)]'
'placeholder'
'PLACEHOLDER'
'your-.*-here'
'<your-'
'INSERT.?HERE'
'YOUR_[A-Z_]+'
)
# Generic dummy value patterns
declare -a GENERIC_PATTERNS=(
'\bfoo\b'
'\bbar\b'
'\bbaz\b'
'\bdummy\b'
)
# Acceptable patterns (don't count these)
declare -a ACCEPTABLE_PATTERNS=(
'\{\{[^}]+\}\}' # {{variable}} template syntax
'\$\{[^}]+\}' # ${variable} template syntax
'\$[A-Z_]+' # $VARIABLE environment variables
)
# Function to check if line contains acceptable pattern
is_acceptable_pattern() {
local line="$1"
for pattern in "${ACCEPTABLE_PATTERNS[@]}"; do
if echo "$line" | grep -qE "$pattern"; then
return 0 # Is acceptable
fi
done
return 1 # Not acceptable
}
# Function to count code examples in markdown
count_code_examples() {
local file="$1"
if [[ ! "$file" =~ \.md$ ]]; then
return 0
fi
# Count code blocks (```)
local count
count=$(grep -c '```' "$file" 2>/dev/null || echo "0")
# Ensure count is numeric and divide by 2 since each code block has opening and closing
if [[ "$count" =~ ^[0-9]+$ ]]; then
count=$((count / 2))
else
count=0
fi
echo "$count"
}
# Check each file
for file in "${files[@]}"; do
((files_checked++)) || true
# Count examples in markdown files
if [[ "$file" =~ \.md$ ]]; then
file_examples=$(count_code_examples "$file")
((example_count += file_examples)) || true
fi
file_issues=0
# Check for placeholder patterns
for pattern in "${PLACEHOLDER_PATTERNS[@]}"; do
while IFS=: read -r line_num line_content; do
# Skip if it's an acceptable pattern
if is_acceptable_pattern "$line_content"; then
continue
fi
((placeholder_count++)) || true
((file_issues++)) || true
issue="$file:$line_num: Placeholder pattern detected"
issues+=("$issue")
# Track TODO/FIXME separately
if echo "$pattern" | grep -qE 'TODO|FIXME|XXX'; then
((todo_count++)) || true
fi
done < <(grep -inE "$pattern" "$file" 2>/dev/null || true)
done
# Check for generic dummy values (only in non-test files)
if [[ ! "$file" =~ test ]] && [[ ! "$file" =~ example ]] && [[ ! "$file" =~ spec ]]; then
for pattern in "${GENERIC_PATTERNS[@]}"; do
while IFS=: read -r line_num line_content; do
# Skip code comments explaining these terms
if echo "$line_content" | grep -qE '(#|//|/\*).*'"$pattern"; then
continue
fi
# Skip if in an acceptable context
if is_acceptable_pattern "$line_content"; then
continue
fi
((file_issues++)) || true
issue="$file:$line_num: Generic placeholder value detected"
issues+=("$issue")
done < <(grep -inE "$pattern" "$file" 2>/dev/null || true)
done
fi
# Track files with issues
if ((file_issues > 0)); then
files_with_issues+=("$file:$file_issues")
fi
done
# Calculate quality score
quality_score=100
((quality_score -= placeholder_count * 10)) || true
((quality_score -= todo_count * 5)) || true
if ((example_count < 2)); then
((quality_score -= 20)) || true
fi
# Ensure score doesn't go negative
if ((quality_score < 0)); then
quality_score=0
fi
# Determine status
status="pass"
if ((quality_score < 60)); then
status="fail"
elif ((quality_score < 80)); then
status="warning"
fi
# Output results
if $JSON_OUTPUT; then
# Build JSON output
cat <<EOF
{
"files_checked": $files_checked,
"example_count": $example_count,
"placeholder_count": $placeholder_count,
"todo_count": $todo_count,
"files_with_issues": ${#files_with_issues[@]},
"quality_score": $quality_score,
"status": "$status",
"issues": [
$(IFS=; for issue in "${issues[@]:0:20}"; do # Limit to first 20 issues
# Escape quotes in issue text
escaped_issue="${issue//\"/\\\"}"
echo " \"$escaped_issue\","
done | sed '$ s/,$//')
],
"files_with_issues_list": [
$(IFS=; for file_info in "${files_with_issues[@]:0:10}"; do # Limit to first 10 files
file_path="${file_info%:*}"
file_count="${file_info#*:}"
echo " {\"file\": \"$file_path\", \"issue_count\": $file_count},"
done | sed '$ s/,$//')
]
}
EOF
else
# Human-readable output
echo ""
echo "Example Quality Validation"
echo "========================================"
echo "Files Checked: $files_checked"
echo "Code Examples Found: $example_count"
echo "Quality Score: $quality_score/100"
echo ""
if ((placeholder_count > 0)) || ((todo_count > 0)); then
echo "Issues Detected:"
echo " • Placeholder patterns: $placeholder_count"
echo " • TODO/FIXME markers: $todo_count"
echo " • Files with issues: ${#files_with_issues[@]}"
echo ""
if ((${#files_with_issues[@]} > 0)); then
echo "Files with issues:"
for file_info in "${files_with_issues[@]:0:5}"; do # Show first 5
file_path="${file_info%:*}"
file_count="${file_info#*:}"
echo "$file_path ($file_count issues)"
done
if ((${#files_with_issues[@]} > 5)); then
echo " ... and $((${#files_with_issues[@]} - 5)) more files"
fi
fi
echo ""
echo "Sample Issues:"
for issue in "${issues[@]:0:5}"; do # Show first 5
echo "$issue"
done
if ((${#issues[@]} > 5)); then
echo " ... and $((${#issues[@]} - 5)) more issues"
fi
else
echo "✓ No placeholder patterns detected"
fi
if ((example_count < 2)); then
echo ""
echo "⚠ Recommendation: Add more code examples (found: $example_count, recommended: 3+)"
fi
echo ""
if [[ "$status" == "pass" ]]; then
echo "Overall: ✓ PASS"
elif [[ "$status" == "warning" ]]; then
echo "Overall: ⚠ WARNINGS"
else
echo "Overall: ✗ FAIL"
fi
echo ""
fi
# Exit with appropriate code
if [[ "$status" == "fail" ]]; then
exit 1
elif [[ "$status" == "warning" ]]; then
exit 0 # Warning is not a failure
else
exit 0
fi

View File

@@ -0,0 +1,344 @@
#!/usr/bin/env python3
# ============================================================================
# License Detector
# ============================================================================
# Purpose: Detect and validate LICENSE file content
# Version: 1.0.0
# Usage: ./license-detector.py <path> [--expected LICENSE] [--json]
# Returns: 0=success, 1=error, JSON output to stdout
# ============================================================================
import sys
import os
import re
import json
import argparse
from pathlib import Path
from typing import Dict, Optional, Tuple
# OSI-approved license patterns
LICENSE_PATTERNS = {
"MIT": {
"pattern": r"Permission is hereby granted, free of charge",
"confidence": 95,
"osi_approved": True,
"full_name": "MIT License"
},
"Apache-2.0": {
"pattern": r"Licensed under the Apache License, Version 2\.0",
"confidence": 95,
"osi_approved": True,
"full_name": "Apache License 2.0"
},
"GPL-3.0": {
"pattern": r"GNU GENERAL PUBLIC LICENSE.*Version 3",
"confidence": 95,
"osi_approved": True,
"full_name": "GNU General Public License v3.0"
},
"GPL-2.0": {
"pattern": r"GNU GENERAL PUBLIC LICENSE.*Version 2",
"confidence": 95,
"osi_approved": True,
"full_name": "GNU General Public License v2.0"
},
"BSD-3-Clause": {
"pattern": r"Redistribution and use in source and binary forms.*3\.",
"confidence": 85,
"osi_approved": True,
"full_name": "BSD 3-Clause License"
},
"BSD-2-Clause": {
"pattern": r"Redistribution and use in source and binary forms",
"confidence": 80,
"osi_approved": True,
"full_name": "BSD 2-Clause License"
},
"ISC": {
"pattern": r"Permission to use, copy, modify, and/or distribute",
"confidence": 90,
"osi_approved": True,
"full_name": "ISC License"
},
"MPL-2.0": {
"pattern": r"Mozilla Public License Version 2\.0",
"confidence": 95,
"osi_approved": True,
"full_name": "Mozilla Public License 2.0"
}
}
# License name variations/aliases
LICENSE_ALIASES = {
"MIT License": "MIT",
"MIT license": "MIT",
"Apache License 2.0": "Apache-2.0",
"Apache 2.0": "Apache-2.0",
"Apache-2": "Apache-2.0",
"GNU GPL v3": "GPL-3.0",
"GPLv3": "GPL-3.0",
"GNU GPL v2": "GPL-2.0",
"GPLv2": "GPL-2.0",
"BSD 3-Clause": "BSD-3-Clause",
"BSD 2-Clause": "BSD-2-Clause",
}
def find_license_file(path: str) -> Optional[str]:
"""Find LICENSE file in path."""
path_obj = Path(path)
# Check if path is directly to LICENSE
if path_obj.is_file() and 'license' in path_obj.name.lower():
return str(path_obj)
# Search for LICENSE in directory
if path_obj.is_dir():
for filename in ['LICENSE', 'LICENSE.txt', 'LICENSE.md', 'COPYING', 'COPYING.txt', 'LICENCE']:
license_path = path_obj / filename
if license_path.exists():
return str(license_path)
return None
def read_plugin_manifest(path: str) -> Optional[str]:
"""Read license from plugin.json."""
path_obj = Path(path)
if path_obj.is_file():
path_obj = path_obj.parent
manifest_path = path_obj / '.claude-plugin' / 'plugin.json'
if not manifest_path.exists():
return None
try:
with open(manifest_path, 'r', encoding='utf-8') as f:
manifest = json.load(f)
return manifest.get('license')
except Exception:
return None
def detect_license(content: str) -> Tuple[Optional[str], int, bool]:
"""
Detect license type from content.
Returns: (license_type, confidence, is_complete)
"""
content_normalized = ' '.join(content.split()) # Normalize whitespace
best_match = None
best_confidence = 0
# Check for license text patterns
for license_id, license_info in LICENSE_PATTERNS.items():
pattern = license_info["pattern"]
if re.search(pattern, content, re.IGNORECASE | re.DOTALL):
confidence = license_info["confidence"]
if confidence > best_confidence:
best_match = license_id
best_confidence = confidence
# Check if it's just a name without full text
is_complete = True
if best_match and len(content.strip()) < 200: # Very short content
is_complete = False
# If no pattern match, check for just license names
if not best_match:
for alias, license_id in LICENSE_ALIASES.items():
if re.search(r'\b' + re.escape(alias) + r'\b', content, re.IGNORECASE):
best_match = license_id
best_confidence = 50 # Lower confidence for name-only
is_complete = False
break
return best_match, best_confidence, is_complete
def normalize_license_name(license_name: str) -> str:
"""Normalize license name for comparison."""
if not license_name:
return ""
# Check if it's already a standard ID
if license_name in LICENSE_PATTERNS:
return license_name
# Check aliases
if license_name in LICENSE_ALIASES:
return LICENSE_ALIASES[license_name]
# Normalize common variations
normalized = license_name.strip()
normalized = re.sub(r'\s+', ' ', normalized)
# Try fuzzy matching
for alias, license_id in LICENSE_ALIASES.items():
if normalized.lower() == alias.lower():
return license_id
return license_name
def licenses_match(detected: str, expected: str) -> Tuple[bool, str]:
"""
Check if detected license matches expected.
Returns: (matches, match_type)
"""
detected_norm = normalize_license_name(detected)
expected_norm = normalize_license_name(expected)
if detected_norm == expected_norm:
return True, "exact"
# Check if they're aliases of the same license
if detected_norm in LICENSE_PATTERNS and expected_norm in LICENSE_PATTERNS:
if LICENSE_PATTERNS[detected_norm]["full_name"] == LICENSE_PATTERNS[expected_norm]["full_name"]:
return True, "alias"
# Fuzzy match
if detected_norm.lower().replace('-', '').replace(' ', '') == expected_norm.lower().replace('-', '').replace(' ', ''):
return True, "fuzzy"
return False, "mismatch"
def main():
parser = argparse.ArgumentParser(description='Detect and validate LICENSE file')
parser.add_argument('path', help='Path to LICENSE file or directory containing it')
parser.add_argument('--expected', help='Expected license type (from plugin.json)', default=None)
parser.add_argument('--strict', action='store_true', help='Strict validation (requires full text)')
parser.add_argument('--json', action='store_true', help='Output JSON format')
args = parser.parse_args()
# Find LICENSE file
license_path = find_license_file(args.path)
if not license_path:
result = {
"error": "LICENSE file not found",
"path": args.path,
"present": False,
"score": 0,
"status": "fail",
"issues": ["LICENSE file not found in specified path"]
}
if args.json:
print(json.dumps(result, indent=2))
else:
print("❌ CRITICAL: LICENSE file not found")
print(f"Path: {args.path}")
print("LICENSE file is required for plugin submission.")
return 1
# Read LICENSE content
try:
with open(license_path, 'r', encoding='utf-8') as f:
content = f.read()
except Exception as e:
result = {
"error": f"Failed to read LICENSE: {str(e)}",
"path": license_path,
"present": True,
"score": 0,
"status": "fail"
}
if args.json:
print(json.dumps(result, indent=2))
else:
print(f"❌ ERROR: Failed to read LICENSE: {e}")
return 1
# Detect license
detected_license, confidence, is_complete = detect_license(content)
# Read expected license from plugin.json if not provided
if not args.expected:
args.expected = read_plugin_manifest(args.path)
# Check consistency
matches_manifest = True
match_type = None
if args.expected:
matches_manifest, match_type = licenses_match(detected_license or "", args.expected)
# Determine if OSI approved
is_osi_approved = False
if detected_license and detected_license in LICENSE_PATTERNS:
is_osi_approved = LICENSE_PATTERNS[detected_license]["osi_approved"]
# Build issues list
issues = []
score = 100
if not detected_license:
issues.append("Unable to identify license type")
score -= 50
elif not is_complete:
issues.append("LICENSE contains only license name, not full text")
score -= 20 if args.strict else 10
if not is_osi_approved and detected_license:
issues.append("License is not OSI-approved")
score -= 30
if args.expected and not matches_manifest:
issues.append(f"LICENSE ({detected_license or 'unknown'}) does not match plugin.json ({args.expected})")
score -= 20
score = max(0, score)
# Determine status
if score >= 80:
status = "pass"
elif score >= 60:
status = "warning"
else:
status = "fail"
# Build result
result = {
"present": True,
"path": license_path,
"detected_license": detected_license,
"confidence": confidence,
"is_complete": is_complete,
"is_osi_approved": is_osi_approved,
"manifest_license": args.expected,
"matches_manifest": matches_manifest,
"match_type": match_type,
"score": score,
"status": status,
"issues": issues
}
# Output
if args.json:
print(json.dumps(result, indent=2))
else:
# Human-readable output
print(f"\nLICENSE Validation Results")
print("=" * 50)
print(f"File: {license_path}")
print(f"Detected: {detected_license or 'Unknown'} (confidence: {confidence}%)")
print(f"Score: {score}/100")
print(f"\nOSI Approved: {'✓ Yes' if is_osi_approved else '✗ No'}")
print(f"Complete Text: {'✓ Yes' if is_complete else '⚠ No (name only)'}")
if args.expected:
print(f"\nConsistency Check:")
print(f" plugin.json: {args.expected}")
print(f" LICENSE file: {detected_license or 'Unknown'}")
print(f" Match: {'✓ Yes' if matches_manifest else '✗ No'}")
if issues:
print(f"\nIssues Found: {len(issues)}")
for issue in issues:
print(f"{issue}")
print(f"\nOverall: {'✓ PASS' if status == 'pass' else '⚠ WARNING' if status == 'warning' else '✗ FAIL'}")
print()
return 0 if status != "fail" else 1
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,311 @@
#!/usr/bin/env python3
# ============================================================================
# README Checker
# ============================================================================
# Purpose: Validate README.md completeness and quality
# Version: 1.0.0
# Usage: ./readme-checker.py <readme-path> [options]
# Returns: 0=success, 1=error, JSON output to stdout
# ============================================================================
import sys
import os
import re
import json
import argparse
from pathlib import Path
from typing import Dict, List, Tuple
# Required sections (case-insensitive patterns)
REQUIRED_SECTIONS = {
"overview": r"(?i)^#{1,3}\s*(overview|description|about)",
"installation": r"(?i)^#{1,3}\s*installation",
"usage": r"(?i)^#{1,3}\s*usage",
"examples": r"(?i)^#{1,3}\s*(examples?|demonstrations?)",
"license": r"(?i)^#{1,3}\s*licen[cs]e"
}
# Optional but recommended sections
RECOMMENDED_SECTIONS = {
"configuration": r"(?i)^#{1,3}\s*(configuration|setup|config)",
"troubleshooting": r"(?i)^#{1,3}\s*(troubleshooting|faq|common.?issues)",
"contributing": r"(?i)^#{1,3}\s*contribut",
"changelog": r"(?i)^#{1,3}\s*(changelog|version.?history|releases)"
}
def find_readme(path: str) -> str:
"""Find README file in path."""
path_obj = Path(path)
# Check if path is directly to README
if path_obj.is_file() and path_obj.name.lower().startswith('readme'):
return str(path_obj)
# Search for README in directory
if path_obj.is_dir():
for filename in ['README.md', 'readme.md', 'README.txt', 'README']:
readme_path = path_obj / filename
if readme_path.exists():
return str(readme_path)
return None
def analyze_sections(content: str) -> Tuple[List[str], List[str]]:
"""Analyze README sections."""
lines = content.split('\n')
found_sections = []
missing_sections = []
# Check required sections
for section_name, pattern in REQUIRED_SECTIONS.items():
found = False
for line in lines:
if re.match(pattern, line.strip()):
found = True
found_sections.append(section_name)
break
if not found:
missing_sections.append(section_name)
return found_sections, missing_sections
def count_examples(content: str) -> int:
"""Count code examples in README."""
# Count code blocks (```...```)
code_blocks = re.findall(r'```[\s\S]*?```', content)
return len(code_blocks)
def check_quality_issues(content: str) -> List[str]:
"""Check for quality issues."""
issues = []
# Check for excessive placeholder text
placeholder_patterns = [
r'TODO',
r'FIXME',
r'XXX',
r'placeholder',
r'your-.*-here',
r'<your-'
]
for pattern in placeholder_patterns:
matches = re.findall(pattern, content, re.IGNORECASE)
if len(matches) > 5: # More than 5 is excessive
issues.append(f"Excessive placeholder patterns: {len(matches)} instances of '{pattern}'")
# Check for very short sections
lines = content.split('\n')
current_section = None
section_lengths = {}
for line in lines:
if re.match(r'^#{1,3}\s+', line):
current_section = line.strip()
section_lengths[current_section] = 0
elif current_section and line.strip():
section_lengths[current_section] += len(line)
for section, length in section_lengths.items():
if length < 100 and any(keyword in section.lower() for keyword in ['installation', 'usage', 'example']):
issues.append(f"Section '{section}' is very short ({length} chars), consider expanding")
return issues
def calculate_score(found_sections: List[str], missing_sections: List[str],
length: int, example_count: int, quality_issues: List[str]) -> int:
"""Calculate README quality score (0-100)."""
score = 100
# Deduct for missing required sections (15 points each)
score -= len(missing_sections) * 15
# Deduct if too short
if length < 200:
score -= 30 # Critical
elif length < 500:
score -= 10 # Warning
# Deduct if no examples
if example_count == 0:
score -= 15
elif example_count < 2:
score -= 5
# Deduct for quality issues (5 points each, max 20)
score -= min(len(quality_issues) * 5, 20)
return max(0, score)
def generate_recommendations(found_sections: List[str], missing_sections: List[str],
length: int, example_count: int, quality_issues: List[str]) -> List[Dict]:
"""Generate actionable recommendations."""
recommendations = []
# Missing sections
for section in missing_sections:
impact = 15
recommendations.append({
"priority": "critical" if section in ["overview", "installation", "usage"] else "important",
"action": f"Add {section.title()} section",
"impact": impact,
"effort": "medium" if section == "examples" else "low",
"description": f"Include a comprehensive {section} section with clear explanations"
})
# Length issues
if length < 500:
gap = 500 - length
recommendations.append({
"priority": "important" if length >= 200 else "critical",
"action": f"Expand README by {gap} characters",
"impact": 10 if length >= 200 else 30,
"effort": "medium",
"description": "Add more detail to existing sections or include additional sections"
})
# Example issues
if example_count < 3:
needed = 3 - example_count
recommendations.append({
"priority": "important",
"action": f"Add {needed} more code example{'s' if needed > 1 else ''}",
"impact": 15 if example_count == 0 else 5,
"effort": "medium",
"description": "Include concrete, copy-pasteable usage examples"
})
# Quality issues
for issue in quality_issues:
recommendations.append({
"priority": "recommended",
"action": "Address quality issue",
"impact": 5,
"effort": "low",
"description": issue
})
return sorted(recommendations, key=lambda x: (
{"critical": 0, "important": 1, "recommended": 2}[x["priority"]],
-x["impact"]
))
def main():
parser = argparse.ArgumentParser(description='Validate README.md quality')
parser.add_argument('path', help='Path to README.md or directory containing it')
parser.add_argument('--sections', help='Comma-separated required sections', default=None)
parser.add_argument('--min-length', type=int, default=500, help='Minimum character count')
parser.add_argument('--strict', action='store_true', help='Enable strict validation')
parser.add_argument('--json', action='store_true', help='Output JSON format')
args = parser.parse_args()
# Find README file
readme_path = find_readme(args.path)
if not readme_path:
result = {
"error": "README.md not found",
"path": args.path,
"present": False,
"score": 0,
"issues": ["README.md file not found in specified path"]
}
print(json.dumps(result, indent=2))
return 1
# Read README content
try:
with open(readme_path, 'r', encoding='utf-8') as f:
content = f.read()
except Exception as e:
result = {
"error": f"Failed to read README: {str(e)}",
"path": readme_path,
"present": True,
"score": 0
}
print(json.dumps(result, indent=2))
return 1
# Analyze README
length = len(content)
found_sections, missing_sections = analyze_sections(content)
example_count = count_examples(content)
quality_issues = check_quality_issues(content)
# Calculate score
score = calculate_score(found_sections, missing_sections, length, example_count, quality_issues)
# Generate recommendations
recommendations = generate_recommendations(found_sections, missing_sections, length, example_count, quality_issues)
# Build result
result = {
"present": True,
"path": readme_path,
"length": length,
"min_length": args.min_length,
"meets_min_length": length >= args.min_length,
"sections": {
"found": found_sections,
"missing": missing_sections,
"required_count": len(REQUIRED_SECTIONS),
"found_count": len(found_sections)
},
"examples": {
"count": example_count,
"sufficient": example_count >= 2
},
"quality_issues": quality_issues,
"score": score,
"rating": (
"excellent" if score >= 90 else
"good" if score >= 75 else
"fair" if score >= 60 else
"needs_improvement" if score >= 40 else
"poor"
),
"recommendations": recommendations[:10], # Top 10
"status": "pass" if score >= 60 and not missing_sections else "warning" if score >= 40 else "fail"
}
# Output
if args.json:
print(json.dumps(result, indent=2))
else:
# Human-readable output
print(f"\nREADME Validation Results")
print("=" * 50)
print(f"File: {readme_path}")
print(f"Length: {length} characters (min: {args.min_length})")
print(f"Score: {score}/100 ({result['rating'].title()})")
print(f"\nSections Found: {len(found_sections)}/{len(REQUIRED_SECTIONS)}")
for section in found_sections:
print(f"{section.title()}")
if missing_sections:
print(f"\nMissing Sections: {len(missing_sections)}")
for section in missing_sections:
print(f"{section.title()}")
print(f"\nCode Examples: {example_count}")
if quality_issues:
print(f"\nQuality Issues: {len(quality_issues)}")
for issue in quality_issues[:5]: # Top 5
print(f"{issue}")
if recommendations:
print(f"\nTop Recommendations:")
for i, rec in enumerate(recommendations[:5], 1):
print(f" {i}. [{rec['priority'].upper()}] {rec['action']} (+{rec['impact']} pts)")
print()
return 0 if score >= 60 else 1
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,308 @@
## Operation: Check LICENSE File
Validate LICENSE file presence, format, and consistency with plugin metadata.
### Parameters from $ARGUMENTS
- **path**: Target plugin/marketplace path (required)
- **expected**: Expected license type (optional, reads from plugin.json if not provided)
- **strict**: Enable strict validation mode (optional, default: false)
- **check-consistency**: Verify consistency with plugin.json (optional, default: true)
### LICENSE Requirements
**File Presence**:
- LICENSE or LICENSE.txt in plugin root
- Also accept: LICENSE.md, COPYING, COPYING.txt
**OSI-Approved Licenses** (recommended):
- MIT License
- Apache License 2.0
- GNU General Public License (GPL) v2/v3
- BSD 2-Clause or 3-Clause License
- Mozilla Public License 2.0
- ISC License
- Creative Commons (for documentation)
**Validation Checks**:
1. **File exists**: LICENSE file present in root
2. **Valid content**: Contains recognized license text
3. **Complete**: Full license text, not just license name
4. **Consistency**: Matches license field in plugin.json
5. **OSI-approved**: Recognized open-source license
### Workflow
1. **Locate LICENSE File**
```
Check for files in plugin root (case-insensitive):
- LICENSE
- LICENSE.txt
- LICENSE.md
- COPYING
- COPYING.txt
- LICENCE (UK spelling)
If multiple found, prefer LICENSE over others
```
2. **Read Plugin Metadata**
```
Read plugin.json
Extract license field value
Store expected license type for comparison
```
3. **Execute License Detector**
```bash
Execute .scripts/license-detector.py with parameters:
- License file path
- Expected license type (from plugin.json)
- Strict mode flag
Script returns:
- detected_license: Identified license type
- confidence: 0-100 (match confidence)
- is_osi_approved: Boolean
- is_complete: Boolean (full text vs just name)
- matches_manifest: Boolean
- issues: Array of problems
```
4. **Validate License Content**
```
Check for license text patterns:
- MIT: "Permission is hereby granted, free of charge..."
- Apache 2.0: "Licensed under the Apache License, Version 2.0"
- GPL-3.0: "GNU GENERAL PUBLIC LICENSE Version 3"
- BSD-2-Clause: "Redistribution and use in source and binary forms"
Detect incomplete licenses:
- Just "MIT" or "MIT License" (missing full text)
- Just "Apache 2.0" (missing full text)
- Links to license without including text
```
5. **Check Consistency**
```
Compare detected license with plugin.json:
- Exact match: ✅ PASS
- Close match (e.g., "MIT" vs "MIT License"): ⚠️ WARNING
- Mismatch: ❌ ERROR
- Not specified in plugin.json: ⚠️ WARNING
Normalize license names for comparison:
- "MIT License" == "MIT"
- "Apache-2.0" == "Apache License 2.0"
- "GPL-3.0" == "GNU GPL v3"
```
6. **Verify OSI Approval**
```
Check against OSI-approved license list:
- MIT: ✅ Approved
- Apache-2.0: ✅ Approved
- GPL-2.0, GPL-3.0: ✅ Approved
- BSD-2-Clause, BSD-3-Clause: ✅ Approved
- Proprietary: ❌ Not approved
- Custom/Unknown: ⚠️ Review required
```
7. **Format Output**
```
Display:
- ✅/❌ File presence
- Detected license type
- OSI approval status
- Consistency with plugin.json
- Completeness (full text vs name only)
- Issues and recommendations
```
### Examples
```bash
# Check LICENSE with defaults (reads expected from plugin.json)
/documentation-validation license path:.
# Check with explicit expected license
/documentation-validation license path:. expected:MIT
# Strict validation (requires full license text)
/documentation-validation license path:. strict:true
# Skip consistency check (only validate file)
/documentation-validation license path:. check-consistency:false
# Check specific plugin
/documentation-validation license path:/path/to/plugin expected:Apache-2.0
```
### Error Handling
**Error: LICENSE file not found**
```
❌ CRITICAL: LICENSE file not found in <path>
Remediation:
1. Create LICENSE file in plugin root directory
2. Include full license text (not just the name)
3. Use an OSI-approved open-source license (MIT recommended)
4. Ensure license field in plugin.json matches LICENSE file
Recommended licenses for plugins:
- MIT: Simple, permissive (most common)
- Apache 2.0: Permissive with patent grant
- GPL-3.0: Copyleft (requires derivatives to use same license)
- BSD-3-Clause: Permissive, similar to MIT
Full license texts available at: https://choosealicense.com/
This is a BLOCKING issue - plugin cannot be submitted without a LICENSE.
```
**Error: Incomplete license text**
```
⚠️ WARNING: LICENSE file contains only license name, not full text
Current content: "MIT License"
Required: Full MIT License text
The LICENSE file should contain the complete license text, not just the name.
For MIT License, include:
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction...
[full license text]
Get full text: https://opensource.org/licenses/MIT
```
**Error: License mismatch with plugin.json**
```
❌ ERROR: LICENSE file does not match plugin.json declaration
plugin.json declares: "Apache-2.0"
LICENSE file contains: "MIT License"
Remediation:
1. Update plugin.json to declare "MIT" license, OR
2. Replace LICENSE file with Apache 2.0 license text
Consistency is required - both files must specify the same license.
```
**Error: Non-OSI-approved license**
```
❌ ERROR: License is not OSI-approved
Detected license: "Proprietary" or "Custom License"
OpenPlugins marketplace requires OSI-approved open-source licenses.
Recommended licenses:
- MIT License (most permissive)
- Apache License 2.0
- GNU GPL v3
- BSD 3-Clause
Choose a license: https://choosealicense.com/
OSI-approved list: https://opensource.org/licenses
This is a BLOCKING issue - plugin cannot be submitted with proprietary license.
```
**Error: Unrecognized license**
```
⚠️ WARNING: Unable to identify license type
The LICENSE file content does not match known license patterns.
Possible issues:
- Custom or modified license (not allowed)
- Corrupted or incomplete license text
- Non-standard format
Remediation:
1. Use standard, unmodified license text from official source
2. Choose from OSI-approved licenses
3. Do not modify standard license text (except copyright holder)
4. Get standard text from https://choosealicense.com/
If using a valid OSI license, ensure text matches standard format exactly.
```
### Output Format
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
LICENSE VALIDATION RESULTS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
File: ✅ LICENSE found
License Type: <detected-license>
Confidence: <0-100>% ✅
OSI Approved: ✅ Yes
Complete Text: ✅ Yes (full license included)
Consistency Check:
plugin.json declares: "<license>"
LICENSE file contains: "<detected-license>"
Match: ✅ Consistent
Validation: ✅ PASS
Recommendations:
- License is valid and properly formatted
- Meets OpenPlugins requirements
- Ready for submission
Overall: <PASS|WARNINGS|FAIL>
```
### Integration
This operation is invoked by:
- `/documentation-validation license path:.` (direct)
- `/documentation-validation full-docs path:.` (as part of complete validation)
- `/validation-orchestrator comprehensive path:.` (via orchestrator)
Results contribute to documentation quality score:
- Present, valid, consistent: +5 points
- Present but issues: 0 points (with warnings)
- Missing: BLOCKING issue (-20 points)
### Common License Patterns
**MIT License Detection**:
```
Pattern: "Permission is hereby granted, free of charge"
Confidence: 95%+
```
**Apache 2.0 Detection**:
```
Pattern: "Licensed under the Apache License, Version 2.0"
Confidence: 95%+
```
**GPL-3.0 Detection**:
```
Pattern: "GNU GENERAL PUBLIC LICENSE" + "Version 3"
Confidence: 95%+
```
**BSD Detection**:
```
Pattern: "Redistribution and use in source and binary forms"
Confidence: 90%+
```
**Request**: $ARGUMENTS

View File

@@ -0,0 +1,193 @@
## Operation: Check README Completeness
Validate README.md completeness, structure, and quality against OpenPlugins standards.
### Parameters from $ARGUMENTS
- **path**: Target plugin/marketplace path (required)
- **sections**: Comma-separated required sections (optional, defaults to standard set)
- **min-length**: Minimum character count (optional, default: 500)
- **strict**: Enable strict validation mode (optional, default: false)
### README Requirements
**Required Sections** (case-insensitive matching):
1. **Overview/Description**: Plugin purpose and functionality
2. **Installation**: How to install and configure
3. **Usage**: How to use the plugin with examples
4. **Examples**: At least 2-3 concrete usage examples
5. **License**: License information or reference
**Quality Criteria**:
- Minimum 500 characters (configurable)
- No excessive placeholder text
- Proper markdown formatting
- Working links (if present)
- Code blocks properly formatted
### Workflow
1. **Locate README File**
```
Check for README.md in plugin root
If not found, check for README.txt or readme.md
If still not found, report critical error
```
2. **Execute README Checker Script**
```bash
Execute .scripts/readme-checker.py with parameters:
- File path to README.md
- Required sections list
- Minimum length threshold
- Strict mode flag
Script returns JSON with:
- sections_found: Array of detected sections
- sections_missing: Array of missing sections
- length: Character count
- quality_score: 0-100
- issues: Array of specific problems
```
3. **Analyze Results**
```
CRITICAL (blocking):
- README.md file missing
- Length < 200 characters
- Missing 3+ required sections
WARNING (should fix):
- Length < 500 characters
- Missing 1-2 required sections
- Missing examples section
RECOMMENDATION (nice to have):
- Add troubleshooting section
- Expand examples
- Add badges or visual elements
```
4. **Calculate Section Score**
```
score = 100
score -= (missing_required_sections × 15)
score -= (length < 500) ? 10 : 0
score -= (no_examples) ? 15 : 0
score = max(0, score)
```
5. **Format Output**
```
Display:
- ✅/❌ File presence
- ✅/⚠️/❌ Each required section
- Length statistics
- Quality score
- Specific improvement recommendations
```
### Examples
```bash
# Check README with defaults
/documentation-validation readme path:.
# Check with custom sections
/documentation-validation readme path:./my-plugin sections:"overview,installation,usage,examples,contributing,license"
# Strict validation with higher standards
/documentation-validation readme path:. min-length:1000 strict:true
# Check specific plugin
/documentation-validation readme path:/path/to/plugin sections:"overview,usage,license"
```
### Error Handling
**Error: README.md not found**
```
❌ CRITICAL: README.md file not found in <path>
Remediation:
1. Create README.md in plugin root directory
2. Include required sections: Overview, Installation, Usage, Examples, License
3. Ensure minimum 500 characters of meaningful content
4. See https://github.com/dhofheinz/open-plugins/blob/main/README.md for example
This is a BLOCKING issue - plugin cannot be submitted without README.
```
**Error: README too short**
```
⚠️ WARNING: README.md is only <X> characters (minimum: 500)
Current length: <X> characters
Required: 500 characters minimum
Gap: <500-X> characters
Remediation:
- Expand installation instructions with examples
- Add 2-3 usage examples with code blocks
- Include configuration options
- Add troubleshooting section
```
**Error: Missing required sections**
```
❌ ERROR: Missing <N> required sections
Missing sections:
- Installation: How to install the plugin
- Examples: At least 2 concrete usage examples
- License: License information or reference to LICENSE file
Remediation:
Add each missing section with meaningful content.
See CONTRIBUTING.md for section requirements.
```
### Output Format
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
README VALIDATION RESULTS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
File: ✅ README.md found
Required Sections:
✅ Overview/Description
✅ Installation
✅ Usage
⚠️ Examples (found 1, recommended: 3+)
✅ License
Length: <X> characters (minimum: 500) ✅
Quality Score: <0-100>/100
Issues Found: <N>
Critical (blocking): <count>
Warnings (should fix): <count>
Recommendations: <count>
Top Recommendations:
1. Add 2 more usage examples with code blocks [+15 pts]
2. Expand installation section with configuration options [+5 pts]
3. Include troubleshooting section [+5 pts]
Overall: <PASS|WARNINGS|FAIL>
```
### Integration
This operation is invoked by:
- `/documentation-validation readme path:.` (direct)
- `/documentation-validation full-docs path:.` (as part of complete validation)
- `/validation-orchestrator comprehensive path:.` (via orchestrator)
Results feed into quality-analysis scoring system.
**Request**: $ARGUMENTS

View File

@@ -0,0 +1,533 @@
## Operation: Full Documentation Validation
Execute comprehensive documentation validation workflow covering all documentation aspects.
### Parameters from $ARGUMENTS
- **path**: Target plugin/marketplace path (required)
- **detailed**: Include detailed sub-reports (optional, default: true)
- **fix-suggestions**: Generate actionable improvement suggestions (optional, default: true)
- **format**: Output format (text|json|markdown) (optional, default: text)
### Full Documentation Workflow
This operation orchestrates all documentation validation sub-operations to provide
a complete documentation quality assessment.
### Workflow
1. **Initialize Validation Context**
```
Create validation context:
- Target path
- Timestamp
- Validation mode: comprehensive
- Results storage structure
Prepare for aggregating results from:
- README validation
- CHANGELOG validation
- LICENSE validation
- Examples validation
```
2. **Execute README Validation**
```
Invoke: check-readme.md operation
Parameters:
- path: <target-path>
- sections: default required sections
- min-length: 500
Capture results:
- README present: Boolean
- Sections found: Array
- Sections missing: Array
- Length: Integer
- Score: 0-100
- Issues: Array
```
3. **Execute CHANGELOG Validation**
```
Invoke: validate-changelog.md operation
Parameters:
- file: CHANGELOG.md
- format: keepachangelog
- require-unreleased: true
Capture results:
- CHANGELOG present: Boolean
- Format compliance: 0-100%
- Version entries: Array
- Issues: Array
- Score: 0-100
```
4. **Execute LICENSE Validation**
```
Invoke: check-license.md operation
Parameters:
- path: <target-path>
- check-consistency: true
Capture results:
- LICENSE present: Boolean
- License type: String
- OSI approved: Boolean
- Consistent with manifest: Boolean
- Issues: Array
- Score: 0-100
```
5. **Execute Examples Validation**
```
Invoke: validate-examples.md operation
Parameters:
- path: <target-path>
- no-placeholders: true
- recursive: true
Capture results:
- Files checked: Integer
- Examples found: Integer
- Placeholders detected: Integer
- Quality score: 0-100
- Issues: Array
```
6. **Aggregate Results**
```
Calculate overall documentation score:
weights = {
readme: 40%, # Most important
examples: 30%, # Critical for usability
license: 20%, # Required for submission
changelog: 10% # Recommended but not critical
}
overall_score = (
readme_score × 0.40 +
examples_score × 0.30 +
license_score × 0.20 +
changelog_score × 0.10
)
Round to integer: 0-100
```
7. **Categorize Issues by Priority**
```
CRITICAL (P0 - Blocking):
- README.md missing
- LICENSE file missing
- README < 200 characters
- Non-OSI-approved license
- License mismatch with manifest
IMPORTANT (P1 - Should Fix):
- README missing 2+ required sections
- README < 500 characters
- No examples in README
- 5+ placeholder patterns
- CHANGELOG has format errors
RECOMMENDED (P2 - Nice to Have):
- CHANGELOG missing
- README missing optional sections
- < 3 examples
- Minor placeholder patterns
```
8. **Generate Improvement Roadmap**
```
Create prioritized action plan:
For each issue:
- Identify impact on overall score
- Estimate effort (Low/Medium/High)
- Calculate score improvement
- Generate specific remediation steps
Sort by: Priority → Score Impact → Effort
Example:
1. [P0] Add LICENSE file → +20 pts → 15 min
2. [P1] Expand README to 500+ chars → +10 pts → 30 min
3. [P1] Add 2 usage examples → +15 pts → 20 min
4. [P2] Create CHANGELOG.md → +10 pts → 15 min
```
9. **Determine Publication Readiness**
```
Publication readiness determination:
READY (90-100):
- All critical requirements met
- High-quality documentation
- No blocking issues
- Immediate submission recommended
READY WITH MINOR IMPROVEMENTS (75-89):
- Critical requirements met
- Some recommended improvements
- Can submit, but improvements increase quality
- Suggested: Address P1 issues before submission
NEEDS WORK (60-74):
- Critical requirements met
- Several important issues
- Should address P1 issues before submission
- Documentation needs expansion
NOT READY (<60):
- Critical issues present
- Insufficient documentation quality
- Must address P0 and P1 issues
- Submission will be rejected
```
10. **Format Output**
```
Based on format parameter:
- text: Human-readable report
- json: Structured JSON for automation
- markdown: Formatted markdown report
```
### Examples
```bash
# Full documentation validation with defaults
/documentation-validation full-docs path:.
# With detailed sub-reports
/documentation-validation full-docs path:. detailed:true
# JSON output for automation
/documentation-validation full-docs path:. format:json
# Without fix suggestions (faster)
/documentation-validation full-docs path:. fix-suggestions:false
# Validate specific plugin
/documentation-validation full-docs path:/path/to/plugin
```
### Error Handling
**Error: Multiple critical issues**
```
❌ CRITICAL: Multiple blocking documentation issues
Documentation Score: <score>/100 ⚠️
BLOCKING ISSUES (<count>):
1. README.md not found
→ Create README.md with required sections
→ Minimum 500 characters
→ Include Overview, Installation, Usage, Examples, License
2. LICENSE file not found
→ Create LICENSE file with OSI-approved license
→ MIT License recommended
→ Must match plugin.json license field
3. License mismatch
→ plugin.json declares "Apache-2.0"
→ LICENSE file contains "MIT"
→ Update one to match the other
IMPORTANT ISSUES (<count>):
- README missing Examples section
- No code examples found
- CHANGELOG.md recommended
YOUR NEXT STEPS:
1. Add LICENSE file (CRITICAL - 15 minutes)
2. Create comprehensive README.md (CRITICAL - 30 minutes)
3. Add 3 usage examples (IMPORTANT - 20 minutes)
After addressing critical issues, revalidate with:
/documentation-validation full-docs path:.
```
**Error: Documentation too sparse**
```
⚠️ WARNING: Documentation exists but is too sparse
Documentation Score: 65/100 ⚠️
Your documentation meets minimum requirements but needs expansion
for professional quality.
AREAS NEEDING IMPROVEMENT:
1. README is only 342 characters (minimum: 500)
→ Expand installation instructions
→ Add more detailed usage examples
→ Include troubleshooting section
2. Only 1 example found (recommended: 3+)
→ Add basic usage example
→ Add advanced example
→ Add configuration example
3. CHANGELOG missing
→ Create CHANGELOG.md
→ Use Keep a Changelog format
→ Document version 1.0.0 features
IMPACT:
Current: 65/100 (Fair)
After improvements: ~85/100 (Good)
Time investment: ~45 minutes
Quality improvement: +20 points
```
### Output Format
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
COMPREHENSIVE DOCUMENTATION VALIDATION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Target: <path>
Type: <marketplace|plugin>
Timestamp: <YYYY-MM-DD HH:MM:SS>
OVERALL DOCUMENTATION SCORE: <0-100>/100 <⭐⭐⭐⭐⭐>
Rating: <Excellent|Good|Fair|Needs Improvement|Poor>
Publication Ready: <Yes|Yes with improvements|Needs work|No>
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
COMPONENT SCORES
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
README (Weight: 40%)
Score: <0-100>/100 ✅
Status: ✅ Complete and comprehensive
Sections: <N>/5 required sections found
Length: <N> characters (minimum: 500) ✅
Issues: None
EXAMPLES (Weight: 30%)
Score: <0-100>/100 ⚠️
Status: ⚠️ Could be improved
Examples found: <N> (recommended: 3+)
Placeholders: <N> detected
Issues: <N> placeholder patterns found
LICENSE (Weight: 20%)
Score: <0-100>/100 ✅
Status: ✅ Valid and consistent
Type: MIT License
OSI Approved: ✅ Yes
Consistency: ✅ Matches plugin.json
Issues: None
CHANGELOG (Weight: 10%)
Score: <0-100>/100 ⚠️
Status: ⚠️ Missing (recommended but not required)
Format: N/A
Versions: 0
Issues: CHANGELOG.md not found
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ISSUES SUMMARY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Critical (P0 - Blocking): <count>
Important (P1 - Should Fix): <count>
Recommended (P2 - Nice to Have): <count>
CRITICAL ISSUES:
[None - Ready for submission] ✅
IMPORTANT ISSUES:
⚠️ 1. Add 2 more usage examples to README
Impact: +15 points
Effort: Low (20 minutes)
⚠️ 2. Replace 3 placeholder patterns in examples
Impact: +10 points
Effort: Low (10 minutes)
RECOMMENDATIONS:
💡 1. Create CHANGELOG.md for version tracking
Impact: +10 points
Effort: Low (15 minutes)
💡 2. Add troubleshooting section to README
Impact: +5 points
Effort: Low (15 minutes)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
IMPROVEMENT ROADMAP
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Current Score: <score>/100
Target Score: 90/100 (Excellent - Publication Ready)
Gap: <gap> points
RECOMMENDED ACTIONS (to reach 90+):
1. [+15 pts] Add usage examples
Priority: High
Effort: 20 minutes
Description:
- Add 2 more concrete usage examples to README
- Include basic, intermediate, and advanced scenarios
- Use real plugin commands and parameters
2. [+10 pts] Clean up placeholder patterns
Priority: Medium
Effort: 10 minutes
Description:
- Replace "YOUR_VALUE" patterns with concrete examples
- Complete or remove TODO markers
- Use template syntax (${VAR}) for user-provided values
3. [+10 pts] Create CHANGELOG.md
Priority: Medium
Effort: 15 minutes
Description:
- Use Keep a Changelog format
- Document version 1.0.0 initial release
- Add [Unreleased] section for future changes
AFTER IMPROVEMENTS:
Projected Score: ~90/100 ⭐⭐⭐⭐⭐
Time Investment: ~45 minutes
Status: Excellent - Ready for submission
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PUBLICATION READINESS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Status: ✅ READY WITH MINOR IMPROVEMENTS
Your plugin documentation meets all critical requirements and is ready
for submission to OpenPlugins marketplace. The recommended improvements
above will increase quality score and provide better user experience.
✅ Strengths:
- Comprehensive README with all required sections
- Valid OSI-approved license (MIT)
- License consistent with plugin.json
- Good documentation structure
⚠️ Improvement Opportunities:
- Add more usage examples for better user onboarding
- Create CHANGELOG for version tracking
- Clean up minor placeholder patterns
NEXT STEPS:
1. (Optional) Address recommended improvements (~45 min)
2. Run validation again to verify improvements
3. Submit to OpenPlugins marketplace
Command to revalidate:
/documentation-validation full-docs path:.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
### Integration
This operation is the primary entry point for complete documentation validation:
**Invoked by**:
- `/documentation-validation full-docs path:.` (direct invocation)
- `/validation-orchestrator comprehensive path:.` (as part of full plugin validation)
- marketplace-validator agent (automatic documentation assessment)
**Invokes sub-operations**:
- `/documentation-validation readme path:.`
- `/documentation-validation changelog file:CHANGELOG.md`
- `/documentation-validation license path:.`
- `/documentation-validation examples path:.`
**Feeds results to**:
- `/quality-analysis full-analysis` (for overall quality scoring)
- `/quality-analysis generate-report` (for report generation)
### JSON Output Format
When `format:json` is specified:
```json
{
"validation_type": "full-documentation",
"target_path": "/path/to/plugin",
"timestamp": "2025-01-15T10:30:00Z",
"overall_score": 85,
"rating": "Good",
"publication_ready": "yes_with_improvements",
"components": {
"readme": {
"score": 90,
"status": "pass",
"present": true,
"sections_found": 5,
"sections_missing": 0,
"length": 1234,
"issues": []
},
"changelog": {
"score": 70,
"status": "warning",
"present": true,
"compliance": 70,
"issues": ["Invalid version header format"]
},
"license": {
"score": 100,
"status": "pass",
"present": true,
"type": "MIT",
"osi_approved": true,
"consistent": true,
"issues": []
},
"examples": {
"score": 75,
"status": "warning",
"examples_found": 2,
"placeholders_detected": 3,
"issues": ["Placeholder patterns detected"]
}
},
"issues": {
"critical": [],
"important": [
{
"component": "examples",
"message": "Add 2 more usage examples",
"impact": 15,
"effort": "low"
}
],
"recommended": [
{
"component": "readme",
"message": "Add troubleshooting section",
"impact": 5,
"effort": "low"
}
]
},
"improvement_roadmap": [
{
"action": "Add usage examples",
"points": 15,
"priority": "high",
"effort": "20 minutes"
}
],
"projected_score_after_improvements": 95
}
```
**Request**: $ARGUMENTS

View File

@@ -0,0 +1,99 @@
---
description: Validate documentation completeness, format, and quality for plugins and marketplaces
---
You are the Documentation Validation coordinator, ensuring comprehensive and high-quality documentation.
## Your Mission
Parse `$ARGUMENTS` to determine the requested documentation validation operation and route to the appropriate sub-command.
## Available Operations
Parse the first word of `$ARGUMENTS` to determine which operation to execute:
- **readme** → Read `.claude/commands/documentation-validation/check-readme.md`
- **changelog** → Read `.claude/commands/documentation-validation/validate-changelog.md`
- **license** → Read `.claude/commands/documentation-validation/check-license.md`
- **examples** → Read `.claude/commands/documentation-validation/validate-examples.md`
- **full-docs** → Read `.claude/commands/documentation-validation/full-documentation.md`
## Argument Format
```
/documentation-validation <operation> [parameters]
```
### Examples
```bash
# Check README completeness
/documentation-validation readme path:. sections:"overview,installation,usage,examples"
# Validate CHANGELOG format
/documentation-validation changelog file:CHANGELOG.md format:keepachangelog
# Check LICENSE file
/documentation-validation license path:. expected:MIT
# Validate example quality
/documentation-validation examples path:. no-placeholders:true
# Run complete documentation validation
/documentation-validation full-docs path:.
```
## Documentation Standards
**README.md Requirements**:
- Overview/Description section
- Installation instructions
- Usage examples (minimum 2)
- Configuration options (if applicable)
- License information
- Length: Minimum 500 characters
**CHANGELOG.md Requirements**:
- Keep a Changelog format
- Version headers ([X.Y.Z] - YYYY-MM-DD)
- Change categories: Added, Changed, Deprecated, Removed, Fixed, Security
- Unreleased section for upcoming changes
**LICENSE Requirements**:
- LICENSE or LICENSE.txt file present
- Valid OSI-approved license
- License matches plugin.json declaration
**Examples Requirements**:
- No placeholder text (TODO, FIXME, XXX, placeholder)
- Complete, runnable examples
- Real values, not dummy data
- Proper formatting and syntax
## Quality Scoring
Documentation contributes to overall quality score:
- Complete README: +15 points
- CHANGELOG present: +10 points
- LICENSE valid: +5 points
- Quality examples: +10 points
## Error Handling
If the operation is not recognized:
1. List all available documentation operations
2. Show documentation standards
3. Provide improvement suggestions
## Base Directory
Base directory for this skill: `.claude/commands/documentation-validation/`
## Your Task
1. Parse `$ARGUMENTS` to extract operation and parameters
2. Read the corresponding operation file
3. Execute documentation validation checks
4. Return detailed findings with specific improvement guidance
**Current Request**: $ARGUMENTS

View File

@@ -0,0 +1,286 @@
## Operation: Validate CHANGELOG Format
Validate CHANGELOG.md format compliance with "Keep a Changelog" standard.
### Parameters from $ARGUMENTS
- **file**: Path to CHANGELOG file (optional, default: CHANGELOG.md)
- **format**: Expected format (optional, default: keepachangelog)
- **strict**: Enable strict validation (optional, default: false)
- **require-unreleased**: Require [Unreleased] section (optional, default: true)
### CHANGELOG Requirements
**Keep a Changelog Format** (https://keepachangelog.com/):
```markdown
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- New features not yet released
## [1.0.0] - 2025-01-15
### Added
- Initial release feature
### Changed
- Modified behavior
### Fixed
- Bug fixes
```
**Required Elements**:
1. **Title**: "Changelog" or "Change Log"
2. **Version Headers**: `## [X.Y.Z] - YYYY-MM-DD` format
3. **Change Categories**: Added, Changed, Deprecated, Removed, Fixed, Security
4. **Unreleased Section**: `## [Unreleased]` for upcoming changes
5. **Chronological Order**: Newest versions first
**Valid Change Categories**:
- **Added**: New features
- **Changed**: Changes in existing functionality
- **Deprecated**: Soon-to-be removed features
- **Removed**: Removed features
- **Fixed**: Bug fixes
- **Security**: Security vulnerability fixes
### Workflow
1. **Locate CHANGELOG File**
```
Check for CHANGELOG.md in plugin root
Also check: CHANGELOG, CHANGELOG.txt, changelog.md, HISTORY.md
If not found, report as missing (WARNING, not CRITICAL)
```
2. **Execute CHANGELOG Validator**
```bash
Execute .scripts/changelog-validator.sh with parameters:
- File path to CHANGELOG
- Expected format (keepachangelog)
- Strict mode flag
- Require unreleased flag
Script returns:
- has_title: Boolean
- has_unreleased: Boolean
- version_headers: Array of version entries
- categories_used: Array of change categories
- issues: Array of format violations
- compliance_score: 0-100
```
3. **Validate Version Headers**
```
For each version header:
- Check format: ## [X.Y.Z] - YYYY-MM-DD
- Validate semantic version (X.Y.Z)
- Validate date format (YYYY-MM-DD)
- Check chronological order (newest first)
Common violations:
- Missing brackets: ## 1.0.0 - 2025-01-15 (should be [1.0.0])
- Wrong date format: ## [1.0.0] - 01/15/2025
- Invalid semver: ## [1.0] - 2025-01-15
```
4. **Validate Change Categories**
```
For each version section:
- Check for valid category headers (### Added, ### Fixed, etc.)
- Warn if no categories used
- Recommend appropriate categories
Invalid category examples:
- "### New Features" (should be "### Added")
- "### Bugs" (should be "### Fixed")
- "### Updates" (should be "### Changed")
```
5. **Calculate Compliance Score**
```
score = 100
score -= (!has_title) ? 10 : 0
score -= (!has_unreleased) ? 15 : 0
score -= (invalid_version_headers × 10)
score -= (invalid_categories × 5)
score -= (wrong_date_format × 5)
score = max(0, score)
```
6. **Format Output**
```
Display:
- ✅/⚠️/❌ File presence
- ✅/❌ Format compliance
- ✅/⚠️ Version headers
- ✅/⚠️ Change categories
- Compliance score
- Specific violations
- Improvement recommendations
```
### Examples
```bash
# Validate default CHANGELOG.md
/documentation-validation changelog file:CHANGELOG.md
# Validate with custom path
/documentation-validation changelog file:./HISTORY.md
# Strict validation (all elements required)
/documentation-validation changelog file:CHANGELOG.md strict:true
# Don't require Unreleased section
/documentation-validation changelog file:CHANGELOG.md require-unreleased:false
# Part of full documentation check
/documentation-validation full-docs path:.
```
### Error Handling
**Error: CHANGELOG not found**
```
⚠️ WARNING: CHANGELOG.md not found in <path>
Remediation:
1. Create CHANGELOG.md in plugin root directory
2. Use "Keep a Changelog" format (https://keepachangelog.com/)
3. Include [Unreleased] section for upcoming changes
4. Document version history with proper headers
Example:
# Changelog
## [Unreleased]
### Added
- Features in development
## [1.0.0] - 2025-01-15
### Added
- Initial release
Note: CHANGELOG is recommended but not required for initial submission.
It becomes important for version updates.
```
**Error: Invalid version header format**
```
❌ ERROR: Invalid version header format detected
Invalid headers found:
- Line 10: "## 1.0.0 - 2025-01-15" (missing brackets)
- Line 25: "## [1.0] - 01/15/2025" (invalid semver and date format)
Correct format:
## [X.Y.Z] - YYYY-MM-DD
Examples:
- ## [1.0.0] - 2025-01-15
- ## [2.1.3] - 2024-12-20
- ## [0.1.0] - 2024-11-05
Remediation:
1. Add brackets around version numbers: [1.0.0]
2. Use semantic versioning: MAJOR.MINOR.PATCH
3. Use ISO date format: YYYY-MM-DD
```
**Error: Missing Unreleased section**
```
⚠️ WARNING: Missing [Unreleased] section
The Keep a Changelog format recommends an [Unreleased] section for tracking
upcoming changes before they're officially released.
Add to top of CHANGELOG (after title):
## [Unreleased]
### Added
- Features in development
### Changed
- Planned changes
```
**Error: Invalid change categories**
```
⚠️ WARNING: Non-standard change categories detected
Invalid categories found:
- "### New Features" (should be "### Added")
- "### Bug Fixes" (should be "### Fixed")
- "### Updates" (should be "### Changed")
Valid categories:
- Added: New features
- Changed: Changes in existing functionality
- Deprecated: Soon-to-be removed features
- Removed: Removed features
- Fixed: Bug fixes
- Security: Security vulnerability fixes
Remediation:
Replace non-standard categories with Keep a Changelog categories.
```
### Output Format
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CHANGELOG VALIDATION RESULTS
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
File: ✅ CHANGELOG.md found
Format: Keep a Changelog
Compliance: <0-100>% ✅/⚠️/❌
Structure:
✅ Title present
✅ [Unreleased] section present
✅ Version headers formatted correctly
✅ Change categories valid
Version Entries: <count>
- [1.0.0] - 2025-01-15 ✅
- [0.2.0] - 2024-12-20 ✅
- [0.1.0] - 2024-11-05 ✅
Change Categories Used:
✅ Added (3 versions)
✅ Changed (2 versions)
✅ Fixed (3 versions)
Issues Found: <N>
Violations:
<List specific issues if any>
Recommendations:
1. Add Security category for vulnerability fixes
2. Expand [Unreleased] section with upcoming features
3. Add links to version comparison (optional)
Overall: <PASS|WARNINGS|FAIL>
```
### Integration
This operation is invoked by:
- `/documentation-validation changelog file:CHANGELOG.md` (direct)
- `/documentation-validation full-docs path:.` (as part of complete validation)
- `/validation-orchestrator comprehensive path:.` (via orchestrator)
Results contribute to documentation quality score:
- Present and compliant: +10 points
- Present but non-compliant: +5 points
- Missing: 0 points (warning but not blocking)
**Request**: $ARGUMENTS

View File

@@ -0,0 +1,335 @@
## Operation: Validate Example Quality
Validate example code quality, detecting placeholders and ensuring examples are complete and runnable.
### Parameters from $ARGUMENTS
- **path**: Target plugin/marketplace path (required)
- **no-placeholders**: Strict placeholder enforcement (optional, default: true)
- **recursive**: Check all markdown and code files recursively (optional, default: true)
- **extensions**: File extensions to check (optional, default: "md,txt,json,sh,py,js")
### Example Quality Requirements
**Complete Examples**:
- Concrete, runnable code or commands
- Real values, not placeholder text
- Proper syntax and formatting
- Context and explanations
- Expected output or results
**No Placeholder Patterns**:
- **TODO**: `TODO`, `@TODO`, `// TODO:`
- **FIXME**: `FIXME`, `@FIXME`, `// FIXME:`
- **XXX**: `XXX`, `@XXX`, `// XXX:`
- **Placeholders**: `placeholder`, `PLACEHOLDER`, `your-value-here`, `<your-value>`, `[YOUR-VALUE]`
- **Generic**: `example`, `sample`, `test`, `dummy`, `foo`, `bar`, `baz`
- **User substitution**: `<username>`, `<your-email>`, `your-api-key`, `INSERT-HERE`
**Acceptable Patterns** (not placeholders):
- Template variables: `{{variable}}`, `${variable}`, `$VARIABLE`
- Documentation examples: `<name>`, `[optional]` in usage syntax
- Actual values: Real plugin names, real commands, concrete examples
### Workflow
1. **Identify Files to Validate**
```
Scan plugin directory for documentation files:
- README.md (primary source)
- CONTRIBUTING.md
- docs/**/*.md
- examples/**/*
- *.sh, *.py, *.js (example scripts)
If recursive:false, only check README.md
```
2. **Execute Example Validator**
```bash
Execute .scripts/example-validator.sh with parameters:
- Path to plugin directory
- No-placeholders flag
- Recursive flag
- File extensions to check
Script returns:
- files_checked: Count of files analyzed
- placeholders_found: Array of placeholder instances
- files_with_issues: Array of files containing placeholders
- example_count: Number of code examples found
- quality_score: 0-100
```
3. **Detect Placeholder Patterns**
```bash
Search for patterns (case-insensitive):
# TODO/FIXME/XXX markers
grep -iE '(TODO|FIXME|XXX|HACK)[:)]' <files>
# Placeholder text
grep -iE '(placeholder|your-.*-here|<your-|INSERT.?HERE)' <files>
# Generic dummy values
grep -iE '\b(foo|bar|baz|dummy|sample|test)\b' <files>
# User substitution patterns
grep -iE '(<username>|<email>|<api-key>|YOUR_[A-Z_]+)' <files>
# Exclude:
- Comments explaining placeholders
- Documentation of template syntax
- Proper template variables ({{x}}, ${x})
```
4. **Analyze Code Blocks**
```
For each code block in markdown:
- Extract language and content
- Check for placeholder patterns
- Verify syntax highlighting specified
- Ensure examples are complete
Example extraction:
```bash
/plugin install my-plugin@marketplace ✅ Concrete
/plugin install <plugin-name> ⚠️ Documentation (acceptable)
/plugin install YOUR_PLUGIN ❌ Placeholder
```
```
5. **Count and Categorize Examples**
```
Count examples by type:
- Command examples: /plugin install ...
- Configuration examples: JSON snippets
- Code examples: Script samples
- Usage examples: Real-world scenarios
Quality criteria:
- At least 2-3 concrete examples
- Examples cover primary use cases
- Examples are copy-pasteable
```
6. **Calculate Quality Score**
```
score = 100
score -= (placeholder_instances × 10) # -10 per placeholder
score -= (todo_markers × 5) # -5 per TODO/FIXME
score -= (example_count < 2) ? 20 : 0 # -20 if < 2 examples
score -= (incomplete_examples × 15) # -15 per incomplete example
score = max(0, score)
```
7. **Format Output**
```
Display:
- Files checked count
- Examples found count
- Placeholders detected
- Quality score
- Specific issues with file/line references
- Improvement recommendations
```
### Examples
```bash
# Validate examples with strict placeholder checking (default)
/documentation-validation examples path:.
# Check only README.md (non-recursive)
/documentation-validation examples path:. recursive:false
# Allow placeholders (lenient mode)
/documentation-validation examples path:. no-placeholders:false
# Check specific file extensions
/documentation-validation examples path:. extensions:"md,sh,py"
# Strict validation of examples directory
/documentation-validation examples path:./examples no-placeholders:true recursive:true
```
### Error Handling
**Error: Placeholders detected**
```
⚠️ WARNING: Placeholder patterns detected in examples
Placeholders found: <N> instances across <M> files
README.md:
- Line 45: /plugin install YOUR_PLUGIN_NAME
^ Should be concrete plugin name
- Line 67: API_KEY=your-api-key-here
^ Should be removed or use template syntax
examples/usage.sh:
- Line 12: # TODO: Add authentication example
^ Complete example or remove TODO
Remediation:
1. Replace "YOUR_PLUGIN_NAME" with actual plugin name
2. Use template syntax for user-provided values: ${API_KEY}
3. Remove TODO markers - complete examples or remove them
4. Provide concrete, copy-pasteable examples
Acceptable patterns:
- Template variables: ${VARIABLE}, {{variable}}
- Documentation syntax: <name> in usage descriptions
- Generic placeholders in template explanations
```
**Error: Too few examples**
```
⚠️ WARNING: Insufficient examples in documentation
Examples found: <N> (minimum recommended: 3)
README.md contains <N> code examples:
- Installation example ✅
- Basic usage ❌ Missing
- Advanced usage ❌ Missing
Remediation:
Add at least 2-3 concrete usage examples showing:
1. Basic usage (most common scenario)
2. Common configuration options
3. Advanced or specialized use case
Example structure:
```bash
# Basic usage
/my-plugin action param:value
# With options
/my-plugin action param:value option:true
# Advanced example
/my-plugin complex-action config:custom nested:value
```
Good examples are copy-pasteable and use real values.
```
**Error: Incomplete examples**
```
⚠️ WARNING: Incomplete or broken examples detected
Incomplete examples: <N>
README.md:
- Line 34: Code block with syntax error
- Line 56: Example missing expected output
- Line 78: Example truncated with "..."
Remediation:
1. Ensure all code examples are syntactically valid
2. Show expected output or results after examples
3. Complete truncated examples (no "..." placeholders)
4. Test examples before including in documentation
Example format:
```bash
# Command with description
/plugin install example-plugin@marketplace
# Expected output:
# ✓ Installing example-plugin@marketplace
# ✓ Plugin installed successfully
```
```
**Error: Generic dummy values**
```
⚠️ WARNING: Generic placeholder values detected
Generic values found:
- README.md:45 - "foo", "bar" used as example values
- examples/config.json:12 - "sample" as placeholder
While "foo/bar" are common in documentation, concrete examples
are more helpful for users.
Remediation:
Replace generic values with realistic examples:
- Instead of "foo", use actual plugin name
- Instead of "bar", use real parameter value
- Instead of "sample", use concrete example
Good: /my-plugin process file:README.md
Bad: /my-plugin process file:foo.txt
```
### Output Format
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EXAMPLE QUALITY VALIDATION
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Files Checked: <N>
Code Examples Found: <N>
Example Count by Type:
- Command examples: <N> ✅
- Configuration examples: <N> ✅
- Usage examples: <N> ⚠️ (recommend 3+)
Placeholder Detection:
TODO/FIXME markers: <N> ❌
Placeholder patterns: <N> ❌
Generic values (foo/bar): <N> ⚠️
Quality Score: <0-100>/100
Issues by File:
README.md: <N> issues
├─ Line 45: YOUR_PLUGIN_NAME (placeholder)
├─ Line 67: TODO marker
└─ Line 89: Generic "foo" value
examples/usage.sh: <N> issues
└─ Line 12: Incomplete example
Recommendations:
1. Replace <N> placeholder patterns with concrete values [+10 pts]
2. Complete or remove <N> TODO markers [+5 pts]
3. Add <N> more usage examples [+15 pts]
Overall: <PASS|WARNINGS|FAIL>
```
### Integration
This operation is invoked by:
- `/documentation-validation examples path:.` (direct)
- `/documentation-validation full-docs path:.` (as part of complete validation)
- `/validation-orchestrator comprehensive path:.` (via orchestrator)
Results contribute to documentation quality score:
- High-quality examples (90+): +10 points
- Some issues (60-89): +5 points
- Poor quality (<60): 0 points
- Missing examples: -10 points
### Special Cases
**Template Documentation**:
If the plugin provides templates or scaffolding, some placeholders
are acceptable when properly documented as template variables.
Example:
```markdown
The generated code includes template variables:
- {{PROJECT_NAME}} - Will be replaced with actual project name
- {{AUTHOR}} - Will be replaced with author information
```
This is acceptable because the placeholders are documented as
intentional template syntax.
**Request**: $ARGUMENTS