sync-component-list.sh 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #!/usr/bin/env bash
  2. #############################################################################
  3. # Documentation Sync Validator
  4. # Validates that component counts in README.md match registry.json
  5. # Used in CI to detect when docs are out of sync
  6. #
  7. # For actual syncing, use the sync-docs.yml GitHub workflow which
  8. # leverages OpenCode to intelligently update documentation
  9. #############################################################################
  10. set -e
  11. # Colors
  12. RED='\033[0;31m'
  13. GREEN='\033[0;32m'
  14. YELLOW='\033[1;33m'
  15. BLUE='\033[0;34m'
  16. CYAN='\033[0;36m'
  17. BOLD='\033[1m'
  18. NC='\033[0m'
  19. # Configuration
  20. REGISTRY_FILE="registry.json"
  21. README_FILE="README.md"
  22. REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
  23. DRY_RUN=false
  24. VERBOSE=false
  25. #############################################################################
  26. # Utility Functions
  27. #############################################################################
  28. print_header() {
  29. echo -e "${CYAN}${BOLD}"
  30. echo "╔════════════════════════════════════════════════════════════════╗"
  31. echo "║ ║"
  32. echo "║ Documentation Sync v1.0.0 ║"
  33. echo "║ Keep README in sync with registry ║"
  34. echo "║ ║"
  35. echo "╚════════════════════════════════════════════════════════════════╝"
  36. echo -e "${NC}"
  37. }
  38. print_success() {
  39. echo -e "${GREEN}✓${NC} $1"
  40. }
  41. print_error() {
  42. echo -e "${RED}✗${NC} $1"
  43. }
  44. print_warning() {
  45. echo -e "${YELLOW}⚠${NC} $1"
  46. }
  47. print_info() {
  48. echo -e "${BLUE}ℹ${NC} $1"
  49. }
  50. usage() {
  51. echo "Usage: $0 [OPTIONS]"
  52. echo ""
  53. echo "Options:"
  54. echo " -d, --dry-run Show what would be changed without modifying files"
  55. echo " -v, --verbose Show detailed output"
  56. echo " -h, --help Show this help message"
  57. echo ""
  58. echo "Description:"
  59. echo " Syncs component counts and lists from registry.json to README.md"
  60. echo " Ensures documentation stays accurate with the component registry"
  61. echo ""
  62. exit 0
  63. }
  64. #############################################################################
  65. # Dependency Checks
  66. #############################################################################
  67. check_dependencies() {
  68. local missing_deps=()
  69. if ! command -v jq &> /dev/null; then
  70. missing_deps+=("jq")
  71. fi
  72. if [ ${#missing_deps[@]} -ne 0 ]; then
  73. print_error "Missing required dependencies: ${missing_deps[*]}"
  74. echo ""
  75. echo "Please install them:"
  76. echo " macOS: brew install ${missing_deps[*]}"
  77. echo " Ubuntu: sudo apt-get install ${missing_deps[*]}"
  78. exit 2
  79. fi
  80. }
  81. #############################################################################
  82. # Registry Parsing
  83. #############################################################################
  84. get_component_count() {
  85. local component_type="$1"
  86. jq -r ".components.${component_type} | length" "$REGISTRY_FILE"
  87. }
  88. get_profile_component_count() {
  89. local profile="$1"
  90. jq -r ".profiles.${profile}.components | length" "$REGISTRY_FILE"
  91. }
  92. get_total_components() {
  93. jq -r '
  94. .components.agents +
  95. .components.subagents +
  96. .components.commands +
  97. .components.tools +
  98. .components.plugins +
  99. .components.contexts +
  100. .components.config | length
  101. ' "$REGISTRY_FILE"
  102. }
  103. #############################################################################
  104. # README Update Functions
  105. #############################################################################
  106. update_profile_counts() {
  107. local readme_content
  108. readme_content=$(cat "$README_FILE")
  109. # Update Essential profile count
  110. local essential_count
  111. essential_count=$(get_profile_component_count "essential")
  112. readme_content=$(echo "$readme_content" | sed -E "s/(Essential.*\()([0-9]+)( components\))/\1${essential_count}\3/g")
  113. # Update Developer profile count
  114. local developer_count
  115. developer_count=$(get_profile_component_count "developer")
  116. readme_content=$(echo "$readme_content" | sed -E "s/(Developer.*\()([0-9]+)( components\))/\1${developer_count}\3/g")
  117. # Update Business profile count
  118. local business_count
  119. business_count=$(get_profile_component_count "business")
  120. readme_content=$(echo "$readme_content" | sed -E "s/(Business.*\()([0-9]+)( components\))/\1${business_count}\3/g")
  121. # Update Full profile count
  122. local full_count
  123. full_count=$(get_profile_component_count "full")
  124. readme_content=$(echo "$readme_content" | sed -E "s/(Full.*\()([0-9]+)( components\))/\1${full_count}\3/g")
  125. # Update Advanced profile count
  126. local advanced_count
  127. advanced_count=$(get_profile_component_count "advanced")
  128. readme_content=$(echo "$readme_content" | sed -E "s/(Advanced.*\()([0-9]+)( components\))/\1${advanced_count}\3/g")
  129. echo "$readme_content"
  130. }
  131. update_component_counts() {
  132. local readme_content="$1"
  133. # Get counts from registry
  134. local agents_count subagents_count commands_count tools_count plugins_count contexts_count
  135. agents_count=$(get_component_count "agents")
  136. subagents_count=$(get_component_count "subagents")
  137. commands_count=$(get_component_count "commands")
  138. tools_count=$(get_component_count "tools")
  139. plugins_count=$(get_component_count "plugins")
  140. contexts_count=$(get_component_count "contexts")
  141. if [ "$VERBOSE" = true ]; then
  142. print_info "Component counts from registry:"
  143. echo " Agents: $agents_count"
  144. echo " Subagents: $subagents_count"
  145. echo " Commands: $commands_count"
  146. echo " Tools: $tools_count"
  147. echo " Plugins: $plugins_count"
  148. echo " Contexts: $contexts_count"
  149. fi
  150. echo "$readme_content"
  151. }
  152. #############################################################################
  153. # Main Logic
  154. #############################################################################
  155. main() {
  156. # Parse arguments
  157. while [[ $# -gt 0 ]]; do
  158. case $1 in
  159. -d|--dry-run)
  160. DRY_RUN=true
  161. shift
  162. ;;
  163. -v|--verbose)
  164. VERBOSE=true
  165. shift
  166. ;;
  167. -h|--help)
  168. usage
  169. ;;
  170. *)
  171. print_error "Unknown option: $1"
  172. usage
  173. ;;
  174. esac
  175. done
  176. print_header
  177. # Check dependencies
  178. check_dependencies
  179. # Change to repo root
  180. cd "$REPO_ROOT"
  181. # Verify files exist
  182. if [ ! -f "$REGISTRY_FILE" ]; then
  183. print_error "Registry file not found: $REGISTRY_FILE"
  184. exit 1
  185. fi
  186. if [ ! -f "$README_FILE" ]; then
  187. print_error "README file not found: $README_FILE"
  188. exit 1
  189. fi
  190. print_info "Reading registry: $REGISTRY_FILE"
  191. print_info "Updating README: $README_FILE"
  192. echo ""
  193. # Update profile counts
  194. print_info "Updating installation profile counts..."
  195. local updated_content
  196. updated_content=$(update_profile_counts)
  197. # Update component counts
  198. print_info "Updating component counts..."
  199. updated_content=$(update_component_counts "$updated_content")
  200. # Check if anything changed
  201. if [ "$updated_content" = "$(cat "$README_FILE")" ]; then
  202. print_success "README is already up to date!"
  203. exit 0
  204. fi
  205. # Show diff if verbose
  206. if [ "$VERBOSE" = true ]; then
  207. echo ""
  208. print_info "Changes to be made:"
  209. diff -u "$README_FILE" <(echo "$updated_content") || true
  210. echo ""
  211. fi
  212. # Apply changes or show dry-run
  213. if [ "$DRY_RUN" = true ]; then
  214. print_warning "DRY RUN - No changes made"
  215. print_info "Run without --dry-run to apply changes"
  216. else
  217. echo "$updated_content" > "$README_FILE"
  218. print_success "README updated successfully!"
  219. fi
  220. echo ""
  221. print_info "Summary:"
  222. echo " Essential: $(get_profile_component_count "essential") components"
  223. echo " Developer: $(get_profile_component_count "developer") components"
  224. echo " Business: $(get_profile_component_count "business") components"
  225. echo " Full: $(get_profile_component_count "full") components"
  226. echo " Advanced: $(get_profile_component_count "advanced") components"
  227. echo ""
  228. echo " Total: $(get_total_components) components"
  229. }
  230. # Run main function
  231. main "$@"