commit 645d0b6a5f70a0adb6c3bbaab793ff0a96888450 Author: Zhongwei Li Date: Sun Nov 30 08:37:09 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..777b938 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,15 @@ +{ + "name": "beads", + "description": "Beads (bd) integration for dependency-aware issue tracking in AI workflows. Provides workflow guidance for issue lifecycle management, dependency tracking, and ready work discovery. Designed for AI-supervised development with bd ready → work → close patterns.", + "version": "0.3.0", + "author": { + "name": "Fred Amaral", + "email": "fred@fredamaral.com.br" + }, + "skills": [ + "./skills" + ], + "hooks": [ + "./hooks" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4ec3544 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# beads + +Beads (bd) integration for dependency-aware issue tracking in AI workflows. Provides workflow guidance for issue lifecycle management, dependency tracking, and ready work discovery. Designed for AI-supervised development with bd ready → work → close patterns. diff --git a/hooks/hooks.json b/hooks/hooks.json new file mode 100644 index 0000000..6db069a --- /dev/null +++ b/hooks/hooks.json @@ -0,0 +1,35 @@ +{ + "hooks": { + "SessionStart": [ + { + "matcher": "startup|resume", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh" + } + ] + }, + { + "matcher": "clear|compact", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh" + } + ] + } + ], + "Stop": [ + { + "matcher": "", + "hooks": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/stop-hook.sh" + } + ] + } + ] + } +} diff --git a/hooks/session-start.sh b/hooks/session-start.sh new file mode 100755 index 0000000..b567d16 --- /dev/null +++ b/hooks/session-start.sh @@ -0,0 +1,120 @@ +#!/usr/bin/env bash +set -euo pipefail +# Session start hook for beads plugin +# Checks bd installation, repo initialization, and injects workflow context + +# Check if bd is installed +if ! command -v bd &>/dev/null; then + cat <<'EOF' +{ + "hookSpecificOutput": { + "hookEventName": "SessionStart", + "additionalContext": "\n**Beads (bd) Not Installed**\n\nInstall beads for dependency-aware issue tracking:\nhttps://github.com/steveyegge/beads\n\nFor skill details: Skill tool with \"beads:using-beads\"\n" + } +} +EOF + exit 0 +fi + +# Check if beads is initialized in current repo +beads_initialized="false" +beads_db_path="" +info_json="" + +if info_json=$(bd info --json 2>/dev/null); then + if echo "$info_json" | grep -q '"database_path"'; then + beads_initialized="true" + if command -v jq &>/dev/null; then + beads_db_path=$(echo "$info_json" | jq -r '.database_path // ""') + fi + fi +fi + +# Build context based on initialization status +if [ "$beads_initialized" = "true" ]; then + # Get counts using jq if available + ready_count="0" + in_progress_count="0" + + if command -v jq &>/dev/null; then + ready_count=$(bd ready --json 2>/dev/null | jq 'length' || echo "0") + in_progress_count=$(bd list --status in_progress --json 2>/dev/null | jq 'length' || echo "0") + fi + + # Shorten path for display + display_path="$beads_db_path" + if [ -n "$beads_db_path" ]; then + display_path=$(echo "$beads_db_path" | sed "s|$HOME|~|") + fi + + context=" +**Beads (bd) - Issue Tracking ACTIVE** + +Database: ${display_path} +Ready: ${ready_count} | In Progress: ${in_progress_count} + +**START OF SESSION CHECKLIST:** +1. Run \`bd ready\` to see what's actionable +2. Run \`bd list --status in_progress\` to see claimed work +3. Claim work with \`bd update ID --status in_progress\` + +**Quick Commands:** +| Action | Command | +|--------|---------| +| What's ready? | \`bd ready\` | +| Start work | \`bd update ID --status in_progress\` | +| Create issue | \`bd create \"title\"\` | +| Add blocker | \`bd dep add BLOCKED BLOCKER\` | +| Finish work | \`bd close ID --reason \"...\"\` | + +**IMPORTANT:** Before ending session, leftover work (TODOs, FIXMEs, review issues) will be captured as beads issues. + +For full workflow: Skill tool with \"beads:using-beads\" +" +else + context=" +**Beads (bd) - NOT INITIALIZED IN THIS REPO** + +Beads is installed but this repository has no .beads/ directory. + +**ACTION REQUIRED:** Initialize beads for this project: +\`\`\`bash +bd init # Use directory name as prefix +bd init --prefix myapp # Or specify custom prefix +\`\`\` + +After initialization: +1. \`bd create \"First issue\"\` - Create your first issue +2. \`bd ready\` - See what's ready to work on + +**Why initialize?** +- Track discovered work as you code +- Manage dependencies between tasks +- Never lose TODOs, FIXMEs, or review items +- AI-friendly workflow with \`bd ready\` + +For full workflow: Skill tool with \"beads:using-beads\" +" +fi + +# Escape for JSON using jq +if command -v jq &>/dev/null; then + context_escaped=$(echo "$context" | jq -Rs . | sed 's/^"//;s/"$//') +else + context_escaped=$(printf '%s' "$context" | \ + sed 's/\\/\\\\/g' | \ + sed 's/"/\\"/g' | \ + sed 's/ /\\t/g' | \ + sed $'s/\r/\\\\r/g' | \ + sed 's/\f/\\f/g' | \ + awk '{printf "%s\\n", $0}') +fi + +cat </dev/null; then + # bd not installed - no action needed + cat <<'EOF' +{ + "decision": "approve", + "reason": "beads not installed" +} +EOF + exit 0 +fi + +# Check if beads is initialized +if ! bd info --json 2>/dev/null | grep -q '"database_path"'; then + # Not initialized - no action needed + cat <<'EOF' +{ + "decision": "approve", + "reason": "beads not initialized in this repo" +} +EOF + exit 0 +fi + +# Check if checkpoint has been completed +# Strategy: If there are open issues OR no uncommitted changes with markers, approve exit +OPEN_ISSUES=$(bd status 2>/dev/null | grep -E "Total Issues:|Open:" | head -2 | tail -1 | awk '{print $2}' || echo "0") +RECENT_MARKERS=$(git diff --name-only HEAD~5 2>/dev/null | head -20 | xargs grep -c -E "(TODO|FIXME|HACK|XXX):" 2>/dev/null | awk '{sum+=$1} END {print sum}' || echo "0") + +# If we have open issues capturing work, or no markers found, allow exit +if [[ "$OPEN_ISSUES" -gt 0 ]] || [[ "$RECENT_MARKERS" -eq 0 ]]; then + cat <<'EOF' +{ + "decision": "approve", + "reason": "beads checkpoint complete - work captured in issues or no markers found" +} +EOF + exit 0 +fi + +# Beads is active - inject prompt to capture leftover work +prompt='**BEADS END-OF-SESSION CHECKPOINT** + +Before ending this session, capture any leftover work as beads issues: + +1. **Search for code markers** in files modified this session: + ```bash + # Find TODOs, FIXMEs, HACKs, XXX in recent files + git diff --name-only HEAD~5 2>/dev/null | head -20 | xargs grep -n -E "(TODO|FIXME|HACK|XXX):" 2>/dev/null | head -30 + ``` + +2. **Check your TodoWrite list** - any incomplete items should become beads issues + +3. **Review any code review findings** that were flagged but not yet addressed + +4. **Create beads issues** for each piece of leftover work: + ```bash + bd create "TODO: [description from code]" -t task -p 2 + bd create "FIXME: [description from code]" -t bug -p 1 + bd create "Code review: [finding]" -t task -p 2 + ``` + +5. **Update in-progress issues** - if leaving work incomplete: + ```bash + bd update ISSUE-ID --status open # Release claim if blocked + bd comment ISSUE-ID "Session ended - progress: [summary]" + ``` + +6. **Run final status**: + ```bash + bd status + ``` + +If there is NO leftover work (all tasks completed, no TODOs found), you may proceed to end the session. + +**DO NOT** end the session without: +- Checking for leftover work markers +- Creating issues for any discovered work +- Updating any in-progress issues with status' + +# Escape for JSON using jq +if command -v jq &>/dev/null; then + prompt_escaped=$(echo "$prompt" | jq -Rs . | sed 's/^"//;s/"$//') +else + prompt_escaped=$(printf '%s' "$prompt" | \ + sed 's/\\/\\\\/g' | \ + sed 's/"/\\"/g' | \ + sed 's/ /\\t/g' | \ + sed $'s/\r/\\\\r/g' | \ + sed 's/\f/\\f/g' | \ + awk '{printf "%s\\n", $0}') +fi + +cat <