-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathissue_watcher.sh
More file actions
executable file
·496 lines (401 loc) · 18.7 KB
/
Copy pathissue_watcher.sh
File metadata and controls
executable file
·496 lines (401 loc) · 18.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
#!/bin/bash
# issue_watcher.sh - Watches for new GitHub issues and runs Claude Code analysis
#
# This script continuously monitors the GitHub repository for new issues that haven't
# been analyzed yet, then runs Claude Code (via 'clide' alias) to analyze each issue.
#
# The script will:
# 1. Check for issues without the "claude-analyzed" label every 60 seconds
# 2. For each new issue, create a detailed analysis prompt
# 3. Run clide (Claude Code) to analyze the issue
# 4. Save the analysis output to a markdown file
# 5. Mark the issue as analyzed to prevent re-processing
# Configuration - the GitHub repository to monitor
REPO="protocolus/promptforge"
# The prompt template that will be sent to Claude Code for issue analysis
CLAUDE_PROMPT="Please analyze this GitHub issue and perform the following tasks:
## STEP 0: Viability Check
First, determine if this issue represents a sensible and constructive request:
- Is the request technically feasible and aligned with the project's goals?
- Does it represent a legitimate bug, enhancement, or question?
- Is it spam, nonsensical, harmful, or a bad idea for the project?
If the issue is NOT viable (spam, nonsensical, harmful, or a bad idea):
- Clearly state: **RECOMMENDATION: CLOSE ISSUE**
- Explain why this issue should be closed
- Suggest the 'wontfix' or 'invalid' label as appropriate
- Be polite but firm in the explanation
If the issue IS viable, continue with the full analysis:
## STEP 1: Issue Classification
Classify this issue into one of these categories:
- bug: Software defect or error that needs fixing
- enhancement: New feature or improvement request
- question: Question or help request
- documentation: Documentation improvement needed
- maintenance: Code cleanup, refactoring, or maintenance task
## STEP 2: GitHub Labeling
Based on your classification, suggest appropriate GitHub labels that should be added to this issue. Consider:
- Issue type (bug, enhancement, question, documentation, maintenance)
- Priority level (high, medium, low)
- Complexity (easy, moderate, complex)
- Component affected (frontend, backend, database, etc.)
- Special labels (wontfix, invalid) if the issue should be closed
## STEP 3: Detailed Analysis
Provide:
1. **Issue Summary**: Brief description of what this issue is about
2. **Impact Assessment**: How this affects users or the system
3. **Priority Justification**: Why you assigned this priority level
4. **Complexity Estimate**: Technical difficulty and time investment
## STEP 4: Implementation Plan
Create a detailed plan with:
1. **Prerequisites**: What needs to be done first
2. **Step-by-step approach**: Numbered list of implementation steps
3. **Files likely to be modified**: List of files that may need changes
4. **Testing strategy**: How to verify the solution works
5. **Potential risks**: What could go wrong during implementation
## STEP 5: Questions and Clarifications
List any questions that need clarification from the issue author before work can begin.
Please format your response in clear markdown sections."
# Color codes for pretty terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
log_message() {
echo -e "${BLUE}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
log_success() {
echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
log_error() {
echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}
# Function to check if all required tools are installed and configured
check_dependencies() {
# Check if GitHub CLI is installed
if ! command -v gh &> /dev/null; then
log_error "GitHub CLI (gh) is not installed"
exit 1
fi
# Check if jq JSON processor is installed
if ! command -v jq &> /dev/null; then
log_error "jq is not installed"
exit 1
fi
# Check if claude CLI is available
if ! command -v claude &> /dev/null; then
log_error "claude CLI is not available"
log_error "Make sure Claude is installed and in your PATH"
exit 1
fi
log_message "claude CLI found - proceeding with issue monitoring"
# Verify GitHub CLI is authenticated
if ! gh auth status &> /dev/null; then
log_error "GitHub CLI is not authenticated. Run 'gh auth login'"
exit 1
fi
}
# Function to parse analysis file and automatically apply suggested GitHub labels
apply_suggested_labels() {
local issue_number=$1
local analysis_file=$2
log_message "Parsing analysis to extract suggested labels for issue #${issue_number}..."
# Extract lines that contain label suggestions from the analysis
# Look for patterns like "- bug", "- enhancement", "- high", etc.
local suggested_labels=""
# Parse the analysis file to find suggested labels
# This looks for common label patterns in the GitHub Labeling section
while IFS= read -r line; do
# Skip if we haven't reached the labeling section yet
if [[ "$line" =~ "## STEP 2: GitHub Labeling" ]]; then
# We're in the labeling section, start looking for labels
continue
fi
# Look for label suggestions (lines that mention specific labels)
if [[ "$line" =~ bug|enhancement|question|documentation|maintenance|high|medium|low|easy|moderate|complex|frontend|backend|database ]]; then
# Extract potential labels from the line
for word in $line; do
case "$word" in
*bug*) suggested_labels="$suggested_labels bug" ;;
*enhancement*) suggested_labels="$suggested_labels enhancement" ;;
*question*) suggested_labels="$suggested_labels question" ;;
*documentation*) suggested_labels="$suggested_labels documentation" ;;
*maintenance*) suggested_labels="$suggested_labels maintenance" ;;
*high*) suggested_labels="$suggested_labels priority-high" ;;
*medium*) suggested_labels="$suggested_labels priority-medium" ;;
*low*) suggested_labels="$suggested_labels priority-low" ;;
*easy*) suggested_labels="$suggested_labels difficulty-easy" ;;
*moderate*) suggested_labels="$suggested_labels difficulty-moderate" ;;
*complex*) suggested_labels="$suggested_labels difficulty-complex" ;;
*frontend*) suggested_labels="$suggested_labels component-frontend" ;;
*backend*) suggested_labels="$suggested_labels component-backend" ;;
*database*) suggested_labels="$suggested_labels component-database" ;;
esac
done
fi
done < "$analysis_file"
# Remove duplicates and apply labels
suggested_labels=$(echo "$suggested_labels" | tr ' ' '\n' | sort -u | tr '\n' ' ')
if [[ -n "$suggested_labels" ]]; then
log_message "Applying suggested labels: $suggested_labels"
# Apply each label individually (GitHub CLI can be finicky with multiple labels)
for label in $suggested_labels; do
if gh issue edit "$issue_number" --repo "$REPO" --add-label "$label" 2>/dev/null; then
log_success "Applied label: $label"
else
log_warning "Could not apply label: $label (may need to be created first)"
fi
sleep 1 # Brief pause between label applications
done
else
log_warning "No clear labels found in analysis for issue #${issue_number}"
fi
}
# Function to post the analysis as a comment on the GitHub issue
post_analysis_comment() {
local issue_number=$1
local analysis_file=$2
log_message "Posting analysis as comment on issue #${issue_number}..."
# Create a formatted comment with header and footer
local temp_comment=$(mktemp)
cat > "$temp_comment" << EOF
## 🤖 Automated Issue Analysis
Hi! I've automatically analyzed this issue using Claude Code. Here's my assessment:
---
$(cat "$analysis_file")
---
*This analysis was generated automatically by the PromptForge issue watcher. The suggestions above are AI-generated and should be reviewed by a human maintainer.*
*Issue analyzed at: $(date '+%Y-%m-%d %H:%M:%S UTC')*
EOF
# Post the comment to the GitHub issue
if gh issue comment "$issue_number" --repo "$REPO" --body-file "$temp_comment" 2>/dev/null; then
log_success "Posted analysis comment on issue #${issue_number}"
log_success "Comment visible at: https://github.com/${REPO}/issues/${issue_number}"
else
log_error "Failed to post comment on issue #${issue_number}"
log_error "Check GitHub permissions for commenting on issues"
fi
# Clean up temporary comment file
rm -f "$temp_comment"
}
# Function to check if Claude recommends closing the issue and close it if needed
check_and_close_if_needed() {
local issue_number=$1
local analysis_file=$2
log_message "Checking if issue #${issue_number} should be closed based on analysis..."
# Check if the analysis contains the close recommendation
if grep -q "RECOMMENDATION: CLOSE ISSUE" "$analysis_file"; then
log_warning "Claude recommends closing issue #${issue_number} as not viable"
# Extract the reason for closing (look for explanation after the recommendation)
local close_reason=""
local found_recommendation=false
while IFS= read -r line; do
if [[ "$line" =~ "RECOMMENDATION: CLOSE ISSUE" ]]; then
found_recommendation=true
continue
fi
# If we found the recommendation, capture the next few lines as the reason
if [[ "$found_recommendation" == true ]] && [[ -n "$line" ]]; then
close_reason="${close_reason}${line}\n"
# Stop after getting a reasonable explanation (usually 2-3 lines)
if [[ $(echo -e "$close_reason" | wc -l) -ge 3 ]]; then
break
fi
fi
done < "$analysis_file"
# Close the issue with a polite message
local close_message=$(mktemp)
cat > "$close_message" << EOF
## Issue Closed by Automated Analysis
This issue has been automatically closed based on the analysis above.
**Reason**: The automated analysis determined that this issue is not viable for implementation.
If you believe this was closed in error, please feel free to:
1. Provide additional context or clarification
2. Explain why this would benefit the project
3. Request that a maintainer review the decision
Thank you for your interest in PromptForge!
---
*This action was performed automatically by the PromptForge issue analyzer.*
EOF
# Post the closing comment
if gh issue comment "$issue_number" --repo "$REPO" --body-file "$close_message" 2>/dev/null; then
log_success "Posted closing explanation on issue #${issue_number}"
else
log_error "Failed to post closing comment on issue #${issue_number}"
fi
# Close the issue
if gh issue close "$issue_number" --repo "$REPO" --reason "not planned" 2>/dev/null; then
log_success "Closed issue #${issue_number} as not viable"
else
log_error "Failed to close issue #${issue_number}"
log_error "May need additional permissions to close issues"
fi
# Clean up
rm -f "$close_message"
else
log_message "Issue #${issue_number} is viable - keeping it open"
fi
}
# Function to process a single GitHub issue
# This handles the complete workflow for analyzing one issue
process_issue() {
local issue_number=$1 # GitHub issue number (e.g., 42)
local issue_title=$2 # The title of the issue
log_message "Processing issue #${issue_number}: ${issue_title}"
# Fetch the full issue content from GitHub
local issue_body=$(gh issue view "$issue_number" --repo "$REPO" --json body --jq '.body')
local issue_url="https://github.com/${REPO}/issues/${issue_number}"
# Create a temporary file containing the complete issue analysis prompt
# This file will be passed to clide (Claude Code) for processing
local temp_file=$(mktemp)
cat > "$temp_file" << EOF
# GitHub Issue Analysis Request
## Issue Details
- **Repository**: ${REPO}
- **Issue Number**: #${issue_number}
- **Title**: ${issue_title}
- **URL**: ${issue_url}
## Issue Description
${issue_body}
## Analysis Request
${CLAUDE_PROMPT}
EOF
log_message "Running claude -p (headless mode) analysis for issue #${issue_number}..."
# Create issues directory if it doesn't exist
mkdir -p issues
# Execute claude with -p flag (headless mode) and save output to markdown file in issues directory
# The output file will be named: issues/issue_[number]_analysis.md
if claude -p < "$temp_file" > "issues/issue_${issue_number}_analysis.md" 2>&1; then
log_success "Analysis completed for issue #${issue_number}"
log_success "Analysis saved to: issues/issue_${issue_number}_analysis.md"
# Parse the analysis to extract suggested labels and apply them automatically
apply_suggested_labels "$issue_number" "issues/issue_${issue_number}_analysis.md"
# Post the analysis as a comment on the GitHub issue
post_analysis_comment "$issue_number" "issues/issue_${issue_number}_analysis.md"
# Check if Claude recommends closing the issue
check_and_close_if_needed "$issue_number" "issues/issue_${issue_number}_analysis.md"
else
log_error "Failed to analyze issue #${issue_number}"
log_error "Check that claude -p is working properly"
fi
# Clean up the temporary prompt file
rm -f "$temp_file"
}
# Main function that continuously watches for new issues
# This is the heart of the script - it runs in an infinite loop
watch_issues() {
log_message "Starting issue watcher for repository: ${REPO}"
log_message "Checking for new issues every 20 seconds..."
log_message "Press Ctrl+C to stop the watcher"
# Infinite loop to continuously monitor for new issues
while true; do
log_message "Checking for new issues..."
# Search for issues that don't have the "clide-analyzed" label
# This prevents us from re-processing issues we've already handled
local new_issues=$(gh issue list --repo "$REPO" --search "-label:clide-analyzed" --json number,title --limit 50)
# Check if we found any new issues to process
if [ "$new_issues" != "[]" ]; then
# Process each new issue found
echo "$new_issues" | jq -c '.[]' | while read -r issue; do
# Extract issue number and title from JSON response
local issue_number=$(echo "$issue" | jq -r '.number')
local issue_title=$(echo "$issue" | jq -r '.title')
log_success "Found new issue #${issue_number}: ${issue_title}"
# Run the full analysis workflow for this issue
process_issue "$issue_number" "$issue_title"
# Mark the issue as processed by adding the "clide-analyzed" label
# This prevents re-processing the same issue in future runs
if gh issue edit "$issue_number" --repo "$REPO" --add-label "clide-analyzed" 2>/dev/null; then
log_success "Marked issue #${issue_number} as analyzed"
else
log_warning "Could not add label to issue #${issue_number} (may need repo permissions)"
fi
# Brief pause between processing issues to avoid GitHub API rate limiting
sleep 5
done
else
log_message "No new issues found"
fi
# Wait 20 seconds before checking for new issues again
log_message "Waiting 20 seconds before next check..."
sleep 20
done
}
# Function to handle graceful shutdown when user presses Ctrl+C
cleanup() {
log_message "Shutting down issue watcher..."
log_message "Thanks for using the GitHub issue watcher!"
exit 0
}
# Set up signal handlers to catch Ctrl+C and other termination signals
trap cleanup SIGINT SIGTERM
# Main script execution function
main() {
log_message "GitHub Issue Watcher for PromptForge"
log_message "Repository: ${REPO}"
# Verify all required tools are installed and configured
check_dependencies
# Setup required GitHub labels
log_message "Checking and setting up required GitHub labels..."
if [ -f "./setup_github_labels.sh" ]; then
if ./setup_github_labels.sh "$REPO"; then
log_success "GitHub labels are ready"
else
log_warning "Some labels could not be created, but continuing anyway"
fi
else
log_warning "setup_github_labels.sh not found - skipping label setup"
log_warning "Some operations may fail if required labels don't exist"
fi
# Start the continuous monitoring loop
watch_issues
}
# Help documentation for users
show_help() {
cat << EOF
GitHub Issue Watcher Script
===========================
This script monitors the protocolus/promptforge repository for new GitHub issues
and automatically runs Claude Code analysis on each new issue found.
Usage: $0 [options]
Options:
-h, --help Show this help message
Requirements:
- GitHub CLI (gh) installed and authenticated with 'gh auth login'
- jq installed for JSON processing
- claude CLI installed with -p (headless) flag support
How it works:
1. Continuously checks for issues without the "clide-analyzed" label
2. For each new issue found:
- Downloads the full issue content
- Creates a detailed analysis prompt
- Runs claude -p (Claude in headless mode) to analyze the issue
- Performs viability check (spam, nonsensical, harmful requests)
- Saves analysis to issues/issue_[number]_analysis.md
- Automatically applies suggested GitHub labels
- Posts analysis as a comment on the GitHub issue
- Closes issue automatically if deemed not viable
- Marks issue with "clide-analyzed" label to prevent re-processing
Output files:
- Analysis results saved in: issues/issue_[number]_analysis.md
- Colored terminal output with timestamps
- Automatic GitHub label application based on analysis
- Analysis posted as comments on GitHub issues
To stop the watcher: Press Ctrl+C
Repository monitored: ${REPO}
EOF
}
# Command line argument handling
case "${1:-}" in
-h|--help)
show_help
exit 0
;;
*)
# Start the main program
main "$@"
;;
esac