validate-agent-structure.sh 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #!/bin/bash
  2. # Validates agent structure and dependencies
  3. set -e
  4. validate_agent() {
  5. local agent_file=$1
  6. local category
  7. local agent
  8. category=$(dirname "$agent_file" | xargs basename)
  9. agent=$(basename "$agent_file" .md)
  10. echo "Validating: $category/$agent"
  11. # Check frontmatter exists
  12. if ! grep -q "^---" "$agent_file"; then
  13. echo "❌ Missing frontmatter"
  14. return 1
  15. fi
  16. # Check required fields
  17. for field in id name description category type; do
  18. if ! grep -q "^$field:" "$agent_file"; then
  19. echo "❌ Missing required field: $field"
  20. return 1
  21. fi
  22. done
  23. # Extract category from frontmatter
  24. fm_category=$(grep "^category:" "$agent_file" | cut -d: -f2 | xargs)
  25. if [ "$fm_category" != "$category" ]; then
  26. echo "❌ Category mismatch: frontmatter says '$fm_category', file is in '$category'"
  27. return 1
  28. fi
  29. # Check prompt variants exist (model-specific only, not 'default')
  30. if grep -q "^variants:" "$agent_file"; then
  31. # Extract variants properly - only lines that are direct children of variants:
  32. variants=$(awk '/^variants:/{flag=1;next}/^[a-zA-Z]/{flag=0}flag && /^ - /{print $2}' "$agent_file")
  33. for variant in $variants; do
  34. # Skip 'default' - the agent file itself is the default
  35. [ "$variant" = "default" ] && continue
  36. variant_file=".opencode/prompts/$category/$agent/$variant.md"
  37. if [ ! -f "$variant_file" ]; then
  38. echo "⚠️ Missing variant: $variant_file"
  39. fi
  40. done
  41. fi
  42. # Check context dependencies exist
  43. if grep -q "^dependencies:" "$agent_file"; then
  44. # Extract context dependencies properly
  45. contexts=$(awk '/^dependencies:/{flag=1}/^[a-zA-Z]/{if(flag && !/^dependencies:/) flag=0}/^ context:/{ctx=1;next}/^ [a-zA-Z]/{ctx=0}flag && ctx && /^ - /{print $2}' "$agent_file")
  46. for context in $contexts; do
  47. context_file=".opencode/context/$context.md"
  48. if [ ! -f "$context_file" ]; then
  49. echo "⚠️ Missing context: $context_file"
  50. fi
  51. done
  52. fi
  53. # Check eval directory exists (optional)
  54. eval_dir="evals/agents/$category/$agent"
  55. if [ ! -d "$eval_dir" ]; then
  56. echo "⚠️ Missing eval directory: $eval_dir (optional but recommended)"
  57. fi
  58. echo "✅ Valid"
  59. return 0
  60. }
  61. # Main execution
  62. echo "Validating agent structure..."
  63. echo ""
  64. failed=0
  65. total=0
  66. # Validate all agents
  67. for category_dir in .opencode/agent/*/; do
  68. category=$(basename "$category_dir")
  69. # Skip subagents directory for now (has different structure)
  70. [ "$category" = "subagents" ] && continue
  71. for agent_file in "$category_dir"*.md; do
  72. [ -f "$agent_file" ] || continue
  73. [ "$(basename "$agent_file")" = "README.md" ] && continue
  74. total=$((total + 1))
  75. if ! validate_agent "$agent_file"; then
  76. failed=$((failed + 1))
  77. fi
  78. echo ""
  79. done
  80. done
  81. # Validate subagents separately (they have nested structure)
  82. if [ -d ".opencode/agent/subagents" ]; then
  83. for subcat_dir in .opencode/agent/subagents/*/; do
  84. for agent_file in "$subcat_dir"*.md; do
  85. [ -f "$agent_file" ] || continue
  86. [ "$(basename "$agent_file")" = "README.md" ] && continue
  87. total=$((total + 1))
  88. if ! validate_agent "$agent_file"; then
  89. failed=$((failed + 1))
  90. fi
  91. echo ""
  92. done
  93. done
  94. fi
  95. echo "========================================"
  96. echo "Validation complete: $((total - failed))/$total passed"
  97. echo "========================================"
  98. if [ $failed -gt 0 ]; then
  99. exit 1
  100. fi