feat(dashboard): add dashboard skill for milestone/issue overview
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
47
skills/dashboard/SKILL.md
Normal file
47
skills/dashboard/SKILL.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
---
|
||||||
|
name: dashboard
|
||||||
|
description: >
|
||||||
|
Display milestones with unblocked issues at a glance.
|
||||||
|
Use when you want to see project progress and which issues are ready to work on.
|
||||||
|
Invoke with /dashboard [milestone-name-filter]
|
||||||
|
model: claude-haiku-4-5
|
||||||
|
user-invocable: true
|
||||||
|
context: fork
|
||||||
|
allowed-tools:
|
||||||
|
- Bash(~/.claude/skills/dashboard/scripts/generate-dashboard.sh*)
|
||||||
|
---
|
||||||
|
|
||||||
|
# Dashboard
|
||||||
|
|
||||||
|
@~/.claude/skills/gitea/SKILL.md
|
||||||
|
|
||||||
|
Display all milestones and their unblocked issues. Issues are considered unblocked if they have no open blockers in their dependency list.
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. **Run the dashboard script** with the milestone filter argument (if provided):
|
||||||
|
```bash
|
||||||
|
~/.claude/skills/dashboard/scripts/generate-dashboard.sh "$1"
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Display the output** to the user
|
||||||
|
|
||||||
|
The script automatically:
|
||||||
|
- Fetches all milestones from the repository
|
||||||
|
- For each milestone, gets all open issues
|
||||||
|
- For each issue, checks dependencies with `tea issues deps list`
|
||||||
|
- Categorizes issues as unblocked (no open dependencies) or blocked (has open dependencies)
|
||||||
|
- Displays results grouped by milestone in this format:
|
||||||
|
|
||||||
|
```
|
||||||
|
## Milestone: Release 1.0
|
||||||
|
|
||||||
|
✓ Unblocked (3):
|
||||||
|
#42 Implement feature X
|
||||||
|
#43 Fix bug in Y
|
||||||
|
#45 Add tests for Z
|
||||||
|
|
||||||
|
⊘ Blocked (2):
|
||||||
|
#40 Feature A (blocked by #39)
|
||||||
|
#41 Feature B (blocked by #38, #37)
|
||||||
|
```
|
||||||
83
skills/dashboard/scripts/generate-dashboard.sh
Executable file
83
skills/dashboard/scripts/generate-dashboard.sh
Executable file
@@ -0,0 +1,83 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Generate dashboard showing milestones with unblocked/blocked issues
|
||||||
|
# Usage: ./generate-dashboard.sh [milestone-filter]
|
||||||
|
|
||||||
|
MILESTONE_FILTER="${1:-}"
|
||||||
|
|
||||||
|
# Get all milestones
|
||||||
|
milestones_json=$(tea milestones -o json)
|
||||||
|
|
||||||
|
# Parse milestone names
|
||||||
|
milestone_names=$(echo "$milestones_json" | jq -r '.[].title')
|
||||||
|
|
||||||
|
# Process each milestone
|
||||||
|
while IFS= read -r milestone; do
|
||||||
|
# Skip if filter provided and doesn't match
|
||||||
|
if [[ -n "$MILESTONE_FILTER" && ! "$milestone" =~ $MILESTONE_FILTER ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "## Milestone: $milestone"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Get open issues for this milestone
|
||||||
|
issues_json=$(tea issues --milestones "$milestone" --state open -o json 2>/dev/null || echo "[]")
|
||||||
|
|
||||||
|
# Skip empty milestones or invalid JSON
|
||||||
|
issue_count=$(echo "$issues_json" | jq -e 'length' 2>/dev/null || echo "0")
|
||||||
|
if [[ "$issue_count" -eq 0 ]]; then
|
||||||
|
echo "No open issues"
|
||||||
|
echo ""
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Arrays for categorizing issues
|
||||||
|
declare -a unblocked=()
|
||||||
|
declare -a blocked=()
|
||||||
|
|
||||||
|
# Process each issue
|
||||||
|
while IFS=$'\t' read -r number title; do
|
||||||
|
# Check dependencies (tea returns plain text "Issue #N has no dependencies" when empty)
|
||||||
|
deps_output=$(tea issues deps list "$number" -o json 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
# If output contains "has no dependencies", treat as empty array
|
||||||
|
if [[ "$deps_output" == *"has no dependencies"* ]]; then
|
||||||
|
deps_json="[]"
|
||||||
|
else
|
||||||
|
deps_json="$deps_output"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Count open dependencies
|
||||||
|
open_deps=$(echo "$deps_json" | jq -r '[.[] | select(.state == "open")] | length' 2>/dev/null || echo "0")
|
||||||
|
|
||||||
|
if [[ "$open_deps" -eq 0 ]]; then
|
||||||
|
# No open blockers - unblocked
|
||||||
|
unblocked+=("#$number $title")
|
||||||
|
else
|
||||||
|
# Has open blockers - blocked
|
||||||
|
blocker_list=$(echo "$deps_json" | jq -r '[.[] | select(.state == "open") | "#\(.index)"] | join(", ")')
|
||||||
|
blocked+=("#$number $title (blocked by $blocker_list)")
|
||||||
|
fi
|
||||||
|
done < <(echo "$issues_json" | jq -r '.[] | [.index, .title] | @tsv')
|
||||||
|
|
||||||
|
# Display unblocked issues
|
||||||
|
echo "✓ Unblocked (${#unblocked[@]}):"
|
||||||
|
if [[ ${#unblocked[@]} -eq 0 ]]; then
|
||||||
|
echo " (none)"
|
||||||
|
else
|
||||||
|
printf ' %s\n' "${unblocked[@]}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Display blocked issues
|
||||||
|
echo "⊘ Blocked (${#blocked[@]}):"
|
||||||
|
if [[ ${#blocked[@]} -eq 0 ]]; then
|
||||||
|
echo " (none)"
|
||||||
|
else
|
||||||
|
printf ' %s\n' "${blocked[@]}"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
done <<< "$milestone_names"
|
||||||
Reference in New Issue
Block a user