claude-evolve 1.6.0 → 1.6.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-clean-corrupted +178 -0
- package/bin/claude-evolve-main +21 -14
- package/lib/csv_fixer.py +65 -3
- package/package.json +1 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
# Function to show help
|
|
6
|
+
show_help() {
|
|
7
|
+
cat <<EOF
|
|
8
|
+
claude-evolve clean-corrupted - Remove corrupted records from evolution CSV
|
|
9
|
+
|
|
10
|
+
USAGE:
|
|
11
|
+
claude-evolve clean-corrupted [OPTIONS]
|
|
12
|
+
|
|
13
|
+
OPTIONS:
|
|
14
|
+
--dry-run Show what would be removed without modifying the CSV
|
|
15
|
+
--help Show this help message
|
|
16
|
+
|
|
17
|
+
DESCRIPTION:
|
|
18
|
+
Removes corrupted records with invalid ID formats, such as:
|
|
19
|
+
- IDs with line numbers and pipe characters (e.g., "00648| gen43-001")
|
|
20
|
+
- IDs with leading digits followed by spaces
|
|
21
|
+
- Any ID containing pipe (|) characters
|
|
22
|
+
|
|
23
|
+
Creates a backup before modifying the CSV.
|
|
24
|
+
|
|
25
|
+
EXAMPLES:
|
|
26
|
+
claude-evolve clean-corrupted # Remove corrupted records
|
|
27
|
+
claude-evolve clean-corrupted --dry-run # Preview what would be removed
|
|
28
|
+
EOF
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
# Parse arguments
|
|
32
|
+
DRY_RUN=false
|
|
33
|
+
|
|
34
|
+
while [[ $# -gt 0 ]]; do
|
|
35
|
+
case $1 in
|
|
36
|
+
--dry-run)
|
|
37
|
+
DRY_RUN=true
|
|
38
|
+
shift
|
|
39
|
+
;;
|
|
40
|
+
--help)
|
|
41
|
+
show_help
|
|
42
|
+
exit 0
|
|
43
|
+
;;
|
|
44
|
+
*)
|
|
45
|
+
echo "[ERROR] Unknown option: $1" >&2
|
|
46
|
+
exit 1
|
|
47
|
+
;;
|
|
48
|
+
esac
|
|
49
|
+
done
|
|
50
|
+
|
|
51
|
+
# Load configuration
|
|
52
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
53
|
+
# shellcheck source=../lib/config.sh
|
|
54
|
+
source "$SCRIPT_DIR/../lib/config.sh"
|
|
55
|
+
|
|
56
|
+
# Use CLAUDE_EVOLVE_CONFIG if set, otherwise default
|
|
57
|
+
if [[ -n ${CLAUDE_EVOLVE_CONFIG:-} ]]; then
|
|
58
|
+
load_config "$CLAUDE_EVOLVE_CONFIG"
|
|
59
|
+
else
|
|
60
|
+
# Check if config.yaml exists in current directory
|
|
61
|
+
if [[ -f "config.yaml" ]]; then
|
|
62
|
+
# Don't export to avoid collision with parallel runs
|
|
63
|
+
CONFIG_FILE="$(pwd)/config.yaml"
|
|
64
|
+
load_config "$CONFIG_FILE"
|
|
65
|
+
else
|
|
66
|
+
load_config
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# Validate configuration
|
|
71
|
+
if ! validate_config; then
|
|
72
|
+
echo "[ERROR] Configuration validation failed" >&2
|
|
73
|
+
exit 1
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Check if CSV exists
|
|
77
|
+
if [[ ! -f "$FULL_CSV_PATH" ]]; then
|
|
78
|
+
echo "[ERROR] Evolution CSV not found: $FULL_CSV_PATH" >&2
|
|
79
|
+
echo "Run 'claude-evolve setup' first or navigate to the correct directory" >&2
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
echo "Checking for corrupted records in: $FULL_CSV_PATH"
|
|
84
|
+
|
|
85
|
+
# Use Python to identify and optionally remove corrupted records
|
|
86
|
+
"$PYTHON_CMD" - <<EOF
|
|
87
|
+
import csv
|
|
88
|
+
import sys
|
|
89
|
+
import re
|
|
90
|
+
import shutil
|
|
91
|
+
from datetime import datetime
|
|
92
|
+
|
|
93
|
+
csv_path = "$FULL_CSV_PATH"
|
|
94
|
+
dry_run = $DRY_RUN
|
|
95
|
+
|
|
96
|
+
def is_valid_candidate_id(candidate_id):
|
|
97
|
+
"""Check if a candidate ID is valid."""
|
|
98
|
+
if not candidate_id or candidate_id == "id":
|
|
99
|
+
return True # Header row
|
|
100
|
+
|
|
101
|
+
# Reject IDs containing pipe characters (line number artifacts)
|
|
102
|
+
if '|' in candidate_id:
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
# Valid ID should match: baseline-NNN or genNN-NNN format
|
|
106
|
+
# Also accept special IDs like "000", "0", etc.
|
|
107
|
+
if re.match(r'^(baseline|gen\d{2})-\d{3}$', candidate_id):
|
|
108
|
+
return True
|
|
109
|
+
if re.match(r'^(000|0|gen00-000)$', candidate_id):
|
|
110
|
+
return True
|
|
111
|
+
|
|
112
|
+
# Reject anything with leading digits followed by non-standard format
|
|
113
|
+
if re.match(r'^\d+\s', candidate_id):
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
# Read CSV
|
|
119
|
+
with open(csv_path, 'r') as f:
|
|
120
|
+
reader = csv.reader(f)
|
|
121
|
+
rows = list(reader)
|
|
122
|
+
|
|
123
|
+
# Identify corrupted records
|
|
124
|
+
corrupted_records = []
|
|
125
|
+
valid_rows = [rows[0]] # Keep header
|
|
126
|
+
|
|
127
|
+
for i, row in enumerate(rows[1:], start=1):
|
|
128
|
+
if not row or len(row) == 0:
|
|
129
|
+
continue
|
|
130
|
+
|
|
131
|
+
candidate_id = row[0] if len(row) > 0 else ""
|
|
132
|
+
|
|
133
|
+
if not is_valid_candidate_id(candidate_id):
|
|
134
|
+
corrupted_records.append((i, candidate_id, row))
|
|
135
|
+
else:
|
|
136
|
+
valid_rows.append(row)
|
|
137
|
+
|
|
138
|
+
# Report findings
|
|
139
|
+
total_records = len(rows) - 1 # Exclude header
|
|
140
|
+
corrupted_count = len(corrupted_records)
|
|
141
|
+
|
|
142
|
+
print(f"\\nTotal records: {total_records}")
|
|
143
|
+
print(f"Corrupted records: {corrupted_count}")
|
|
144
|
+
print(f"Valid records: {len(valid_rows) - 1}") # Exclude header
|
|
145
|
+
|
|
146
|
+
if corrupted_count > 0:
|
|
147
|
+
print("\\n🔍 Corrupted records found:")
|
|
148
|
+
for line_num, candidate_id, row in corrupted_records[:20]:
|
|
149
|
+
status = row[4] if len(row) > 4 else "unknown"
|
|
150
|
+
print(f" Line {line_num}: {candidate_id} (status: {status})")
|
|
151
|
+
|
|
152
|
+
if len(corrupted_records) > 20:
|
|
153
|
+
print(f" ... and {len(corrupted_records) - 20} more")
|
|
154
|
+
|
|
155
|
+
if not dry_run:
|
|
156
|
+
# Create backup
|
|
157
|
+
backup_path = f"{csv_path}.backup.{datetime.now().strftime('%Y%m%d-%H%M%S')}"
|
|
158
|
+
shutil.copy2(csv_path, backup_path)
|
|
159
|
+
print(f"\\n✅ Created backup: {backup_path}")
|
|
160
|
+
|
|
161
|
+
# Write cleaned CSV
|
|
162
|
+
with open(csv_path, 'w', newline='') as f:
|
|
163
|
+
writer = csv.writer(f, quoting=csv.QUOTE_NONNUMERIC)
|
|
164
|
+
for row in valid_rows:
|
|
165
|
+
writer.writerow(row)
|
|
166
|
+
|
|
167
|
+
print(f"✅ Removed {corrupted_count} corrupted records from CSV")
|
|
168
|
+
print(f"✅ Cleaned CSV saved to: {csv_path}")
|
|
169
|
+
else:
|
|
170
|
+
print("\\n[DRY RUN] No changes made. Run without --dry-run to remove corrupted records.")
|
|
171
|
+
else:
|
|
172
|
+
print("\\n✅ No corrupted records found!")
|
|
173
|
+
|
|
174
|
+
sys.exit(0)
|
|
175
|
+
EOF
|
|
176
|
+
|
|
177
|
+
echo ""
|
|
178
|
+
echo "Done!"
|
package/bin/claude-evolve-main
CHANGED
|
@@ -66,6 +66,7 @@ COMMANDS:
|
|
|
66
66
|
status Show evolution progress and current leader
|
|
67
67
|
autostatus Auto-updating status display (real-time)
|
|
68
68
|
cleanup Clean up unchanged algorithms and descendants
|
|
69
|
+
clean-corrupted Remove corrupted records from evolution CSV
|
|
69
70
|
cleanup-duplicates Alias for cleanup (deprecated)
|
|
70
71
|
help Show this help message
|
|
71
72
|
|
|
@@ -92,16 +93,17 @@ show_menu() {
|
|
|
92
93
|
echo
|
|
93
94
|
echo "What would you like to do?"
|
|
94
95
|
echo
|
|
95
|
-
echo " 1) setup
|
|
96
|
-
echo " 2) ideate
|
|
97
|
-
echo " 3) run
|
|
98
|
-
echo " 4) analyze
|
|
99
|
-
echo " 5) edit
|
|
100
|
-
echo " 6) status
|
|
101
|
-
echo " 7) autostatus
|
|
102
|
-
echo " 8)
|
|
103
|
-
echo " 9)
|
|
104
|
-
echo "
|
|
96
|
+
echo " 1) setup - Initialize evolution workspace"
|
|
97
|
+
echo " 2) ideate - Generate new algorithm ideas"
|
|
98
|
+
echo " 3) run - Execute evolution candidates"
|
|
99
|
+
echo " 4) analyze - Analyze evolution results"
|
|
100
|
+
echo " 5) edit - Manage candidate statuses by generation"
|
|
101
|
+
echo " 6) status - Show evolution progress and current leader"
|
|
102
|
+
echo " 7) autostatus - Auto-updating status display (real-time)"
|
|
103
|
+
echo " 8) clean-corrupted - Remove corrupted records from CSV"
|
|
104
|
+
echo " 9) config - Manage configuration settings"
|
|
105
|
+
echo " h) help - Show help message"
|
|
106
|
+
echo " 0) exit - Exit"
|
|
105
107
|
echo
|
|
106
108
|
|
|
107
109
|
# Show workspace status
|
|
@@ -152,7 +154,7 @@ check_for_updates
|
|
|
152
154
|
# Main logic
|
|
153
155
|
if [[ $# -eq 0 ]]; then
|
|
154
156
|
show_menu
|
|
155
|
-
read -r -p "Enter your choice (1-9, 0): " choice
|
|
157
|
+
read -r -p "Enter your choice (1-9, h, 0): " choice
|
|
156
158
|
|
|
157
159
|
case $choice in
|
|
158
160
|
1) exec "$SCRIPT_DIR/claude-evolve-setup" ;;
|
|
@@ -162,14 +164,15 @@ if [[ $# -eq 0 ]]; then
|
|
|
162
164
|
5) exec "$SCRIPT_DIR/claude-evolve-edit" ;;
|
|
163
165
|
6) exec "$SCRIPT_DIR/claude-evolve-status" ;;
|
|
164
166
|
7) exec "$SCRIPT_DIR/claude-evolve-autostatus" ;;
|
|
165
|
-
8) exec "$SCRIPT_DIR/claude-evolve-
|
|
166
|
-
9)
|
|
167
|
+
8) exec "$SCRIPT_DIR/claude-evolve-clean-corrupted" ;;
|
|
168
|
+
9) exec "$SCRIPT_DIR/claude-evolve-config" ;;
|
|
169
|
+
h|H) show_help ;;
|
|
167
170
|
0)
|
|
168
171
|
echo "Goodbye!"
|
|
169
172
|
exit 0
|
|
170
173
|
;;
|
|
171
174
|
*)
|
|
172
|
-
echo -e "${RED}Invalid choice. Please select 1-9 or 0.${NC}"
|
|
175
|
+
echo -e "${RED}Invalid choice. Please select 1-9, h, or 0.${NC}"
|
|
173
176
|
exit 1
|
|
174
177
|
;;
|
|
175
178
|
esac
|
|
@@ -214,6 +217,10 @@ cleanup-duplicates|cleanup)
|
|
|
214
217
|
shift
|
|
215
218
|
exec "$SCRIPT_DIR/claude-evolve-cleanup" "$@"
|
|
216
219
|
;;
|
|
220
|
+
clean-corrupted)
|
|
221
|
+
shift
|
|
222
|
+
exec "$SCRIPT_DIR/claude-evolve-clean-corrupted" "$@"
|
|
223
|
+
;;
|
|
217
224
|
config)
|
|
218
225
|
shift
|
|
219
226
|
exec "$SCRIPT_DIR/claude-evolve-config" "$@"
|
package/lib/csv_fixer.py
CHANGED
|
@@ -2,25 +2,87 @@
|
|
|
2
2
|
"""
|
|
3
3
|
CSV format fixer for claude-evolve
|
|
4
4
|
Ensures proper quoting of CSV fields, especially descriptions
|
|
5
|
+
Also filters out corrupted records with invalid ID formats
|
|
5
6
|
"""
|
|
6
7
|
|
|
7
8
|
import csv
|
|
8
9
|
import sys
|
|
10
|
+
import re
|
|
11
|
+
|
|
12
|
+
def is_valid_candidate_id(candidate_id):
|
|
13
|
+
"""
|
|
14
|
+
Check if a candidate ID is valid.
|
|
15
|
+
Valid formats:
|
|
16
|
+
- baseline-000
|
|
17
|
+
- gen00-000
|
|
18
|
+
- gen01-001, gen02-042, etc.
|
|
19
|
+
|
|
20
|
+
Invalid formats (to reject):
|
|
21
|
+
- 00648| gen43-001 (line numbers with pipes)
|
|
22
|
+
- Any ID containing | character
|
|
23
|
+
- Any ID with leading numbers followed by |
|
|
24
|
+
"""
|
|
25
|
+
if not candidate_id or candidate_id == "id":
|
|
26
|
+
return True # Header row
|
|
27
|
+
|
|
28
|
+
# Reject IDs containing pipe characters (line number artifacts)
|
|
29
|
+
if '|' in candidate_id:
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
# Valid ID should match: baseline-NNN or genNN-NNN format
|
|
33
|
+
# Also accept special IDs like "000", "0", etc.
|
|
34
|
+
if re.match(r'^(baseline|gen\d{2})-\d{3}$', candidate_id):
|
|
35
|
+
return True
|
|
36
|
+
if re.match(r'^(000|0|gen00-000)$', candidate_id):
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
# Reject anything with leading digits followed by non-standard format
|
|
40
|
+
if re.match(r'^\d+\s', candidate_id):
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
return True
|
|
9
44
|
|
|
10
45
|
def fix_csv_format(input_file, output_file):
|
|
11
46
|
"""
|
|
12
47
|
Read a CSV file and ensure all fields are properly quoted.
|
|
13
48
|
The csv module handles quoting automatically based on content.
|
|
49
|
+
Also filters out rows with invalid candidate IDs.
|
|
14
50
|
"""
|
|
15
51
|
with open(input_file, 'r') as infile:
|
|
16
52
|
reader = csv.reader(infile)
|
|
17
53
|
rows = list(reader)
|
|
18
|
-
|
|
54
|
+
|
|
55
|
+
rejected_count = 0
|
|
56
|
+
filtered_rows = []
|
|
57
|
+
|
|
58
|
+
for i, row in enumerate(rows):
|
|
59
|
+
# Always keep header
|
|
60
|
+
if i == 0:
|
|
61
|
+
filtered_rows.append(row)
|
|
62
|
+
continue
|
|
63
|
+
|
|
64
|
+
# Skip empty rows
|
|
65
|
+
if not row or len(row) == 0:
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
candidate_id = row[0] if len(row) > 0 else ""
|
|
69
|
+
|
|
70
|
+
# Check if candidate ID is valid
|
|
71
|
+
if not is_valid_candidate_id(candidate_id):
|
|
72
|
+
rejected_count += 1
|
|
73
|
+
print(f"[WARN] Rejecting corrupted record with invalid ID: {candidate_id}", file=sys.stderr)
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
filtered_rows.append(row)
|
|
77
|
+
|
|
78
|
+
if rejected_count > 0:
|
|
79
|
+
print(f"[INFO] Filtered out {rejected_count} corrupted records", file=sys.stderr)
|
|
80
|
+
|
|
19
81
|
with open(output_file, 'w', newline='') as outfile:
|
|
20
82
|
writer = csv.writer(outfile, quoting=csv.QUOTE_NONNUMERIC)
|
|
21
|
-
|
|
83
|
+
|
|
22
84
|
# Write all rows - csv.writer handles quoting automatically
|
|
23
|
-
for row in
|
|
85
|
+
for row in filtered_rows:
|
|
24
86
|
writer.writerow(row)
|
|
25
87
|
|
|
26
88
|
if __name__ == "__main__":
|