thrivekit 2.0.13 → 2.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/ralph/loop.sh +149 -6
- package/ralph/verify/review.sh +3 -15
package/package.json
CHANGED
package/ralph/loop.sh
CHANGED
|
@@ -2,6 +2,90 @@
|
|
|
2
2
|
# shellcheck shell=bash
|
|
3
3
|
# loop.sh - The autonomous development loop
|
|
4
4
|
|
|
5
|
+
# Pre-flight checks to catch common issues before wasting iterations
|
|
6
|
+
preflight_checks() {
|
|
7
|
+
echo "--- Pre-flight Checks ---"
|
|
8
|
+
local warnings=0
|
|
9
|
+
|
|
10
|
+
# Check API connectivity if configured
|
|
11
|
+
local api_url
|
|
12
|
+
api_url=$(get_config '.api.baseUrl' "")
|
|
13
|
+
if [[ -n "$api_url" ]]; then
|
|
14
|
+
printf " API connectivity ($api_url)... "
|
|
15
|
+
if curl -sf --connect-timeout 5 "$api_url" >/dev/null 2>&1 || \
|
|
16
|
+
curl -sf --connect-timeout 5 "${api_url}/health" >/dev/null 2>&1 || \
|
|
17
|
+
curl -sf --connect-timeout 5 "${api_url}/api/health" >/dev/null 2>&1; then
|
|
18
|
+
print_success "ok"
|
|
19
|
+
else
|
|
20
|
+
print_warning "unreachable"
|
|
21
|
+
echo " Is your API server running?"
|
|
22
|
+
((warnings++))
|
|
23
|
+
fi
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# Check frontend connectivity if configured
|
|
27
|
+
local test_url
|
|
28
|
+
test_url=$(get_config '.testUrlBase' "")
|
|
29
|
+
if [[ -n "$test_url" ]]; then
|
|
30
|
+
printf " Frontend connectivity ($test_url)... "
|
|
31
|
+
if curl -sf --connect-timeout 5 "$test_url" >/dev/null 2>&1; then
|
|
32
|
+
print_success "ok"
|
|
33
|
+
else
|
|
34
|
+
print_warning "unreachable"
|
|
35
|
+
echo " Is your frontend dev server running?"
|
|
36
|
+
((warnings++))
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Check for common migration issues in Python projects
|
|
41
|
+
local backend_dir
|
|
42
|
+
backend_dir=$(get_config '.directories.backend' "")
|
|
43
|
+
if [[ -n "$backend_dir" && -d "$backend_dir" ]]; then
|
|
44
|
+
# Check for alembic migrations
|
|
45
|
+
if [[ -d "$backend_dir/alembic" ]] || [[ -d "$backend_dir/migrations" ]]; then
|
|
46
|
+
printf " Database migrations... "
|
|
47
|
+
# Try to verify DB connection via alembic or Django
|
|
48
|
+
if [[ -f "$backend_dir/alembic.ini" ]]; then
|
|
49
|
+
if (cd "$backend_dir" && alembic current >/dev/null 2>&1); then
|
|
50
|
+
print_success "ok"
|
|
51
|
+
else
|
|
52
|
+
print_warning "check DB connection"
|
|
53
|
+
echo " Run: cd $backend_dir && alembic current"
|
|
54
|
+
((warnings++))
|
|
55
|
+
fi
|
|
56
|
+
fi
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Check Docker if docker-compose exists
|
|
61
|
+
for compose_file in "docker-compose.yml" "docker-compose.yaml" "compose.yml"; do
|
|
62
|
+
if [[ -f "$compose_file" ]]; then
|
|
63
|
+
printf " Docker services... "
|
|
64
|
+
if docker compose ps --quiet 2>/dev/null | grep -q .; then
|
|
65
|
+
print_success "running"
|
|
66
|
+
elif docker-compose ps --quiet 2>/dev/null | grep -q .; then
|
|
67
|
+
print_success "running"
|
|
68
|
+
else
|
|
69
|
+
print_warning "not running"
|
|
70
|
+
echo " Run: docker compose up -d"
|
|
71
|
+
((warnings++))
|
|
72
|
+
fi
|
|
73
|
+
break
|
|
74
|
+
fi
|
|
75
|
+
done
|
|
76
|
+
|
|
77
|
+
echo ""
|
|
78
|
+
if [[ $warnings -gt 0 ]]; then
|
|
79
|
+
print_warning "$warnings pre-flight warning(s) - loop may fail on connectivity issues"
|
|
80
|
+
echo ""
|
|
81
|
+
read -r -p "Continue anyway? [Y/n] " response
|
|
82
|
+
if [[ "$response" =~ ^[Nn] ]]; then
|
|
83
|
+
echo "Aborted. Fix the issues and try again."
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
|
|
5
89
|
run_loop() {
|
|
6
90
|
local max_iterations="$DEFAULT_MAX_ITERATIONS"
|
|
7
91
|
local specific_story=""
|
|
@@ -26,6 +110,9 @@ run_loop() {
|
|
|
26
110
|
# Validate prerequisites
|
|
27
111
|
check_dependencies
|
|
28
112
|
|
|
113
|
+
# Pre-flight checks to catch issues before wasting iterations
|
|
114
|
+
preflight_checks
|
|
115
|
+
|
|
29
116
|
if [[ ! -f "$RALPH_DIR/prd.json" ]]; then
|
|
30
117
|
# Check for misplaced PRD in subdirectories
|
|
31
118
|
local found_prd
|
|
@@ -73,7 +160,11 @@ run_loop() {
|
|
|
73
160
|
local iteration=0
|
|
74
161
|
local last_story=""
|
|
75
162
|
local consecutive_failures=0
|
|
76
|
-
local max_story_retries=
|
|
163
|
+
local max_story_retries=5
|
|
164
|
+
local total_attempts=0
|
|
165
|
+
local skipped_stories=()
|
|
166
|
+
local start_time
|
|
167
|
+
start_time=$(date +%s)
|
|
77
168
|
|
|
78
169
|
while [[ $iteration -lt $max_iterations ]]; do
|
|
79
170
|
# Check for stop signal
|
|
@@ -108,19 +199,37 @@ run_loop() {
|
|
|
108
199
|
fi
|
|
109
200
|
|
|
110
201
|
if [[ -z "$story" ]]; then
|
|
202
|
+
print_progress_summary "$start_time" "$total_attempts" "${#skipped_stories[@]}"
|
|
111
203
|
send_notification "✅ Ralph finished: All stories passed!"
|
|
112
204
|
archive_feature
|
|
113
205
|
return 0
|
|
114
206
|
fi
|
|
115
207
|
|
|
208
|
+
((total_attempts++))
|
|
209
|
+
|
|
116
210
|
# Track repeated failures on same story
|
|
117
211
|
if [[ "$story" == "$last_story" ]]; then
|
|
118
212
|
((consecutive_failures++))
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
213
|
+
|
|
214
|
+
# Circuit breaker: skip to next story after max retries
|
|
215
|
+
if [[ $consecutive_failures -gt $max_story_retries ]]; then
|
|
216
|
+
print_error "Circuit breaker: $story failed $max_story_retries times, skipping to next story"
|
|
217
|
+
echo ""
|
|
218
|
+
echo " Saved failure context to: $RALPH_DIR/failures/$story.txt"
|
|
219
|
+
mkdir -p "$RALPH_DIR/failures"
|
|
220
|
+
cp "$RALPH_DIR/last_failure.txt" "$RALPH_DIR/failures/$story.txt" 2>/dev/null || true
|
|
221
|
+
skipped_stories+=("$story")
|
|
222
|
+
# Mark as skipped (not passed, but move on)
|
|
223
|
+
jq --arg id "$story" '(.stories[] | select(.id==$id)) |= . + {skipped: true}' "$RALPH_DIR/prd.json" > "$RALPH_DIR/prd.json.tmp" && mv "$RALPH_DIR/prd.json.tmp" "$RALPH_DIR/prd.json"
|
|
224
|
+
last_story=""
|
|
225
|
+
consecutive_failures=0
|
|
226
|
+
continue
|
|
123
227
|
fi
|
|
228
|
+
|
|
229
|
+
# Exponential backoff before retry
|
|
230
|
+
local backoff=$((2 ** (consecutive_failures - 1)))
|
|
231
|
+
print_warning "Retry $consecutive_failures/$max_story_retries for $story (waiting ${backoff}s...)"
|
|
232
|
+
sleep "$backoff"
|
|
124
233
|
else
|
|
125
234
|
consecutive_failures=1
|
|
126
235
|
last_story="$story"
|
|
@@ -305,9 +414,10 @@ run_loop() {
|
|
|
305
414
|
done
|
|
306
415
|
|
|
307
416
|
print_warning "Max iterations ($max_iterations) reached"
|
|
417
|
+
print_progress_summary "$start_time" "$total_attempts" "${#skipped_stories[@]}"
|
|
308
418
|
local passed failed
|
|
309
419
|
passed=$(jq '[.stories[] | select(.passes==true)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
310
|
-
failed=$(jq '[.stories[] | select(.passes==false)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
420
|
+
failed=$(jq '[.stories[] | select(.passes==false and .skipped!=true)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
311
421
|
send_notification "⚠️ Ralph stopped: $passed passed, $failed remaining (max iterations reached)"
|
|
312
422
|
return 1
|
|
313
423
|
}
|
|
@@ -532,6 +642,39 @@ build_prompt() {
|
|
|
532
642
|
_inject_developer_dna
|
|
533
643
|
}
|
|
534
644
|
|
|
645
|
+
# Print progress summary at end of run
|
|
646
|
+
print_progress_summary() {
|
|
647
|
+
local start_time="$1"
|
|
648
|
+
local total_attempts="$2"
|
|
649
|
+
local skipped_count="$3"
|
|
650
|
+
|
|
651
|
+
local end_time
|
|
652
|
+
end_time=$(date +%s)
|
|
653
|
+
local duration=$((end_time - start_time))
|
|
654
|
+
local hours=$((duration / 3600))
|
|
655
|
+
local minutes=$(((duration % 3600) / 60))
|
|
656
|
+
|
|
657
|
+
local passed failed total
|
|
658
|
+
passed=$(jq '[.stories[] | select(.passes==true)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
659
|
+
failed=$(jq '[.stories[] | select(.passes==false and .skipped!=true)] | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
660
|
+
total=$(jq '.stories | length' "$RALPH_DIR/prd.json" 2>/dev/null || echo "0")
|
|
661
|
+
|
|
662
|
+
echo ""
|
|
663
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
664
|
+
print_success "COMPLETE"
|
|
665
|
+
echo ""
|
|
666
|
+
echo " Stories: $passed/$total passed"
|
|
667
|
+
[[ "$skipped_count" -gt 0 ]] && echo " Skipped: $skipped_count (hit circuit breaker)"
|
|
668
|
+
echo " Attempts: $total_attempts total iterations"
|
|
669
|
+
if [[ $hours -gt 0 ]]; then
|
|
670
|
+
echo " Duration: ${hours}h ${minutes}m"
|
|
671
|
+
else
|
|
672
|
+
echo " Duration: ${minutes}m"
|
|
673
|
+
fi
|
|
674
|
+
echo ""
|
|
675
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
676
|
+
}
|
|
677
|
+
|
|
535
678
|
# Mark feature as complete (keep PRD for appending new stories)
|
|
536
679
|
archive_feature() {
|
|
537
680
|
local feature_name
|
package/ralph/verify/review.sh
CHANGED
|
@@ -78,21 +78,9 @@ Check for these issues:
|
|
|
78
78
|
|
|
79
79
|
## Response Format
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"issues": [
|
|
85
|
-
{
|
|
86
|
-
"severity": "critical|warning|info",
|
|
87
|
-
"category": "security|error-handling|edge-case|quality|performance|scalability|a11y|architecture|compliance",
|
|
88
|
-
"file": "path/to/file",
|
|
89
|
-
"line": 123,
|
|
90
|
-
"message": "Description of the issue",
|
|
91
|
-
"suggestion": "How to fix it"
|
|
92
|
-
}
|
|
93
|
-
],
|
|
94
|
-
"summary": "Brief overall assessment"
|
|
95
|
-
}
|
|
81
|
+
IMPORTANT: Output ONLY raw JSON, no markdown formatting, no code blocks, no explanation.
|
|
82
|
+
|
|
83
|
+
{"pass": true/false, "issues": [{"severity": "critical|warning|info", "category": "security|error-handling|edge-case|quality|performance|scalability|a11y|architecture|compliance", "file": "path/to/file", "line": 123, "message": "Description", "suggestion": "Fix"}], "summary": "Brief assessment"}
|
|
96
84
|
|
|
97
85
|
Only fail (pass: false) for critical or multiple warning-level issues.
|
|
98
86
|
EOF
|