verify-context.sh 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #!/usr/bin/env bash
  2. # verify-context.sh - Validate context structure for Claude Code plugin
  3. # Exit codes: 0 (valid), 1 (invalid)
  4. set -euo pipefail
  5. # Colors for output
  6. RED='\033[0;31m'
  7. GREEN='\033[0;32m'
  8. YELLOW='\033[1;33m'
  9. NC='\033[0m' # No Color
  10. # Counters
  11. ERRORS=0
  12. WARNINGS=0
  13. # Get plugin root directory
  14. PLUGIN_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
  15. CONTEXT_DIR="${PLUGIN_ROOT}/context"
  16. MANIFEST_FILE="${PLUGIN_ROOT}/.context-manifest.json"
  17. echo "🔍 Verifying context structure..."
  18. echo ""
  19. # Function to report error
  20. error() {
  21. echo -e "${RED}✗ ERROR:${NC} $1"
  22. ((ERRORS++))
  23. }
  24. # Function to report warning
  25. warning() {
  26. echo -e "${YELLOW}⚠ WARNING:${NC} $1"
  27. ((WARNINGS++))
  28. }
  29. # Function to report success
  30. success() {
  31. echo -e "${GREEN}✓${NC} $1"
  32. }
  33. # Check 1: Context directory exists
  34. echo "Checking context directory..."
  35. if [[ ! -d "$CONTEXT_DIR" ]]; then
  36. error "Context directory not found: $CONTEXT_DIR"
  37. else
  38. success "Context directory exists"
  39. fi
  40. # Check 2: Required top-level categories exist
  41. echo ""
  42. echo "Checking required categories..."
  43. REQUIRED_CATEGORIES=(
  44. "core"
  45. "openagents-repo"
  46. "development"
  47. "ui"
  48. "content-creation"
  49. "data"
  50. "product"
  51. "learning"
  52. )
  53. for category in "${REQUIRED_CATEGORIES[@]}"; do
  54. if [[ ! -d "$CONTEXT_DIR/$category" ]]; then
  55. warning "Missing category: $category"
  56. else
  57. success "Category exists: $category"
  58. fi
  59. done
  60. # Check 3: Navigation files exist
  61. echo ""
  62. echo "Checking navigation files..."
  63. # Main navigation
  64. if [[ ! -f "$CONTEXT_DIR/navigation.md" ]]; then
  65. error "Missing main navigation.md"
  66. else
  67. success "Main navigation.md exists"
  68. # Validate navigation.md structure
  69. if ! grep -q "^# Context Navigation" "$CONTEXT_DIR/navigation.md"; then
  70. warning "navigation.md missing expected header"
  71. fi
  72. fi
  73. # Category navigation files
  74. for category in "${REQUIRED_CATEGORIES[@]}"; do
  75. NAV_FILE="$CONTEXT_DIR/$category/navigation.md"
  76. if [[ -d "$CONTEXT_DIR/$category" ]] && [[ ! -f "$NAV_FILE" ]]; then
  77. warning "Missing navigation.md in $category/"
  78. fi
  79. done
  80. # Check 4: Core standards exist
  81. echo ""
  82. echo "Checking core standards..."
  83. CORE_STANDARDS=(
  84. "core/standards/code-quality.md"
  85. "core/standards/documentation.md"
  86. "core/standards/test-coverage.md"
  87. )
  88. for standard in "${CORE_STANDARDS[@]}"; do
  89. if [[ ! -f "$CONTEXT_DIR/$standard" ]]; then
  90. warning "Missing core standard: $standard"
  91. else
  92. success "Found: $standard"
  93. fi
  94. done
  95. # Check 5: Validate .context-manifest.json
  96. echo ""
  97. echo "Checking .context-manifest.json..."
  98. if [[ ! -f "$MANIFEST_FILE" ]]; then
  99. warning ".context-manifest.json not found (run download-context.sh first)"
  100. else
  101. success ".context-manifest.json exists"
  102. # Validate JSON format
  103. if ! jq empty "$MANIFEST_FILE" 2>/dev/null; then
  104. error ".context-manifest.json is not valid JSON"
  105. else
  106. success ".context-manifest.json is valid JSON"
  107. # Check required fields
  108. REQUIRED_FIELDS=("version" "source" "updated_at" "categories")
  109. for field in "${REQUIRED_FIELDS[@]}"; do
  110. if ! jq -e ".$field" "$MANIFEST_FILE" >/dev/null 2>&1; then
  111. error ".context-manifest.json missing required field: $field"
  112. else
  113. success "Manifest has field: $field"
  114. fi
  115. done
  116. fi
  117. fi
  118. # Check 6: Validate context file metadata
  119. echo ""
  120. echo "Checking context file metadata..."
  121. CONTEXT_FILES=$(find "$CONTEXT_DIR" -name "*.md" -type f 2>/dev/null || true)
  122. CHECKED_FILES=0
  123. INVALID_FILES=0
  124. for file in $CONTEXT_FILES; do
  125. # Skip navigation files (they have different format)
  126. if [[ "$file" == *"/navigation.md" ]]; then
  127. continue
  128. fi
  129. ((CHECKED_FILES++))
  130. # Check for context metadata comment
  131. if ! head -n 1 "$file" | grep -q "^<!-- Context:"; then
  132. ((INVALID_FILES++))
  133. if [[ $INVALID_FILES -le 5 ]]; then
  134. warning "Missing context metadata: ${file#$CONTEXT_DIR/}"
  135. fi
  136. fi
  137. done
  138. if [[ $CHECKED_FILES -gt 0 ]]; then
  139. if [[ $INVALID_FILES -eq 0 ]]; then
  140. success "All $CHECKED_FILES context files have metadata"
  141. else
  142. warning "$INVALID_FILES of $CHECKED_FILES files missing metadata"
  143. fi
  144. fi
  145. # Check 7: Verify no broken internal links
  146. echo ""
  147. echo "Checking for broken internal links..."
  148. BROKEN_LINKS=0
  149. for file in $CONTEXT_FILES; do
  150. # Extract markdown links
  151. while IFS= read -r link; do
  152. # Skip external links
  153. if [[ "$link" =~ ^https?:// ]]; then
  154. continue
  155. fi
  156. # Resolve relative path
  157. FILE_DIR=$(dirname "$file")
  158. LINK_PATH="$FILE_DIR/$link"
  159. if [[ ! -f "$LINK_PATH" ]]; then
  160. ((BROKEN_LINKS++))
  161. if [[ $BROKEN_LINKS -le 5 ]]; then
  162. warning "Broken link in ${file#$CONTEXT_DIR/}: $link"
  163. fi
  164. fi
  165. done < <(grep -oP '\[.*?\]\(\K[^)]+' "$file" 2>/dev/null || true)
  166. done
  167. if [[ $BROKEN_LINKS -eq 0 ]]; then
  168. success "No broken internal links found"
  169. elif [[ $BROKEN_LINKS -gt 5 ]]; then
  170. warning "Found $BROKEN_LINKS broken links (showing first 5)"
  171. fi
  172. # Summary
  173. echo ""
  174. echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  175. echo "Summary:"
  176. echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  177. if [[ $ERRORS -eq 0 ]] && [[ $WARNINGS -eq 0 ]]; then
  178. echo -e "${GREEN}✓ Context structure is valid${NC}"
  179. exit 0
  180. elif [[ $ERRORS -eq 0 ]]; then
  181. echo -e "${YELLOW}⚠ Context structure is valid with $WARNINGS warnings${NC}"
  182. exit 0
  183. else
  184. echo -e "${RED}✗ Context structure has $ERRORS errors and $WARNINGS warnings${NC}"
  185. exit 1
  186. fi