Files
siriusscan--sirius/scripts/agent-identities/lint-agents.sh
T
wehub-resource-sync 161ef94b4f
Check engine pin consistency / Dockerfile / CI pin consistency (push) Successful in 8s
Sirius CI/CD Pipeline / Detect Changes (push) Successful in 23s
Validate Docker Configuration / Validate Docker Compose Configuration (push) Successful in 47s
Sirius CI/CD Pipeline / Build API (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build UI (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Engine Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge API Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Merge UI Manifest (push) Has been cancelled
Sirius CI/CD Pipeline / Build Engine (${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Build Infra (${{ matrix.service }}, ${{ matrix.platform }}) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-postgres) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-rabbitmq) (push) Has been cancelled
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-valkey) (push) Has been cancelled
Sirius CI/CD Pipeline / Integration Test (push) Has been cancelled
Sirius CI/CD Pipeline / Public Stack Contract (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Deployment (sirius-demo branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Dispatch Demo Canary (main branch) (push) Has been cancelled
Sirius CI/CD Pipeline / Guard Registry Namespace (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:25 +08:00

380 lines
9.8 KiB
Bash
Executable File

#!/bin/bash
# Sirius Agent Identity Linting System
# Validates agent identity quality, consistency, and compliance
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
AGENTS_DIR="../../.cursor/agents"
SCRIPT_DIR="$(dirname "$0")"
LOG_FILE="tmp/agent-lint-$(date +%Y%m%d-%H%M%S).log"
# Create tmp directory if it doesn't exist
mkdir -p tmp
# Required YAML front matter fields
REQUIRED_FIELDS=("name" "title" "description" "role_type" "version" "last_updated" "llm_context" "context_window_target")
OPTIONAL_FIELDS=("author" "specialization" "technology_stack" "system_integration_level" "categories" "tags" "related_docs" "dependencies")
# Valid values for specific fields
VALID_ROLE_TYPES=("engineering" "design" "product" "operations" "qa" "documentation")
VALID_LLM_CONTEXTS=("high" "medium" "low")
VALID_INTEGRATION_LEVELS=("none" "low" "medium" "high")
# Length constraints
MIN_LINES=150
MAX_LINES=500
TARGET_MIN=200
TARGET_MAX=400
# Counters
TOTAL_FILES=0
PASSED_FILES=0
FAILED_FILES=0
WARNINGS=0
# Functions
log() {
echo -e "${BLUE}[$(date +'%H:%M:%S')]${NC} $1" | tee -a "$LOG_FILE"
}
success() {
echo -e "${GREEN}$1${NC}" | tee -a "$LOG_FILE"
}
warning() {
echo -e "${YELLOW}⚠️ $1${NC}" | tee -a "$LOG_FILE"
((WARNINGS++))
}
error() {
echo -e "${RED}$1${NC}" | tee -a "$LOG_FILE"
}
# Check if file has YAML front matter
check_yaml_front_matter() {
local file="$1"
local has_yaml=false
if head -n 1 "$file" | grep -q "^---$"; then
has_yaml=true
fi
if [ "$has_yaml" = false ]; then
error "Missing YAML front matter in $file"
return 1
fi
return 0
}
# Extract YAML front matter
extract_yaml() {
local file="$1"
local yaml_start=0
local yaml_end=0
local line_num=0
while IFS= read -r line; do
((line_num++))
if [ "$line" = "---" ]; then
if [ $yaml_start -eq 0 ]; then
yaml_start=$line_num
else
yaml_end=$line_num
break
fi
fi
done < "$file"
if [ $yaml_start -gt 0 ] && [ $yaml_end -gt 0 ]; then
sed -n "${yaml_start},${yaml_end}p" "$file"
fi
}
# Check required fields
check_required_fields() {
local file="$1"
local yaml_content
local missing_fields=()
yaml_content=$(extract_yaml "$file")
if [ -z "$yaml_content" ]; then
return 1
fi
for field in "${REQUIRED_FIELDS[@]}"; do
if ! echo "$yaml_content" | grep -q "^${field}:"; then
missing_fields+=("$field")
fi
done
if [ ${#missing_fields[@]} -gt 0 ]; then
error "Missing required fields in $file: ${missing_fields[*]}"
return 1
fi
return 0
}
# Validate enumerated field values
validate_enum_fields() {
local file="$1"
local yaml_content
local errors=0
yaml_content=$(extract_yaml "$file")
if [ -z "$yaml_content" ]; then
return 1
fi
# Check role_type
local role_type=$(echo "$yaml_content" | grep "^role_type:" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | tr -d '"')
if [ -n "$role_type" ]; then
local valid=false
for valid_type in "${VALID_ROLE_TYPES[@]}"; do
if [ "$role_type" = "$valid_type" ]; then
valid=true
break
fi
done
if [ "$valid" = false ]; then
error "Invalid role_type '$role_type' in $file. Must be one of: ${VALID_ROLE_TYPES[*]}"
((errors++))
fi
fi
# Check llm_context
local llm_context=$(echo "$yaml_content" | grep "^llm_context:" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | tr -d '"')
if [ -n "$llm_context" ]; then
local valid=false
for valid_ctx in "${VALID_LLM_CONTEXTS[@]}"; do
if [ "$llm_context" = "$valid_ctx" ]; then
valid=true
break
fi
done
if [ "$valid" = false ]; then
error "Invalid llm_context '$llm_context' in $file. Must be one of: ${VALID_LLM_CONTEXTS[*]}"
((errors++))
fi
fi
# Check system_integration_level (optional)
local integration_level=$(echo "$yaml_content" | grep "^system_integration_level:" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | tr -d '"')
if [ -n "$integration_level" ]; then
local valid=false
for valid_level in "${VALID_INTEGRATION_LEVELS[@]}"; do
if [ "$integration_level" = "$valid_level" ]; then
valid=true
break
fi
done
if [ "$valid" = false ]; then
error "Invalid system_integration_level '$integration_level' in $file. Must be one of: ${VALID_INTEGRATION_LEVELS[*]}"
((errors++))
fi
fi
return $errors
}
# Validate version format (semver)
validate_version() {
local file="$1"
local yaml_content
yaml_content=$(extract_yaml "$file")
if [ -z "$yaml_content" ]; then
return 1
fi
local version=$(echo "$yaml_content" | grep "^version:" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | tr -d '"')
if [ -n "$version" ]; then
if ! echo "$version" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
error "Invalid version format '$version' in $file. Must be semver (e.g., 1.0.0)"
return 1
fi
fi
return 0
}
# Validate date format (ISO 8601)
validate_date() {
local file="$1"
local yaml_content
yaml_content=$(extract_yaml "$file")
if [ -z "$yaml_content" ]; then
return 1
fi
local date=$(echo "$yaml_content" | grep "^last_updated:" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | tr -d '"')
if [ -n "$date" ]; then
if ! echo "$date" | grep -qE '^[0-9]{4}-[0-9]{2}-[0-9]{2}$'; then
error "Invalid date format '$date' in $file. Must be YYYY-MM-DD"
return 1
fi
fi
return 0
}
# Check length constraints
check_length() {
local file="$1"
local line_count=$(wc -l < "$file")
if [ $line_count -lt $MIN_LINES ]; then
error "File $file is too short ($line_count lines). Minimum: $MIN_LINES"
return 1
elif [ $line_count -gt $MAX_LINES ]; then
error "File $file is too long ($line_count lines). Maximum: $MAX_LINES"
return 1
elif [ $line_count -lt $TARGET_MIN ] || [ $line_count -gt $TARGET_MAX ]; then
warning "File $file length ($line_count lines) outside target range ($TARGET_MIN-$TARGET_MAX)"
fi
return 0
}
# Check context window target
check_context_target() {
local file="$1"
local yaml_content
yaml_content=$(extract_yaml "$file")
if [ -z "$yaml_content" ]; then
return 1
fi
local target=$(echo "$yaml_content" | grep "^context_window_target:" | cut -d: -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | tr -d '"')
if [ -n "$target" ]; then
# Only check if it's a valid integer
if [[ "$target" =~ ^[0-9]+$ ]]; then
if [ "$target" -lt $MIN_LINES ] || [ "$target" -gt $MAX_LINES ]; then
warning "context_window_target $target in $file outside valid range ($MIN_LINES-$MAX_LINES)"
fi
fi
fi
return 0
}
# Validate file naming
check_filename() {
local file="$1"
local basename=$(basename "$file")
if ! echo "$basename" | grep -qE '^[a-z0-9-]+\.agent\.md$'; then
error "Invalid filename format: $basename. Must match [a-z0-9-]+.agent.md"
return 1
fi
return 0
}
# Main validation function
validate_file() {
local file="$1"
local file_errors=0
log "Validating $file..."
# Check filename format
if ! check_filename "$file"; then
((file_errors++))
fi
# Check YAML front matter exists
if ! check_yaml_front_matter "$file"; then
((file_errors++))
return 1 # Can't continue without YAML
fi
# Check required fields
if ! check_required_fields "$file"; then
((file_errors++))
fi
# Validate enum fields
if ! validate_enum_fields "$file"; then
((file_errors++))
fi
# Validate version format
if ! validate_version "$file"; then
((file_errors++))
fi
# Validate date format
if ! validate_date "$file"; then
((file_errors++))
fi
# Check length constraints
if ! check_length "$file"; then
((file_errors++))
fi
# Check context window target
check_context_target "$file"
if [ $file_errors -eq 0 ]; then
success "$(basename $file) passed validation"
return 0
else
error "$(basename $file) failed validation with $file_errors error(s)"
return 1
fi
}
# Main script
log "Starting agent identity validation..."
log "Agents directory: $AGENTS_DIR"
log "=================================================="
# Find all agent files
for file in "$AGENTS_DIR"/*.agent.md; do
if [ -f "$file" ]; then
((TOTAL_FILES++))
if validate_file "$file"; then
((PASSED_FILES++))
else
((FAILED_FILES++))
fi
echo ""
fi
done
# Summary
log "=================================================="
log "Validation Summary:"
log " Total files: $TOTAL_FILES"
log " Passed: $PASSED_FILES"
log " Failed: $FAILED_FILES"
log " Warnings: $WARNINGS"
log "=================================================="
if [ $FAILED_FILES -eq 0 ]; then
success "All agent identities passed validation!"
if [ $WARNINGS -gt 0 ]; then
warning "Validation passed with $WARNINGS warning(s)"
exit 0
fi
exit 0
else
error "Validation failed for $FAILED_FILES agent identit(y|ies)"
exit 1
fi