claude-evolve 1.3.10 → 1.3.12
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 +53 -10
- package/bin/claude-evolve-worker +27 -17
- package/lib/config.sh +13 -7
- package/lib/csv-lock.sh +54 -25
- package/package.json +1 -1
|
@@ -63,7 +63,18 @@ count_pending() {
|
|
|
63
63
|
return
|
|
64
64
|
fi
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
# Use Python for proper CSV parsing with quoted fields
|
|
67
|
+
echo "$csv_content" | "$PYTHON_CMD" -c "
|
|
68
|
+
import csv
|
|
69
|
+
import sys
|
|
70
|
+
reader = csv.reader(sys.stdin)
|
|
71
|
+
next(reader) # Skip header
|
|
72
|
+
count = 0
|
|
73
|
+
for row in reader:
|
|
74
|
+
if len(row) >= 5 and (row[4] == 'pending' or row[4] == ''):
|
|
75
|
+
count += 1
|
|
76
|
+
print(count)
|
|
77
|
+
"
|
|
67
78
|
}
|
|
68
79
|
|
|
69
80
|
# Start a worker
|
|
@@ -198,20 +209,42 @@ trap 'echo "[DISPATCHER] Exiting with code $?" >&2' EXIT
|
|
|
198
209
|
# Check for stuck "running" candidates from previous runs
|
|
199
210
|
check_stuck_candidates() {
|
|
200
211
|
if read_csv_with_lock csv_content; then
|
|
201
|
-
local stuck_count=$(echo "$csv_content" |
|
|
212
|
+
local stuck_count=$(echo "$csv_content" | "$PYTHON_CMD" -c "
|
|
213
|
+
import csv
|
|
214
|
+
import sys
|
|
215
|
+
reader = csv.reader(sys.stdin)
|
|
216
|
+
next(reader) # Skip header
|
|
217
|
+
count = 0
|
|
218
|
+
for row in reader:
|
|
219
|
+
if len(row) >= 5 and row[4] == 'running':
|
|
220
|
+
count += 1
|
|
221
|
+
print(count)
|
|
222
|
+
")
|
|
202
223
|
if [[ $stuck_count -gt 0 ]]; then
|
|
203
224
|
echo "[DISPATCHER] Found $stuck_count candidates stuck in 'running' status"
|
|
204
225
|
echo "[DISPATCHER] Resetting them to 'pending' for retry..."
|
|
205
226
|
|
|
206
227
|
# Reset stuck candidates
|
|
207
228
|
if acquire_csv_lock; then
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
229
|
+
"$PYTHON_CMD" -c "
|
|
230
|
+
import csv
|
|
231
|
+
import sys
|
|
232
|
+
|
|
233
|
+
# Read CSV
|
|
234
|
+
with open('$FULL_CSV_PATH', 'r') as f:
|
|
235
|
+
reader = csv.reader(f)
|
|
236
|
+
rows = list(reader)
|
|
237
|
+
|
|
238
|
+
# Reset running to pending
|
|
239
|
+
for i in range(1, len(rows)):
|
|
240
|
+
if len(rows[i]) >= 5 and rows[i][4] == 'running':
|
|
241
|
+
rows[i][4] = 'pending'
|
|
242
|
+
|
|
243
|
+
# Write back
|
|
244
|
+
with open('${FULL_CSV_PATH}.tmp', 'w', newline='') as f:
|
|
245
|
+
writer = csv.writer(f)
|
|
246
|
+
writer.writerows(rows)
|
|
247
|
+
" && mv -f "${FULL_CSV_PATH}.tmp" "$FULL_CSV_PATH"
|
|
215
248
|
release_csv_lock
|
|
216
249
|
fi
|
|
217
250
|
fi
|
|
@@ -247,7 +280,17 @@ while true; do
|
|
|
247
280
|
# Debug: Show CSV status if no pending
|
|
248
281
|
if [[ $pending_count -eq 0 ]]; then
|
|
249
282
|
total_rows=$(read_csv_with_lock csv_content && echo "$csv_content" | wc -l | xargs)
|
|
250
|
-
complete_count=$(read_csv_with_lock csv_content && echo "$csv_content" |
|
|
283
|
+
complete_count=$(read_csv_with_lock csv_content && echo "$csv_content" | "$PYTHON_CMD" -c "
|
|
284
|
+
import csv
|
|
285
|
+
import sys
|
|
286
|
+
reader = csv.reader(sys.stdin)
|
|
287
|
+
next(reader) # Skip header
|
|
288
|
+
count = 0
|
|
289
|
+
for row in reader:
|
|
290
|
+
if len(row) >= 5 and row[4] == 'complete':
|
|
291
|
+
count += 1
|
|
292
|
+
print(count)
|
|
293
|
+
")
|
|
251
294
|
echo "[DISPATCHER] CSV has $((total_rows-1)) total candidates, $complete_count complete"
|
|
252
295
|
fi
|
|
253
296
|
|
package/bin/claude-evolve-worker
CHANGED
|
@@ -74,29 +74,39 @@ if ! read_csv_with_lock csv_content; then
|
|
|
74
74
|
exit 1
|
|
75
75
|
fi
|
|
76
76
|
|
|
77
|
-
# Extract candidate data
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
77
|
+
# Extract candidate data using Python
|
|
78
|
+
eval "$("$PYTHON_CMD" -c "
|
|
79
|
+
import csv
|
|
80
|
+
import sys
|
|
81
|
+
import io
|
|
82
|
+
|
|
83
|
+
csv_content = '''$csv_content'''
|
|
84
|
+
reader = csv.reader(io.StringIO(csv_content))
|
|
85
|
+
next(reader) # Skip header
|
|
86
|
+
|
|
87
|
+
found = False
|
|
88
|
+
for row in reader:
|
|
89
|
+
if len(row) >= 5 and row[0] == '$candidate_id':
|
|
90
|
+
# Escape special characters for shell
|
|
91
|
+
desc = row[2].replace('\\\\', '\\\\\\\\').replace('\"', '\\\\\"').replace('\$', '\\\\\$').replace('\`', '\\\\\`')
|
|
92
|
+
print(f'id=\"{row[0]}\"')
|
|
93
|
+
print(f'based_on_id=\"{row[1]}\"')
|
|
94
|
+
print(f'description=\"{desc}\"')
|
|
95
|
+
print(f'performance=\"{row[3]}\"')
|
|
96
|
+
print(f'status=\"{row[4]}\"')
|
|
97
|
+
print('found=true')
|
|
98
|
+
found = True
|
|
99
|
+
break
|
|
100
|
+
|
|
101
|
+
if not found:
|
|
102
|
+
print('found=false')
|
|
103
|
+
")"
|
|
90
104
|
|
|
91
105
|
if [[ $found == false ]]; then
|
|
92
106
|
echo "[ERROR] Candidate ID not found: $candidate_id" >&2
|
|
93
107
|
exit 1
|
|
94
108
|
fi
|
|
95
109
|
|
|
96
|
-
# Clean up description
|
|
97
|
-
description=${description#\"}
|
|
98
|
-
description=${description%\"}
|
|
99
|
-
|
|
100
110
|
echo "[WORKER-$$] Description: $description"
|
|
101
111
|
echo "[WORKER-$$] Based on ID: $based_on_id"
|
|
102
112
|
|
package/lib/config.sh
CHANGED
|
@@ -150,16 +150,22 @@ load_config() {
|
|
|
150
150
|
fi
|
|
151
151
|
|
|
152
152
|
# Create full paths - ALL paths are relative to evolution_dir
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
# Make evolution_dir absolute if it's relative
|
|
154
|
+
if [[ "$EVOLUTION_DIR" = /* ]]; then
|
|
155
|
+
FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
|
|
156
|
+
else
|
|
157
|
+
FULL_EVOLUTION_DIR="$(cd "$EVOLUTION_DIR" 2>/dev/null && pwd)" || FULL_EVOLUTION_DIR="$EVOLUTION_DIR"
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
FULL_ALGORITHM_PATH="$FULL_EVOLUTION_DIR/$ALGORITHM_FILE"
|
|
161
|
+
FULL_EVALUATOR_PATH="$FULL_EVOLUTION_DIR/$EVALUATOR_FILE"
|
|
162
|
+
FULL_BRIEF_PATH="$FULL_EVOLUTION_DIR/$BRIEF_FILE"
|
|
163
|
+
FULL_CSV_PATH="$FULL_EVOLUTION_DIR/$EVOLUTION_CSV"
|
|
158
164
|
|
|
159
165
|
if [[ -n $OUTPUT_DIR ]]; then
|
|
160
|
-
FULL_OUTPUT_DIR="$
|
|
166
|
+
FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR/$OUTPUT_DIR"
|
|
161
167
|
else
|
|
162
|
-
FULL_OUTPUT_DIR="$
|
|
168
|
+
FULL_OUTPUT_DIR="$FULL_EVOLUTION_DIR"
|
|
163
169
|
fi
|
|
164
170
|
}
|
|
165
171
|
|
package/lib/csv-lock.sh
CHANGED
|
@@ -94,19 +94,19 @@ update_csv_row_with_lock() {
|
|
|
94
94
|
local target_id="$1"
|
|
95
95
|
local field="$2"
|
|
96
96
|
local value="$3"
|
|
97
|
-
local csv_file="${EVOLUTION_DIR:-evolution}/evolution.csv"
|
|
97
|
+
local csv_file="${FULL_CSV_PATH:-${EVOLUTION_DIR:-evolution}/evolution.csv}"
|
|
98
98
|
|
|
99
99
|
if ! acquire_csv_lock; then
|
|
100
100
|
return 1
|
|
101
101
|
fi
|
|
102
102
|
|
|
103
|
-
# Determine field position
|
|
103
|
+
# Determine field position (0-based for Python)
|
|
104
104
|
local field_pos
|
|
105
105
|
case "$field" in
|
|
106
|
-
"status") field_pos=
|
|
107
|
-
"performance") field_pos=
|
|
108
|
-
"description") field_pos=
|
|
109
|
-
"basedOnId") field_pos=
|
|
106
|
+
"status") field_pos=4 ;;
|
|
107
|
+
"performance") field_pos=3 ;;
|
|
108
|
+
"description") field_pos=2 ;;
|
|
109
|
+
"basedOnId") field_pos=1 ;;
|
|
110
110
|
*)
|
|
111
111
|
echo "ERROR: Unknown field: $field" >&2
|
|
112
112
|
release_csv_lock
|
|
@@ -114,11 +114,27 @@ update_csv_row_with_lock() {
|
|
|
114
114
|
;;
|
|
115
115
|
esac
|
|
116
116
|
|
|
117
|
-
# Update CSV using
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
# Update CSV using Python
|
|
118
|
+
"$PYTHON_CMD" -c "
|
|
119
|
+
import csv
|
|
120
|
+
import sys
|
|
121
|
+
|
|
122
|
+
# Read CSV
|
|
123
|
+
with open('$csv_file', 'r') as f:
|
|
124
|
+
reader = csv.reader(f)
|
|
125
|
+
rows = list(reader)
|
|
126
|
+
|
|
127
|
+
# Update the specific field
|
|
128
|
+
for i in range(1, len(rows)):
|
|
129
|
+
if rows[i][0] == '$target_id':
|
|
130
|
+
rows[i][$field_pos] = '$value'
|
|
131
|
+
break
|
|
132
|
+
|
|
133
|
+
# Write back
|
|
134
|
+
with open('${csv_file}.tmp', 'w', newline='') as f:
|
|
135
|
+
writer = csv.writer(f)
|
|
136
|
+
writer.writerows(rows)
|
|
137
|
+
" && mv -f "${csv_file}.tmp" "$csv_file"
|
|
122
138
|
|
|
123
139
|
release_csv_lock
|
|
124
140
|
return 0
|
|
@@ -127,27 +143,40 @@ update_csv_row_with_lock() {
|
|
|
127
143
|
# Find next pending candidate with lock
|
|
128
144
|
# Usage: next_pending=$(find_next_pending_with_lock)
|
|
129
145
|
find_next_pending_with_lock() {
|
|
130
|
-
local csv_file="${EVOLUTION_DIR:-evolution}/evolution.csv"
|
|
146
|
+
local csv_file="${FULL_CSV_PATH:-${EVOLUTION_DIR:-evolution}/evolution.csv}"
|
|
131
147
|
|
|
132
148
|
if ! acquire_csv_lock; then
|
|
133
149
|
return 1
|
|
134
150
|
fi
|
|
135
151
|
|
|
136
|
-
# Find oldest pending candidate and update to running
|
|
137
|
-
local candidate=$(
|
|
138
|
-
|
|
139
|
-
|
|
152
|
+
# Find oldest pending candidate and update to running using Python
|
|
153
|
+
local candidate=$("$PYTHON_CMD" -c "
|
|
154
|
+
import csv
|
|
155
|
+
import sys
|
|
156
|
+
|
|
157
|
+
# Read CSV
|
|
158
|
+
with open('$csv_file', 'r') as f:
|
|
159
|
+
reader = csv.reader(f)
|
|
160
|
+
rows = list(reader)
|
|
161
|
+
|
|
162
|
+
# Find first pending candidate
|
|
163
|
+
candidate_id = None
|
|
164
|
+
for i in range(1, len(rows)):
|
|
165
|
+
if len(rows[i]) >= 5 and (rows[i][4] == 'pending' or rows[i][4] == ''):
|
|
166
|
+
candidate_id = rows[i][0]
|
|
167
|
+
rows[i][4] = 'running' # Update status
|
|
168
|
+
break
|
|
169
|
+
|
|
170
|
+
# Write back if we found a candidate
|
|
171
|
+
if candidate_id:
|
|
172
|
+
with open('${csv_file}.tmp', 'w', newline='') as f:
|
|
173
|
+
writer = csv.writer(f)
|
|
174
|
+
writer.writerows(rows)
|
|
175
|
+
print(candidate_id)
|
|
176
|
+
")
|
|
140
177
|
|
|
141
178
|
if [ -n "$candidate" ]; then
|
|
142
|
-
|
|
143
|
-
awk -F',' -v OFS=',' -v id="$candidate" '
|
|
144
|
-
NR==1 || $1 != id { print }
|
|
145
|
-
$1 == id {
|
|
146
|
-
# Preserve existing fields but set status to running
|
|
147
|
-
if ($5 == "" || $5 == "pending") $5 = "running"
|
|
148
|
-
print
|
|
149
|
-
}
|
|
150
|
-
' "$csv_file" > "${csv_file}.tmp" && mv -f "${csv_file}.tmp" "$csv_file"
|
|
179
|
+
mv -f "${csv_file}.tmp" "$csv_file"
|
|
151
180
|
fi
|
|
152
181
|
|
|
153
182
|
release_csv_lock
|