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.
@@ -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=1800 # Cap at 30 minutes
1644
+ max_wait_seconds=300 # Cap at 5 minutes
1645
1645
 
1646
1646
  while true; do
1647
1647
  if [[ $use_strategies == true ]]; then
@@ -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
- echo "[DISPATCHER] Starting unified evolution engine"
296
- echo "[DISPATCHER] Configuration: max_workers=$MAX_WORKERS, timeout=${timeout_seconds:-none}"
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
- # Clean up any stuck 'running' statuses and duplicates at startup
299
- if [[ -f "$FULL_CSV_PATH" ]]; then
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
- echo "[DISPATCHER] Resetting any stuck 'running' candidates to 'pending'..."
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
- # Validate CSV and clean up stuck statuses and duplicates
324
- if [[ -f "$FULL_CSV_PATH" ]]; then
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
- exit 1
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
- # Check for and clean up invalid entries
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
- exit 1
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
- # Then validate and clean stuck statuses
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' # Pass FULL_OUTPUT_DIR to Python script
370
- script_dir = '$SCRIPT_DIR' # Pass SCRIPT_DIR for sys.path.append
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 at startup - give them another chance
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' # Reset status to pending
415
- # Clear performance and other fields if desired, for a clean retry
416
- if len(rows[i]) > 3: rows[i][3] = '' # Performance
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. Please check the error message above."
450
- exit 1
439
+ echo "[ERROR] CSV validation failed during cleanup" >&2
440
+ return 1
451
441
  fi
452
- fi
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] Stopping evolution run due to API usage limits" >&2
589
- break
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)
@@ -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=1800 # Cap at 30 minutes
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-evolve",
3
- "version": "1.8.13",
3
+ "version": "1.8.14",
4
4
  "bin": {
5
5
  "claude-evolve": "./bin/claude-evolve",
6
6
  "claude-evolve-main": "./bin/claude-evolve-main",