fix(doc-guardian): make hook silent by default

- Remove all output by default to prevent workflow interruption
- Queue changes silently to .doc-guardian-queue
- Add file+type deduplication (same file won't be queued twice)
- Add DOC_GUARDIAN_VERBOSE=1 env var for opt-in notifications
- Users run /doc-sync or /doc-audit to process queue

Fixes #312 (partial - addresses issues 1, 2, 3)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-28 22:09:45 -05:00
parent 6e9b703151
commit 3c3b3b4575

View File

@@ -1,11 +1,12 @@
#!/bin/bash #!/bin/bash
# doc-guardian notification hook # doc-guardian notification hook
# Tracks documentation dependencies and queues updates # Tracks documentation dependencies and queues updates
# This is a command hook - guaranteed not to block workflow
# #
# IMPORTANT: Output is purely informational - uses passive language # SILENT BY DEFAULT - No output to avoid interrupting Claude's workflow.
# to avoid triggering Claude to seek user confirmation. # Changes are queued to .doc-guardian-queue for later processing.
# Run /doc-sync to process the queue when ready. # Run /doc-sync or /doc-audit to see and process pending updates.
#
# Set DOC_GUARDIAN_VERBOSE=1 to enable notification output.
# Read tool input from stdin (JSON with file_path) # Read tool input from stdin (JSON with file_path)
INPUT=$(cat) INPUT=$(cat)
@@ -48,40 +49,26 @@ DEPENDENT_DOCS="${DOC_DEPS[$MODIFIED_TYPE]}"
# Queue file for tracking pending updates # Queue file for tracking pending updates
QUEUE_FILE="${CLAUDE_PROJECT_ROOT:-.}/.doc-guardian-queue" QUEUE_FILE="${CLAUDE_PROJECT_ROOT:-.}/.doc-guardian-queue"
# Debounce: skip notification if same type was logged in last 5 seconds # Add to queue (always, for deduplication we check file+type combo)
# This prevents 4+ rapid notifications during batch edits # Format: timestamp | type | file_path | dependent_docs
DEBOUNCE_SECONDS=5 QUEUE_ENTRY="$(date +%Y-%m-%dT%H:%M:%S) | $MODIFIED_TYPE | $FILE_PATH | $DEPENDENT_DOCS"
# Check if this exact file+type combo already exists in queue (dedup)
if [ -f "$QUEUE_FILE" ]; then if [ -f "$QUEUE_FILE" ]; then
LAST_ENTRY=$(tail -1 "$QUEUE_FILE" 2>/dev/null || true) if grep -qF "| $MODIFIED_TYPE | $FILE_PATH |" "$QUEUE_FILE" 2>/dev/null; then
LAST_TYPE=$(echo "$LAST_ENTRY" | cut -d'|' -f2 | tr -d ' ') # Already queued, skip silently
LAST_TIME=$(echo "$LAST_ENTRY" | cut -d'|' -f1 | tr -d ' ')
if [ "$LAST_TYPE" = "$MODIFIED_TYPE" ] && [ -n "$LAST_TIME" ]; then
# Convert timestamps to seconds for comparison
LAST_EPOCH=$(date -d "$LAST_TIME" +%s 2>/dev/null || echo "0")
NOW_EPOCH=$(date +%s)
DIFF=$((NOW_EPOCH - LAST_EPOCH))
if [ "$DIFF" -lt "$DEBOUNCE_SECONDS" ]; then
# Still add to queue, but skip notification
{
echo "$(date +%Y-%m-%dT%H:%M:%S) | $MODIFIED_TYPE | $FILE_PATH | $DEPENDENT_DOCS"
} >> "$QUEUE_FILE" 2>/dev/null || true
exit 0 exit 0
fi fi
fi fi
fi
# Add to queue (create if doesn't exist, append if does) # Add to queue
{ echo "$QUEUE_ENTRY" >> "$QUEUE_FILE" 2>/dev/null || true
echo "$(date +%Y-%m-%dT%H:%M:%S) | $MODIFIED_TYPE | $FILE_PATH | $DEPENDENT_DOCS"
} >> "$QUEUE_FILE" 2>/dev/null || true
# Count pending updates # SILENT by default - only output if DOC_GUARDIAN_VERBOSE is set
# This prevents Claude from stopping to ask about documentation updates
if [ "${DOC_GUARDIAN_VERBOSE:-0}" = "1" ]; then
PENDING_COUNT=$(wc -l < "$QUEUE_FILE" 2>/dev/null | tr -d ' ' || echo "1") PENDING_COUNT=$(wc -l < "$QUEUE_FILE" 2>/dev/null | tr -d ' ' || echo "1")
echo "[doc-guardian] queued: $MODIFIED_TYPE ($PENDING_COUNT pending)"
# Output passive notification (no action implied) fi
# Uses "queued" instead of "update needed" to avoid triggering Claude to ask about it
echo "[doc-guardian] drift queued: $MODIFIED_TYPE$DEPENDENT_DOCS ($PENDING_COUNT total)"
exit 0 exit 0