--- name: feature-metrics description: 'Feature-level orchestration metrics and analytics. Analyzes completed features from actual project artifacts (spec.md, tasks.md) rather than orchestration sessions. Shows completion rates, test metrics, and git history. v2.8.0: Initial release with feature detection and comprehensive analytics.' command_type: project --- # Feature-Level Metrics Dashboard ```bash #!/bin/bash # Parse arguments PROJECT_PATH="" RECENT_COUNT=10 EXPORT_FILE="" FEATURE_NUMBER="" SPRINT_FILTER="" SHOW_DETAILS=false while [[ $# -gt 0 ]]; do case $1 in --recent) RECENT_COUNT="$2" shift 2 ;; --export) EXPORT_FILE="${2:-feature-metrics-$(date +%Y%m%d_%H%M%S).csv}" shift 2 ;; --feature) FEATURE_NUMBER="$2" shift 2 ;; --sprint) SPRINT_FILTER="$2" shift 2 ;; --details) SHOW_DETAILS=true shift ;; --path) PROJECT_PATH="$2" shift 2 ;; *) if [ -z "$PROJECT_PATH" ] && [ -d "$1" ]; then PROJECT_PATH="$1" fi shift ;; esac done # Default to current directory if no path specified PROJECT_PATH="${PROJECT_PATH:-$(pwd)}" # Source the feature metrics collector library SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" PLUGIN_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "$PLUGIN_ROOT/lib/feature-metrics-collector.sh" # Set project root for library export PROJECT_ROOT="$PROJECT_PATH" echo "๐Ÿ“Š SpecLabs Feature-Level Metrics Dashboard" echo "============================================" echo "" echo "Project: $PROJECT_PATH" echo "" # Collect all feature data echo "๐Ÿ” Scanning for features..." features_json=$(fm_analyze_all_features "$PROJECT_PATH") # Check if any features found total_features=$(echo "$features_json" | jq 'length') if [ "$total_features" -eq 0 ]; then echo "" echo "โ„น๏ธ No features found in $PROJECT_PATH" echo "" echo "Features are detected by the presence of spec.md files." echo "Make sure you're in a project directory with SpecSwarm features." echo "" echo "Searched for:" echo " - */spec.md" echo " - features/*/spec.md" echo " - .features/*/spec.md" echo "" exit 0 fi echo "โœ… Found $total_features features" echo "" # Calculate aggregates aggregates=$(fm_calculate_aggregates "$features_json") # Display based on requested view if [ -n "$FEATURE_NUMBER" ]; then #========================================================================== # SINGLE FEATURE DETAILS #========================================================================== echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "Feature $FEATURE_NUMBER Details" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "" # Find the feature feature=$(echo "$features_json" | jq --arg num "$FEATURE_NUMBER" \ '.[] | select(.metadata.feature_number == $num)') if [ -z "$feature" ] || [ "$feature" = "null" ]; then echo "โŒ Feature $FEATURE_NUMBER not found" exit 1 fi # Display metadata echo "๐Ÿ“‹ Metadata" echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" echo "$feature" | jq -r '" Name: \(.metadata.feature_name) Status: \(.metadata.status) Parent Branch: \(.metadata.parent_branch) Created: \(.metadata.created_at) Completed: \(.metadata.completed_at // "N/A") Directory: \(.metadata.feature_dir)"' echo "" # Display task stats echo "โœ… Tasks" echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" echo "$feature" | jq -r '" Total: \(.tasks.total) Completed: \(.tasks.completed) (\(.tasks.completion_rate)%) Failed: \(.tasks.failed) Pending: \(.tasks.pending)"' echo "" # Display test stats if [ "$(echo "$feature" | jq '.tests.total_tests')" -gt 0 ]; then echo "๐Ÿงช Tests" echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" echo "$feature" | jq -r '" Total: \(.tests.total_tests) Passing: \(.tests.passing_tests) (\(.tests.pass_rate)%) Failing: \(.tests.failing_tests)"' echo "" fi # Display git stats echo "๐Ÿ”€ Git History" echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" echo "$feature" | jq -r '" Branch: \(.git.branch) Commits: \(.git.commits) Merged: \(.git.merged) Merge Date: \(.git.merge_date // "N/A")"' echo "" elif [ -n "$SPRINT_FILTER" ]; then #========================================================================== # SPRINT AGGREGATE VIEW #========================================================================== echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "Sprint: $SPRINT_FILTER" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "" # Filter features for this sprint sprint_features=$(fm_filter_features "$features_json" "metadata.parent_branch" "$SPRINT_FILTER") sprint_count=$(echo "$sprint_features" | jq 'length') if [ "$sprint_count" -eq 0 ]; then echo "โ„น๏ธ No features found for sprint: $SPRINT_FILTER" exit 0 fi # Calculate sprint aggregates sprint_aggregates=$(fm_calculate_aggregates "$sprint_features") echo "๐Ÿ“Š Sprint Statistics" echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" echo "$sprint_aggregates" | jq -r '" Total Features: \(.features.total) Completed: \(.features.completed) In Progress: \(.features.in_progress) Total Tasks: \(.tasks.total) Completed: \(.tasks.completed) Failed: \(.tasks.failed) Avg Completion Rate: \(.tasks.avg_completion_rate)% Total Tests: \(.tests.total) Passing: \(.tests.passing) (\(.tests.avg_pass_rate)%) Failing: \(.tests.failing)"' echo "" echo "๐Ÿ“ Features in $SPRINT_FILTER" echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" echo "$sprint_features" | jq -r '.[] | " [\(.metadata.feature_number)] \(.metadata.feature_name) Status: \(.metadata.status) | Tasks: \(.tasks.completed)/\(.tasks.total) | Tests: \(.tests.passing_tests)/\(.tests.total_tests)\n"' echo "" else #========================================================================== # DASHBOARD SUMMARY VIEW #========================================================================== echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "Overall Statistics" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "" echo "๐Ÿ“Š Features" echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" echo "$aggregates" | jq -r '" Total: \(.features.total) Completed: \(.features.completed) In Progress: \(.features.in_progress)"' echo "" echo "โœ… Tasks" echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" echo "$aggregates" | jq -r '" Total: \(.tasks.total) Completed: \(.tasks.completed) Failed: \(.tasks.failed) Avg Completion Rate: \(.tasks.avg_completion_rate)%"' echo "" echo "๐Ÿงช Tests" echo "โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€" if [ "$(echo "$aggregates" | jq '.tests.total')" -gt 0 ]; then echo "$aggregates" | jq -r '" Total: \(.tests.total) Passing: \(.tests.passing) (\(.tests.avg_pass_rate)%) Failing: \(.tests.failing)"' else echo " No test data found" fi echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "Recent Features (Last $RECENT_COUNT)" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "" # Get recent features recent_features=$(fm_get_recent "$features_json" "$RECENT_COUNT") # Display recent features table echo "$recent_features" | jq -r '.[] | "[\(.metadata.feature_number)] \(.metadata.feature_name) Status: \(.metadata.status) | Parent: \(.metadata.parent_branch) Tasks: \(.tasks.completed)/\(.tasks.total) (\(.tasks.completion_rate)%) | Tests: \(.tests.passing_tests)/\(.tests.total_tests) (\(.tests.pass_rate)%) Created: \(.metadata.created_at) "' # Sprint breakdown echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "Features by Sprint/Parent Branch" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "" # Group by parent branch echo "$features_json" | jq -r 'group_by(.metadata.parent_branch) | .[] | "[\(.[0].metadata.parent_branch)] Features: \(length) Tasks Completed: \([.[].tasks.completed] | add)/\([.[].tasks.total] | add) "' fi # Export to CSV if requested if [ -n "$EXPORT_FILE" ]; then echo "" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "Exporting to CSV" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "" exported_file=$(fm_export_csv "$features_json" "$EXPORT_FILE") echo "โœ… Metrics exported to: $exported_file" echo "" echo "Total rows: $((total_features + 1))" # +1 for header echo "" fi # Help message for next steps echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "Available Commands" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "" echo " /speclabs:feature-metrics Dashboard summary" echo " /speclabs:feature-metrics --recent 20 Show last 20 features" echo " /speclabs:feature-metrics --feature 015 Feature 015 details" echo " /speclabs:feature-metrics --sprint sprint-4 Sprint aggregates" echo " /speclabs:feature-metrics --export Export to CSV" echo " /speclabs:feature-metrics --path /project Analyze specific project" echo "" ``` This command provides comprehensive feature-level metrics by analyzing actual project artifacts instead of orchestration sessions. ## What It Tracks **Feature Detection**: - Scans for spec.md files to identify features - Works with any feature directory structure - No orchestration session required **Metrics Collected**: 1. **Feature Metadata** (from spec.md YAML): - Feature number, name, status - Parent branch, created/completed dates - Directory location 2. **Task Statistics** (from tasks.md): - Total, completed, failed, pending tasks - Completion rate percentage - Status markers (โœ… COMPLETED, โŒ FAILED) 3. **Test Metrics** (from validation/testing docs): - Total tests, passing, failing - Pass rate percentage - Extracted from validation summaries 4. **Git History**: - Branch information - Commit counts - Merge status and dates ## Usage Examples ### Dashboard Summary ```bash /speclabs:feature-metrics ``` Shows overall statistics and recent features. ### Feature Details ```bash /speclabs:feature-metrics --feature 015 ``` Complete metrics for Feature 015. ### Sprint Analysis ```bash /speclabs:feature-metrics --sprint sprint-4 ``` Aggregated metrics for all features in sprint-4. ### Export to CSV ```bash /speclabs:feature-metrics --export /speclabs:feature-metrics --export metrics-2025-11.csv ``` ### Analyze Different Project ```bash /speclabs:feature-metrics --path /home/user/projects/myapp ``` ## Key Features **No Session Required**: Analyzes actual feature artifacts, works with v2.6.1+ features that use `/specswarm:implement` **Sprint Tracking**: Group features by parent branch for sprint-level analytics **Export Capabilities**: CSV export for spreadsheet analysis **Git Integration**: Tracks merge status and commit history **Comprehensive**: Combines metadata, tasks, tests, and git data in one view ## Difference from `/speclabs:metrics` | Feature | /speclabs:metrics | /speclabs:feature-metrics | |---------|-------------------|---------------------------| | Data Source | Orchestration sessions | Project artifacts (spec.md, tasks.md) | | Workflow | Pre-v2.6.1 (per-task orchestration) | v2.6.1+ (specswarm implement) | | Use Case | Task-level automation tracking | Feature-level completion analytics | | Requires Session | Yes | No | ## Feature 015 Example Feature 015 (Testing Infrastructure) metrics would show: - 76 total tasks - 76 completed tasks (100%) - 136 total tests - 131 passing tests (96.3%) - Parent branch: sprint-4 - Status: Complete - Git: Merged to sprint-4 This data comes from reading Feature 015's actual files, not orchestration sessions.