claude-evolve 1.5.3 → 1.5.6
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-analyze +36 -12
- package/bin/claude-evolve-autostatus +35 -12
- package/bin/claude-evolve-edit +182 -17
- package/bin/claude-evolve-ideate +130 -40
- package/bin/claude-evolve-migrate-llm-columns +120 -0
- package/bin/claude-evolve-run +71 -1
- package/bin/claude-evolve-setup +1 -1
- package/bin/claude-evolve-status +35 -7
- package/bin/claude-evolve-worker +151 -42
- package/lib/__pycache__/evolution_csv.cpython-311.pyc +0 -0
- package/lib/__pycache__/evolution_csv.cpython-313.pyc +0 -0
- package/lib/ai-cli.sh +45 -14
- package/lib/config.sh +27 -18
- package/lib/csv_fixer.py +35 -0
- package/lib/evolution_csv.py +28 -7
- package/lib/memory_limit_wrapper.py +222 -0
- package/package.json +1 -1
- package/templates/config.yaml +21 -10
|
@@ -513,6 +513,9 @@ print(f'max_desc=\"{desc_escaped}\"')
|
|
|
513
513
|
# Calculate total data points for dynamic sizing
|
|
514
514
|
total_data_points=$(awk 'END {print NR-1}' "$data_file") # Subtract header row
|
|
515
515
|
|
|
516
|
+
# Count unique generations
|
|
517
|
+
unique_generations=$(awk '{if(NR>1) print $4}' "$data_file" | sort -nu | wc -l)
|
|
518
|
+
|
|
516
519
|
# AIDEV-NOTE: Dynamic dot sizing based on data point count
|
|
517
520
|
# Use significantly larger dots when there are fewer data points for better visibility
|
|
518
521
|
if [[ $total_data_points -lt 35 ]]; then
|
|
@@ -530,16 +533,24 @@ print(f'max_desc=\"{desc_escaped}\"')
|
|
|
530
533
|
# Find all generations that have data
|
|
531
534
|
generations=($(awk '{if(NR>1) print $4}' "$data_file" | sort -n | uniq))
|
|
532
535
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
536
|
+
# If too many generations (>10), use a simplified plot without individual generation legends
|
|
537
|
+
if [[ $unique_generations -gt 10 ]]; then
|
|
538
|
+
# Single plot with color gradient based on generation number
|
|
539
|
+
plot_cmd="\"$data_file\" using 1:3:(\$4) with points palette pointsize $regular_dot_size notitle"
|
|
540
|
+
gen_plots_added=1
|
|
541
|
+
else
|
|
542
|
+
# Original plotting with individual generation legends
|
|
543
|
+
for gen_num in "${generations[@]}"; do
|
|
544
|
+
if [[ -n $gen_num ]]; then
|
|
545
|
+
color=$(get_gen_color "$gen_num")
|
|
546
|
+
if [[ $gen_plots_added -gt 0 ]]; then
|
|
547
|
+
plot_cmd="$plot_cmd, \\"$'\n'
|
|
548
|
+
fi
|
|
549
|
+
plot_cmd="${plot_cmd} \"$data_file\" using (\$4==$gen_num?\$1:1/0):3 with points linecolor rgb \"$color\" pointsize $regular_dot_size title \"Gen $gen_num\""
|
|
550
|
+
((gen_plots_added++))
|
|
538
551
|
fi
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
fi
|
|
542
|
-
done
|
|
552
|
+
done
|
|
553
|
+
fi
|
|
543
554
|
|
|
544
555
|
# Add novel candidates
|
|
545
556
|
if [[ -s "$novel_file" ]] && [[ $(wc -l < "$novel_file") -gt 1 ]]; then
|
|
@@ -586,6 +597,9 @@ print(f'max_desc=\"{desc_escaped}\"')
|
|
|
586
597
|
set terminal png size 1200,800
|
|
587
598
|
set output "$output_file"
|
|
588
599
|
|
|
600
|
+
# Define unique generations count
|
|
601
|
+
unique_gens = $unique_generations
|
|
602
|
+
|
|
589
603
|
# Set up multiplot with proper spacing
|
|
590
604
|
set multiplot layout 2,1 margins 0.08,0.82,0.15,0.95 spacing 0.1,0.15
|
|
591
605
|
|
|
@@ -595,7 +609,9 @@ set title "$EVOLUTION_CONTEXT Algorithm Evolution Performance Over Time" font ",
|
|
|
595
609
|
unset xlabel
|
|
596
610
|
set ylabel "Performance Score"
|
|
597
611
|
set grid y # Only show horizontal grid lines
|
|
598
|
-
|
|
612
|
+
|
|
613
|
+
# Show legend only if 10 or fewer generations
|
|
614
|
+
if (unique_gens <= 10) set key outside right; else unset key
|
|
599
615
|
|
|
600
616
|
# AIDEV-NOTE: Remove x-axis entirely to avoid tick problems with large datasets
|
|
601
617
|
unset xtics
|
|
@@ -603,6 +619,9 @@ set autoscale
|
|
|
603
619
|
set yrange [*:*] # Auto-scale y-axis only
|
|
604
620
|
|
|
605
621
|
# Define colors for generations
|
|
622
|
+
# Use palette for many generations
|
|
623
|
+
if (unique_gens > 10) set palette model RGB defined (0 "#1f77b4", 1 "#ff7f0e", 2 "#2ca02c", 3 "#d62728", 4 "#9467bd", 5 "#8c564b", 6 "#e377c2")
|
|
624
|
+
|
|
606
625
|
plot $plot_cmd
|
|
607
626
|
|
|
608
627
|
#=================== BOTTOM PLOT: Generation Medians ===================
|
|
@@ -614,8 +633,13 @@ set boxwidth 0.6
|
|
|
614
633
|
unset key
|
|
615
634
|
set grid y
|
|
616
635
|
|
|
617
|
-
# Set custom x-axis labels
|
|
618
|
-
|
|
636
|
+
# Set custom x-axis labels (but hide if too many generations)
|
|
637
|
+
if (unique_gens > 10) {
|
|
638
|
+
set xtics auto
|
|
639
|
+
set xtics rotate by -45
|
|
640
|
+
} else {
|
|
641
|
+
set xtics ($xtics_labels)
|
|
642
|
+
}
|
|
619
643
|
|
|
620
644
|
# Auto-scale for generation plot too
|
|
621
645
|
set autoscale
|
|
@@ -38,6 +38,7 @@ else
|
|
|
38
38
|
load_config
|
|
39
39
|
fi
|
|
40
40
|
|
|
41
|
+
|
|
41
42
|
# Run the Python autostatus script
|
|
42
43
|
exec "$PYTHON_CMD" -c '
|
|
43
44
|
import os
|
|
@@ -118,9 +119,27 @@ class AutoStatus:
|
|
|
118
119
|
"working_dir": os.path.dirname(self.csv_path)
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
# Helpers
|
|
123
|
+
def parse_candidate_id(cid):
|
|
124
|
+
"""Return (gen_num, seq_num) for ids like gen123-045; fall back to large numbers."""
|
|
125
|
+
try:
|
|
126
|
+
left, right = cid.split("-", 1)
|
|
127
|
+
gen_num = int(left[3:]) if left.startswith("gen") else 10**9
|
|
128
|
+
seq_num = int(right)
|
|
129
|
+
return gen_num, seq_num
|
|
130
|
+
except Exception:
|
|
131
|
+
return 10**9, 10**9
|
|
132
|
+
|
|
133
|
+
def is_earlier(cid_a, cid_b):
|
|
134
|
+
"""True if cid_a is earlier than cid_b by generation, then sequence."""
|
|
135
|
+
ga, sa = parse_candidate_id(cid_a)
|
|
136
|
+
gb, sb = parse_candidate_id(cid_b)
|
|
137
|
+
return (ga, sa) < (gb, sb)
|
|
138
|
+
|
|
139
|
+
|
|
121
140
|
# Process candidates by generation
|
|
122
|
-
all_candidates = []
|
|
123
141
|
stats_by_gen = {}
|
|
142
|
+
leader = None # Track overall leader with earliest-wins tie behavior
|
|
124
143
|
|
|
125
144
|
for row in rows[1:]: # Skip header
|
|
126
145
|
if len(row) >= 1 and row[0]: # Must have an ID
|
|
@@ -157,20 +176,24 @@ class AutoStatus:
|
|
|
157
176
|
description = row[2] if len(row) > 2 else "No description"
|
|
158
177
|
candidate_info = (candidate_id, description, score)
|
|
159
178
|
stats_by_gen[gen]["candidates"].append(candidate_info)
|
|
160
|
-
|
|
179
|
+
|
|
180
|
+
# Update overall leader: highest raw score; ties -> earliest ID
|
|
181
|
+
if leader is None or score > leader[2] or (score == leader[2] and is_earlier(candidate_id, leader[0])):
|
|
182
|
+
leader = candidate_info
|
|
183
|
+
|
|
184
|
+
# Update generation best: highest raw score; ties -> earliest ID
|
|
185
|
+
if "best" not in stats_by_gen[gen]:
|
|
186
|
+
stats_by_gen[gen]["best"] = candidate_info
|
|
187
|
+
else:
|
|
188
|
+
best_id, _, best_score = stats_by_gen[gen]["best"]
|
|
189
|
+
if score > best_score or (score == best_score and is_earlier(candidate_id, best_id)):
|
|
190
|
+
stats_by_gen[gen]["best"] = candidate_info
|
|
161
191
|
except ValueError:
|
|
162
192
|
pass
|
|
163
193
|
|
|
164
|
-
#
|
|
165
|
-
leader = None
|
|
166
|
-
if all_candidates:
|
|
167
|
-
leader = max(all_candidates, key=lambda x: x[2])
|
|
168
|
-
|
|
169
|
-
# Find best performer in each generation
|
|
194
|
+
# Ensure every generation has a best field
|
|
170
195
|
for gen in stats_by_gen:
|
|
171
|
-
if stats_by_gen[gen]
|
|
172
|
-
stats_by_gen[gen]["best"] = max(stats_by_gen[gen]["candidates"], key=lambda x: x[2])
|
|
173
|
-
else:
|
|
196
|
+
if "best" not in stats_by_gen[gen]:
|
|
174
197
|
stats_by_gen[gen]["best"] = None
|
|
175
198
|
|
|
176
199
|
return {
|
|
@@ -344,4 +367,4 @@ class AutoStatus:
|
|
|
344
367
|
csv_path = "'"$FULL_CSV_PATH"'"
|
|
345
368
|
auto_status = AutoStatus(csv_path)
|
|
346
369
|
auto_status.run()
|
|
347
|
-
'
|
|
370
|
+
'
|
package/bin/claude-evolve-edit
CHANGED
|
@@ -20,7 +20,10 @@ show_help() {
|
|
|
20
20
|
claude-evolve edit - Manage evolution candidate statuses by generation or status
|
|
21
21
|
|
|
22
22
|
USAGE:
|
|
23
|
-
claude-evolve edit <selector> <action>
|
|
23
|
+
claude-evolve edit [--recent-generations=N] <selector> <action>
|
|
24
|
+
|
|
25
|
+
OPTIONS:
|
|
26
|
+
--recent-generations=N Limit operations to the most recent N generations only
|
|
24
27
|
|
|
25
28
|
SELECTORS:
|
|
26
29
|
gen01, gen02, etc. Target specific generation
|
|
@@ -41,29 +44,56 @@ ACTIONS:
|
|
|
41
44
|
delete Delete candidates from CSV and remove .py files (asks confirmation)
|
|
42
45
|
|
|
43
46
|
EXAMPLES:
|
|
44
|
-
claude-evolve edit gen03 failed
|
|
45
|
-
claude-evolve edit failed pending
|
|
46
|
-
claude-evolve edit
|
|
47
|
-
claude-evolve edit complete failed
|
|
48
|
-
claude-evolve edit
|
|
49
|
-
claude-evolve edit
|
|
50
|
-
claude-evolve edit
|
|
47
|
+
claude-evolve edit gen03 failed # Mark all gen03 as failed
|
|
48
|
+
claude-evolve edit failed pending # Reset all failed candidates to pending
|
|
49
|
+
claude-evolve edit --recent-generations=15 failed pending # Reset only recent 15 gen failures
|
|
50
|
+
claude-evolve edit --recent-generations=5 complete failed # Re-run recent 5 gen completions
|
|
51
|
+
claude-evolve edit failed failed-retry1 # Convert failed to retry status (bug fixing)
|
|
52
|
+
claude-evolve edit complete failed # Mark all complete as failed for re-run
|
|
53
|
+
claude-evolve edit all pending # Mark everything as pending for re-run
|
|
54
|
+
claude-evolve edit gen02 reboot # Full reset of gen02 (delete files + clear data)
|
|
55
|
+
claude-evolve edit gen02 delete # Delete gen02 from CSV and remove .py files
|
|
51
56
|
|
|
52
57
|
DESCRIPTION:
|
|
53
58
|
This command helps manage evolution runs when you need to re-evaluate candidates.
|
|
54
59
|
Use status selectors (failed, complete, etc.) to bulk-change candidates by status.
|
|
55
60
|
Use 'reboot' for complete reset including file deletion.
|
|
61
|
+
Use --recent-generations to limit operations to recent work only, useful for large systems.
|
|
56
62
|
EOF
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
# Parse arguments
|
|
60
|
-
|
|
66
|
+
recent_generations=""
|
|
67
|
+
args=()
|
|
68
|
+
|
|
69
|
+
while [[ $# -gt 0 ]]; do
|
|
70
|
+
case "$1" in
|
|
71
|
+
--recent-generations=*)
|
|
72
|
+
recent_generations="${1#*=}"
|
|
73
|
+
if [[ ! "$recent_generations" =~ ^[1-9][0-9]*$ ]]; then
|
|
74
|
+
echo "[ERROR] --recent-generations must be a positive integer" >&2
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
shift
|
|
78
|
+
;;
|
|
79
|
+
--help|-h)
|
|
80
|
+
show_help
|
|
81
|
+
exit 0
|
|
82
|
+
;;
|
|
83
|
+
*)
|
|
84
|
+
args+=("$1")
|
|
85
|
+
shift
|
|
86
|
+
;;
|
|
87
|
+
esac
|
|
88
|
+
done
|
|
89
|
+
|
|
90
|
+
if [[ ${#args[@]} -ne 2 ]]; then
|
|
61
91
|
show_help
|
|
62
92
|
exit 1
|
|
63
93
|
fi
|
|
64
94
|
|
|
65
|
-
SELECTOR="$
|
|
66
|
-
ACTION="$
|
|
95
|
+
SELECTOR="${args[0]}"
|
|
96
|
+
ACTION="${args[1]}"
|
|
67
97
|
|
|
68
98
|
# Validate configuration
|
|
69
99
|
if ! validate_config; then
|
|
@@ -99,7 +129,11 @@ update_candidates_status() {
|
|
|
99
129
|
local new_status="$2"
|
|
100
130
|
local clear_scores="$3"
|
|
101
131
|
|
|
102
|
-
|
|
132
|
+
local filter_msg=""
|
|
133
|
+
if [[ -n "$recent_generations" ]]; then
|
|
134
|
+
filter_msg=" (limited to recent $recent_generations generations)"
|
|
135
|
+
fi
|
|
136
|
+
echo "[INFO] Updating candidates matching '$selector' to status: $new_status${filter_msg}"
|
|
103
137
|
|
|
104
138
|
# Use Python to safely edit the CSV
|
|
105
139
|
"$PYTHON_CMD" -c "
|
|
@@ -112,6 +146,7 @@ csv_file = '$FULL_CSV_PATH'
|
|
|
112
146
|
selector = '$selector'
|
|
113
147
|
new_status = '$new_status'
|
|
114
148
|
clear_scores = '$clear_scores' == 'true'
|
|
149
|
+
recent_generations = '$recent_generations'
|
|
115
150
|
|
|
116
151
|
|
|
117
152
|
try:
|
|
@@ -127,6 +162,31 @@ try:
|
|
|
127
162
|
header = rows[0]
|
|
128
163
|
updated_count = 0
|
|
129
164
|
|
|
165
|
+
# If recent_generations is specified, determine which generations to include
|
|
166
|
+
recent_gen_set = set()
|
|
167
|
+
if recent_generations and recent_generations.isdigit():
|
|
168
|
+
n_recent = int(recent_generations)
|
|
169
|
+
|
|
170
|
+
# Find all generation numbers from candidate IDs
|
|
171
|
+
all_generations = set()
|
|
172
|
+
for i in range(1, len(rows)):
|
|
173
|
+
row = rows[i]
|
|
174
|
+
if len(row) < 1:
|
|
175
|
+
continue
|
|
176
|
+
candidate_id = row[0]
|
|
177
|
+
|
|
178
|
+
# Extract generation number from candidate_id (e.g., gen01-001 -> 1)
|
|
179
|
+
match = re.match(r'^gen(\d+)-', candidate_id)
|
|
180
|
+
if match:
|
|
181
|
+
gen_num = int(match.group(1))
|
|
182
|
+
all_generations.add(gen_num)
|
|
183
|
+
|
|
184
|
+
# Get the most recent N generations
|
|
185
|
+
if all_generations:
|
|
186
|
+
sorted_generations = sorted(all_generations, reverse=True)
|
|
187
|
+
recent_gen_set = set(sorted_generations[:n_recent])
|
|
188
|
+
print(f'[INFO] Filtering to recent generations: {sorted(recent_gen_set)}', file=sys.stderr)
|
|
189
|
+
|
|
130
190
|
# Update matching rows
|
|
131
191
|
for i in range(1, len(rows)):
|
|
132
192
|
row = rows[i]
|
|
@@ -152,6 +212,18 @@ try:
|
|
|
152
212
|
else:
|
|
153
213
|
matches = current_status == selector
|
|
154
214
|
|
|
215
|
+
# Apply recent generations filter if specified
|
|
216
|
+
if matches and recent_gen_set:
|
|
217
|
+
# Extract generation number from candidate_id
|
|
218
|
+
gen_match = re.match(r'^gen(\d+)-', candidate_id)
|
|
219
|
+
if gen_match:
|
|
220
|
+
candidate_gen = int(gen_match.group(1))
|
|
221
|
+
if candidate_gen not in recent_gen_set:
|
|
222
|
+
matches = False # Filter out this candidate
|
|
223
|
+
else:
|
|
224
|
+
# Non-generation candidates (like baseline) - exclude when filtering by recent generations
|
|
225
|
+
matches = False
|
|
226
|
+
|
|
155
227
|
if matches:
|
|
156
228
|
if clear_scores:
|
|
157
229
|
# Clear everything after description (keep id, basedOnId, description)
|
|
@@ -192,6 +264,12 @@ delete_evolution_files() {
|
|
|
192
264
|
return
|
|
193
265
|
fi
|
|
194
266
|
|
|
267
|
+
local filter_msg=""
|
|
268
|
+
if [[ -n "$recent_generations" ]]; then
|
|
269
|
+
filter_msg=" (limited to recent $recent_generations generations)"
|
|
270
|
+
fi
|
|
271
|
+
echo "[INFO] Deleting evolution files for '$selector'${filter_msg}..."
|
|
272
|
+
|
|
195
273
|
local deleted_count=0
|
|
196
274
|
|
|
197
275
|
if [[ "$selector" == "all" ]]; then
|
|
@@ -225,15 +303,46 @@ import re
|
|
|
225
303
|
|
|
226
304
|
csv_file = '$FULL_CSV_PATH'
|
|
227
305
|
selector = '$selector'
|
|
306
|
+
recent_generations = '$recent_generations'
|
|
228
307
|
|
|
229
308
|
|
|
230
309
|
try:
|
|
231
310
|
with open(csv_file, 'r') as f:
|
|
232
311
|
reader = csv.reader(f)
|
|
233
|
-
|
|
312
|
+
rows = list(reader)
|
|
313
|
+
|
|
314
|
+
if not rows:
|
|
315
|
+
print('')
|
|
316
|
+
sys.exit(0)
|
|
317
|
+
|
|
318
|
+
# Skip header if present
|
|
319
|
+
start_idx = 1 if rows and rows[0] and rows[0][0].lower() == 'id' else 0
|
|
320
|
+
|
|
321
|
+
# Determine recent generations if filtering is requested
|
|
322
|
+
recent_gen_set = set()
|
|
323
|
+
if recent_generations and recent_generations.isdigit():
|
|
324
|
+
n_recent = int(recent_generations)
|
|
325
|
+
|
|
326
|
+
# Find all generation numbers from candidate IDs
|
|
327
|
+
all_generations = set()
|
|
328
|
+
for row in rows[start_idx:]:
|
|
329
|
+
if len(row) < 1:
|
|
330
|
+
continue
|
|
331
|
+
candidate_id = row[0]
|
|
332
|
+
|
|
333
|
+
# Extract generation number from candidate_id (e.g., gen01-001 -> 1)
|
|
334
|
+
match = re.match(r'^gen(\d+)-', candidate_id)
|
|
335
|
+
if match:
|
|
336
|
+
gen_num = int(match.group(1))
|
|
337
|
+
all_generations.add(gen_num)
|
|
338
|
+
|
|
339
|
+
# Get the most recent N generations
|
|
340
|
+
if all_generations:
|
|
341
|
+
sorted_generations = sorted(all_generations, reverse=True)
|
|
342
|
+
recent_gen_set = set(sorted_generations[:n_recent])
|
|
234
343
|
|
|
235
344
|
candidates = []
|
|
236
|
-
for row in
|
|
345
|
+
for row in rows[start_idx:]:
|
|
237
346
|
if len(row) < 1:
|
|
238
347
|
continue
|
|
239
348
|
|
|
@@ -249,6 +358,18 @@ try:
|
|
|
249
358
|
else:
|
|
250
359
|
matches = current_status == selector
|
|
251
360
|
|
|
361
|
+
# Apply recent generations filter if specified
|
|
362
|
+
if matches and recent_gen_set:
|
|
363
|
+
# Extract generation number from candidate_id
|
|
364
|
+
gen_match = re.match(r'^gen(\d+)-', candidate_id)
|
|
365
|
+
if gen_match:
|
|
366
|
+
candidate_gen = int(gen_match.group(1))
|
|
367
|
+
if candidate_gen not in recent_gen_set:
|
|
368
|
+
matches = False # Filter out this candidate
|
|
369
|
+
else:
|
|
370
|
+
# Non-generation candidates (like baseline) - exclude when filtering by recent generations
|
|
371
|
+
matches = False
|
|
372
|
+
|
|
252
373
|
if matches:
|
|
253
374
|
candidates.append(candidate_id)
|
|
254
375
|
|
|
@@ -284,7 +405,11 @@ except Exception as e:
|
|
|
284
405
|
delete_candidates_from_csv() {
|
|
285
406
|
local selector="$1"
|
|
286
407
|
|
|
287
|
-
|
|
408
|
+
local filter_msg=""
|
|
409
|
+
if [[ -n "$recent_generations" ]]; then
|
|
410
|
+
filter_msg=" (limited to recent $recent_generations generations)"
|
|
411
|
+
fi
|
|
412
|
+
echo "[INFO] Deleting candidates matching '$selector' from CSV${filter_msg}..."
|
|
288
413
|
|
|
289
414
|
"$PYTHON_CMD" -c "
|
|
290
415
|
import sys
|
|
@@ -293,6 +418,7 @@ from lib.evolution_csv import EvolutionCSV
|
|
|
293
418
|
import re
|
|
294
419
|
|
|
295
420
|
selector = '$selector'
|
|
421
|
+
recent_generations = '$recent_generations'
|
|
296
422
|
deleted_count = 0
|
|
297
423
|
|
|
298
424
|
with EvolutionCSV('$FULL_CSV_PATH') as csv:
|
|
@@ -306,6 +432,29 @@ with EvolutionCSV('$FULL_CSV_PATH') as csv:
|
|
|
306
432
|
has_header = rows and rows[0] and rows[0][0].lower() == 'id'
|
|
307
433
|
start_idx = 1 if has_header else 0
|
|
308
434
|
|
|
435
|
+
# Determine recent generations if filtering is requested
|
|
436
|
+
recent_gen_set = set()
|
|
437
|
+
if recent_generations and recent_generations.isdigit():
|
|
438
|
+
n_recent = int(recent_generations)
|
|
439
|
+
|
|
440
|
+
# Find all generation numbers from candidate IDs
|
|
441
|
+
all_generations = set()
|
|
442
|
+
for row in rows[start_idx:]:
|
|
443
|
+
if not row or not row[0].strip():
|
|
444
|
+
continue
|
|
445
|
+
candidate_id = row[0].strip()
|
|
446
|
+
|
|
447
|
+
# Extract generation number from candidate_id (e.g., gen01-001 -> 1)
|
|
448
|
+
match = re.match(r'^gen(\d+)-', candidate_id)
|
|
449
|
+
if match:
|
|
450
|
+
gen_num = int(match.group(1))
|
|
451
|
+
all_generations.add(gen_num)
|
|
452
|
+
|
|
453
|
+
# Get the most recent N generations
|
|
454
|
+
if all_generations:
|
|
455
|
+
sorted_generations = sorted(all_generations, reverse=True)
|
|
456
|
+
recent_gen_set = set(sorted_generations[:n_recent])
|
|
457
|
+
|
|
309
458
|
for row in rows[start_idx:]:
|
|
310
459
|
if not row or not row[0].strip():
|
|
311
460
|
continue
|
|
@@ -327,6 +476,18 @@ with EvolutionCSV('$FULL_CSV_PATH') as csv:
|
|
|
327
476
|
else:
|
|
328
477
|
matches = current_status == selector
|
|
329
478
|
|
|
479
|
+
# Apply recent generations filter if specified
|
|
480
|
+
if matches and recent_gen_set:
|
|
481
|
+
# Extract generation number from candidate_id
|
|
482
|
+
gen_match = re.match(r'^gen(\d+)-', candidate_id)
|
|
483
|
+
if gen_match:
|
|
484
|
+
candidate_gen = int(gen_match.group(1))
|
|
485
|
+
if candidate_gen not in recent_gen_set:
|
|
486
|
+
matches = False # Filter out this candidate
|
|
487
|
+
else:
|
|
488
|
+
# Non-generation candidates (like baseline) - exclude when filtering by recent generations
|
|
489
|
+
matches = False
|
|
490
|
+
|
|
330
491
|
if matches:
|
|
331
492
|
candidates_to_delete.append(candidate_id)
|
|
332
493
|
|
|
@@ -341,7 +502,11 @@ with EvolutionCSV('$FULL_CSV_PATH') as csv:
|
|
|
341
502
|
}
|
|
342
503
|
|
|
343
504
|
# Main execution
|
|
344
|
-
|
|
505
|
+
info_msg="Processing '$SELECTOR' with action: $ACTION"
|
|
506
|
+
if [[ -n "$recent_generations" ]]; then
|
|
507
|
+
info_msg="$info_msg (limited to recent $recent_generations generations)"
|
|
508
|
+
fi
|
|
509
|
+
echo "[INFO] $info_msg"
|
|
345
510
|
|
|
346
511
|
case "$ACTION" in
|
|
347
512
|
failed)
|
|
@@ -387,4 +552,4 @@ echo "[INFO] Edit operation complete"
|
|
|
387
552
|
|
|
388
553
|
# Call status command to show current state
|
|
389
554
|
echo ""
|
|
390
|
-
"$SCRIPT_DIR/claude-evolve-status" --brief
|
|
555
|
+
"$SCRIPT_DIR/claude-evolve-status" --brief
|