claude-evolve 1.8.13 → 1.8.14
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-ideate +1 -1
- package/bin/claude-evolve-run +87 -68
- package/bin/claude-evolve-worker +1 -1
- package/package.json +1 -1
package/bin/claude-evolve-ideate
CHANGED
|
@@ -1641,7 +1641,7 @@ echo "[INFO] Starting ideation for generation $CURRENT_GENERATION"
|
|
|
1641
1641
|
# Main execution with retry logic and exponential backoff
|
|
1642
1642
|
retry_count=0
|
|
1643
1643
|
wait_seconds=300 # Start with 5 minutes
|
|
1644
|
-
max_wait_seconds=
|
|
1644
|
+
max_wait_seconds=300 # Cap at 5 minutes
|
|
1645
1645
|
|
|
1646
1646
|
while true; do
|
|
1647
1647
|
if [[ $use_strategies == true ]]; then
|
package/bin/claude-evolve-run
CHANGED
|
@@ -275,29 +275,34 @@ count_pending_candidates() {
|
|
|
275
275
|
# Function to get CSV stats
|
|
276
276
|
get_csv_stats() {
|
|
277
277
|
local csv_path="${1:-$FULL_CSV_PATH}"
|
|
278
|
-
|
|
278
|
+
|
|
279
279
|
if [[ ! -f "$csv_path" ]]; then
|
|
280
280
|
echo "[ERROR] CSV not found at: $csv_path" >&2
|
|
281
281
|
echo "0 0 0"
|
|
282
282
|
return
|
|
283
283
|
fi
|
|
284
|
-
|
|
284
|
+
|
|
285
285
|
local total_rows complete_count pending_count
|
|
286
286
|
total_rows=$(wc -l < "$csv_path" | tr -d '[:space:]')
|
|
287
287
|
complete_count=$(grep ',complete' "$csv_path" 2>/dev/null | wc -l | tr -d '[:space:]')
|
|
288
|
-
|
|
288
|
+
|
|
289
289
|
# Count pending using UNIFIED CSV logic
|
|
290
290
|
pending_count=$("$PYTHON_CMD" "$SCRIPT_DIR/../lib/evolution_csv.py" "$csv_path" count)
|
|
291
|
-
|
|
291
|
+
|
|
292
292
|
echo "$total_rows $complete_count $pending_count"
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
|
|
296
|
-
|
|
295
|
+
# Function to perform full CSV cleanup (duplicates, stuck statuses, missing files, etc.)
|
|
296
|
+
cleanup_csv_full() {
|
|
297
|
+
if [[ ! -f "$FULL_CSV_PATH" ]]; then
|
|
298
|
+
echo "[DISPATCHER] No CSV file to clean up" >&2
|
|
299
|
+
return 0
|
|
300
|
+
fi
|
|
301
|
+
|
|
302
|
+
echo "[DISPATCHER] Performing full CSV cleanup..." >&2
|
|
297
303
|
|
|
298
|
-
#
|
|
299
|
-
|
|
300
|
-
echo "[DISPATCHER] Checking for duplicate candidates..."
|
|
304
|
+
# Remove duplicate candidates
|
|
305
|
+
echo "[DISPATCHER] Checking for duplicate candidates..." >&2
|
|
301
306
|
"$PYTHON_CMD" -c "
|
|
302
307
|
import sys
|
|
303
308
|
sys.path.insert(0, '$SCRIPT_DIR/..')
|
|
@@ -312,53 +317,49 @@ except Exception as e:
|
|
|
312
317
|
print(f'[ERROR] Failed to remove duplicates: {e}', file=sys.stderr)
|
|
313
318
|
" 2>&1 || true
|
|
314
319
|
|
|
315
|
-
|
|
320
|
+
# Reset stuck 'running' candidates
|
|
321
|
+
echo "[DISPATCHER] Resetting any stuck 'running' candidates to 'pending'..." >&2
|
|
316
322
|
if "$SCRIPT_DIR/claude-evolve-edit" running pending >/dev/null 2>&1; then
|
|
317
|
-
echo "[DISPATCHER] Successfully reset stuck candidates"
|
|
323
|
+
echo "[DISPATCHER] Successfully reset stuck candidates" >&2
|
|
318
324
|
else
|
|
319
|
-
echo "[DISPATCHER] No stuck candidates found or edit command not available"
|
|
325
|
+
echo "[DISPATCHER] No stuck candidates found or edit command not available" >&2
|
|
320
326
|
fi
|
|
321
|
-
fi
|
|
322
327
|
|
|
323
|
-
#
|
|
324
|
-
|
|
325
|
-
echo "[DISPATCHER] Validating CSV and cleaning up..."
|
|
326
|
-
|
|
327
|
-
# First check for and clean up duplicates
|
|
328
|
-
echo "[DISPATCHER] Checking for duplicate entries..."
|
|
328
|
+
# Clean up duplicates with the dedicated cleanup script
|
|
329
|
+
echo "[DISPATCHER] Checking for duplicate entries..." >&2
|
|
329
330
|
duplicate_check_output=$("$PYTHON_CMD" "$SCRIPT_DIR/claude-evolve-cleanup-duplicates" "$FULL_CSV_PATH" 2>&1)
|
|
330
331
|
if echo "$duplicate_check_output" | grep -q "Found.*duplicate"; then
|
|
331
|
-
echo "[DISPATCHER] WARNING: Duplicate entries detected in CSV!"
|
|
332
|
-
echo "$duplicate_check_output"
|
|
333
|
-
echo "[DISPATCHER] Automatically cleaning up duplicates..."
|
|
332
|
+
echo "[DISPATCHER] WARNING: Duplicate entries detected in CSV!" >&2
|
|
333
|
+
echo "$duplicate_check_output" >&2
|
|
334
|
+
echo "[DISPATCHER] Automatically cleaning up duplicates..." >&2
|
|
334
335
|
if "$PYTHON_CMD" "$SCRIPT_DIR/claude-evolve-cleanup-duplicates" "$FULL_CSV_PATH" --fix; then
|
|
335
|
-
echo "[DISPATCHER] Duplicates cleaned up successfully"
|
|
336
|
+
echo "[DISPATCHER] Duplicates cleaned up successfully" >&2
|
|
336
337
|
else
|
|
337
338
|
echo "[ERROR] Failed to clean up duplicates" >&2
|
|
338
|
-
|
|
339
|
+
return 1
|
|
339
340
|
fi
|
|
340
341
|
else
|
|
341
|
-
echo "[DISPATCHER] No duplicates found"
|
|
342
|
+
echo "[DISPATCHER] No duplicates found" >&2
|
|
342
343
|
fi
|
|
343
|
-
|
|
344
|
-
#
|
|
345
|
-
echo "[DISPATCHER] Checking for invalid entries..."
|
|
344
|
+
|
|
345
|
+
# Clean up invalid entries
|
|
346
|
+
echo "[DISPATCHER] Checking for invalid entries..." >&2
|
|
346
347
|
invalid_check_output=$("$PYTHON_CMD" "$SCRIPT_DIR/claude-evolve-clean-invalid" "$FULL_CSV_PATH" --dry-run 2>&1)
|
|
347
348
|
if echo "$invalid_check_output" | grep -q "Found.*invalid"; then
|
|
348
|
-
echo "[DISPATCHER] WARNING: Invalid entries detected in CSV!"
|
|
349
|
-
echo "$invalid_check_output"
|
|
350
|
-
echo "[DISPATCHER] Automatically cleaning up invalid entries..."
|
|
349
|
+
echo "[DISPATCHER] WARNING: Invalid entries detected in CSV!" >&2
|
|
350
|
+
echo "$invalid_check_output" >&2
|
|
351
|
+
echo "[DISPATCHER] Automatically cleaning up invalid entries..." >&2
|
|
351
352
|
if "$PYTHON_CMD" "$SCRIPT_DIR/claude-evolve-clean-invalid" "$FULL_CSV_PATH"; then
|
|
352
|
-
echo "[DISPATCHER] Invalid entries cleaned up successfully"
|
|
353
|
+
echo "[DISPATCHER] Invalid entries cleaned up successfully" >&2
|
|
353
354
|
else
|
|
354
355
|
echo "[ERROR] Failed to clean up invalid entries" >&2
|
|
355
|
-
|
|
356
|
+
return 1
|
|
356
357
|
fi
|
|
357
358
|
else
|
|
358
|
-
echo "[DISPATCHER] No invalid entries found"
|
|
359
|
+
echo "[DISPATCHER] No invalid entries found" >&2
|
|
359
360
|
fi
|
|
360
|
-
|
|
361
|
-
#
|
|
361
|
+
|
|
362
|
+
# Clean stuck statuses and missing files
|
|
362
363
|
if ! "$PYTHON_CMD" -c "
|
|
363
364
|
import csv
|
|
364
365
|
import sys
|
|
@@ -366,90 +367,88 @@ import os
|
|
|
366
367
|
from pathlib import Path
|
|
367
368
|
|
|
368
369
|
csv_file = '$FULL_CSV_PATH'
|
|
369
|
-
full_output_dir = '$FULL_OUTPUT_DIR'
|
|
370
|
-
script_dir = '$SCRIPT_DIR'
|
|
370
|
+
full_output_dir = '$FULL_OUTPUT_DIR'
|
|
371
|
+
script_dir = '$SCRIPT_DIR'
|
|
371
372
|
|
|
372
373
|
try:
|
|
373
|
-
# Read CSV - let Python's csv module handle all the complexity
|
|
374
374
|
with open(csv_file, 'r') as f:
|
|
375
375
|
reader = csv.reader(f)
|
|
376
376
|
rows = list(reader)
|
|
377
|
-
|
|
377
|
+
|
|
378
378
|
if not rows:
|
|
379
379
|
print('[ERROR] CSV is empty')
|
|
380
380
|
sys.exit(1)
|
|
381
|
-
|
|
382
|
-
# Basic sanity checks
|
|
383
|
-
header = rows[0]
|
|
384
|
-
num_fields = len(header)
|
|
385
|
-
|
|
381
|
+
|
|
386
382
|
if len(rows) == 1:
|
|
387
383
|
print('[INFO] CSV has no data rows (only header)')
|
|
388
|
-
|
|
384
|
+
|
|
389
385
|
changed_count = 0
|
|
390
|
-
|
|
386
|
+
|
|
391
387
|
# Clean up any stuck 'running' statuses
|
|
392
388
|
for i in range(1, len(rows)):
|
|
393
389
|
if len(rows[i]) > 4 and rows[i][4] == 'running':
|
|
394
390
|
rows[i][4] = ''
|
|
395
391
|
changed_count += 1
|
|
396
392
|
|
|
397
|
-
# Reset failed-parent-missing to pending
|
|
393
|
+
# Reset failed-parent-missing to pending - give them another chance
|
|
398
394
|
for i in range(1, len(rows)):
|
|
399
395
|
if len(rows[i]) > 4 and rows[i][4] == 'failed-parent-missing':
|
|
400
396
|
rows[i][4] = 'pending'
|
|
401
397
|
changed_count += 1
|
|
402
|
-
|
|
398
|
+
|
|
403
399
|
# Check for missing Python files for completed/failed candidates
|
|
404
400
|
for i in range(1, len(rows)):
|
|
405
401
|
if len(rows[i]) > 4:
|
|
406
402
|
candidate_id = rows[i][0]
|
|
407
403
|
status = rows[i][4]
|
|
408
|
-
|
|
409
|
-
# Only check if status implies a file should exist
|
|
404
|
+
|
|
410
405
|
if status in ['complete', 'failed', 'failed-ai-retry', 'failed-retry1', 'failed-retry2', 'failed-retry3']:
|
|
411
406
|
expected_file = Path(full_output_dir) / f'evolution_{candidate_id}.py'
|
|
412
407
|
if not expected_file.is_file():
|
|
413
408
|
print(f'[INFO] Detected missing file for {candidate_id} (status: {status}). Resetting to pending.')
|
|
414
|
-
rows[i][4] = 'pending'
|
|
415
|
-
|
|
416
|
-
if len(rows[i]) >
|
|
417
|
-
if len(rows[i]) > 5: rows[i][5] = '' # LLM used for run
|
|
409
|
+
rows[i][4] = 'pending'
|
|
410
|
+
if len(rows[i]) > 3: rows[i][3] = ''
|
|
411
|
+
if len(rows[i]) > 5: rows[i][5] = ''
|
|
418
412
|
changed_count += 1
|
|
419
|
-
|
|
413
|
+
|
|
420
414
|
if changed_count > 0:
|
|
421
|
-
# Write back
|
|
422
415
|
with open(csv_file + '.tmp', 'w', newline='') as f:
|
|
423
416
|
writer = csv.writer(f)
|
|
424
417
|
writer.writerows(rows)
|
|
425
418
|
os.rename(csv_file + '.tmp', csv_file)
|
|
426
419
|
print(f'[INFO] Reset {changed_count} candidates (stuck running or missing files) to pending')
|
|
427
|
-
|
|
428
|
-
# Count pending candidates using UNIFIED logic
|
|
420
|
+
|
|
429
421
|
sys.path.append(script_dir + '/..')
|
|
430
422
|
from lib.evolution_csv import EvolutionCSV
|
|
431
|
-
|
|
423
|
+
|
|
432
424
|
with EvolutionCSV(csv_file) as csv_ops:
|
|
433
|
-
# Auto-fix any corrupted status fields before counting
|
|
434
425
|
fixed = csv_ops.cleanup_corrupted_status_fields()
|
|
435
426
|
if fixed > 0:
|
|
436
427
|
print(f'[INFO] Auto-fixed {fixed} corrupted status field(s)', file=sys.stderr)
|
|
437
428
|
pending = csv_ops.count_pending_candidates()
|
|
438
429
|
|
|
439
430
|
print(f'[INFO] CSV loaded: {len(rows)-1} total candidates, {pending} pending')
|
|
440
|
-
|
|
431
|
+
|
|
441
432
|
except csv.Error as e:
|
|
442
433
|
print(f'[ERROR] CSV parsing error: {e}')
|
|
443
|
-
print('[ERROR] The CSV file appears to be malformed')
|
|
444
434
|
sys.exit(1)
|
|
445
435
|
except Exception as e:
|
|
446
436
|
print(f'[ERROR] Failed to read CSV: {e}')
|
|
447
437
|
sys.exit(1)
|
|
448
438
|
" 2>&1; then
|
|
449
|
-
echo "[ERROR] CSV validation failed
|
|
450
|
-
|
|
439
|
+
echo "[ERROR] CSV validation failed during cleanup" >&2
|
|
440
|
+
return 1
|
|
451
441
|
fi
|
|
452
|
-
|
|
442
|
+
|
|
443
|
+
echo "[DISPATCHER] Full CSV cleanup complete" >&2
|
|
444
|
+
return 0
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
echo "[DISPATCHER] Starting unified evolution engine"
|
|
448
|
+
echo "[DISPATCHER] Configuration: max_workers=$MAX_WORKERS, timeout=${timeout_seconds:-none}"
|
|
449
|
+
|
|
450
|
+
# Perform full CSV cleanup at startup
|
|
451
|
+
cleanup_csv_full || exit 1
|
|
453
452
|
|
|
454
453
|
# Automatic cleanup detection - check for unchanged algorithms and warn user
|
|
455
454
|
echo "[DISPATCHER] Checking for duplicate/unchanged algorithms..."
|
|
@@ -585,8 +584,28 @@ while true; do
|
|
|
585
584
|
|
|
586
585
|
# Check if API limit was reached
|
|
587
586
|
if [[ "$api_limit_reached" == "true" ]]; then
|
|
588
|
-
echo "[DISPATCHER]
|
|
589
|
-
|
|
587
|
+
echo "[DISPATCHER] All AI models hit usage limits" >&2
|
|
588
|
+
echo "[DISPATCHER] Waiting 5 minutes before restarting the run process..." >&2
|
|
589
|
+
|
|
590
|
+
# Wait 5 minutes with countdown
|
|
591
|
+
remaining=300
|
|
592
|
+
while [[ $remaining -gt 0 ]]; do
|
|
593
|
+
if [[ $((remaining % 60)) -eq 0 ]]; then
|
|
594
|
+
echo "[DISPATCHER] Restarting in $((remaining / 60)) minutes..." >&2
|
|
595
|
+
fi
|
|
596
|
+
sleep 60
|
|
597
|
+
remaining=$((remaining - 60))
|
|
598
|
+
done
|
|
599
|
+
|
|
600
|
+
echo "[DISPATCHER] Restarting run process to clear stuck states and retry..." >&2
|
|
601
|
+
# Perform full CSV cleanup to reset stuck states, just like at startup
|
|
602
|
+
cleanup_csv_full || {
|
|
603
|
+
echo "[ERROR] CSV cleanup failed after API limit wait" >&2
|
|
604
|
+
# Continue anyway - better to try than to stop completely
|
|
605
|
+
}
|
|
606
|
+
# Clear the flag and continue - this restarts the main loop
|
|
607
|
+
api_limit_reached=false
|
|
608
|
+
continue
|
|
590
609
|
fi
|
|
591
610
|
|
|
592
611
|
# Periodic cleanup of stuck candidates (every 5 iterations, ~25 seconds)
|
package/bin/claude-evolve-worker
CHANGED
|
@@ -104,7 +104,7 @@ call_ai_for_evolution() {
|
|
|
104
104
|
local retry_count=0
|
|
105
105
|
local max_retries=3
|
|
106
106
|
local wait_seconds=300 # Start with 5 minutes
|
|
107
|
-
local max_wait_seconds=
|
|
107
|
+
local max_wait_seconds=300 # Cap at 5 minutes
|
|
108
108
|
|
|
109
109
|
while true; do
|
|
110
110
|
# Capture file state before AI call
|