#!/usr/bin/env bash # update-steering-references.sh # # Reads frontmatter (name, description) from steering files: # - steering/eks.md (hub) # - steering/workflows/*.md (workflows) # - steering/commands/**/*.md (slash commands) # # Rebuilds the Steering Reference table in README.md between # and markers. # # Usage: # ./misc/update-steering-references.sh # run from repo root # ./misc/update-steering-references.sh --dry-run # preview without writing set -euo pipefail REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" README="$REPO_ROOT/README.md" STEERING_DIR="$REPO_ROOT/steering" DRY_RUN=false if [[ "${1:-}" == "--dry-run" ]]; then DRY_RUN=true fi # --- Parse frontmatter from a markdown file --- parse_frontmatter() { local file="$1" local key="$2" awk -v key="$key" ' /^---$/ { block++; next } block == 1 && $0 ~ "^" key ":" { sub("^" key ":[ ]*", "") print exit } block >= 2 { exit } ' "$file" } # --- Build the Steering Reference table --- build_table() { echo '## Steering (Optional)' echo '' echo '> _This table is auto-generated by [`misc/update-steering-references.sh`](misc/update-steering-references.sh). Do not edit manually._' echo '' echo '| Steering File | Description |' echo '|--------------|-------------|' # Collect steering files: hubs first (any steering/*.md), then workflows local steering_files=() # Hub files: every top-level steering/*.md (alphabetical). Historically only # steering/eks.md existed; as more hubs appear (steering/apex.md, future # steering/rds.md, ...) they each get a row here. while IFS= read -r -d '' hub; do if [[ -f "$hub" ]]; then steering_files+=("$hub") fi done < <(find "$STEERING_DIR" -maxdepth 1 -type f -name '*.md' -print0 | sort -z) # Then workflow files (sorted) if [[ -d "$STEERING_DIR/workflows" ]]; then for wf in "$STEERING_DIR/workflows"/*.md; do if [[ -f "$wf" ]]; then steering_files+=("$wf") fi done fi for steering_file in "${steering_files[@]}"; do local name description rel_path name="$(parse_frontmatter "$steering_file" "name")" description="$(parse_frontmatter "$steering_file" "description")" # Skip files without frontmatter name if [[ -z "$name" ]]; then continue fi if [[ -z "$description" ]]; then description="_(no description in frontmatter)_" fi # Build relative path from repo root rel_path="${steering_file#$REPO_ROOT/}" echo "| **[$name]($rel_path)** | $description |" done # Collect command files (hub first — shortest basename per directory, then rest sorted) local command_files=() hub_files=() other_files=() if [[ -d "$STEERING_DIR/commands" ]]; then while IFS= read -r -d '' cmd; do local base base="$(basename "$cmd" .md)" # Hub files have no hyphen (e.g., eks.md); sub-commands do (e.g., eks-design.md) if [[ "$base" != *-* ]]; then hub_files+=("$cmd") else other_files+=("$cmd") fi done < <(find "$STEERING_DIR/commands" -name '*.md' -print0 | sort -z) command_files=("${hub_files[@]}" "${other_files[@]}") fi if [[ ${#command_files[@]} -gt 0 ]]; then echo '' echo '### Slash Commands (Claude Code)' echo '' echo '| Command | Description |' echo '|---------|-------------|' for cmd_file in "${command_files[@]}"; do local cmd_name cmd_desc cmd_rel_path cmd_name="$(parse_frontmatter "$cmd_file" "name")" cmd_desc="$(parse_frontmatter "$cmd_file" "description")" if [[ -z "$cmd_name" ]]; then continue fi if [[ -z "$cmd_desc" ]]; then cmd_desc="_(no description in frontmatter)_" fi cmd_rel_path="${cmd_file#$REPO_ROOT/}" echo "| **[/$cmd_name]($cmd_rel_path)** | $cmd_desc |" done fi } # --- Replace the section in README.md --- START_MARKER='' END_MARKER='' if ! grep -q "$START_MARKER" "$README"; then echo "ERROR: Could not find $START_MARKER in $README" >&2 echo "Add the markers around the Steering section first." >&2 exit 1 fi if ! grep -q "$END_MARKER" "$README"; then echo "ERROR: Could not find $END_MARKER in $README" >&2 exit 1 fi # Build the new content NEW_SECTION="$(build_table)" if $DRY_RUN; then echo "=== DRY RUN — would replace Steering Reference with: ===" echo "" echo "$START_MARKER" echo "$NEW_SECTION" echo "$END_MARKER" echo "" echo "=== No changes written ===" exit 0 fi # Use awk to replace everything between the markers (inclusive) awk -v start="$START_MARKER" -v end="$END_MARKER" -v new_section="$NEW_SECTION" ' $0 == start { print start print new_section skip = 1 next } $0 == end { print end skip = 0 next } !skip { print } ' "$README" > "$README.tmp" mv "$README.tmp" "$README" echo "✅ Steering Reference table updated in README.md" echo " Steering files found:" while IFS= read -r -d '' f; do if [[ -f "$f" ]]; then local_name="$(parse_frontmatter "$f" "name")" if [[ -n "$local_name" ]]; then echo " - $local_name (${f#$REPO_ROOT/})" fi fi done < <(find "$STEERING_DIR" -maxdepth 1 -type f -name '*.md' -print0 | sort -z) for f in "$STEERING_DIR/workflows"/*.md; do if [[ -f "$f" ]]; then local_name="$(parse_frontmatter "$f" "name")" if [[ -n "$local_name" ]]; then echo " - $local_name (${f#$REPO_ROOT/})" fi fi done if [[ -d "$STEERING_DIR/commands" ]]; then echo " Command files found:" while IFS= read -r -d '' f; do local_name="$(parse_frontmatter "$f" "name")" if [[ -n "$local_name" ]]; then echo " - /$local_name (${f#$REPO_ROOT/})" fi done < <(find "$STEERING_DIR/commands" -name '*.md' -print0 | sort -z) fi