Initial commit
This commit is contained in:
289
hooks/README.md
Normal file
289
hooks/README.md
Normal file
@@ -0,0 +1,289 @@
|
||||
# SpecWeave GitHub Plugin Hooks
|
||||
|
||||
**Plugin**: `specweave-github`
|
||||
**Location**: `plugins/specweave-github/hooks/`
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
This hook provides GitHub Issues sync functionality for SpecWeave increments.
|
||||
|
||||
**Key Features**:
|
||||
- ✅ Updates GitHub issue checkboxes based on `tasks.md` completion status
|
||||
- ✅ Posts progress comments with percentage completion
|
||||
- ✅ Bidirectional sync (local → GitHub)
|
||||
- ✅ Non-blocking (failures don't stop core workflow)
|
||||
- ✅ Self-contained (no dependencies on core plugin)
|
||||
|
||||
**IMPORTANT CHANGE (v0.26.0)**: This hook is NO LONGER automatically triggered on task completion. GitHub sync should be done manually or on increment completion to avoid excessive API calls and performance overhead.
|
||||
|
||||
---
|
||||
|
||||
## Available Hooks
|
||||
|
||||
### 1. `post-task-completion.sh`
|
||||
|
||||
**Triggers**: Manual invocation or increment completion (NOT on task completion)
|
||||
|
||||
**Preconditions**:
|
||||
- ✅ Active increment exists (`.specweave/increments/####/`)
|
||||
- ✅ `metadata.json` has `.github.issue` field
|
||||
- ✅ GitHub CLI (`gh`) installed and authenticated
|
||||
- ✅ `tasks.md` file exists in increment
|
||||
|
||||
**Actions**:
|
||||
1. Reads completed tasks from `tasks.md`
|
||||
2. Fetches GitHub issue body
|
||||
3. Updates checkboxes for completed tasks
|
||||
4. Posts progress comment with percentage
|
||||
5. Logs all actions to `.specweave/logs/hooks-debug.log`
|
||||
|
||||
**Example Flow**:
|
||||
```
|
||||
Task T-003 completed in tasks.md
|
||||
↓
|
||||
Hook fires (PostToolUse + TodoWrite matcher)
|
||||
↓
|
||||
GitHub issue #42 checkboxes updated: [ ] T-003 → [x] T-003
|
||||
↓
|
||||
Progress comment posted: "Progress Update: 3/5 tasks (60%)"
|
||||
↓
|
||||
Log: "[GitHub] ✅ GitHub sync complete"
|
||||
```
|
||||
|
||||
**Dependencies**:
|
||||
- `gh` CLI (GitHub CLI)
|
||||
- `jq` for JSON parsing
|
||||
- Bash 4.0+
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Hook Registration
|
||||
|
||||
**DEPRECATED (v0.26.0)**: This hook is NO LONGER automatically registered on TodoWrite events.
|
||||
|
||||
**Previous behavior (v0.24.0 and earlier)**:
|
||||
- Hook automatically fired on EVERY task completion
|
||||
- Caused excessive GitHub API calls
|
||||
- Created performance overhead and duplicate executions
|
||||
|
||||
**New behavior (v0.26.0+)**:
|
||||
- Hook must be invoked manually via `/specweave-github:sync`
|
||||
- OR triggered on increment completion (not task completion)
|
||||
- Reduces API calls by 90%+
|
||||
- Eliminates duplicate hook executions
|
||||
|
||||
### Usage
|
||||
|
||||
**Manual Sync** (recommended workflow):
|
||||
```bash
|
||||
# After completing several tasks, sync progress to GitHub
|
||||
/specweave-github:sync
|
||||
|
||||
# Or sync specific feature
|
||||
/specweave-github:sync FS-048
|
||||
```
|
||||
|
||||
**Automatic Sync Options**:
|
||||
1. **On Increment Completion**: Add hook to specweave plugin's post-increment-completion
|
||||
2. **Periodic Sync**: Set up cron job or CI/CD trigger
|
||||
3. **On Demand**: Call `/specweave-github:sync` when needed
|
||||
|
||||
### Metadata Format
|
||||
|
||||
Increments must have `metadata.json` with GitHub issue link:
|
||||
|
||||
```json
|
||||
{
|
||||
"github": {
|
||||
"issue": 42,
|
||||
"url": "https://github.com/owner/repo/issues/42",
|
||||
"repo": "owner/repo"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
### Automatic (Recommended)
|
||||
|
||||
When `specweave init` runs, all plugin hooks are automatically installed:
|
||||
|
||||
```bash
|
||||
npx specweave init my-project
|
||||
# Installs all plugins including specweave-github
|
||||
# Hooks auto-register via hooks.json
|
||||
```
|
||||
|
||||
### Manual (Development)
|
||||
|
||||
For testing or development:
|
||||
|
||||
```bash
|
||||
# Install plugin
|
||||
/plugin install specweave-github
|
||||
|
||||
# Verify hook registration
|
||||
cat ~/.claude/settings.json
|
||||
# Should show specweave-github hooks registered
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Hook Independently
|
||||
|
||||
```bash
|
||||
# Test syntax
|
||||
bash -n plugins/specweave-github/hooks/post-task-completion.sh
|
||||
|
||||
# Test execution (requires active increment + GitHub issue)
|
||||
./plugins/specweave-github/hooks/post-task-completion.sh
|
||||
```
|
||||
|
||||
### Test with GitHub Issue
|
||||
|
||||
1. Create increment: `/specweave:increment "test feature"`
|
||||
2. Create GitHub issue: `/specweave-github:create-issue 0001`
|
||||
3. Complete several tasks via TodoWrite
|
||||
4. **Manually trigger sync**: `/specweave-github:sync`
|
||||
5. Check GitHub issue for updates
|
||||
|
||||
---
|
||||
|
||||
## Logging
|
||||
|
||||
All GitHub sync actions are logged to:
|
||||
|
||||
```
|
||||
.specweave/logs/hooks-debug.log
|
||||
```
|
||||
|
||||
**Example Log Output**:
|
||||
```
|
||||
[2025-11-10] [GitHub] 🔗 GitHub sync hook fired
|
||||
[2025-11-10] [GitHub] 🔄 Syncing to GitHub issue #42
|
||||
[2025-11-10] [GitHub] 📊 Syncing task checkboxes to GitHub issue #42
|
||||
[2025-11-10] [GitHub] Completed tasks found: T-001 T-002 T-003
|
||||
[2025-11-10] [GitHub] Updated checkbox for task: T-001
|
||||
[2025-11-10] [GitHub] Updated checkbox for task: T-002
|
||||
[2025-11-10] [GitHub] Updated checkbox for task: T-003
|
||||
[2025-11-10] [GitHub] ✅ Issue description checkboxes updated
|
||||
[2025-11-10] [GitHub] ✅ Progress comment posted (60%)
|
||||
[2025-11-10] [GitHub] ✅ GitHub sync complete
|
||||
```
|
||||
|
||||
**Log Prefixes**:
|
||||
- `[GitHub]` - All messages from this hook
|
||||
- `🔗` - Hook fired
|
||||
- `🔄` - Syncing started
|
||||
- `📊` - Syncing task data
|
||||
- `✅` - Success
|
||||
- `⚠️` - Warning (non-blocking failure)
|
||||
- `ℹ️` - Info (skipped due to precondition)
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### How It Works with Core Plugin
|
||||
|
||||
**Before (v0.12.x)**:
|
||||
```
|
||||
Core hook (500+ lines)
|
||||
├── Sound notifications
|
||||
├── Living docs sync
|
||||
├── Translation
|
||||
├── GitHub sync ← Embedded in core!
|
||||
├── JIRA sync ← Embedded in core!
|
||||
└── ADO sync ← Embedded in core!
|
||||
```
|
||||
|
||||
**After (v0.13.0+)**:
|
||||
```
|
||||
Core hook (330 lines) GitHub plugin hook (241 lines)
|
||||
├── Sound notifications ├── Check for GitHub issue
|
||||
├── Living docs sync ├── Update checkboxes
|
||||
├── Translation ├── Post progress comment
|
||||
└── Self-reflection └── Log actions
|
||||
```
|
||||
|
||||
**Key Benefits**:
|
||||
- ✅ **Separation of concerns**: Core plugin has NO external tool dependencies
|
||||
- ✅ **Optional plugin**: GitHub sync only runs if `specweave-github` installed
|
||||
- ✅ **Independent testing**: Test GitHub sync in isolation
|
||||
- ✅ **Cleaner code**: Each hook <250 lines, single responsibility
|
||||
- ✅ **Parallel execution**: Claude Code runs all hooks concurrently
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Hook Not Firing
|
||||
|
||||
**Check**:
|
||||
1. Plugin installed: `/plugin list --installed | grep specweave-github`
|
||||
2. Hook registered: `cat ~/.claude/settings.json | grep specweave-github`
|
||||
3. Active increment: `cat .specweave/logs/current-increment`
|
||||
4. GitHub issue linked: `cat .specweave/increments/####/metadata.json | jq .github`
|
||||
|
||||
### GitHub CLI Not Found
|
||||
|
||||
**Fix**:
|
||||
```bash
|
||||
# macOS
|
||||
brew install gh
|
||||
|
||||
# Linux
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
|
||||
sudo apt update
|
||||
sudo apt install gh
|
||||
|
||||
# Authenticate
|
||||
gh auth login
|
||||
```
|
||||
|
||||
### Sync Failures
|
||||
|
||||
**Check logs**:
|
||||
```bash
|
||||
tail -f .specweave/logs/hooks-debug.log | grep '\[GitHub\]'
|
||||
```
|
||||
|
||||
**Common issues**:
|
||||
- ❌ No `metadata.json`: Create GitHub issue via `/specweave-github:create-issue`
|
||||
- ❌ Not authenticated: Run `gh auth login`
|
||||
- ❌ Invalid issue number: Check `metadata.json` has correct issue ID
|
||||
- ❌ Network error: Check internet connection
|
||||
|
||||
---
|
||||
|
||||
## Migration from v0.12.x
|
||||
|
||||
If upgrading from SpecWeave v0.12.x or earlier:
|
||||
|
||||
1. **Automatic**: Run `specweave init` (re-installs all hooks)
|
||||
2. **Manual**: Copy `plugins/specweave-github/hooks/` to `.claude/hooks/` (not recommended)
|
||||
|
||||
**No action needed**: Existing increments with GitHub issues will continue to sync automatically.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- **Core Plugin Hooks**: `plugins/specweave/hooks/README.md`
|
||||
- **Architecture Analysis**: `.specweave/increments/0018-strict-increment-discipline-enforcement/reports/HOOKS-ARCHITECTURE-ANALYSIS.md`
|
||||
- **Claude Code Hooks Guide**: https://code.claude.com/docs/en/hooks-guide
|
||||
- **GitHub Sync Command**: `plugins/specweave-github/commands/specweave-github-sync.md`
|
||||
|
||||
---
|
||||
|
||||
**Version**: v0.13.0+
|
||||
**Last Updated**: 2025-11-10
|
||||
319
hooks/post-task-completion.sh
Executable file
319
hooks/post-task-completion.sh
Executable file
@@ -0,0 +1,319 @@
|
||||
#!/bin/bash
|
||||
|
||||
# SpecWeave GitHub Sync Hook
|
||||
# Runs after task completion to sync progress to GitHub Projects
|
||||
#
|
||||
# ARCHITECTURE (v0.19.0+): IMMUTABLE DESCRIPTIONS + PROGRESS COMMENTS
|
||||
# - User Story files (.specweave/docs/internal/specs/) ↔ GitHub Issues
|
||||
# - Issue descriptions created once (IMMUTABLE snapshot)
|
||||
# - All updates via progress comments (audit trail)
|
||||
#
|
||||
# This hook is part of the specweave-github plugin and handles:
|
||||
# - Finding which spec user stories the current work belongs to
|
||||
# - Syncing progress via GitHub comments (NOT editing issue body)
|
||||
# - Creating audit trail of all changes over time
|
||||
# - Notifying stakeholders via GitHub notifications
|
||||
#
|
||||
# Dependencies:
|
||||
# - Node.js and TypeScript CLI (dist/cli/commands/sync-spec-content.js)
|
||||
# - GitHub CLI (gh) must be installed and authenticated
|
||||
# - ProgressCommentBuilder (lib/progress-comment-builder.ts)
|
||||
|
||||
set +e # EMERGENCY FIX: Prevents Claude Code crashes
|
||||
|
||||
# EMERGENCY KILL SWITCH
|
||||
if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# CIRCUIT BREAKER & FILE LOCKING
|
||||
# ============================================================================
|
||||
|
||||
# CIRCUIT BREAKER: Auto-disable after consecutive failures
|
||||
CIRCUIT_BREAKER_FILE=".specweave/state/.hook-circuit-breaker-github"
|
||||
CIRCUIT_BREAKER_THRESHOLD=3
|
||||
|
||||
mkdir -p ".specweave/state" 2>/dev/null || true
|
||||
|
||||
if [[ -f "$CIRCUIT_BREAKER_FILE" ]]; then
|
||||
FAILURE_COUNT=$(cat "$CIRCUIT_BREAKER_FILE" 2>/dev/null || echo 0)
|
||||
if (( FAILURE_COUNT >= CIRCUIT_BREAKER_THRESHOLD )); then
|
||||
# Circuit breaker is OPEN - hooks are disabled
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# FILE LOCK: Only allow 1 GitHub sync hook at a time
|
||||
LOCK_FILE=".specweave/state/.hook-github-sync.lock"
|
||||
LOCK_TIMEOUT=15 # seconds (GitHub sync can take longer)
|
||||
|
||||
LOCK_ACQUIRED=false
|
||||
for i in {1..15}; do
|
||||
if mkdir "$LOCK_FILE" 2>/dev/null; then
|
||||
LOCK_ACQUIRED=true
|
||||
trap 'rmdir "$LOCK_FILE" 2>/dev/null || true' EXIT
|
||||
break
|
||||
fi
|
||||
|
||||
# Check for stale lock
|
||||
if [[ -d "$LOCK_FILE" ]]; then
|
||||
LOCK_AGE=$(($(date +%s) - $(stat -f "%m" "$LOCK_FILE" 2>/dev/null || echo 0)))
|
||||
if (( LOCK_AGE > LOCK_TIMEOUT )); then
|
||||
rmdir "$LOCK_FILE" 2>/dev/null || true
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 0.2
|
||||
done
|
||||
|
||||
if [[ "$LOCK_ACQUIRED" == "false" ]]; then
|
||||
# Another instance is running, skip
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# PROJECT ROOT DETECTION
|
||||
# ============================================================================
|
||||
|
||||
# Find project root by searching upward for .specweave/ directory
|
||||
find_project_root() {
|
||||
local dir="$1"
|
||||
while [ "$dir" != "/" ]; do
|
||||
if [ -d "$dir/.specweave" ]; then
|
||||
echo "$dir"
|
||||
return 0
|
||||
fi
|
||||
dir="$(dirname "$dir")"
|
||||
done
|
||||
# Fallback: try current directory
|
||||
if [ -d "$(pwd)/.specweave" ]; then
|
||||
pwd
|
||||
else
|
||||
echo "$(pwd)"
|
||||
fi
|
||||
}
|
||||
|
||||
PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
|
||||
cd "$PROJECT_ROOT" 2>/dev/null || true
|
||||
|
||||
# ============================================================================
|
||||
# CONFIGURATION
|
||||
# ============================================================================
|
||||
|
||||
LOGS_DIR=".specweave/logs"
|
||||
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
|
||||
|
||||
mkdir -p "$LOGS_DIR" 2>/dev/null || true
|
||||
|
||||
# ============================================================================
|
||||
# PRECONDITIONS CHECK
|
||||
# ============================================================================
|
||||
|
||||
echo "[$(date)] [GitHub] 🔗 GitHub sync hook fired" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
# Check if Node.js is available
|
||||
if ! command -v node &> /dev/null; then
|
||||
echo "[$(date)] [GitHub] ⚠️ Node.js not found, skipping GitHub sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
cat <<EOF
|
||||
{
|
||||
"continue": true
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check if github-spec-content-sync CLI exists
|
||||
SYNC_CLI="$PROJECT_ROOT/dist/src/cli/commands/sync-spec-content.js"
|
||||
if [ ! -f "$SYNC_CLI" ]; then
|
||||
echo "[$(date)] [GitHub] ⚠️ sync-spec-content CLI not found at $SYNC_CLI, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
cat <<EOF
|
||||
{
|
||||
"continue": true
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for gh CLI
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "[$(date)] [GitHub] ⚠️ GitHub CLI (gh) not found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
cat <<EOF
|
||||
{
|
||||
"continue": true
|
||||
}
|
||||
EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# DETECT ALL SPECS (Multi-Spec Support)
|
||||
# ============================================================================
|
||||
|
||||
# Strategy: Use multi-spec detector to find ALL specs referenced in current increment
|
||||
|
||||
# 1. Detect current increment (temporary context)
|
||||
CURRENT_INCREMENT=$(ls -td .specweave/increments/*/ 2>/dev/null | xargs -n1 basename | grep -v "_backlog" | grep -v "_archive" | grep -v "_working" | head -1)
|
||||
|
||||
if [ -z "$CURRENT_INCREMENT" ]; then
|
||||
echo "[$(date)] [GitHub] ℹ️ No active increment, checking for spec changes..." >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
# Fall through to sync all changed specs
|
||||
fi
|
||||
|
||||
# 2. Use TypeScript CLI to detect all specs
|
||||
DETECT_CLI="$PROJECT_ROOT/dist/src/cli/commands/detect-specs.js"
|
||||
|
||||
if [ -f "$DETECT_CLI" ]; then
|
||||
echo "[$(date)] [GitHub] 🔍 Detecting all specs in increment $CURRENT_INCREMENT..." >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
# Call detect-specs CLI and capture JSON output
|
||||
DETECTION_RESULT=$(node "$DETECT_CLI" 2>> "$DEBUG_LOG" || echo "{}")
|
||||
|
||||
# Extract spec count
|
||||
SPEC_COUNT=$(echo "$DETECTION_RESULT" | node -e "const fs=require('fs'); const data=JSON.parse(fs.readFileSync(0,'utf-8')); console.log(data.specs?.length || 0)")
|
||||
|
||||
echo "[$(date)] [GitHub] 📋 Detected $SPEC_COUNT spec(s)" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
# Store detection result for later use
|
||||
echo "$DETECTION_RESULT" > /tmp/specweave-detected-specs.json
|
||||
else
|
||||
echo "[$(date)] [GitHub] ⚠️ detect-specs CLI not found at $DETECT_CLI, falling back to git diff" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
SPEC_COUNT=0
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# SYNC ALL DETECTED SPECS TO GITHUB (Multi-Spec Support)
|
||||
# ============================================================================
|
||||
|
||||
if [ -f /tmp/specweave-detected-specs.json ] && [ "$SPEC_COUNT" -gt 0 ]; then
|
||||
# Multi-spec sync: Loop through all detected specs
|
||||
echo "[$(date)] [GitHub] 🔄 Syncing $SPEC_COUNT spec(s) to GitHub..." >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
# Extract spec paths using Node.js
|
||||
SPEC_PATHS=$(node -e "
|
||||
const fs = require('fs');
|
||||
const data = JSON.parse(fs.readFileSync('/tmp/specweave-detected-specs.json', 'utf-8'));
|
||||
const syncable = data.specs.filter(s => s.syncEnabled && s.project !== '_parent');
|
||||
syncable.forEach(s => console.log(s.path));
|
||||
" 2>> "$DEBUG_LOG")
|
||||
|
||||
# Count syncable specs
|
||||
SYNCABLE_COUNT=$(echo "$SPEC_PATHS" | grep -v '^$' | wc -l | tr -d ' ')
|
||||
|
||||
if [ "$SYNCABLE_COUNT" -gt 0 ]; then
|
||||
echo "[$(date)] [GitHub] 📋 Syncing $SYNCABLE_COUNT syncable spec(s) (excluding _parent)" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
# Sync each spec
|
||||
echo "$SPEC_PATHS" | while read -r SPEC_FILE; do
|
||||
if [ -n "$SPEC_FILE" ] && [ -f "$SPEC_FILE" ]; then
|
||||
# Extract project and spec ID from path
|
||||
SPEC_NAME=$(basename "$SPEC_FILE" .md)
|
||||
PROJECT=$(basename "$(dirname "$SPEC_FILE")")
|
||||
|
||||
echo "[$(date)] [GitHub] 🔄 Syncing $PROJECT/$SPEC_NAME..." >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
(cd "$PROJECT_ROOT" && node "$SYNC_CLI" --spec "$SPEC_FILE" --provider github) 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
|
||||
echo "[$(date)] [GitHub] ⚠️ Spec sync failed for $PROJECT/$SPEC_NAME (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
}
|
||||
|
||||
echo "[$(date)] [GitHub] ✅ Synced $PROJECT/$SPEC_NAME" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
echo "[$(date)] [GitHub] ✅ Multi-spec sync complete ($SYNCABLE_COUNT synced)" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
else
|
||||
echo "[$(date)] [GitHub] ℹ️ No syncable specs (all specs are _parent or syncEnabled=false)" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Cleanup temp file
|
||||
rm -f /tmp/specweave-detected-specs.json 2>/dev/null || true
|
||||
else
|
||||
# Fallback: Sync all modified specs (check git diff)
|
||||
echo "[$(date)] [GitHub] 🔄 Checking for modified specs..." >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
MODIFIED_SPECS=$(git diff --name-only HEAD .specweave/docs/internal/specs/**/*.md 2>/dev/null || echo "")
|
||||
|
||||
if [ -n "$MODIFIED_SPECS" ]; then
|
||||
echo "[$(date)] [GitHub] 📝 Found modified specs:" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
echo "$MODIFIED_SPECS" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
# Sync each modified spec
|
||||
echo "$MODIFIED_SPECS" | while read -r SPEC_FILE; do
|
||||
if [ -n "$SPEC_FILE" ] && [ -f "$SPEC_FILE" ]; then
|
||||
echo "[$(date)] [GitHub] 🔄 Syncing $SPEC_FILE..." >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
(cd "$PROJECT_ROOT" && node "$SYNC_CLI" --spec "$SPEC_FILE" --provider github) 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
echo "[$(date)] [GitHub] ✅ Batch spec sync complete" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
else
|
||||
echo "[$(date)] [GitHub] ℹ️ No modified specs found, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# EPIC GITHUB ISSUE SYNC (DEPRECATED v0.24.0+)
|
||||
# ============================================================================
|
||||
#
|
||||
# ⚠️ DEPRECATED: SpecWeave now syncs ONLY at User Story level.
|
||||
#
|
||||
# Feature/Epic-level issues are no longer updated.
|
||||
# Use /specweave-github:sync instead to sync User Story issues.
|
||||
#
|
||||
# To re-enable (NOT recommended):
|
||||
# export SPECWEAVE_ENABLE_EPIC_SYNC=true
|
||||
#
|
||||
# @see .specweave/increments/0047-us-task-linkage/reports/GITHUB-TITLE-FORMAT-FIX-PLAN.md
|
||||
# ============================================================================
|
||||
|
||||
if [ "$SPECWEAVE_ENABLE_EPIC_SYNC" = "true" ]; then
|
||||
echo "[$(date)] [GitHub] 🔄 Checking for Epic GitHub issue update (DEPRECATED)..." >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
# Find active increment ID
|
||||
ACTIVE_INCREMENT=$(ls -t .specweave/increments/ | grep -v '^\.' | while read inc; do
|
||||
if [ -f ".specweave/increments/$inc/metadata.json" ]; then
|
||||
STATUS=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' ".specweave/increments/$inc/metadata.json" 2>/dev/null | sed 's/.*"\([^"]*\)".*/\1/' || true)
|
||||
if [ "$STATUS" = "active" ]; then
|
||||
echo "$inc"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done | head -1)
|
||||
|
||||
if [ -n "$ACTIVE_INCREMENT" ]; then
|
||||
echo "[$(date)] [GitHub] 🎯 Active increment: $ACTIVE_INCREMENT" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
|
||||
# Run Epic sync script (silently, errors logged to debug log)
|
||||
if [ -f "$PROJECT_ROOT/scripts/update-epic-github-issue.sh" ]; then
|
||||
echo "[$(date)] [GitHub] 🚀 Updating Epic GitHub issue (DEPRECATED)..." >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
"$PROJECT_ROOT/scripts/update-epic-github-issue.sh" "$ACTIVE_INCREMENT" >> "$DEBUG_LOG" 2>&1 || true
|
||||
echo "[$(date)] [GitHub] ⚠️ Epic sync is deprecated. Use /specweave-github:sync instead." >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
else
|
||||
echo "[$(date)] [GitHub] ⚠️ Epic sync script not found, skipping" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
echo "[$(date)] [GitHub] ℹ️ No active increment found, skipping Epic sync" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
echo "[$(date)] [GitHub] ℹ️ Epic sync disabled (sync at User Story level only)" >> "$DEBUG_LOG" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# CIRCUIT BREAKER UPDATE
|
||||
# ============================================================================
|
||||
# Reset circuit breaker on successful completion (all errors are caught above)
|
||||
echo "0" > "$CIRCUIT_BREAKER_FILE" 2>/dev/null || true
|
||||
|
||||
# ============================================================================
|
||||
# OUTPUT TO CLAUDE
|
||||
# ============================================================================
|
||||
|
||||
cat <<EOF
|
||||
{
|
||||
"continue": true
|
||||
}
|
||||
EOF
|
||||
|
||||
# ALWAYS exit 0 - NEVER let hook errors crash Claude Code
|
||||
exit 0
|
||||
Reference in New Issue
Block a user