claude-evolve 1.2.14 → 1.3.1
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/bin/claude-evolve-run-parallel +31 -31
- package/bin/claude-evolve-worker +4 -2
- package/lib/config.sh +19 -4
- package/lib/csv-lock.sh +6 -2
- package/package.json +1 -1
|
@@ -44,8 +44,8 @@ fi
|
|
|
44
44
|
# Prepare logging
|
|
45
45
|
mkdir -p logs
|
|
46
46
|
|
|
47
|
-
# Track active workers
|
|
48
|
-
|
|
47
|
+
# Track active workers (using regular array for compatibility)
|
|
48
|
+
worker_pids=()
|
|
49
49
|
consecutive_failures=0
|
|
50
50
|
MAX_FAILURES=10
|
|
51
51
|
rate_limit_hit=false
|
|
@@ -57,7 +57,7 @@ count_pending() {
|
|
|
57
57
|
return
|
|
58
58
|
fi
|
|
59
59
|
|
|
60
|
-
echo "$csv_content" | awk -F',' 'NR>1 && $5 == "pending" { count++ } END { print count+0 }'
|
|
60
|
+
echo "$csv_content" | awk -F',' 'NR>1 && ($5 == "pending" || $5 == "") { count++ } END { print count+0 }'
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
# Start a worker
|
|
@@ -68,7 +68,7 @@ start_worker() {
|
|
|
68
68
|
echo "[DISPATCHER] Starting worker..."
|
|
69
69
|
$worker_cmd &
|
|
70
70
|
local pid=$!
|
|
71
|
-
worker_pids
|
|
71
|
+
worker_pids+=($pid)
|
|
72
72
|
echo "[DISPATCHER] Worker $pid started"
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -100,13 +100,17 @@ handle_worker_exit() {
|
|
|
100
100
|
esac
|
|
101
101
|
|
|
102
102
|
# Remove from tracking
|
|
103
|
-
|
|
103
|
+
local new_pids=()
|
|
104
|
+
for p in "${worker_pids[@]}"; do
|
|
105
|
+
[[ $p != "$pid" ]] && new_pids+=($p)
|
|
106
|
+
done
|
|
107
|
+
worker_pids=("${new_pids[@]}")
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
# Signal handler for graceful shutdown
|
|
107
111
|
shutdown_workers() {
|
|
108
112
|
echo "[DISPATCHER] Shutting down workers..."
|
|
109
|
-
for pid in "${
|
|
113
|
+
for pid in "${worker_pids[@]}"; do
|
|
110
114
|
if kill -0 "$pid" 2>/dev/null; then
|
|
111
115
|
echo "[DISPATCHER] Stopping worker $pid"
|
|
112
116
|
kill -TERM "$pid" 2>/dev/null || true
|
|
@@ -119,15 +123,17 @@ shutdown_workers() {
|
|
|
119
123
|
sleep 1
|
|
120
124
|
((timeout--))
|
|
121
125
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
126
|
+
local new_pids=()
|
|
127
|
+
for pid in "${worker_pids[@]}"; do
|
|
128
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
129
|
+
new_pids+=($pid)
|
|
125
130
|
fi
|
|
126
131
|
done
|
|
132
|
+
worker_pids=("${new_pids[@]}")
|
|
127
133
|
done
|
|
128
134
|
|
|
129
135
|
# Force kill remaining workers
|
|
130
|
-
for pid in "${
|
|
136
|
+
for pid in "${worker_pids[@]}"; do
|
|
131
137
|
if kill -0 "$pid" 2>/dev/null; then
|
|
132
138
|
echo "[DISPATCHER] Force killing worker $pid"
|
|
133
139
|
kill -KILL "$pid" 2>/dev/null || true
|
|
@@ -163,24 +169,18 @@ while true; do
|
|
|
163
169
|
|
|
164
170
|
echo "[DISPATCHER] Status: $pending_count pending, $active_workers active workers"
|
|
165
171
|
|
|
166
|
-
#
|
|
172
|
+
# Debug: Show CSV status if no pending
|
|
173
|
+
if [[ $pending_count -eq 0 ]]; then
|
|
174
|
+
total_rows=$(read_csv_with_lock csv_content && echo "$csv_content" | wc -l | xargs)
|
|
175
|
+
complete_count=$(read_csv_with_lock csv_content && echo "$csv_content" | awk -F',' 'NR>1 && $5 == "complete" { count++ } END { print count+0 }')
|
|
176
|
+
echo "[DISPATCHER] CSV has $((total_rows-1)) total candidates, $complete_count complete"
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# If no pending work and no active workers, we're done
|
|
167
180
|
if [[ $pending_count -eq 0 && $active_workers -eq 0 ]]; then
|
|
168
|
-
echo "[DISPATCHER] No
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if [[ ! -f "$ideate_script" ]]; then
|
|
172
|
-
echo "[DISPATCHER] No ideate script found. Evolution complete."
|
|
173
|
-
break
|
|
174
|
-
fi
|
|
175
|
-
|
|
176
|
-
if ! "$ideate_script"; then
|
|
177
|
-
echo "[ERROR] Failed to generate new ideas" >&2
|
|
178
|
-
break
|
|
179
|
-
fi
|
|
180
|
-
|
|
181
|
-
# Recount after ideation
|
|
182
|
-
pending_count=$(count_pending)
|
|
183
|
-
echo "[DISPATCHER] Generated ideas. New pending count: $pending_count"
|
|
181
|
+
echo "[DISPATCHER] No pending candidates found. Evolution complete."
|
|
182
|
+
echo "[DISPATCHER] Run 'claude-evolve ideate' to generate more candidates."
|
|
183
|
+
break
|
|
184
184
|
fi
|
|
185
185
|
|
|
186
186
|
# Start workers if we have pending work and capacity
|
|
@@ -198,14 +198,14 @@ while true; do
|
|
|
198
198
|
|
|
199
199
|
# Wait for any worker to finish
|
|
200
200
|
if [[ $active_workers -gt 0 ]]; then
|
|
201
|
-
#
|
|
202
|
-
|
|
201
|
+
# Poll for finished workers (macOS compatible)
|
|
202
|
+
sleep 5 # Check every 5 seconds
|
|
203
203
|
|
|
204
204
|
# Check which workers have finished
|
|
205
|
-
for pid in "${
|
|
205
|
+
for pid in "${worker_pids[@]}"; do
|
|
206
206
|
if ! kill -0 "$pid" 2>/dev/null; then
|
|
207
207
|
# Get exit status
|
|
208
|
-
wait "$pid"
|
|
208
|
+
wait "$pid" 2>/dev/null
|
|
209
209
|
exit_code=$?
|
|
210
210
|
handle_worker_exit "$pid" "$exit_code"
|
|
211
211
|
fi
|
package/bin/claude-evolve-worker
CHANGED
|
@@ -187,7 +187,8 @@ eval_exit_code=0
|
|
|
187
187
|
|
|
188
188
|
if [[ -n $timeout_seconds ]]; then
|
|
189
189
|
echo "[WORKER-$$] Evaluation timeout: ${timeout_seconds}s"
|
|
190
|
-
|
|
190
|
+
# For Modal compatibility, don't capture stderr
|
|
191
|
+
if eval_output=$(timeout "$timeout_seconds" "$PYTHON_CMD" "$FULL_EVALUATOR_PATH" "$output_file"); then
|
|
191
192
|
eval_exit_code=0
|
|
192
193
|
else
|
|
193
194
|
eval_exit_code=$?
|
|
@@ -198,7 +199,8 @@ if [[ -n $timeout_seconds ]]; then
|
|
|
198
199
|
fi
|
|
199
200
|
fi
|
|
200
201
|
else
|
|
201
|
-
|
|
202
|
+
# For Modal compatibility, don't capture stderr
|
|
203
|
+
if eval_output=$("$PYTHON_CMD" "$FULL_EVALUATOR_PATH" "$output_file"); then
|
|
202
204
|
eval_exit_code=0
|
|
203
205
|
else
|
|
204
206
|
eval_exit_code=$?
|
package/lib/config.sh
CHANGED
|
@@ -58,14 +58,29 @@ load_config() {
|
|
|
58
58
|
# Simple YAML parsing for key: value pairs and nested structures
|
|
59
59
|
local in_ideation_section=false
|
|
60
60
|
local in_parallel_section=false
|
|
61
|
-
while IFS='
|
|
61
|
+
while IFS='' read -r line; do
|
|
62
62
|
# Skip comments and empty lines
|
|
63
|
-
[[ $
|
|
63
|
+
[[ $line =~ ^[[:space:]]*# ]] || [[ -z $line ]] && continue
|
|
64
|
+
|
|
65
|
+
# Parse key:value from line
|
|
66
|
+
if [[ ! $line =~ ^([^:]+):(.*)$ ]]; then
|
|
67
|
+
continue
|
|
68
|
+
fi
|
|
69
|
+
key="${BASH_REMATCH[1]}"
|
|
70
|
+
value="${BASH_REMATCH[2]}"
|
|
71
|
+
|
|
72
|
+
# Check if key is indented (for nested sections)
|
|
73
|
+
local is_indented=false
|
|
74
|
+
[[ $key =~ ^[[:space:]]+ ]] && is_indented=true
|
|
75
|
+
|
|
64
76
|
|
|
65
77
|
# Remove leading/trailing whitespace
|
|
66
78
|
key=$(echo "$key" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
67
79
|
value=$(echo "$value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
68
80
|
|
|
81
|
+
# Remove inline comments from value
|
|
82
|
+
value=$(echo "$value" | sed 's/[[:space:]]*#.*$//')
|
|
83
|
+
|
|
69
84
|
# Remove quotes from value
|
|
70
85
|
value=$(echo "$value" | sed 's/^"//;s/"$//')
|
|
71
86
|
|
|
@@ -78,8 +93,8 @@ load_config() {
|
|
|
78
93
|
in_parallel_section=true
|
|
79
94
|
in_ideation_section=false
|
|
80
95
|
continue
|
|
81
|
-
elif [[ $
|
|
82
|
-
#
|
|
96
|
+
elif [[ $is_indented == false ]] && [[ $in_ideation_section == true || $in_parallel_section == true ]]; then
|
|
97
|
+
# Non-indented key found while in a section, exit nested sections
|
|
83
98
|
in_ideation_section=false
|
|
84
99
|
in_parallel_section=false
|
|
85
100
|
fi
|
package/lib/csv-lock.sh
CHANGED
|
@@ -135,14 +135,18 @@ find_next_pending_with_lock() {
|
|
|
135
135
|
|
|
136
136
|
# Find oldest pending candidate and update to running
|
|
137
137
|
local candidate=$(awk -F',' '
|
|
138
|
-
NR>1 && $5 == "pending" { print $1; exit }
|
|
138
|
+
NR>1 && ($5 == "pending" || $5 == "") { print $1; exit }
|
|
139
139
|
' "$csv_file")
|
|
140
140
|
|
|
141
141
|
if [ -n "$candidate" ]; then
|
|
142
142
|
# Update status to running while we have the lock
|
|
143
143
|
awk -F',' -v OFS=',' -v id="$candidate" '
|
|
144
144
|
NR==1 || $1 != id { print }
|
|
145
|
-
$1 == id {
|
|
145
|
+
$1 == id {
|
|
146
|
+
# Preserve existing fields but set status to running
|
|
147
|
+
if ($5 == "" || $5 == "pending") $5 = "running"
|
|
148
|
+
print
|
|
149
|
+
}
|
|
146
150
|
' "$csv_file" > "${csv_file}.tmp" && mv -f "${csv_file}.tmp" "$csv_file"
|
|
147
151
|
fi
|
|
148
152
|
|