Initial commit
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
#!/bin/bash
|
||||
# Auto-progress workflow when cascade events occur
|
||||
# OPINIONATED: Auto-applies status changes when automatic=true (default behavior)
|
||||
#
|
||||
# This example hook demonstrates the recommended opinionated approach:
|
||||
# - Automatically logs cascade events when automatic=true
|
||||
# - Relies on Task Orchestrator orchestration Skills to apply status changes
|
||||
# - Provides audit trail of all cascade events
|
||||
#
|
||||
# For manual confirmation instead, use progressive-disclosure.sh example
|
||||
|
||||
INPUT=$(cat)
|
||||
|
||||
# Extract cascade events from tool response
|
||||
CASCADE_EVENTS=$(echo "$INPUT" | jq -r '.tool_output.data.cascadeEvents // []')
|
||||
|
||||
# Check if any cascade events detected
|
||||
if [ "$CASCADE_EVENTS" == "[]" ] || [ "$CASCADE_EVENTS" == "null" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "════════════════════════════════════════════"
|
||||
echo "🔄 CASCADE EVENT PROCESSING (Opinionated Mode)"
|
||||
echo "════════════════════════════════════════════"
|
||||
|
||||
# Create metrics directory
|
||||
LOG_DIR="$CLAUDE_PROJECT_DIR/.claude/metrics"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
# Process each cascade event
|
||||
EVENT_COUNT=0
|
||||
echo "$CASCADE_EVENTS" | jq -c '.[]' | while read -r event; do
|
||||
EVENT_COUNT=$((EVENT_COUNT + 1))
|
||||
EVENT_TYPE=$(echo "$event" | jq -r '.event')
|
||||
TARGET_TYPE=$(echo "$event" | jq -r '.targetType')
|
||||
TARGET_ID=$(echo "$event" | jq -r '.targetId')
|
||||
TARGET_NAME=$(echo "$event" | jq -r '.targetName')
|
||||
CURRENT_STATUS=$(echo "$event" | jq -r '.currentStatus')
|
||||
SUGGESTED_STATUS=$(echo "$event" | jq -r '.suggestedStatus')
|
||||
AUTOMATIC=$(echo "$event" | jq -r '.automatic')
|
||||
FLOW=$(echo "$event" | jq -r '.flow')
|
||||
REASON=$(echo "$event" | jq -r '.reason')
|
||||
|
||||
echo ""
|
||||
echo "Event #$EVENT_COUNT: $EVENT_TYPE"
|
||||
echo " Target: $TARGET_NAME ($TARGET_TYPE)"
|
||||
echo " Status: $CURRENT_STATUS → $SUGGESTED_STATUS"
|
||||
echo " Flow: $FLOW"
|
||||
echo " Reason: $REASON"
|
||||
|
||||
# OPINIONATED: Auto-apply if automatic=true (recommended default)
|
||||
if [ "$AUTOMATIC" == "true" ]; then
|
||||
echo " ✅ AUTO-APPLY: Logging for orchestrator to apply status"
|
||||
|
||||
# Log the cascade event for audit trail
|
||||
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
echo "$TIMESTAMP,$EVENT_TYPE,$TARGET_TYPE,$TARGET_ID,\"$TARGET_NAME\",$CURRENT_STATUS,$SUGGESTED_STATUS,$FLOW,auto" \
|
||||
>> "$LOG_DIR/cascade-events.csv"
|
||||
|
||||
# Note: Actual status application handled by orchestration Skills
|
||||
# This hook provides the audit trail and notification
|
||||
echo " Cascade event logged - orchestrator will apply status automatically"
|
||||
|
||||
else
|
||||
# Manual confirmation required
|
||||
echo " ⚠️ MANUAL CONFIRMATION: User approval required"
|
||||
echo " Feature/Task Orchestration Skill will prompt for confirmation"
|
||||
|
||||
# Log as manual
|
||||
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
echo "$TIMESTAMP,$EVENT_TYPE,$TARGET_TYPE,$TARGET_ID,\"$TARGET_NAME\",$CURRENT_STATUS,$SUGGESTED_STATUS,$FLOW,manual" \
|
||||
>> "$LOG_DIR/cascade-events.csv"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "════════════════════════════════════════════"
|
||||
echo "✓ Cascade event processing complete"
|
||||
echo " Log: .claude/metrics/cascade-events.csv"
|
||||
echo "════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,128 @@
|
||||
#!/bin/bash
|
||||
# Log all cascade events to CSV for analytics
|
||||
# Non-blocking, observation-only hook for understanding workflow patterns
|
||||
#
|
||||
# This example hook is SAFE to add - it only logs, never blocks or modifies behavior
|
||||
# Use this to understand cascade event patterns before implementing auto-apply hooks
|
||||
#
|
||||
# Logs include:
|
||||
# - All cascade events (first_task_started, all_tasks_complete, all_features_complete, custom)
|
||||
# - Auto vs manual confirmation flags
|
||||
# - Workflow flow context
|
||||
# - Summary statistics
|
||||
|
||||
INPUT=$(cat)
|
||||
|
||||
# Extract cascade events
|
||||
CASCADE_EVENTS=$(echo "$INPUT" | jq -r '.tool_output.data.cascadeEvents // []')
|
||||
|
||||
if [ "$CASCADE_EVENTS" == "[]" ] || [ "$CASCADE_EVENTS" == "null" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create metrics directory
|
||||
LOG_DIR="$CLAUDE_PROJECT_DIR/.claude/metrics"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
# Define log files
|
||||
CASCADE_LOG="$LOG_DIR/cascade-events.csv"
|
||||
SUMMARY_LOG="$LOG_DIR/cascade-summary.json"
|
||||
|
||||
# Create header if file doesn't exist
|
||||
if [ ! -f "$CASCADE_LOG" ]; then
|
||||
echo "timestamp,event,target_type,target_id,target_name,current_status,suggested_status,flow,automatic,reason" \
|
||||
> "$CASCADE_LOG"
|
||||
fi
|
||||
|
||||
echo "📊 Cascade Event Logger - Recording events for analytics"
|
||||
|
||||
# Log each cascade event
|
||||
EVENT_COUNT=0
|
||||
echo "$CASCADE_EVENTS" | jq -c '.[]' | while read -r event; do
|
||||
EVENT_COUNT=$((EVENT_COUNT + 1))
|
||||
|
||||
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
EVENT_TYPE=$(echo "$event" | jq -r '.event')
|
||||
TARGET_TYPE=$(echo "$event" | jq -r '.targetType')
|
||||
TARGET_ID=$(echo "$event" | jq -r '.targetId')
|
||||
TARGET_NAME=$(echo "$event" | jq -r '.targetName')
|
||||
CURRENT_STATUS=$(echo "$event" | jq -r '.currentStatus')
|
||||
SUGGESTED_STATUS=$(echo "$event" | jq -r '.suggestedStatus')
|
||||
FLOW=$(echo "$event" | jq -r '.flow')
|
||||
AUTOMATIC=$(echo "$event" | jq -r '.automatic')
|
||||
REASON=$(echo "$event" | jq -r '.reason')
|
||||
|
||||
# Append to CSV (escape quotes in names/reasons)
|
||||
TARGET_NAME_ESCAPED=$(echo "$TARGET_NAME" | sed 's/"/""/g')
|
||||
REASON_ESCAPED=$(echo "$REASON" | sed 's/"/""/g')
|
||||
|
||||
echo "$TIMESTAMP,$EVENT_TYPE,$TARGET_TYPE,$TARGET_ID,\"$TARGET_NAME_ESCAPED\",$CURRENT_STATUS,$SUGGESTED_STATUS,$FLOW,$AUTOMATIC,\"$REASON_ESCAPED\"" \
|
||||
>> "$CASCADE_LOG"
|
||||
|
||||
echo " ✓ Event #$EVENT_COUNT: $EVENT_TYPE ($TARGET_TYPE) - auto=$AUTOMATIC, flow=$FLOW"
|
||||
done
|
||||
|
||||
# Update summary statistics
|
||||
if [ -f "$CASCADE_LOG" ]; then
|
||||
TOTAL_EVENTS=$(tail -n +2 "$CASCADE_LOG" 2>/dev/null | wc -l | tr -d ' ')
|
||||
AUTO_EVENTS=$(tail -n +2 "$CASCADE_LOG" 2>/dev/null | grep ",true," | wc -l | tr -d ' ')
|
||||
MANUAL_EVENTS=$(tail -n +2 "$CASCADE_LOG" 2>/dev/null | grep ",false," | wc -l | tr -d ' ')
|
||||
|
||||
# Count by event type
|
||||
FIRST_TASK=$(tail -n +2 "$CASCADE_LOG" 2>/dev/null | grep "first_task_started" | wc -l | tr -d ' ')
|
||||
ALL_TASKS=$(tail -n +2 "$CASCADE_LOG" 2>/dev/null | grep "all_tasks_complete" | wc -l | tr -d ' ')
|
||||
ALL_FEATURES=$(tail -n +2 "$CASCADE_LOG" 2>/dev/null | grep "all_features_complete" | wc -l | tr -d ' ')
|
||||
|
||||
# Count by flow
|
||||
DEFAULT_FLOW=$(tail -n +2 "$CASCADE_LOG" 2>/dev/null | grep ",default_flow," | wc -l | tr -d ' ')
|
||||
RAPID_FLOW=$(tail -n +2 "$CASCADE_LOG" 2>/dev/null | grep ",rapid_prototype_flow," | wc -l | tr -d ' ')
|
||||
REVIEW_FLOW=$(tail -n +2 "$CASCADE_LOG" 2>/dev/null | grep ",with_review_flow," | wc -l | tr -d ' ')
|
||||
|
||||
cat > "$SUMMARY_LOG" <<EOF
|
||||
{
|
||||
"total_cascade_events": $TOTAL_EVENTS,
|
||||
"automatic_events": $AUTO_EVENTS,
|
||||
"manual_events": $MANUAL_EVENTS,
|
||||
"by_event_type": {
|
||||
"first_task_started": $FIRST_TASK,
|
||||
"all_tasks_complete": $ALL_TASKS,
|
||||
"all_features_complete": $ALL_FEATURES
|
||||
},
|
||||
"by_flow": {
|
||||
"default_flow": $DEFAULT_FLOW,
|
||||
"rapid_prototype_flow": $RAPID_FLOW,
|
||||
"with_review_flow": $REVIEW_FLOW
|
||||
},
|
||||
"auto_percentage": $(( TOTAL_EVENTS > 0 ? (AUTO_EVENTS * 100) / TOTAL_EVENTS : 0 )),
|
||||
"last_updated": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
}
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
echo "📈 Summary Statistics:"
|
||||
echo " Total Events: $TOTAL_EVENTS"
|
||||
echo " Auto-Apply: $AUTO_EVENTS ($((TOTAL_EVENTS > 0 ? (AUTO_EVENTS * 100) / TOTAL_EVENTS : 0))%)"
|
||||
echo " Manual Confirm: $MANUAL_EVENTS"
|
||||
echo ""
|
||||
echo " By Event Type:"
|
||||
echo " first_task_started: $FIRST_TASK"
|
||||
echo " all_tasks_complete: $ALL_TASKS"
|
||||
echo " all_features_complete: $ALL_FEATURES"
|
||||
echo ""
|
||||
echo " By Workflow Flow:"
|
||||
echo " default_flow: $DEFAULT_FLOW"
|
||||
echo " rapid_prototype_flow: $RAPID_FLOW"
|
||||
echo " with_review_flow: $REVIEW_FLOW"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✓ Cascade events logged successfully"
|
||||
echo " CSV Log: .claude/metrics/cascade-events.csv"
|
||||
echo " Summary: .claude/metrics/cascade-summary.json"
|
||||
echo ""
|
||||
echo " Analytics Queries:"
|
||||
echo " tail -10 .claude/metrics/cascade-events.csv # Recent events"
|
||||
echo " cat .claude/metrics/cascade-summary.json # Summary stats"
|
||||
echo ""
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,161 @@
|
||||
#!/bin/bash
|
||||
# Flow-aware quality gate - different validation per workflow flow
|
||||
# OPINIONATED: Skips tests for prototypes, enforces for production (default behavior)
|
||||
#
|
||||
# This example hook demonstrates the recommended opinionated approach:
|
||||
# - rapid_prototype_flow: SKIP tests (fast iteration)
|
||||
# - with_review_flow: STRICT validation (security/compliance)
|
||||
# - default_flow: STANDARD tests (normal development)
|
||||
#
|
||||
# Customize flow detection and gates based on your project needs
|
||||
|
||||
INPUT=$(cat)
|
||||
|
||||
# Extract operation and container type
|
||||
OPERATION=$(echo "$INPUT" | jq -r '.tool_input.operation')
|
||||
CONTAINER_TYPE=$(echo "$INPUT" | jq -r '.tool_input.containerType')
|
||||
STATUS=$(echo "$INPUT" | jq -r '.tool_input.status')
|
||||
|
||||
# Only run for feature status changes to testing/completed
|
||||
if [ "$OPERATION" != "setStatus" ] || [ "$CONTAINER_TYPE" != "feature" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$STATUS" != "testing" ] && [ "$STATUS" != "completed" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Extract feature ID
|
||||
FEATURE_ID=$(echo "$INPUT" | jq -r '.tool_input.id')
|
||||
|
||||
# Query feature tags to determine active flow
|
||||
DB_PATH="$CLAUDE_PROJECT_DIR/data/tasks.db"
|
||||
TAGS=$(sqlite3 "$DB_PATH" \
|
||||
"SELECT tags FROM Features WHERE id='$FEATURE_ID'" 2>/dev/null)
|
||||
|
||||
if [ -z "$TAGS" ]; then
|
||||
echo "⚠️ Could not determine feature tags, using default_flow"
|
||||
TAGS=""
|
||||
fi
|
||||
|
||||
# Determine active flow from tags
|
||||
FLOW="default_flow"
|
||||
if echo "$TAGS" | grep -qE "prototype|spike|experiment"; then
|
||||
FLOW="rapid_prototype_flow"
|
||||
elif echo "$TAGS" | grep -qE "security|compliance|audit"; then
|
||||
FLOW="with_review_flow"
|
||||
fi
|
||||
|
||||
echo "════════════════════════════════════════════"
|
||||
echo "🔍 FLOW-AWARE QUALITY GATE"
|
||||
echo "════════════════════════════════════════════"
|
||||
echo " Detected Flow: $FLOW"
|
||||
echo " Feature Tags: $TAGS"
|
||||
echo " Target Status: $STATUS"
|
||||
echo ""
|
||||
|
||||
# Flow-specific quality gates
|
||||
case "$FLOW" in
|
||||
"rapid_prototype_flow")
|
||||
# OPINIONATED: Skip tests for prototypes (fast iteration)
|
||||
echo "⚡ RAPID PROTOTYPE FLOW"
|
||||
echo " Skipping all quality gates for fast iteration"
|
||||
echo " Rationale: Prototypes prioritize speed over validation"
|
||||
echo ""
|
||||
echo " ✅ Quality gate skipped (by design)"
|
||||
echo "════════════════════════════════════════════"
|
||||
exit 0
|
||||
;;
|
||||
|
||||
"with_review_flow")
|
||||
# OPINIONATED: Strict validation for security/compliance
|
||||
echo "🔒 SECURITY/COMPLIANCE FLOW"
|
||||
echo " Enforcing strict quality gates"
|
||||
echo ""
|
||||
|
||||
cd "$CLAUDE_PROJECT_DIR"
|
||||
|
||||
# Gate 1: Full test suite
|
||||
echo " [1/2] Running full test suite..."
|
||||
if ! ./gradlew test; then
|
||||
cat << EOF
|
||||
{
|
||||
"decision": "block",
|
||||
"reason": "Security/compliance flow requires all tests to pass. Please fix failing tests before completing feature."
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
echo " ✅ Tests passed"
|
||||
|
||||
# Gate 2: Security scan (if trivy available)
|
||||
if command -v trivy >/dev/null 2>&1; then
|
||||
echo " [2/2] Running security vulnerability scan..."
|
||||
if ! trivy fs .; then
|
||||
cat << EOF
|
||||
{
|
||||
"decision": "block",
|
||||
"reason": "Security vulnerabilities detected. Please remediate before completing feature."
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
echo " ✅ Security scan passed"
|
||||
else
|
||||
echo " [2/2] Security scan tool (trivy) not installed, skipping"
|
||||
echo " ⚠️ Install trivy for security validation"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo " ✅ All strict quality gates passed"
|
||||
echo "════════════════════════════════════════════"
|
||||
;;
|
||||
|
||||
"default_flow")
|
||||
# OPINIONATED: Standard test suite for default flow
|
||||
echo "✓ DEFAULT FLOW"
|
||||
echo " Running standard quality gates"
|
||||
echo ""
|
||||
|
||||
cd "$CLAUDE_PROJECT_DIR"
|
||||
|
||||
echo " [1/1] Running standard test suite..."
|
||||
if ! ./gradlew test; then
|
||||
cat << EOF
|
||||
{
|
||||
"decision": "block",
|
||||
"reason": "Tests are failing. Please fix failing tests before completing feature."
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
echo " ✅ Tests passed"
|
||||
|
||||
echo ""
|
||||
echo " ✅ Standard quality gates passed"
|
||||
echo "════════════════════════════════════════════"
|
||||
;;
|
||||
|
||||
*)
|
||||
# Unknown flow, use default behavior
|
||||
echo "⚠️ UNKNOWN FLOW: $FLOW"
|
||||
echo " Falling back to default flow behavior"
|
||||
echo ""
|
||||
|
||||
cd "$CLAUDE_PROJECT_DIR"
|
||||
if ! ./gradlew test; then
|
||||
cat << EOF
|
||||
{
|
||||
"decision": "block",
|
||||
"reason": "Tests are failing. Please fix failing tests before completing feature."
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo " ✅ Tests passed"
|
||||
echo "════════════════════════════════════════════"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user